Содержание
Сложности развертывания контейнерных stateful-приложений и как их решить с Argo Rollouts и Kubernetes Downward API: примеры YAML-конфигураций канареечного развертывания Spark-приложения.
Расширение стратегий развертывания в Kubernetes с Argo Rollouts
Мы уже писали, в чем сложности оркестрации параллельных заданий на платформе Kubernetes и как их можно решить с помощью Argo Workflows — контейнерного движка рабочих процессов с открытым исходным кодом. Однако, помимо Argo Workflows, в экосистеме Argo есть еще один полезный инструмент, который пригодится для управления контейнерными распределенными приложениями — Argo Rollouts. Это контроллер Kubernetes, который включает набор пользовательских определений ресурсов (CRD, Custom Resource Definition) для реализации расширенных возможностей развертывания приложений в Kubernetes, в т.ч. сине-зеленое и канареечное развертывание. Подробнее про стратегии развертывания мы писали здесь. В Kubernetes есть объект Deployment, который позволяет разработчикам автоматически развертывать приложения на узлах кластера этой платформы управления контейнерными приложениями. Однако, в объекте Deployment отсутствуют популярные стратегии развертывания, в частности, сине-зеленое и канареечное. Argo Rollouts, реализованный как Kubernetes CRD, расширяет объекта Deployment, позволяя использовать эффективные стратегии развертывания. По умолчанию он поддерживает только одну службу/приложение. Однако, это можно исправить, изменив соответствующие настройки.
Пример конфигурации Argo Rollouts для развертывания новой версии Spark-приложения с использованием стратегии канареечного развертывания может выглядеть как следующий YAML-файл:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: spark-app
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: spark-app
template:
metadata:
labels:
app: spark-app
spec:
containers:
- name: spark-container
image: my-spark-app:2.0 # Текущая версия приложения
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
strategy:
canary:
steps:
- setWeight: 20 # Отправка 20% трафика на новую версию
- pause:
duration: 60s # Пауза для мониторинга
- setWeight: 50 # Увеличение до 50%
- pause:
duration: 60s
- setWeight: 100 # Полный переход на новую версию
analysis:
templates:
- templateName: rollout-analysis
args:
- name: success-rate
value: "95"
analysis:
templates:
- name: rollout-analysis
metrics:
- name: success-rate
interval: 1m
count: 3
successCondition: result >= 95
provider:
prometheus:
address: http://prometheus-server.default.svc.cluster.local
query: |
sum(rate(http_requests_total{app="spark-app", status=~"2.."}[1m]))
/
sum(rate(http_requests_total{app="spark-app"}[1m])) * 100
В этой конфигурации канареечного развертывания сперва 20% трафика перенаправляется на новую версию Spark-приложения. Затем после временной паузы (1 минута) для мониторинга стабильности доля трафика увеличивается до 50% трафика. После новой паузы выполняется полный переход на новую версию. Также используется шаблон rollout-analysis, который проверяет показатель success-rate, рассчитываемый как отношение успешных HTTP-запросов (статусы 2xx) к общему числу запросов за 1 минуту. По условию не менее 95% запросов должны быть успешными.
Развертывание stateful-приложений
Argo Rollouts довольно просто использовать для stateless-приложений. Он поддерживает несколько распространенных провайдеров трафика, включая Kubernetes API Gateway, и может автоматически включать или отключать производственный трафик в новой версии приложения в случае сине-зеленого развертывания или постепенно переключать трафик для канареечного. Но для stateful-приложений, которые зависят от базы данных или очереди, возможностей Argo Rollouts недостаточно. Однако, многие Spark- или Flink-приложения распределенной обработки данных являются stateful, поскольку данные в реальном времени поступают непрерывно, и для их корректной обработки часто требуется хранить состояние между событиями. Например, для вычисления скользящих средних или агрегаций по окнам времени необходимо запоминать предыдущие данные. Кроме того, многие аналитические задачи включают в себя операции, которые зависят от предыдущих значений данных. Stateful-обработка позволяет выполнять такие операции, как группировка, сортировка или объединение данных на основе накопленного состояния. Наконец, хранение состояния позволяет системе восстанавливаться после сбоев без потери данных.
Возвращаясь к проблеме развертывания stateful-приложений, отметим, что стабильное приложение отслеживает производственную очередь или базу данных, где хранятся состояния. После запуска новой, предварительной, версии приложения она тоже будет забирать рабочие данные из производственной очереди, чего следует избежать в тестовом режиме. Разумеется, можно просто приостановить развертывание и вручную перенаправить новую версию приложения в другую очередь. Это решение будет работать, но оно не очень изящное. Можно сделать по-другому, используя Argo Rollouts вместе с Kubernetes Downward API.

