Облачная экосистема - Евгений Сергеевич Штольц 17 стр.


Node-Selectors: < none>

Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s

node.kubernetes.io/unreachable:NoExecute for 300s

Events:

Type Reason Age From Message

Normal Scheduled 3m44s default-scheduler Successfully assigned default/liveness to node01

Normal Pulled 68s (x3 over 3m35s) kubelet, node01 Container image "alpine:3.5" already present on machine

Normal Created 68s (x3 over 3m35s) kubelet, node01 Created container healtcheck

Normal Started 68s (x3 over 3m34s) kubelet, node01 Started container healtcheck

Warning Unhealthy 23s (x9 over 3m3s) kubelet, node01 Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory

Normal Killing 23s (x3 over 2m53s) kubelet, node01 Container healtcheck failed liveness probe, will be restarted

Также мы видим и на событиях кластера, что когда cat /tmp/health терпит неудачу контейнере пересоздаётся:

controlplane $ kubectl get events


controlplane $ kubectl get events | grep pod/liveness

13m Normal Scheduled pod/liveness Successfully assigned default/liveness to node01

13m Normal Pulling pod/liveness Pulling image "alpine:3.5"

13m Normal Pulled pod/liveness Successfully pulled image "alpine:3.5"

10m Normal Created pod/liveness Created container healtcheck

10m Normal Started pod/liveness Started container healtcheck

10m Warning Unhealthy pod/liveness Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory

10m Normal Killing pod/liveness Container healtcheck failed liveness probe, will be restarted

10m Normal Pulled pod/liveness Container image "alpine:3.5" already present on machine

8m32s Normal Scheduled pod/liveness Successfully assigned default/liveness to node01

4m41s Normal Pulled pod/liveness Container image "alpine:3.5" already present on machine

4m41s Normal Created pod/liveness Created container healtcheck

4m41s Normal Started pod/liveness Started container healtcheck

2m51s Warning Unhealthy pod/liveness Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory

5m11s Normal Killing pod/liveness Container healtcheck failed liveness probe, will be restarted

Рассмотрим RadyNess пробу. Доступность этой пробы свидетельствует, что приложение готово к принятию запросов и можно на него сервис может переключать трафик:

controlplane $ cat << EOF > readiness.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

name: readiness

spec:

replicas: 2

selector:

matchLabels:

app: readiness

template:

metadata:

labels:

app: readiness

spec:

containers:

 name: readiness

image: python

args:

 /bin/sh

 -c

 sleep 15 && (hostname > health) && python -m http.server 9000

readinessProbe:

exec:

command:

 cat

 /tmp/healthy

initialDelaySeconds: 1

periodSeconds: 5

EOF


controlplane $ kubectl create -f readiness.yaml

deployment.apps/readiness created


controlplane $ kubectl get pods

NAME READY STATUS RESTARTS AGE

readiness-fd8d996dd-cfsdb 0/1 ContainerCreating 0 7s

readiness-fd8d996dd-sj8pl 0/1 ContainerCreating 0 7s


controlplane $ kubectl get pods

NAME READY STATUS RESTARTS AGE

readiness-fd8d996dd-cfsdb 0/1 Running 0 6m29s

readiness-fd8d996dd-sj8pl 0/1 Running 0 6m29s


controlplane $ kubectl exec -it readiness-fd8d996dd-cfsdb curl localhost:9000/health

readiness-fd8d996dd-cfsdb

Наши контейнера отлично работают. Добавим в них трафик:

controlplane $ kubectl expose deploy readiness \

-type=LoadBalancer \

-name=readiness \

-port=9000 \

-target-port=9000

service/readiness exposed


controlplane $ kubectl get svc readiness

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

readiness LoadBalancer 10.98.36.51 < pending> 9000:32355/TCP 98s


controlplane $ curl localhost:9000


controlplane $ for i in {1..5}; do curl $IP:9000/health; done

1

2

3

4

5

Каждый контейнер имеет задержку. Проверим, что будет, если один из контейнеров перезапустить будет ли на него перенаправляться трафик:

controlplane $ kubectl get pods

NAME READY STATUS RESTARTS AGE

