Проби
Існує три види проб, які можна застосувати у маніфесті пода:
- liveness;
- readiness;
- startup.
Liveness Probe
Це проба, яка дозволяє зрозуміти, чи додаток всередині пода все ще працює. Якщо проба завершується не успішно, то контейнер перезапуститься згідно з його restart policy. Ця проба дозволяє розв'язати проблеми deadlocks та інші, які призводять до перебоїв у роботі додатка.
У пробі можливо перевірити:
- статус виконання баш команди та задати саму команду;
- статус виконання HTTP-виклику;
- TCP Socket (kubelet спробує відкрити сокет до контейнера по заданому порту).
💡 Про інші перевірки можеш почитати у «Define a gRPC liveness probe».
На практиці ж найчастіше ми будемо використовувати якийсь ендпоінт в API нашого додатка, який Kubernetes буде викликати з певною періодичністю. Якщо відповіді з цього ендпоінту не буде або вона буде не очікуваного статусу, тоді kubelet прийме рішення перезапустити под. Liveness-проба викликається протягом усього життя контейнера.
Readiness Probe
Ця проба використовується, щоб визначити чи под готовий приймати трафік. Поки контейнер NotReady, на нього не буде йти трафік з сервісів (про них ми поговоримо у наступній темі ). Завдяки Readiness-пробі ми можемо бути впевненими у тому, що трафік буде йти лише на ті поди, які готові його приймати та що ми не втратимо дані через це. Тут також можна налаштувати різні типи цієї проби, та на практиці найчастіше це теж ендпоінт який буде викликати Kubernetes.
Startup Probe
Остання проба — це Startup, яка використовується, щоб перевірити чи додаток в середині контейнера вже запустився. Якщо в додатку є Startup-проба, то вона автоматично відключає дві інші проби, допоки Startup не буде закінчуватись успішно. Ця проба потрібна тим додаткам, яким потрібно більше часу для того, щоб запуститись і почати працювати.
Приклад
Тепер перейдемо до практики. Далі ми модифікуємо наш маніфест і допишемо туди Readiness і Liveness проби. І також додамо відповідні ендпоінти до нашого коду на Python. Для початку додамо Liveness Probe:
apiVersion: v1
kind: Pod
metadata:
name: kube2py
labels:
app: kube2py
spec:
containers:
- name: kube2py
image: kulyk404/kub2py
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
Додана секція livenessProbe містить наступні поля:
httpGet— метод проби;/health— шлях для виконанняhttpGet-виклику;8080— порт, на який будемо робити виклик;60— початкова затримка, після якої починають відправлятись запити (у секундах);5— інтервали між відправленням запитів (у секундах).
Тепер зробимо те ж саме для Readiness Probe:
apiVersion: v1
kind: Pod
metadata:
name: kube2py
labels:
app: kube2py
spec:
containers:
- name: kube2py
image: kulyk404/kub2py
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 60
periodSeconds: 5
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
Додана секція readinessProbe містить:
httpGet— метод проби;/ready— шлях для виконанняhttpGet-виклику;8080— порт, на який будемо слати запит;5— початкова затримка, після якої починають відправлятись запити (у секундах);5— інтервали між відправленням запитів (у секундах).
Додамо два ендпоінти /health та /ready:
from flask import Flask, Response, send_file
import os
import time
app = Flask(__name__)
start_time = time.time()
# Define the startup period (in seconds)
startup_period = 40
@app.route('/')
def hello():
return f'''
Docker is Awesome!
<pre> ## .</pre>
<pre> ## ## ## ==</pre>
<pre> ## ## ## ## ===</pre>
<pre> /""""""""""""""""\___/ ===</pre>
<pre> ~~~ (~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===-- ~~~</pre>
<pre> \______ o __/</pre>
<pre> \ \ __/</pre>
<pre> \____\______/</pre>
'''
@app.route('/logo')
def docker_logo():
return send_file('docker-logo.png', mimetype='image/png')
@app.route('/health')
def health_check():
return Response("Healthy", status=200)
@app.route('/ready')
def readiness_check():
# You can add logic here to determine if the app is ready. For simplicity, we'll just return 200.
if time.time() < start_time + startup_period:
# Application is not ready, return a non-200 status code
return Response("Not Ready", status=503)
else:
# Application is ready, return 200
return Response("Ready", status=200)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
Для health як Response вертатиметься Healthy і статус 200:
Для ready встановлений таймер:
Якщо додаток не готовий, то статус-код 503 вертатиметься як Response:
@app.route('/ready')
def readiness_check():
# You can add logic here to determine if the app is ready. For simplicity, we'll just return 200.
if time.time() < start_time + startup_period:
# Application is not ready, return a non-200 status code
return Response("Not Ready", status=503)
else:
# Application is ready, return 200
return Response("Ready", status=200)
Тепер видалимо наш старий под і створимо новий. Але для початку потрібно повторити збілдити імедж, тегнути, залити, і вже тоді створювати новий:
docker build . -t ikulyk404/kub2py:1.1.0
docker push ikulyk404/kub2py:1.1.0
kubectl delete pod kube2py -n mateapp
kubectl apply -f app-pod.yml
pod/kube2py created
Перевіримо всі поди:
kubectl get pods -n mateapp
NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 189 7d21h
kube2py 0/1 Running 0 76s
nginx 1/1 Running 0 7d21h
Под створився, але контейнер у ньому ще не Ready — це якраз через ту затримку яку ми виставили для Readiness-проби. Глянемо логи:
kubectl logs kube2py -n mateapp
* Serving Flask app 'app'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:8080
* Running on http://10.1.0.11:8080
Press CTRL+C to quit
10.1.0.1 - - [30/Jan/2024 10:07:14] "GET /ready HTTP/1.1" 503 -
10.1.0.1 - - [30/Jan/2024 10:07:19] "GET /ready HTTP/1.1" 503 -
10.1.0.1 - - [30/Jan/2024 10:07:24] "GET /ready HTTP/1.1" 503 -
10.1.0.1 - - [30/Jan/2024 10:07:29] "GET /ready HTTP/1.1" 503 -
10.1.0.1 - - [30/Jan/2024 10:07:34] "GET /ready HTTP/1.1" 503 -
10.1.0.1 - - [30/Jan/2024 10:07:39] "GET /ready HTTP/1.1" 503 -
10.1.0.1 - - [30/Jan/2024 10:07:44] "GET /ready HTTP/1.1" 503 -
10.1.0.1 - - [30/Jan/2024 10:07:49] "GET /ready HTTP/1.1" 200 -
10.1.0.1 - - [30/Jan/2024 10:07:54] "GET /ready HTTP/1.1" 200 -
kubelet зробив сім невдалих запитів перед тим, як наша логіка почала повертати успішні статуси.
Ще одна важлива команда — це kubectl get events -A. Вона показує івенти у неймспейсі, а прапорець -A каже, що це команда для усіх неймспейсів:
kubectl get events -n mateapp
2m4s Normal Created pod/kube2py Created container kube2py
2m4s Normal Started pod/kube2py Started container kube2py
88s Warning Unhealthy pod/kube2py Readiness probe failed: HTTP probe failed with statuscode: 503
Перевіримо чи все працює за допомогою port-forward:
kubectl port-forward pod/kube2py 8081:8080 -n mateapp
Forwarding from 127.0.0.1:8081 -> 8080
Forwarding from [::1]:8081 -> 8080