Kubernetes Downward API – это встроенный механизм Kubernetes, который позволяет передавать любые метки Pod в контейнерное приложение, монтируя их как файлы или переменные среды.

Kubernetes Downward API отлично сочетается с эфемерными метками Argo Rollouts, позволяющими указать контроллеру, что надо автоматически добавлять или удалять определенные метки в развертывание. Эти метки можно преобразовать в конфигурацию приложения с помощью API Downward. Чтобы приложение знало об этих изменениях, необходимо обеспечить автоматическую перезагрузку параметров конфигурации при обновлении файлов, которые их содержат. Это реализуется на стороне кода приложения. В результате процесс развертывания будет выглядеть так:

Пример манифеста Rollout для Spark-приложения, который использует Downward API для передачи меток в конфигурацию приложения, может выглядеть так:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: spark-app-rollout
namespace: default
spec:
replicas: 3
strategy:
canary:
steps:
- setWeight: 25
- pause:
duration: 10m
- setWeight: 50
- pause:
duration: 10m
- setWeight: 100
selector:
matchLabels:
app: spark-app
template:
metadata:
labels:
app: spark-app
# Эфемерная метка, управляемая Argo Rollouts
rollout-pod-template-hash: "{{.Rollout.Status.CurrentPodHash}}"
spec:
containers:
- name: spark-container
image: spark:3.1.1
ports:
- containerPort: 8080
env:
- name: APP_VERSION
valueFrom:
fieldRef:
fieldPath: metadata.labels['rollout-pod-template-hash']
# Использование Downward API для передачи меток в приложение
volumeMounts:
- name: config
mountPath: /etc/config
readOnly: true
volumes:
- name: config
downwardAPI:
items:
- path: "app-version"
fieldRef:
fieldPath: metadata.labels['rollout-pod-template-hash']
В этом примере, также, как и в прошлом, используется стратегия канареечного развертывания, чтобы постепенно увеличивать количество подов с новой версией приложения с мониторингом стабильности. Эфемерная метка rollout-pod-template-hash служит уникальным идентификатором версии приложения и автоматически обновляется контроллером Argo Rollouts при каждом изменении шаблона пода. Эта эфемерная метка передается внутрь контейнера с помощью переменной окружения APP_VERSION. Конфигурация тома монтируется как конфигурационный файл, содержащий значение метки. Это полезно, когда приложение читает конфигурацию из файловой системы.
Вышеприведенный манифеста надо сохранить в YAML-файл и применить его в kubectl, используя команду apply –f. Отслеживать статус Rollout можно также через CLI-утилиту, вызвав в kubectl команду argo rollouts get rollout или использовать интерфейс пользователя Argo Rollouts для наглядного мониторинга.
Для развертывания новой версии Spark-приложения следует обновить образ контейнера в манифесте Rollout и снова применить изменения. После этого Argo Rollouts автоматически начнет процесс канареечного развертывания с обновленной конфигурацией, используя Downward API для передачи новых меток в приложение.
Научитесь работать с Kubernetes и Argo Workflows на специализированных курсах в нашем лицензированном учебном центре обучения и повышения квалификации для разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве:
Источники