readiness-5dd64c6c79-9vq62 0/1 CrashLoopBackOff 6 15m

readiness-5dd64c6c79-sblvl 0/1 CrashLoopBackOff 6 15m


kubectl exec -it .... -c .... bash -c "rm -f healt"


controlplane $ for i in {1..5}; do echo $i; done

1

2

3

4

5


controlplane $ kubectl delete deploy readiness

deployment.apps "readiness" deleted

Рассмотрим ситуацию, когда контейнер становится временно недоступен для работы:

(hostname > health) && (python -m http.server 9000 &) && sleep 60 && rm health && sleep 60 && (hostname > health) sleep 6000

/bin/sh -c sleep 60 && (python -m http.server 9000 &) && PID=$! && sleep 60 && kill -9 $PID

По умолчанию, в состояние Running контейнер переходит по завершения выполнения скриптов в Dockerfile и запуску скрипта, заданного в инструкции CMD, если он переопределён в конфигурации в разделе Command. Но, на практике, если у нас база данных, ей нужно ещё подняться (прочитать данные и перенести их оперативную память и другие действия), а это может занять значительно время, при этом она не будет отвечать на соединения, и другие приложения, хотя и прочитают в состоянии готовность принимать соединения не смогут этого сделать. Также, контейнер переходи в состояние Feils, когда падает главный процесс в контейнере. В случае с базой данных, она может бесконечно пытаться выполнить неправильный запрос и не сможет отвечать на приходящие запросы, при этом контейнер не буде перезапущен, так как формально демон (сервер) базы данных не упал. Для этих случаев и придуманы два идентификатора: readinessProbe и livenessProbe, проверяющих по кастомному скрипту или HTTP запросу переход контейнера в рабочее состояние или его неисправность.

esschtolts@cloudshell:~/bitrix (essch)$ cat health_check.yaml

apiVersion: v1

kind: Pod

metadata:

labels:

test: healtcheck

name: healtcheck

name: healtcheck

spec:

containers:

 name: healtcheck

image: alpine:3.5

args:

 /bin/sh

 -c

 sleep 12; touch /tmp/healthy; sleep 10; rm -rf /tmp/healthy; sleep 60

readinessProbe:

exec:

command:

 cat

 /tmp/healthy

initialDelaySeconds: 5

periodSeconds: 5

livenessProbe:

exec:

command:

 cat

 /tmp/healthy

initialDelaySeconds: 15

periodSeconds: 5

Контейнер стартует через 3 секунды и через 5 секунд начинается проверка на готовность каждые 5 секунд. На второй проверке (на 15 секунде жизни) проверка на готовность cat /tmp/healthy увенчается успехом. В это время начинает осуществляться проверка на работоспособность livenessProbe и на второй проверке (на 25 секунде) заканчивается ошибкой, после чего контейнер признаётся не рабочим и пересоздается.

esschtolts@cloudshell:~/bitrix (essch)$ kubectl create -f health_check.yaml && sleep 4 && kubectl get

pods && sleep 10 && kubectl get pods && sleep 10 && kubectl get pods

pod "liveness-exec" created

NAME READY STATUS RESTARTS AGE

liveness-exec 0/1 Running 0 5s

NAME READY STATUS RESTARTS AGE

liveness-exec 0/1 Running 0 15s

NAME READY STATUS RESTARTS AGE

liveness-exec 1/1 Running 0 26s

esschtolts@cloudshell:~/bitrix (essch)$ kubectl get pods

NAME READY STATUS RESTARTS AGE

liveness-exec 0/1 Running 0 53s

esschtolts@cloudshell:~/bitrix (essch)$ kubectl get pods

NAME READY STATUS RESTARTS AGE

liveness-exec 0/1 Running 0 1m

esschtolts@cloudshell:~/bitrix (essch)$ kubectl get pods

NAME READY STATUS RESTARTS AGE

liveness-exec 1/1 Running 1 1m

