Объяснение паттерна Sidecar на примере

Kubernetes - это движок оркестрации контейнеров с открытым исходным кодом для автоматического развертывания, масштабирования и управления контейнеризированными приложениями. Под (Pod) – это базовое понятие при проектировании приложений в Kubernetes. Kubernetes оперирует подами, а не контейнерами, при этом поды включают в себя контейнеры. Под может содержать в себе описания одного или нескольких контейнеров, монтируемых разделов, IP-адресов и настроек того, как контейнеры должны работать внутри пода.

Под, содержащий один контейнер, относится к одно-контейнерным подам и это самый распространенный вариант их использования в Kubernetes. Под, который содержит несколько связанных контейнеров, относится к мульти-контейнерным подам. Есть несколько паттернов для мульти-контейнерных подов и один из них — это паттерн sidecar. В этом посте мы на примере проекта детально рассмотрим этот паттерн.

  • Что такое контейнер Sidecar

  • Другие паттерны

  • Пример

  • Тестируем с объектом Deployment

  • Как настроить ресурсные ограничения Resource Limits

  • Когда мы должны использовать этот паттерн

  • Итог

  • Заключение

Что такое Sidecar-контейнер

Sidecar-контейнер — это контейнер, который должен быть запущен рядом с основным контейнером внутри пода. Этот паттерн нужен для расширения и улучшения функциональности основного приложения без внесения в него изменений. Сейчас мы знаем, что технология контейнеризации позволяет собирать все зависимости, чтобы мы могли запустить приложение где угодно. Контейнер делает только одну вещь и делает её хорошо.

Представьте, что у вас есть под с одним контейнером, который очень хорошо работает, и вы бы хотели добавить какой-то функционал к этому контейнеру, не внося в него изменений. Как тогда можно добавить или расширить для него какие-то функции? Паттерн Sidecar может помочь именно в такой ситуации.

На диаграмме выше видно, как вы можете создать любое количество Sidecar контейнеров и ваш основной контейнер будет успешно с ними взаимодействовать. Все контейнеры работают параллельно и полный функционал будет доступен только если каждый из контейнеров успешно запущен. В большинстве случаев sidecar-контейнеры просты и легковесны и потребляют намного меньше ресурсов чем основной контейнер.


Другие паттерны

Вот некоторые другие паттерны, которые можно использовать для повседневной работы в Kubernetes:


Пример проекта

Здесь пример проекта, который вы можете скопировать и запустить на своих мощностях. Предварительно вам нужно установить Minikube.

https://github.com/bbachi/k8s-sidecar-container-pattern.git

Давайте запустим простой проект, чтобы понять как работает этот паттерн. Здесь под, в котором есть основной и sidecar контейнеры. Основной контейнер это Nginx, слушающий на порту 80, который отдает страницу index.html из volume, примонтированного в location workdir. И sidecar-контейнер с образом busybox, который пишет лог с timestamp в тот же самый файл. Так как sidecar-контейнер и основной контейнер запущены параллельно, Nginx будет показывать новую информацию каждый раз, когда вы делаете обращение через браузер.

apiVersion: v1
kind: Pod
metadata:
  name: sidecar-container-demo
spec:
  containers:
  - image: busybox
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo echo $(date -u) 'Hi I am from Sidecar container' >> /var/log/index.html; sleep 5;done"]
    name: sidecar-container
    resources: {}
    volumeMounts:
    - name: var-logs
      mountPath: /var/log
  - image: nginx
    name: main-container
    resources: {}
    ports:
      - containerPort: 80
    volumeMounts:
    - name: var-logs
      mountPath: /usr/share/nginx/html
  dnsPolicy: Default
  volumes:
  - name: var-logs
    emptyDir: {}
// create the pod
kubectl create -f pod.yml
// list the pods
kubectl get po
// exec into pod
kubectl exec -it sidecar-container-demo -c main-container -- /bin/sh
# apt-get update && apt-get install -y curl
# curl localhost

Вы можете установить curl и сделать запрос на localhost, чтобы проверить ответ сервера.

Тестирование Sidecar Container
Тестирование Sidecar Container

Тестирование с объектом Deployment

Давайте создадим сущность deployment с тем же определением подов и 5 репликами. Я создал service с типом порта NodePort, чтобы мы могли получить доступ к deployment через браузер. Поды создаются динамически и поддержкой заданного состояния всегда занимается deployment controller, поэтому у вас не может быть одного статического IP для доступа к поду, вместо этого вам нужно создать сущность service, которая будет открывать определенный порт во внешний мир. Внутри кластера service перенаправляет запросы извне на 80 порт контейнеров с соответствующими селекторами (тут много изменений оригинального текста).  Вы увидите как это работает через некоторое время.

Deployment
Deployment

Теперь давайте посмотрим на приведенный ниже deployment, в котором мы определили один основной контейнер и два sidecar-контейнера. Все контейнеры работают параллельно. Два sidecar-контейнера пишут лог в директорию /var/log. Основной контейнер с Nginx будет отдавать эти файлы, когда мы будем подключаться к порту 80. Вы увидите это в действии через некоторое время.

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx-webapp
  name: nginx-webapp
