Объяснение паттерна 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, чтобы проверить ответ сервера.
Тестирование с объектом Deployment
Давайте создадим сущность deployment с тем же определением подов и 5 репликами. Я создал service с типом порта NodePort, чтобы мы могли получить доступ к deployment через браузер. Поды создаются динамически и поддержкой заданного состояния всегда занимается deployment controller, поэтому у вас не может быть одного статического IP для доступа к поду, вместо этого вам нужно создать сущность service, которая будет открывать определенный порт во внешний мир. Внутри кластера service перенаправляет запросы извне на 80 порт контейнеров с соответствующими селекторами (тут много изменений оригинального текста). Вы увидите как это работает через некоторое время.
Теперь давайте посмотрим на приведенный ниже 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
На диаграмме выше вы можете видеть 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-контейнерах. Главное, что нам нужно понять, это то, что все контейнеры работают параллельно, поэтому при настройке ограничений ресурсов для пода вы должны это учитывать.
Суммировать все ограничения ресурсов для основных контейнеров, а также для дополнительных контейнеров (поскольку все контейнеры работают параллельно).
Когда нам нужно использовать этот паттерн
Вот несколько сценариев, в которых вы можете использовать этот паттерн:
Всегда, когда вы хотите дополнить функционал уже существующего единичного контейнера без внесения в него изменений
Вы можете использовать этот контейнер для синхронизации кода основного контейнера с кодом на 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. Помните об этих моментах, когда добавляете функционал в основной контейнер или используйте отдельный контейнер.