kubectl logs $(kubectl get PODs -l app=lamp -o JSON | jq ".items[0].metadata.name" | sed 's/"//g') -c init
Целесообразно выбирать для единичных задач маленькие образа, например, alpine:3.5:
esschtolts@cloudshell:~ (essch)$ docker pull alpine 1>\dev\null
esschtolts@cloudshell:~ (essch)$ docker pull ubuntu 1>\dev\null
esschtolts@cloudshell:~ (essch)$ docker images
REPOSITORY TAGIMAGE ID CREATED SIZE
ubuntu latest 93fd78260bd1 4 weeks ago 86.2MB
alpine latest 196d12cf6ab1 3 months ago 4.41MB
Немного изменив код существенно сэкономили на размере образа:
image: alpine:3.5
command:
/bin/bash
-c
|
cd /app
apk update add wget && rm -rf /var/cache/apk/*
tar -xf small_business_encode.tar.gz
rm -f small_business_encode.tar.gz
sed -i '5i php_value short_open_tag 1' .htaccess
sed -i 's/#php_value display_errors 1/php_value display_errors 1/' .htaccess
sed -i '5i php_value opcache.revalidate_freq 0' .htaccess
sed -i 's/#php_flag default_charset UTF-8/php_flag default_charset UTF-8/' .htaccess
chmod -R 0777 .
volumeMounts:
Существуют также минималистичные образа с предустановленными пакетами, такие как APIne с git: axeclbr/git и golang:1-alpine.
Способы обеспечения устойчивости к сбоям
Любой процесс может упасть. В случае с контейнером, если падает основной процесс, то падает и контейнер, содержащий его. Это нормально, если падение случилось в процессе корректного завершения работы. К примеру, наше приложение в контейнере делает бэкап базы данных, таком случае после выполнения контейнера мы получаем сделанную работу. Для демонстрации, возьмём команду sleep:
vagrant@ubuntu:~$ sudo docker pull ubuntu > /dev/null
vagrant@ubuntu:~$ sudo docker run -d ubuntu sleep 60
0bd80651c6f97167b27f4e8df675780a14bd9e0a5c3f8e5e8340a98fc351bc64
vagrant@ubuntu:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
0bd80651c6f9 ubuntu "sleep 60" 15 seconds ago Up 12 seconds distracted_kalam
vagrant@ubuntu:~$ sleep 60
vagrant@ubuntu:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
vagrant@ubuntu:~$ sudo docker ps -a | grep ubuntu
0bd80651c6f9 ubuntu "sleep 60" 4 minutes ago Exited (0) 3 minutes ago distracted_kalam
В случае с бэкапам это норма, а в случае с приложениями, которые не должны завершаться нет. Типичный прием веб-сервер. Самое простое в таком случае заново рестартовать его:
vagrant@ubuntu:~$ sudo docker run -d restart=always ubuntu sleep 10
c3bc2d2e37a68636080898417f5b7468adc73a022588ae073bdb3a5bba270165
vagrant@ubuntu:~$ sleep 30
vagrant@ubuntu:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS
c3bc2d2e37a6 ubuntu sleep 10" 46 seconds ago Up 1 second
Мы видим, что, когда контейнер падает он рестартует. Как результат у нас всегда приложение в двух состояниях поднимается или поднято. Если веб-сервер падает от какой-то редкой ошибки это норма, но, скорее всего, ошибка в обработке запросов, и он будет падать на каждом таком запросе, а в мониторинге мы увидим поднятый контейнер. Такой веб-сервер лучше мёртвый, чем наполовину живой. Но, при этом нормальный веб-сервер может не стартануть из-за редких ошибок, например, из-за отсутствия подключения к базе данных из-за нестабильности сети. В таком случает, приложение должно уметь обрабатывать ошибки и завершаться. А в случае падения из-за ошибок кода не перезапускать, чтобы увидеть неработоспособность и отправить на починку разработчикам. В случает же плавающей ошибки можно попробовать несколько раз:
vagrant@ubuntu:~$ sudo docker run -d restart=on-failure:3 ubuntu sleep 10
056c4fc6986a13936e5270585e0dc1782a9246f01d6243dd247cb03b7789de1c
vagrant@ubuntu:~$ sleep 10
vagrant@ubuntu:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c3bc2d2e37a6 ubuntu "sleep 10" 9 minutes ago Up 2 seconds keen_sinoussi
vagrant@ubuntu:~$ sleep 10
vagrant@ubuntu:~$ sleep 10
vagrant@ubuntu:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c3bc2d2e37a6 ubuntu "sleep 10" 10 minutes ago Up 9 seconds keen_sinoussi
vagrant@ubuntu:~$ sleep 10
vagrant@ubuntu:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c3bc2d2e37a6 ubuntu "sleep 10" 10 minutes ago Up 2 seconds keen_sinoussi
Другим аспектом является то, когда считать контейнер умершим. По умолчанию это падание процесса. Но, далеко, не всегда приложение само падает в случае ошибки, чтобы дать контейнеру его перезапустить. Например, сервер может быть разработан неправильно и пытаться во время своего запуска скачать необходимые библиотеки, при этом этой возможности у него нет, например, из-за блокировки запросов файрволлом. В таком сценарии сервер может долго ожидать, если не прописан адекватный таймаут. В таком случае, нам нужно проверить работоспособность. Для веб-сервера это ответ на определённый url, например:
docker run rm -d \
-name=elasticsearch \
-health-cmd="curl silent fail localhost:9200/_cluster/health || exit 1" \
-health-interval=5s \
-health-retries=12 \
-health-timeout=20s \
{image}
Для демонстрации мы возьмём команду создания файла. Если приложение не достигло в отведённый лимит времени (поставим пок 0) рабочего состояния (к примеру, создания файла), то помечается как на рабочее, но до этого делается заданное кол-во проверок:
vagrant@ubuntu:~$ sudo docker run \
d name healt \
-health-timeout=0s \
-health-interval=5s \
vagrant@ubuntu:~$ sudo docker run \
d name healt \
-health-timeout=0s \
-health-interval=5s \
-health-retries=3 \
-health-cmd="ls /halth" \
ubuntu bash -c 'sleep 1000'
c0041a8d973e74fe8c96a81b6f48f96756002485c74e51a1bd4b3bc9be0d9ec5
vagrant@ubuntu:~$ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c0041a8d973e ubuntu "bash -c 'sleep 1000'" 4 seconds ago Up 3 seconds (health: starting) healt
vagrant@ubuntu:~$ sleep 20
vagrant@ubuntu:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c0041a8d973e ubuntu "bash -c 'sleep 1000'" 38 seconds ago Up 37 seconds (unhealthy) healt
vagrant@ubuntu:~$ sudo docker rm -f healt
healt
Если же хотя бы одна из проверок сработала то контейнер помечается как работоспособный (healthy) сразу:
vagrant@ubuntu:~$ sudo docker run \
d name healt \
-health-timeout=0s \
-health-interval=5s \
-health-retries=3 \
-health-cmd="ls /halth" \
ubuntu bash -c 'touch /halth && sleep 1000'
vagrant@ubuntu:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
160820d11933 ubuntu "bash -c 'touch /hal" 4 seconds ago Up 2 seconds (health: starting) healt
vagrant@ubuntu:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
160820d11933 ubuntu "bash -c 'touch /hal" 6 seconds ago Up 5 seconds (healthy) healt
vagrant@ubuntu:~$ sudo docker rm -f healt
healt
При этом проверки повторяются всё время с заданным интервалом:
vagrant@ubuntu:~$ sudo docker run \
d name healt \
-health-timeout=0s \
-health-interval=5s \
-health-retries=3 \
-health-cmd="ls /halth" \
ubuntu bash -c 'touch /halth && sleep 60 && rm -f /halth && sleep 60'
vagrant@ubuntu:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8ec3a4abf74b ubuntu "bash -c 'touch /hal" 7 seconds ago Up 5 seconds (health: starting) healt
vagrant@ubuntu:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8ec3a4abf74b ubuntu "bash -c 'touch /hal" 24 seconds ago Up 22 seconds (healthy) healt
vagrant@ubuntu:~$ sleep 60
vagrant@ubuntu:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8ec3a4abf74b ubuntu "bash -c 'touch /hal" About a minute ago Up About a minute (unhealthy) healt
Kubernetes предоставляет (kubernetes.io/docs/tasks/configure-POD-container/configure-liveness-readiness-probes/) три инструмента, которые проверяют состояние контейнера из вне. Они имеют больше значение, так они служат не только для информирования, но и для управления жизненным циклом приложения, накатом и откатом обновления. Их неправильная настройка может, и часто такое бывает, приводят к неработоспособности приложения. Так, к если liveness проба буте срабатывать до начала работы приложения Kubernetes будет убивать контейнер, не дав ему подняться. Рассмотрим её более подробно. Проба liveness служит для определения работоспособности приложения и в случае, если приложение сломалось и не отвечает на пробу liveness Kubernetes перезагружает контейнер. В качестве примера возьмём shell-пробу, из-за простоты демонстрации работы, но на практике её следует использовать только в крайних случаях, например, если контейнер запускается не как долгоживущий сервер, а как JOB, выполняющий свою работу и завершающий своё существование, достигнув результата. Для проверок серверов лучше использовать HTTP-пробы, которые уже имеют встроенный выделенный проксировщик и не требуют наличия в контейнере curl и не зависящие от внешних настроек kube-proxy. При использовании баз данных нужно использовать TCP-пробу, так как HTTPпротокол они обычно не поддерживают. Создадим долгоживущий контейнер в www.katacoda.com/courses/kubernetes/playground:
controlplane $ cat << EOF > liveness.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness
spec:
containers:
name: healtcheck
image: alpine:3.5
args:
/bin/sh
-c
touch /tmp/healthy; sleep 10; rm -rf /tmp/healthy; sleep 60
livenessProbe:
exec:
command:
cat
/tmp/healthy
initialDelaySeconds: 15
periodSeconds: 5
EOF
controlplane $ kubectl create -f liveness.yaml
pod/liveness created
controlplane $ kubectl get pods
NAME READY STATUS RESTARTS AGE
liveness 1/1 Running 2 2m11s
controlplane $ kubectl describe pod/liveness | tail -n 10
Type Reason Age From Message
Normal Scheduled 2m37s default-scheduler Successfully assigned default/liveness to node01
Normal Pulling 2m33s kubelet, node01 Pulling image "alpine:3.5"
Normal Pulled 2m30s kubelet, node01 Successfully pulled image "alpine:3.5"
Normal Created 33s (x3 over 2m30s) kubelet, node01 Created container healtcheck
Normal Started 33s (x3 over 2m30s) kubelet, node01 Started container healtcheck
Normal Pulled 33s (x2 over 93s) kubelet, node01 Container image "alpine:3.5" already present on machine
Warning Unhealthy 3s (x9 over 2m13s) kubelet, node01 Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
Normal Killing 3s (x3 over 2m3s) kubelet, node01 Container healtcheck failed liveness probe, will be restarted
Мы видим, что контейнер постоянно перезапускается.
controlplane $ cat << EOF > liveness.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness
spec:
containers:
name: healtcheck
image: alpine:3.5
args:
/bin/sh
-c
touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 60
livenessProbe:
exec:
command:
cat
/tmp/healthy
initialDelaySeconds: 15
periodSeconds: 5
EOF
controlplane $ kubectl create -f liveness.yaml
pod/liveness created
controlplane $ kubectl get pods
NAME READY STATUS RESTARTS AGE
liveness 1/1 Running 2 2m53s
controlplane $ kubectl describe pod/liveness | tail -n 15
SecretName: default-token-9v5mb
Optional: false
QoS Class: BestEffort
Node-Selectors: < none>