spec:
  replicas: 5
  selector:
    matchLabels:
      app: nginx-webapp
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx-webapp
    spec:
      containers:
      - image: busybox
        command: ["/bin/sh"]
        args: ["-c", "while true; do echo echo $(date -u) 'Hi I am from Sidecar container 1' >> /var/log/index.html; sleep 5;done"]
        name: sidecar-container1
        resources: {}
        volumeMounts:
          - name: var-logs
            mountPath: /var/log
      - image: busybox
        command: ["/bin/sh"]
        args: ["-c", "while true; do echo echo $(date -u) 'Hi I am from Sidecar container 2' >> /var/log/index.html; sleep 5;done"]
        name: sidecar-container2
        resources: {}
        volumeMounts:
          - name: var-logs
            mountPath: /var/log
      - image: nginx
        name: main-container
        resources: {}
        ports:
          - containerPort: 80
        volumeMounts:
          - name: var-logs
            mountPath: /usr/share/nginx/html
      dnsPolicy: Default
      volumes:
      - name: var-logs
        emptyDir: {}
status: {}

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-webapp
  labels:
    run: nginx-webapp
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    app: nginx-webapp
  type: NodePort

И выполним следующие команды, чтобы протестировать deployment.

// create a deployment
kubectl create -f manifest.yml
// list the deployment, pods, and service
kubectl get deploy -o wide
kubectl get po -o wide
kubectl get svc -o wide
deployment в действии
deployment в действии

На диаграмме выше вы можете видеть 5 подов, запущенных на разных IP-адресах и service, связывающие порты 32123 и 80. Вы можете получить доступ к этому deployment из браузера через IP ворке-ноды Kubernetes 192.168.64.2 и через порт сервиса 32123:

http://192.168.64.2:32123

Вы также можете протестировать под следующими командами:

// exec into main container of the pod
kubectl exec -it nginx-webapp-7c8b4d4f8d-9qmdm -c main-container -- /bin/sh
// install curl
# apt-get update && apt-get install -y curl
# curl localhost
Паттерн Sidecar в действии
Паттерн Sidecar в действии

Как настроить ограничения ресурсов

Настроить ограничения ресурсов очень важно, если речь идет о sidecar-контейнерах. Главное, что нам нужно понять, это то, что все контейнеры работают параллельно, поэтому при настройке ограничений ресурсов для пода вы должны это учитывать.

  • Суммировать все ограничения ресурсов для основных контейнеров, а также для дополнительных контейнеров (поскольку все контейнеры работают параллельно).


Когда нам нужно использовать этот паттерн

Вот несколько сценариев, в которых вы можете использовать этот паттерн:

  • Всегда, когда вы хотите дополнить функционал уже существующего единичного контейнера без внесения в него изменений

  • Вы можете использовать этот контейнер для синхронизации кода основного контейнера с кодом на git-сервере используя pull.(You can use this pattern to synchronize the main container code with the git server pull.)

  • Вы можете использовать этот контейнер, чтобы отправлять логи основного контейнера на внешний сервер.

  • Вы можете использовать этот контейнер для задач, связанных с установлением сети (network-related tasks.).


Итог

  • Под, который содержит один контейнер, относится к одно-контейнерному поду и это самый распространенный шаблон его использования.

  • Под, содержащий несколько взаимосвязанных контейнеров, относится к мульти-контейнерному поду.

  • Паттерн Sidecar - это один из паттернов, которые мы используем постоянно для расширения или изменения функционала существующих контейнеров.

  • Sidecar-контейнер запускается параллельно с основным контейнером. Поэтому вам нужно учитывать ограничения ресурсов для sidecar-контейнера прежде, чем вы задаете запросы/ограничения ресурсов для пода.

  • Контейнер с приложением и Sidecar-контейнер запускаются параллельно, что значит, что они будут работать в одно и то же время. Поэтому вам нужно суммировать все запросы/ограничения ресурсов для контейнеров, прежде чем задавать запросы/ограничения ресурсов для подов.

  • Вам нужно настроить health checks для sidecar-контейнеров так же, как и для основных контейнеров, что бы быть уверенными, что они в порядке.

  • Все поды, порожденные deployment не имеют статического IP-адреса, поэтому вам нужно создать сущность service, чтобы дать к ним доступ из внешнего мира.

  • Сущность service перенаправляет трафик внутри кластера с внешних портов на порты контейнера в соответствии с выбранными селекторами.


Заключение

Знать проверенные временем паттерны в kubernetes полезно. Убедитесь, что все ваши sidecar-контейнеры достаточно просты и малы, потому что вам нужно будет просуммировать все запросы и ограничения ресурсов прежде чем задавать их для пода в целом. Также нужно быть уверенным, что Sidecar-контейнеры “здоровы”, настроив health checks. Помните об этих моментах, когда добавляете функционал в основной контейнер или используйте отдельный контейнер.