Pods

Articles

PODs

Pod - наименьшая сущность в k8s. Обычно, pod = контейнер по принципу 1:1. Однако, можно несколько контейнеров разместить в 1 pod, при условии, что они функционально разные. Обычно это главный контейнер приложения и вспомогательные контейнеры, которые с ним связаны.

В обычном Docker, если развернуть множество копий “контейнер приложения” + “вспомогательный контейнер”, то нужно будет иметь карту взаимосвязей между ними всеми. Более того, в случае выхода из строя контейнера с приложением, нужно будет вручную удалять сопутствующий вспомогательный контейнер. От этого всего избавляют pod-ы, в рамках которых всё размещается, обеспечивается внутренняя связность, и далее k8s размножает готовые копии pod-ов в рамках кластера.

Pod-ы добавляют функционал к контейнерам:

  • Labels and annotations
  • Restart policies
  • Probes (startup probes, readiness probes, liveness probes, and potentially more)
  • Affinity and anti-affinity rules
  • Termination control
  • Security policies
  • Resource requests and limits

Работа с pod-ами ведётся с помощью API или инструмента kubectl:

kubectl run nginx --image nginx # образ nginx будет скачан с DockerHub
kubectl get pods # список всех pod-ов и их статусов
kubectl get pods --selector app=App1 # отфильтровать вывод по заданному label

Создание Pod через файл YAML

Создадим pod-definition.yml:

apiVersion: v1
kind: Pod       
metadata: 
  name: myapp-pod
  labels:
    app: myapp
    type: front-end
spec:
  containers:
    - name: nginx-container
      image: nginx

Далее создаём pod командой:

kubectl create -f pod-definition.yml
kubectl get pods

Посмотреть доступные поля, подробную информацию о поле у pod:

kubectl explain pods --recursive
kubectl explain pod.spec.restartPolicy

Посмотреть конкретное поле у всех pod, например, образ image, из которого он сделан:

kubectl get pods -o jsonpath={.items[*].spec.containers[*].image}

Можно у работающего Pod получить спецификацию в YAML, из которой он сделан:

kubectl get pod <имя pod> -o yaml > pod-definition.yaml

Удалить Pod

kubectl delete pod <имя Pod> --now 

Обновить Pod

В конфигурацию pod можно добавить период обновления (например, 30 секунд) и установить “imagePullPolicy: “Always”. Удалить Pod с помощью kubectl delete pod pod_name. Новый контейнер будет создан на последней версии образа, после чего старый контейнер будет удалён.

spec:
  terminationGracePeriodSeconds: 30
  containers:
  - name: my_container
    image: my_image:latest
    imagePullPolicy: "Always"

Есть вариант “дёргать” за Deployment, вызывая тем самым обновление:

kubectl patch deployment <имя deployment> -p \
  '{"spec":{"template":{"spec":{"terminationGracePeriodSeconds":31}}}}'

Выполнение задач в Pod

Если необходимо, чтобы Pod поработал и выключился, без перезапуска, то необходимо поменять его restartPolicy, которая по умолчанию стоит в Always - то есть перезапуск всегда по завершении работы.

spec:
  containers:
  - name: my_container
    image: my_image:latest
  restartPolicy: Never # ещё вариант OnFailure

Императивные команды

В отличие от декларативных, такие команды позволяют быстро решить однократную задачу.

kubectl run nginx --image=nginx --dry-run=client -o yaml # --dry-run=client - не создаёт объект, сообщает о возможности его создания

kubectl run httpd --image=httpd:alpine --port=80 --expose=true # создать Pod из образа httpd:alpine и к нему сразу создать ClusterIP с публикацией порта

Multi-Container PODs

Несколько контейнеров в 1 POD делят один адрес IP (между собой они общаются через адаптер localhost), хранилище. Есть несколько типовых сценариев:

  • Sidecar pattern - самый популярный случай, один контейнер отрабатывает задачу (например, выгрузки данных на веб-сайт), а другой решает вспомогательную задачу (например, синхронизация данных для последующей выгрузки);
  • Init pattern - перед запуском контейнера с основным ПО сначала стартует вспомогательный контейнер, который производит настройку окружения;
  • Adapter pattern - ПО в основном контейнере обрабатывает данные, а вспомогательный контейнер передаёт эти данные в другое приложение в понятном ему формате. Например, система SIEM не понимает формат логов приложения, и вспомогательный модуль парсит и транслирует логи в понятный для SIEM формат;
  • Ambassador pattern - ПО в основном контейнере отрабатывает задачи, а вспомогательный контейнер вызывает через API внешние системы, чтобы собрать с них данные для обработки, либо передать данные в эти системы.

PODы стартуют атомарно - только после успешного старта всех контейнеров POD считается запущенным. Частичный запуск не допускается. POD целиком всеми контейнерами размещается на одной ноде worker.

apiVersion: v1
kind: Pod        
metadata: 
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
    - name: nginx-container
      image: nginx
      ports:
        - containerPort: 8080
    - name: log-agent
      image: log-agent

InitContainer - не живёт постоянно, а выполняется ДО загрузки остальных контейнеров в Pod, поэтому его инициализация - в отдельной секции:

apiVersion: v1
kind: Pod        
metadata: 
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
    - name: myapp-container
      image: nginx
      ports:
        - containerPort: 8080
  initContainers:
    - name: init-service
      image: busybox
      command: [ 'sh', '-c', 'git clone <some repo to be used by app>' ]

Если таких InitContainer несколько, они будут выполняться последовательно один за другим. Если любой InitContainer не сможет выполниться успешно, k8s будет перезапускать Pod, пока InitContainer успешно не завершится.