Дегустация Argo Rollouts: Experiments, Analysis. Часть 2

от автора

И снова здравствуйте! Я – Евгений Симигин, занимаюсь внедрением DevOps-практик в Центре компетенций по разработке облачных и интернет-решений МТС Digital. Как я и обещал – это вторая часть нашего обзора Argo Rollouts, из которой вы узнаете о том, как в процессе выкатки нового релиза организовать еще и тестирование. Первая часть статьи – по ссылке.

Рассмотренные в первой половине статьи механизмы послужат нам существенным подспорьем, однако итоговое решение – прошло все успешно или нет – принимается на основе звонков от разгневанных пользователей алертов от системы мониторинга. Тут на помощь нам спешат analysis и experiments.Они позволят вклиниться в шаги выкатки и выставить критерии для принятия решения: идем мы дальше или откатываем ревизию.

Прежде всего мы задаем «правила игры» – то, что мы будем анализировать и критерии «что такое хорошо, что такое плохо». Для этого служат AnalysisTemplate ClusterAnalysisTemplate

apiVersion: argoproj.io/v1alpha1 kind: AnalysisTemplate metadata:   name: error-rate spec:   args:   - name: service-name   - name: api-token     valueFrom:       secretKeyRef:         name: token-secret         key: apiToken   - name: api-url     value: http://example/measure   - name: host   metrics:   - name: error-rate     interval: 5m     successCondition: result[0] <= 0.95     failureLimit: 3     provider:       prometheus:         address: http://prometheus.example.com:9090         query: |           sum(irate(             istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code=~"5.*"}[5m]           )) /           sum(irate(             istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}"}[5m]           ))   - name: webmetric     successCondition: result == 'true'     provider:       web:         # placeholders are resolved when an AnalysisRun is created         url: "{{ args.api-url }}?service={{ args.service-name }}"         headers:           - key: Authorization             value: "Bearer {{ args.api-token }}"         jsonPath: "{$.results.ok}"   - name: http-benchmark     failureLimit: 100     interval: 5s     provider:       job:         spec:           template:             spec:               containers:               - name: load-tester                 image: argoproj/load-tester:latest                 command: [sh, -xec]                 args:                 - |                   wrk -t1 -c1 -d5 -s report.lua http://{{args.host}}/color                   jq -e '.errors_ratio <= 0.05' report.json               restartPolicy: Never           backoffLimit: 0

Прошу прощения за огромный шаблон (его пришлось склеить из трех), но это сделано для максимальной наглядности.

  1. args: – можно задать переменные для шаблона и при запуске экземпляра анализа их можно переопределить. Значения можно взять из секретов

  2. metrics: – массив тестов. Метрики поддерживают разные провайдеры. В примере показаны istio, web и job.

  3. Если что-то не прошло нашу проверку – откатываем изменения (поведение можно менять)

  4. Для метрики http-benchmark запускается отдельный контейнер (по ссылке вы можете посмотреть файл report.lua, который формирует структуру отчета). Провайдер job позволяет нам подпихнуть любой контейнер с нашими автотестами и прогнать их без переключение реального трафика (для этого используется experiment).

  5. Шаблонизация очень удобна, если ваши сервисы поставляются разными командами: так вы задаете единые критерии для всех. Особенно это помогает с теми, у кого нет времени на написание автотестов.

Подключаем шаблон к Rollout. Сначала рассмотрим поведение при canary-стратегии:

  strategy:     canary:       analysis:         templates:         - templateName: error-rate # имя шаблона         - templateName: Mytemplate # можно подключать несколько шаблонов сразу           clusterScope: true #это служит для подключения ClusterAnalysisTemplate         startingStep: 2 # Ждём когда rollout дойдёт до 2 шага (40%) и стартуем         args:         - name: service-name           value: guestbook-svc.default.svc.cluster.local       steps:       - setWeight: 20       - pause: {duration: 10m}       - setWeight: 40       - pause: {duration: 10m}       - setWeight: 60       - pause: {duration: 10m}       - setWeight: 80       - pause: {duration: 10m}

В данном манифесте показан пример анализа в фоне: Rollout потихоньку подменяет поды, а инстанс анализа делает своё дело до тех пор, пока не завершится накат новой ревизии или же возникнет ошибка и тогда нас ждёт Rollback. Есть другой вариант применения – Inline Analysis. Он позволяет нам вклиниться в steps, анализироваться столько сколько хочется и только потом переходить на другие шаги.

      steps:       - setWeight: 20       - pause: {duration: 5m}       - analysis:           templates:           - templateName: success-rate           args:           - name: service-name             value: guestbook-svc.default.svc.cluster.local

Тут будет необходим тюнинг шаблона анализа, без interval и count ваш тест выполнится один раз

  metrics:   - name: success-rate     successCondition: result[0] >= 0.95     interval: 60s     count: 5     provider:       prometheus:         address: http://prometheus.example.com:9090         query: ...

Тут уже в зависимости от количества новых подов, мы можем выбрать различные наборы и продолжительность наших тестов. А теперь рассмотрим BlueGreen – стратегию: в данном случае мы можем проводить проверку до переключения трафика и после:

  strategy:     blueGreen:       activeService: active-svc       previewService: preview-svc       prePromotionAnalysis: # прогоняем тесты и переключем         templates:         - templateName: smoke-tests #...или...       scaleDownDelaySeconds: 600 # сколько живёт текущая реплика после переключения       postPromotionAnalysis: # прогоняем тесты после переключения         templates:         - templateName: smoke-tests

