Введение
Init-контейнер (контейнер инициализации) запускается перед основными контейнерами приложения в поде (Pod). Каждый init-контейнер должен успешно завершить свою работу, прежде чем Kubernetes запустит следующий init-контейнер или любой обычный контейнер. Это делает init-контейнеры полезными для подготовки файлов, проверки зависимостей или выполнения небольших задач по настройке, которые не должны постоянно выполняться параллельно с основным приложением.
В этой лабораторной работе вы добавите init-контейнер, который записывает файл запуска в общий том emptyDir, подтвердите, что контейнер приложения может прочитать этот файл, изучите статус завершения и логи init-контейнера, а затем примените этот же шаблон в шаблоне Deployment.
Подготовка пространства имен для Init-контейнеров
На этом этапе вы подготовите чистое пространство имен (namespace) для практики работы с init-контейнерами.
Начните работу в директории /home/labex/project. В этой директории вы будете создавать манифесты Pod и Deployment.
mkdir -p /home/labex/project
cd /home/labex/project
Проверьте доступность API-сервера Kubernetes. Если виртуальная машина только что запустилась и узел еще не готов, подождите несколько секунд и повторите команду.
kubectl get nodes --request-timeout=5s
Ожидаемый вывод:
NAME STATUS ROLES AGE VERSION
labex-v135 Ready control-plane ... v1.35...
Init-контейнеры работают внутри подов, поэтому перед созданием рабочих нагрузок убедитесь, что системный под сетевого плагина готов.
kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s
Ожидаемый вывод:
pod/calico-node-... condition met
Создайте пространство имен с именем ckad-prep-init:
kubectl create namespace ckad-prep-init
Установите это пространство имен в качестве текущего контекста:
kubectl config set-context --current --namespace=ckad-prep-init
Проверьте текущее пространство имен:
kubectl config view --minify --output 'jsonpath={..namespace}'; echo
Ожидаемый вывод:
ckad-prep-init
Подготовка общих данных перед запуском приложения
На этом этапе вы создадите под, в котором init-контейнер подготовит файл до запуска контейнера приложения.
Том emptyDir создается при назначении пода на узел и является общим для всех контейнеров внутри этого пода. И init-контейнер, и контейнер приложения монтируют этот том в директорию /work. Init-контейнер записывает файл /work/startup.txt, а затем завершает работу. Только после его успешного завершения Kubernetes запускает контейнер приложения.
Создайте файл init-file-pod.yaml:
cat > init-file-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: init-file-demo
labels:
app: init-file-demo
spec:
terminationGracePeriodSeconds: 0
volumes:
- name: shared-work
emptyDir: {}
initContainers:
- name: prepare-startup-file
image: busybox:1.36
command:
- /bin/sh
- -c
- 'echo init-started; echo prepared-by-init > /work/startup.txt; echo init-finished'
volumeMounts:
- name: shared-work
mountPath: /work
containers:
- name: app
image: busybox:1.36
command:
- /bin/sh
- -c
- 'echo app-started; cat /work/startup.txt; sleep 3600'
volumeMounts:
- name: shared-work
mountPath: /work
EOF
Примените манифест:
kubectl apply -f init-file-pod.yaml
Ожидаемый вывод:
pod/init-file-demo created
Дождитесь готовности пода:
kubectl wait --for=condition=Ready pod/init-file-demo --timeout=120s
Ожидаемый вывод:
pod/init-file-demo condition met
Прочитайте файл изнутри контейнера приложения. Это доказывает, что init-контейнер подготовил данные в общем томе до запуска приложения.
kubectl exec init-file-demo -c app -- cat /work/startup.txt
Ожидаемый вывод:
prepared-by-init
Проверка статуса и логов Init-контейнера
На этом этапе вы убедитесь, что init-контейнер завершил работу до того, как основной контейнер приложения начал выполнение.
Статусы init-контейнеров отображаются в поле .status.initContainerStatuses, а обычных контейнеров — в .status.containerStatuses. Init-контейнер должен иметь статус Completed (завершен), так как он успешно выполнил свою задачу.
kubectl get pod init-file-demo -o 'jsonpath={.status.initContainerStatuses[0].name}{" "}{.status.initContainerStatuses[0].state.terminated.reason}{"\n"}'
Ожидаемый вывод:
prepare-startup-file Completed
Теперь проверьте статус обычного контейнера приложения. Он должен быть готов и запущен.
kubectl get pod init-file-demo -o 'jsonpath={.status.containerStatuses[0].name}{" "}{.status.containerStatuses[0].ready}{" "}{.status.containerStatuses[0].state.running.startedAt}{"\n"}'
Ожидаемый вывод включает:
app true ...
Прочитайте логи init-контейнера. Несмотря на то, что init-контейнер завершил работу, его логи остаются доступными через команду kubectl logs -c.
kubectl logs init-file-demo -c prepare-startup-file
Ожидаемый вывод:
init-started
init-finished
Прочитайте логи контейнера приложения. Приложение запускается после того, как init-контейнер записывает файл, поэтому его логи содержат подготовленное значение.
kubectl logs init-file-demo -c app
Ожидаемый вывод включает:
app-started
prepared-by-init
Добавление Init-контейнера в Deployment
На этом этапе вы используете тот же шаблон init-контейнера внутри Deployment.
Для рабочих нагрузок приложений обычно принято размещать init-контейнеры в шаблоне пода контроллера, а не создавать отдельные поды. Когда Deployment создает под, Kubernetes сначала запускает init-контейнер для каждого пода, созданного на основе этого шаблона.
Создайте файл init-deployment.yaml:
cat > init-deployment.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: init-web
spec:
replicas: 1
selector:
matchLabels:
app: init-web
template:
metadata:
labels:
app: init-web
spec:
terminationGracePeriodSeconds: 0
volumes:
- name: web-content
emptyDir: {}
initContainers:
- name: render-index
image: busybox:1.36
command:
- /bin/sh
- -c
- 'echo deployment-init > /site/index.txt'
volumeMounts:
- name: web-content
mountPath: /site
containers:
- name: web
image: busybox:1.36
command:
- /bin/sh
- -c
- 'cat /site/index.txt; sleep 3600'
volumeMounts:
- name: web-content
mountPath: /site
EOF
Примените Deployment:
kubectl apply -f init-deployment.yaml
Ожидаемый вывод:
deployment.apps/init-web created
Дождитесь готовности Deployment:
kubectl wait --for=condition=Available deployment/init-web --timeout=120s
Ожидаемый вывод:
deployment.apps/init-web condition met
Найдите под, созданный Deployment:
web_pod="$(kubectl get pods -l app=init-web -o 'jsonpath={.items[0].metadata.name}')"
echo "$web_pod"
Ожидаемый вывод показывает сгенерированное имя пода:
init-web-...
Прочитайте логи контейнера приложения из этого пода:
kubectl logs "$web_pod" -c web
Ожидаемый вывод:
deployment-init
Проверьте статус завершения init-контейнера внутри пода, созданного Deployment:
kubectl get pod "$web_pod" -o 'jsonpath={.status.initContainerStatuses[0].name}{" "}{.status.initContainerStatuses[0].state.terminated.reason}{"\n"}'
Ожидаемый вывод:
render-index Completed
Резюме
Вы добавили init-контейнеры в под и в шаблон Deployment. Вы использовали том emptyDir для обмена подготовленными файлами с контейнером приложения, проверили статус завершения init-контейнера, прочитали логи init-контейнера и приложения, а также подтвердили, что этот шаблон успешно работает для подов, управляемых контроллером.