Kubernetes предоставляет ещё и startup, переделяющий момент, когда можно включить readiness и liveness пробы в работу. Это полезно в том случае, если, к примеру, мы скачиваем приложение. Рассмотрим более подробно. Для эксперимента возьмём www.katacoda.com/courses/Kubernetes/playground и Python. Существует TCP, EXEC и HTTP, но лучше использовать HTTP, так как EXEC порождает процессы и может оставлять их в виде "зомби процессов". К тому же, если сервер обеспечивает взаимодействие по HTTP, то именно по нему и нужно проверять (https://www.katacoda.com/courses/kubernetes/playground):

controlplane $ kubectl version short

Client Version: v1.18.0

Server Version: v1.18.0


cat << EOF > job.yaml

apiVersion: v1

kind: Pod

metadata:

name: healt

spec:

containers:

 name: python

image: python

command: ['sh', '-c', 'sleep 60 && (echo "work" > health) && sleep 60 && python -m http.server 9000']

readinessProbe:

httpGet:

path: /health

port: 9000

initialDelaySeconds: 3

periodSeconds: 3

livenessProbe:

httpGet:

path: /health

port: 9000

initialDelaySeconds: 3

periodSeconds: 3

startupProbe:

exec:

command:

 cat

 /health

initialDelaySeconds: 3

periodSeconds: 3

restartPolicy: OnFailure

EOF


controlplane $ kubectl create -f job.yaml

pod/healt


controlplane $ kubectl get pods # ещё не загружен

NAME READY STATUS RESTARTS AGE

healt 0/1 Running 0 11s


controlplane $ sleep 30 && kubectl get pods # ещё не загружен, но образ уже стянут

NAME READY STATUS RESTARTS AGE

healt 0/1 Running 0 51s


controlplane $ sleep 60 && kubectl get pods

NAME READY STATUS RESTARTS AGE

healt 0/1 Running 1 116s


controlplane $ kubectl delete -f job.yaml

pod "healt" deleted

Самодиагностика микро сервисного приложения

Рассмотрим работу probe на примере микро сервисного приложения bookinfo, входящего в состав Istio как пример: https://github.com/istio/istio/tree/master/samples/bookinfo. Демонстрация будет в www.katacoda.com/courses/istio/deploy-istio-on-kubernetes. После разворачивания будет доступны

Управление инфраструктурой

Хотя, и у Kubernetes есть свой графический интерфейс UI-дашборд, но кроме мониторинга и простейших действий не предоставляет. Больше возможностей даёт OpenShift, предоставляя совмещения графического и текстового создания. Полноценный продукт с сформированной экосистемой Google в Kubernetes не предоставляет, но предоставляет облачное решение Google Cloud Platform. Однако, существуют и сторонние решения, такие как Open Shift и Rancher, позволяющие пользоваться полноценно через графический интерфейс на своих мощностях. При желании, конечно, можно синхронизироваться с облаком.

Каждый продукт, зачастую, не совместим с друг другом по API, единственным известным исключением является Mail. Cloud, в котором заявляется поддержка Open Shift. Но, существует стороннее решение, реализующее подход "инфраструктура как код" и поддерживающее API большинства известных экосистем Terraform. Он, так же как Kubernetes, применяет концепция инфраструктура как код, но только не к контейнеризации, а к виртуальным машинам (серверам, сетям, дискам). Принцип Инфраструктура как код подразумевает наличии декларативной конфигурации то есть описания результата без явного указания самих действий. При активации конфигурация (в Kubernetes это kubectl apply -f name_config .yml, а в Hashicorp Terraform terraform apply) системы приводится в соответствие с конфигурационными файлами, при изменении конфигурации или инфраструктуры, инфраструктура, в конфликтующих частях с её декларацией приводится в соответствие, при этом сама система решает, как этого достичь, причём поведение может быть различным, например, при изменении метаинформации в POD она будет изменена, а при изменении образа POD будет удалён и создан уже новым. Если, до этого мы создавали серверную инфраструктуру для контейнеров в императивном виде с помощью команды gcloud публичного облака Google Cloud Platform (GCP), то теперь рассмотрим, как создать аналогичное с помощью конфигурация в декларативном описании паттерна инфраструктура как код с помощью универсального инструмента Terraform, поддерживающего облако GCP.

Назад Дальше