В первом случае контроллер просто не переключит трафик, во втором будет производиться откат, поэтому рекомендуется увеличить (в разумных пределах) scaleDownDelaySeconds, чтобы контроллер не уничтожал сразу предыдущую реплику. В случае проблем он быстро перекинет лейблы и мы не будем ожидать старта контейнеров.

Как всегда есть исключения из правил: метрика вроде бы есть, но если не выполняется – давайте не будем из-за нее останавливать релиз. Для этого служит механизм dry-run: можно пометить метрики и выкатка не зафейлится, если все плохо.

Пример dry-run метрик
#В манифесте AnalysisTemplate ...   dryRun:   - metricName: .*   metrics:   - name: total-5xx-errors # в манифестах rollout ...   steps:   - analysis:       templates:       - templateName: random-fail       - templateName: always-pass       dryRun:       - metricName: .*

Еще есть состояние inconclusive или, говоря по-русски, «нипанятна» – состояние, когда заданы success и failed границы, но мы не попали. В таком случае Rollout встает на паузу и ждет ручного вмешательства. На мой взгляд, лучше не допускать дырки в диапазонах и однозначно задавать критерии.

  metrics:   - name: success-rate     successCondition: result[0] >= 0.90     failureCondition: result[0] < 0.50

Мы рассмотрели Analysis, который позволял нам подстелить соломку в случае плохого релиза, а теперь пора перейти к целому «стогу» – experiments. Согласно документации, в первом случае мы переключаем реальный клиентский трафик (хотя в случае BlueGreen prePromotionAnalysis ничего не переключается). Experiments позволяет нам развернуть произвольное количество replicaset в с разными контейнерами, прогнать по ним тесты, сравнить и принять решение о судьбе релиза.

длинная портянка из документации
apiVersion: argoproj.io/v1alpha1 kind: Experiment metadata:   name: example-experiment spec:   # Duration of the experiment, beginning from when all ReplicaSets became healthy (optional)   # If omitted, will run indefinitely until terminated, or until all analyses which were marked   # `requiredForCompletion` have completed.   duration: 20m    # Deadline in seconds in which a ReplicaSet should make progress towards becoming available.   # If exceeded, the Experiment will fail.   progressDeadlineSeconds: 30    # List of pod template specs to run in the experiment as ReplicaSets   templates:   - name: purple     # Number of replicas to run (optional). If omitted, will run a single replica     replicas: 1     selector:       matchLabels:         app: canary-demo         color: purple     template:       metadata:         labels:           app: canary-demo           color: purple       spec:         containers:         - name: rollouts-demo           image: argoproj/rollouts-demo:purple           imagePullPolicy: Always           ports:           - name: http             containerPort: 8080             protocol: TCP   - name: orange     replicas: 1     minReadySeconds: 10     selector:       matchLabels:         app: canary-demo         color: orange     template:       metadata:         labels:           app: canary-demo           color: orange       spec:         containers:         - name: rollouts-demo           image: argoproj/rollouts-demo:orange           imagePullPolicy: Always           ports:           - name: http             containerPort: 8080             protocol: TCP    # List of AnalysisTemplate references to perform during the experiment   analyses:   - name: purple     templateName: http-benchmark     args:     - name: host       value: purple   - name: orange     templateName: http-benchmark     args:     - name: host       value: orange   - name: compare-results     templateName: compare     # If requiredForCompletion is true for an analysis reference, the Experiment will not complete     # until this analysis has completed.     requiredForCompletion: true     args:     - name: host       value: purple

Также можно запускать автономные эксперименты не привязанных к процессу выкатки. Это может быть востребовано у тестировщиков – запустил/забыл/вспомнил/сравнил. Вот так можно подглядывать за экспериментом:

Способ подключения из rollout похож на AnalysisTemplate:

  strategy:     canary:        steps:       - experiment:           duration: 1h           templates:           - name: baseline             specRef: stable           - name: canary             specRef: canary           analyses:           - name : mann-whitney             templateName: mann-whitney             args:             - name: baseline-hash               value: "{{templates.baseline.podTemplateHash}}"             - name: canary-hash               value: "{{templates.canary.podTemplateHash}}"

Можно сделать еще интереснее: развернуть N-экспериментальных replicaset, переключить какой-то процент боевого трафика на них и посмотреть, что из этого получится (работает только на SMI, ALB, Istio):

    steps:       - experiment:           duration: 1h           templates:             - name: experiment-baseline               specRef: stable               weight: 5             - name: experiment-canary               specRef: canary               weight: 5

Есть еще удобная функция – не писать весь spec в манифесте rollout, а прицепиться к существующему deployment:

# манифест rollout spec:   replicas: 5   selector:     matchLabels:       app: rollout-ref-deployment   workloadRef:     apiVersion: apps/v1     kind: Deployment     name: rollout-ref-deployment   strategy: #...

Обратите внимание, что rollout не управляет количеством реплик deployment. После наката, у вас будет задвоение (но это позволяет избежать простоя) и если все прошло успешно, вы уменьшаете число реплик у deployment до нуля. С этого момента deployment служит по сути шаблоном spec: все дальнейшие изменения вы делаете в нем (но число реплик всегда должно быть 0), а rollout контроллер отслеживает изменения и порождает replicaset.

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

Если у вас есть замечания, благодарности, или вы хотите поделиться опытом – добро пожаловать в комментарии.

Всем удачных релизов!


ссылка на оригинал статьи https://habr.com/ru/company/ru_mts/blog/695744/


Комментарии

Добавить комментарий

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