Добавление Init-контейнеров

KubernetesBeginner
Практиковаться сейчас

Введение

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-контейнера и приложения, а также подтвердили, что этот шаблон успешно работает для подов, управляемых контроллером.