# Kubernetes Argo Rollouts

<https://habr.com/ru/companies/slurm/articles/704502/>

![](/files/r2dPfNWciQT5mebLULsM)

Что такое Argo Rollouts? Это контроллер Kubernetes и набор CRD для дополнительных возможностей развёртывания — сине-зелёное, канареечное, прогрессивное, анализ канареечного развёртывания и экспериментирование.

В этой статье поговорим о продвинутых возможностях развёртывания с кастомными ресурсами Kubernetes.

## Argo Rollouts

Как мы увидим, Argo Rollouts предоставляет ресурс rollout в Kubernetes API, на который можно заменить встроенный ресурс deployment. Использование расширенных возможностей в виде ресурса Kubernetes API даёт несколько преимуществ:

* Знакомые методы работы — управляйте развёртываниями с помощью манифестов Kubernetes и *kubectl* CLI.
* Простота понимания — используйте знакомые возможности развёртывания.
* Аутентификация/авторизация — используйте имеющиеся в Kubernetes механизмы для аутентификации и авторизации.
* Привычная программируемость — используйте знакомый API для Argo Rollouts.
* Совместимость с любым решением для непрерывной поставки (CD) — Argo Rollouts развёртывается с помощью манифеста Kubernetes, поэтому может использоваться с любым решением CD.

Другие популярные решения с расширенными возможностями развёртывания не дают этих преимуществ:

* [Spinnaker](https://spinnaker.io/): опенсорс-решение для непрерывной поставки.
* SASS для непрерывной интеграции: [GitLab](https://docs.gitlab.com/ee/user/project/clusters/), [GitHub Actions](https://github.com/marketplace/actions/deploy-to-kubernetes-cluster),[CodeFresh](https://codefresh.io/kubernetes-tutorial/fully-automated-canary-deployments-kubernetes/) и т. д.

Все примеры кода и конфигураций, которые мы будем использовать в этой статье, можно [скачать здесь](https://github.com/larkintuckerllc/hello-argo-rollouts).

## Кластер

Примеры из этой статьи выполнялись в кластере Google Kubernetes Engine (GKE) версии *1.17.14-gke.1600*, но должны работать в любом другом кластере Kubernetes. Лучше если это будет Kubernetes версии 1.15.x и выше.

Итак, вам понадобится:

* Кластер Kubernetes версии 1.15.x и выше.
* kubectl CLI, совместимый с кластером.
* [Установка](https://argoproj.github.io/argo-rollouts/installation/#controller-installation) контроллера Argo Rollouts в кластер.
* [Установка](https://argoproj.github.io/argo-rollouts/installation/#kubectl-plugin-installation) плагина Argo Rollouts kubectl.

## Код рабочей нагрузки

[Рабочая нагрузка](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/server.js) в этом примере представляет собой Express [*Hello World*](https://expressjs.com/en/starter/hello-world.html) и [клиент Prometheus для Node.js](https://github.com/siimon/prom-client). У рабочей нагрузки есть две конечные точки: */* возвращает Hello World!, а */metrics* возвращает метрики в формате Prometheus. Помимо стандартных метрик Node.js конечная точка */metrics* предоставляет две метрики, которые мы будем использовать в примерах:

* *app\_requests\_total*: общее число запросов, исключая конечную точку */metrics*, обработанных рабочей нагрузкой.
* *app\_not\_found\_total*: общее число запросов, которые не соответствовали двум конечным точкам; возвращается ошибка *404*.

Рабочая нагрузка [встроена](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/Dockerfile) в образ контейнера и доступна в [репозитории](https://hub.docker.com/repository/docker/sckmkny/app-1) Docker Hub. В примере мы будем использовать три тега:

* *0.2.0 и 0.3.0*: образы, которые работают ожидаемо.
* *0.3.1*: повреждённый образ, у которого запросы к конечной точке */* входят в метрику *app\_not\_found\_total*.

## Манифесты Kubernetes для рабочей нагрузки

В этой статье мы будем развёртывать разные вариации рабочей нагрузки для иллюстрации разных концепций. Развёртывать рабочие нагрузки мы будем с помощью манифестов Kubernetes в папках проекта. Их имена будут начинаться на *k8s*.

Здесь мы её использовать не будем, но в проекте есть папка [*k8s*](https://github.com/larkintuckerllc/hello-argo-rollouts/tree/master/k8s) с финальной работающей рабочей нагрузкой. Она используется в конфигурации Travis CI для иллюстрации простейшего процесса непрерывной поставки (в этой статье мы не будем его рассматривать).

## Загрузка манифестов Kubernetes

В целях иллюстрации нам понадобится HTTP-трафик для рабочих нагрузок. В папке [*load*](https://github.com/larkintuckerllc/hello-argo-rollouts/tree/master/load) проекта есть нужные манифесты Kubernetes для создания равномерного распределения запросов к конечной точке */* (каждое задание создаёт один запрос в секунду) по всем pod’ам рабочей нагрузки.

## Prometheus и Grafana

Чтобы использовать расширенные возможности анализа в Argo Rollouts, нам понадобится рабочая нагрузка Prometheus в кластере, которая скрейпит конечные точки сервисов, предоставляющие метрики в формате Prometheus. Для визуализации метрик, которые мы будем анализировать, мы также запустим в кластере Grafana.

Для удобства в папке [monitoring](https://github.com/larkintuckerllc/hello-argo-rollouts/tree/master/monitoring) есть нужные манифесты Kubernetes для создания подходящих рабочих нагрузок Prometheus и Grafana. Больше об этих рабочих нагрузках см. в статьях [*с примерами Prometheus*](https://codeburst.io/prometheus-by-example-4804ab86e741) и [*с примерами Grafana*](https://codeburst.io/grafana-by-example-58726443e317)*.*

## k8s-deployment-working

Прежде чем приступить к использованию возможностей Argo Rollouts, давайте вспомним, как мы создаём канареечное развёртывание с помощью deployment. В первой вариации рабочей нагрузки, в изначально стабильном состоянии, у нас есть следующие ресурсы:

* [*Сервис app-1*](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/k8s-deployment-working/app-1-00-service.yaml): предоставляет внутреннюю балансировку нагрузки для pod’ов в deployment’ах *app-1* и *app-1-canary*.
* [*Deployment app-1*](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/k8s-deployment-working/app-1-02-deployment.yaml): содержит пять pod’ов с рабочим образом, *0.3.0*.
* [*Deployment app-1-canary*](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/k8s-deployment-working/app-1-01-canary-deployment.yaml): содержит один pod с рабочим образом, *0.3.0*.

Проверим все эти ресурсы следующей командой:

```
$ kubectl get all
NAME                                READY   STATUS    RESTARTS   AGE
pod/app-1-6fbf6fb56f-4dshr          1/1     Running   0          16s
pod/app-1-6fbf6fb56f-f8zxr          1/1     Running   0          16s
pod/app-1-6fbf6fb56f-hclt9          1/1     Running   0          15s
pod/app-1-6fbf6fb56f-jlc29          1/1     Running   0          16s
pod/app-1-6fbf6fb56f-qq848          1/1     Running   0          16s
pod/app-1-canary-6fbf6fb56f-9n9sg   1/1     Running   0          118s
NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/app-1        ClusterIP   10.8.12.240   <none>        80/TCP    18m
service/kubernetes   ClusterIP   10.8.0.1      <none>        443/TCP   2d8h
NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app-1          5/5     5            5           16s
deployment.apps/app-1-canary   1/1     1            1           118s
NAME                                      DESIRED   CURRENT   READY   AGE
replicaset.apps/app-1-6fbf6fb56f          5         5         5       17s
replicaset.apps/app-1-canary-6fbf6fb56f   1         1         1       119s
```

Итак, всё на месте. Теперь мы подаём нагрузку и видим, что средний процент запросов с ошибкой *404* равен *0*.

![](/files/hBNInSY7S5l2XYkMs3co)

Напоминаю, что мы отслеживаем эти две метрики:

* *app\_requests\_total*: общее число запросов, исключая конечную точку */metrics*, обработанных рабочей нагрузкой.
* *app\_not\_found\_total*: общее число запросов, которые не соответствовали двум конечным точкам; возвращается ошибка *404*.

Вот метрика, которая визуализирована на схеме:

```
avg(rate(app_not_founds_total{kubernetes_namespace="default",
kubernetes_name="app-1"}[$__interval])) /
(avg(rate(app_requests_total{kubernetes_namespace="default",
kubernetes_name="app-1"}[$__interval])) > 0) or
avg(rate(app_requests_total{kubernetes_namespace="default",
kubernetes_name="app-1"}[$__interval]))
```

**Примечание**: оператор *or* усложняет выражение, но зато мы видим значение *0*, если средняя частота запросов равняется *0* (деление на ноль нам не мешает)

## k8s-deployment-broken

Здесь мы добавим в \*[deployment app-1-canary](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/k8s-deployment-broken/app-1-01-canary-deployment.yaml)\*поломанный образ *0.3.1*. На практике сначала всегда нужно обновлять канареечный deployment, чтобы заметить проблемы, пока они затрагивают только часть рабочей нагрузки.

Пускаем трафик и видим, что примерно *1/6* (чуть больше *16%*) запросов завершаются ошибкой 404, и все эти запросы от сломанного канареечного pod’а.

![](/files/GPY4Cg4q5lKaoovD2Dxc)

Увидев эту проблему с канареечным deployment’ом, мы решили откатить *app-1-canary*.

```
$ kubectl rollout undo deployment.v1.apps/app-1-canary
deployment.apps/app-1-canary rolled back
```

Давайте посмотрим на наши ресурсы после отката.

```
$ kubectl get all
...
NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app-1          5/5     5            5           103s
deployment.apps/app-1-canary   1/1     1            1           104s
NAME                                      DESIRED   CURRENT   READY   AGE
replicaset.apps/app-1-6fbf6fb56f          5         5         5       103s
replicaset.apps/app-1-canary-597ff54bb6   0         0         0       70s
replicaset.apps/app-1-canary-6fbf6fb56f   1         1         1       104s
```

Обратите внимание:

* Тут почти всё то же самое, что было до того, как мы добавили в *app-1-canary* поломанный образ, только теперь у нас есть дополнительный набор реплик с *0* реплик — это он управлял проблемным pod’ом.

Смотрим историю deployment’а:

```
$ kubectl rollout history deployment.v1.apps/app-1-canary
deployment.apps/app-1-canary
REVISION  CHANGE-CAUSE
2         <none>
3         <none>
```

Обратите внимание:

* Версия *1* (уже не отображается) обозначала изначальное состояние с рабочим образом.
* Версия *2* соответствует deployment’у с поломанным образом.
* Версия *3* отражает текущее состояния после отката. Версии неизменяемы, так что откат создал новую версию.
* В выходных данных мало информации. Например, непонятно, как сопоставить версии с наборами реплик.

## k8s-rollout-manual-working

Здесь мы реплицируем канареечную функцию с помощью Argo Rollouts. В этой вариации рабочей нагрузки мы начинаем с изначально стабильного состояния со следующими ресурсами:

* [*Сервис app-1*](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/k8s-rollout-manual-working/app-1-00-service.yaml): предоставляет внутреннюю балансировку нагрузки для pod’ов в rollout’е *app-1*.
* [*Rollout app-1*](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/k8s-rollout-manual-working/app-1-01-rollout.yaml): как и deployment до этого, он предоставляет пять pod’ов с рабочим образом, *0.3.0*.

Проверим ресурсы следующей командой:

```
$ kubectl get all
NAME                         READY   STATUS    RESTARTS   AGE
pod/app-1-55c599b68f-fbwzd   1/1     Running   0          33s
pod/app-1-55c599b68f-mlxxj   1/1     Running   0          33s
pod/app-1-55c599b68f-n4lvg   1/1     Running   0          33s
pod/app-1-55c599b68f-nntnq   1/1     Running   0          33s
pod/app-1-55c599b68f-qg44l   1/1     Running   0          33s
NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/app-1        ClusterIP   10.8.15.149   <none>        80/TCP    35s
service/kubernetes   ClusterIP   10.8.0.1      <none>        443/TCP   3d9h
NAME                               DESIRED   CURRENT   READY   AGE
replicaset.apps/app-1-55c599b68f   5         5         5       34s
```

Проверяем rollout:

```
$ kubectl get rollout app-1
NAME    DESIRED   CURRENT   UP-TO-DATE   AVAILABLE
app-1   5         5         5            5
```

Обратите внимание:

* rollout — это не deployment, так что в выходных данных команды *kubectl get all* мы его не видим.
* Rollout, как и deployment, управляет наборами реплик (которые, в свою очередь, управляют pod’ами).
* Выходные данные у rollout’а такие же, как у deployment’а, потому что у них один интерфейс API.

Мы можем узнать больше о rollout’е следующей командой:

```
$ kubectl argo rollouts get rollout app-1
Name:            app-1
Namespace:       default
Status:          ✔ Healthy
Strategy:        Canary
  Step:          8/8
  SetWeight:     100
  ActualWeight:  100
Images:          sckmkny/app-1:0.3.0 (stable)
Replicas:
  Desired:       5
  Current:       5
  Updated:       5
  Ready:         5
  Available:     5
NAME                               KIND        STATUS     AGE  INFO
⟳ app-1                            Rollout     ✔ Healthy  16m
└──# revision:1
   └──⧉ app-1-55c599b68f           ReplicaSet  ✔ Healthy  16m  stable
      ├──□ app-1-55c599b68f-fbwzd  Pod         ✔ Running  16m  ready:1/1
      ├──□ app-1-55c599b68f-mlxxj  Pod         ✔ Running  16m  ready:1/1
      ├──□ app-1-55c599b68f-n4lvg  Pod         ✔ Running  16m  ready:1/1
      ├──□ app-1-55c599b68f-nntnq  Pod         ✔ Running  16m  ready:1/1
      └──□ app-1-55c599b68f-qg44l  Pod         ✔ Running  16m  ready:1/1
```

**Примечание.** Дальше мы будем использовать только подробный вывод для rollout’а, потому что он гораздо интереснее. Пока мы говорили о сходствах rollout’а и deployment’а. Теперь поговорим о различиях.

В примере с *рабочим deployment’ом* у нас было *0*% запросов с ошибкой.

## k8s-rollout-manual-broken

Теперь добавим в \*[rollout app-1](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/k8s-rollout-manual-broken/app-1-01-rollout.yaml)\*поломанный образ *0.3.1*. Здесь, в отличие от deployment’а, rollout обновил одну реплику и остановился.

Давайте посмотрим поближе:

```
$ kubectl argo rollouts get rollout app-1
Name:            app-1
Namespace:       default
Status:          ॥ Paused
Message:         CanaryPauseStep
Strategy:        Canary
  Step:          1/8
  SetWeight:     20
  ActualWeight:  20
Images:          sckmkny/app-1:0.3.0 (stable)
                 sckmkny/app-1:0.3.1 (canary)
Replicas:
  Desired:       5
  Current:       5
  Updated:       1
  Ready:         5
  Available:     5
NAME                               KIND        STATUS     AGE   INFO
⟳ app-1                            Rollout     ॥ Paused   23h
├──# revision:2
│  └──⧉ app-1-57c5db7ccd           ReplicaSet  ✔ Healthy  113s  canary
│     └──□ app-1-57c5db7ccd-9w7rz  Pod         ✔ Running  113s  ready:1/1
└──# revision:1
   └──⧉ app-1-55c599b68f           ReplicaSet  ✔ Healthy  23h   stable
      ├──□ app-1-55c599b68f-fbwzd  Pod         ✔ Running  23h   ready:1/1
      ├──□ app-1-55c599b68f-mlxxj  Pod         ✔ Running  23h   ready:1/1
      ├──□ app-1-55c599b68f-n4lvg  Pod         ✔ Running  23h   ready:1/1
      └──□ app-1-55c599b68f-nntnq  Pod         ✔ Running  23h   ready:1/1
```

Обратите внимание:

* В отличие от deployment’а, rollout остановился, пока никто из pod’ов ещё не сообщил о проблеме. Deployment останавливается, только если кто-то из pod’ов не готов.
* Как видим, rollout тоже создал один канареечный pod.

Давайте посмотрим на главное различие между настройкой deployment’а и rollout’а — блок *strategy*. Вот блок strategy для rollout’а [*app-1–01-rollout.yaml*](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/k8s-rollout-manual-broken/app-1-01-rollout.yaml)*:*

```
strategy:
  canary:
    steps:
    - setWeight: 20
    - pause: {duration: 5m}
    - analysis:
        templates:
        - templateName: not-found-percentage
        args:
        - name: service-name
          value: app-1
```

Обратите внимание:

* Эти восемь шагов (steps) соответствуют восьми шагам, указанным в подробных выходных данных rollout’а, причём там мы видим, что последним был выполнен шаг *1*
* Weight — это процент от количества реплик, которые мы хотели обновить. На *20*% процесс остановился, обновив одну реплику (*5 \* 0,2 = 1*).
* Для паузы не указана длительность, а значит мы должны вручную разрешить или запретить продолжение операции.
* Этот пример немного надуманный, потому что шаги после первой паузы нам не нужны (приводятся здесь для иллюстрации).

Если бы мы пустили трафик, то увидели бы, что примерно *1/5* (чуть больше 20%) запросов завершаются ошибкой 404, и все эти запросы поступают от сломанного канареечного pod’а.

Увидев эту проблему, мы решили отменить rollout *app-1*.

```
$ kubectl argo rollouts abort app-1
rollout 'app-1' aborted
```

В подробных выходных данных видно, что произошло:

```
$ kubectl argo rollouts get rollout app-1
Name:            app-1
Namespace:       default
Status:          ✖ Degraded
Message:         RolloutAborted: Rollout is aborted
Strategy:        Canary
  Step:          0/8
  SetWeight:     0
  ActualWeight:  0
Images:          sckmkny/app-1:0.3.0 (stable)
Replicas:
  Desired:       5
  Current:       5
  Updated:       0
  Ready:         5
  Available:     5
NAME                               KIND        STATUS        AGE  INFO
⟳ app-1                            Rollout     ✖ Degraded    23h
├──# revision:2
│  └──⧉ app-1-57c5db7ccd           ReplicaSet  • ScaledDown  18m  canary
└──# revision:1
   └──⧉ app-1-55c599b68f           ReplicaSet  ✔ Healthy     23h  stable
      ├──□ app-1-55c599b68f-fbwzd  Pod         ✔ Running     23h  ready:1/1
      ├──□ app-1-55c599b68f-mlxxj  Pod         ✔ Running     23h  ready:1/1
      ├──□ app-1-55c599b68f-n4lvg  Pod         ✔ Running     23h  ready:1/1
      ├──□ app-1-55c599b68f-nntnq  Pod         ✔ Running     23h  ready:1/1
      └──□ app-1-55c599b68f-rz92r  Pod         ✔ Running     92s  ready:1/1
```

Обратите внимание:

* Здесь мы видим, что rollout находится в состоянии Degraded, потому что у последней версии (revision) нет реплик.

Чтобы вернуть rollout в состояние Healthy, мы обновляем [*rollout app-1*](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/k8s-rollout-manual-working/app-1-01-rollout.yaml), взяв изначальный образ *0.3.0*.

Вот что у нас получится:

```
$ kubectl argo rollouts get rollout app-1
Name:            app-1
Namespace:       default
Status:          ✔ Healthy
Strategy:        Canary
  Step:          8/8
  SetWeight:     100
  ActualWeight:  100
Images:          sckmkny/app-1:0.3.0 (stable)
Replicas:
  Desired:       5
  Current:       5
  Updated:       5
  Ready:         5
  Available:     5
NAME                               KIND        STATUS        AGE    INFO
⟳ app-1                            Rollout     ✔ Healthy     23h
├──# revision:3
│  └──⧉ app-1-55c599b68f           ReplicaSet  ✔ Healthy     23h    stable
│     ├──□ app-1-55c599b68f-fbwzd  Pod         ✔ Running     23h    ready:1/1
│     ├──□ app-1-55c599b68f-mlxxj  Pod         ✔ Running     23h    ready:1/1
│     ├──□ app-1-55c599b68f-n4lvg  Pod         ✔ Running     23h    ready:1/1
│     ├──□ app-1-55c599b68f-nntnq  Pod         ✔ Running     23h    ready:1/1
│     └──□ app-1-55c599b68f-rz92r  Pod         ✔ Running     4m18s  ready:1/1
└──# revision:2
   └──⧉ app-1-57c5db7ccd           ReplicaSet  • ScaledDown  21m
```

Обратите внимание:

* В отличие от deployment’а, мы можем легко связать версию с набором реплик, например здесь у revision *3* тот же Replicaset, что и у revision *1* (из предыдущих выходных данных).

## k8s-rollout-analysis-initial

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

* [*Сервис app-1*](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/k8s-rollout-analysis-initial/app-1-00-service.yaml): предоставляет внутреннюю балансировку нагрузки для pod’ов в rollout’е *app-1* (тот же, что и раньше).
* [*Rollout app-1*](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/k8s-rollout-analysis-initial/app-1-01-rollout.yaml): rollout, который автоматизирует анализ канареечного pod’а, то есть на основе метрики выбирает — продолжить или отменить rollout.
* [*Шаблон анализа app-1*](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/k8s-rollout-analysis-initial/00-not-found-percentage-analysistemplate.yaml): метрика и логика, которую использует rollout. В этом шаблоне мы видим те же шаги, которые делали вручную, когда смотрели на панель Grafana, чтобы узнать, всё ли в порядке с pod’ом.

Давайте посмотрим на блок strategy для этого rollout’а.

```
strategy:
  canary:
    steps:
    - setWeight: 20
    - pause: {duration: 5m}
    - analysis:
        templates:
        - templateName: not-found-percentage
        args:
        - name: service-name
          value: app-1
```

Обратите внимание:

* На первом шаге мы выполняем один канаречный pod в течение пяти минут. Этого достаточно, чтобы Prometheus успел насобирать метрики.
* Здесь мы проиллюстрируем использование параметризованного шаблона и передадим в AnalysisTemplate *service-name: app-1*.

Как видите, ничего особо не поменялось:

```
$ kubectl argo rollouts get rollout app-1
Name:            app-1
Namespace:       default
Status:          ✔ Healthy
Strategy:        Canary
  Step:          3/3
  SetWeight:     100
  ActualWeight:  100
Images:          sckmkny/app-1:0.2.0 (stable)
Replicas:
  Desired:       5
  Current:       5
  Updated:       5
  Ready:         5
  Available:     5

NAME                              KIND        STATUS     AGE  INFO
⟳ app-1                           Rollout     ✔ Healthy  13s
└──# revision:1
   └──⧉ app-1-58dcdc8db           ReplicaSet  ✔ Healthy  13s  stable
      ├──□ app-1-58dcdc8db-5tcsd  Pod         ✔ Running  13s  ready:1/1
      ├──□ app-1-58dcdc8db-7vk29  Pod         ✔ Running  13s  ready:1/1
      ├──□ app-1-58dcdc8db-gf4x4  Pod         ✔ Running  13s  ready:1/1
      ├──□ app-1-58dcdc8db-hp9sl  Pod         ✔ Running  13s  ready:1/1
      └──□ app-1-58dcdc8db-m4bz5  Pod         ✔ Running  13s  ready:1/1
```

## k8s-rollout-analysis-working

Теперь добавим в [*rollout app-1*](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/k8s-rollout-analysis-working/app-1-01-rollout.yaml) ещё один рабочий образ *0.3.0*, чтобы показать автоматическое продолжение rollout’а. Через *5* минут проверяем, как дела:

Обратите внимание:

```
$ kubectl argo rollouts get rollout app-1
Name:            app-1
Namespace:       default
Status:          ✔ Healthy
Strategy:        Canary
  Step:          3/3
  SetWeight:     100
  ActualWeight:  100
Images:          sckmkny/app-1:0.3.0 (stable)
Replicas:
  Desired:       5
  Current:       5
  Updated:       5
  Ready:         5
  Available:     5

NAME                               KIND         STATUS        AGE   INFO
⟳ app-1                            Rollout      ✔ Healthy     22m
├──# revision:2
│  ├──⧉ app-1-55c599b68f           ReplicaSet   ✔ Healthy     14m   stable
│  │  ├──□ app-1-55c599b68f-6fx2z  Pod          ✔ Running     14m   ready:1/1
│  │  ├──□ app-1-55c599b68f-lcj7r  Pod          ✔ Running     9m9s  ready:1/1
│  │  ├──□ app-1-55c599b68f-qdl7k  Pod          ✔ Running     9m9s  ready:1/1
│  │  ├──□ app-1-55c599b68f-fkvr6  Pod          ✔ Running     9m7s  ready:1/1
│  │  └──□ app-1-55c599b68f-h2jmq  Pod          ✔ Running     9m7s  ready:1/1
│  └──α app-1-55c599b68f-2-2       AnalysisRun  ✔ Successful  9m9s  ✔ 1
└──# revision:1
   └──⧉ app-1-58dcdc8db            ReplicaSet   • ScaledDown  22m
```

* Как видим, rollout автоматически переведён в версию *2*
* Появился новый ресурс: успешный AnalysisRun.

Давайте изучим его самую важную часть:

```
$ kubectl describe analysisrun app-1-55c599b68f-2-2
...
Status:
  Metric Results:
    Count:  1
    Measurements:
      Finished At:  2021-02-13T15:21:50Z
      Phase:        Successful
      Started At:   2021-02-13T15:21:50Z
      Value:        [0]
    Name:           not-found-percentage
    Phase:          Successful
    Successful:     1
  Phase:            Successful
  Started At:       2021-02-13T15:21:50Z
...
```

Обратите внимание:

Мы видим не только состояние Succesful, но и фактическое значение (здесь это *0*), возвращённое запросом Prometheus.

## k8s-rollout-analysis-broken

Теперь добавим в [*rollout app-1*](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/k8s-rollout-analysis-broken/app-1-01-rollout.yaml) поломанный образ *0.3.1.*, чтобы показать автоматическую отмену rollout’а. Через *5* минут проверяем, как дела:

```
$ kubectl argo rollouts get rollout app-1
Name:            app-1
Namespace:       default
Status:          ✖ Degraded
Message:         RolloutAborted: metric "not-found-percentage" assessed Failed due to failed (1) > failureLimit (0)
Strategy:        Canary
  Step:          0/3
  SetWeight:     0
  ActualWeight:  0
Images:          sckmkny/app-1:0.3.0 (stable)
Replicas:
  Desired:       5
  Current:       5
  Updated:       0
  Ready:         5
  Available:     5

NAME                               KIND         STATUS        AGE  INFO
⟳ app-1                            Rollout      ✖ Degraded    45m
├──# revision:3
│  ├──⧉ app-1-57c5db7ccd           ReplicaSet   • ScaledDown  16m  canary
│  └──α app-1-57c5db7ccd-3-2       AnalysisRun  ✖ Failed      11m  ✖ 1
├──# revision:2
│  ├──⧉ app-1-55c599b68f           ReplicaSet   ✔ Healthy     37m  stable
│  │  ├──□ app-1-55c599b68f-6fx2z  Pod          ✔ Running     37m  ready:1/1
│  │  ├──□ app-1-55c599b68f-lcj7r  Pod          ✔ Running     32m  ready:1/1
│  │  ├──□ app-1-55c599b68f-qdl7k  Pod          ✔ Running     32m  ready:1/1
│  │  ├──□ app-1-55c599b68f-h2jmq  Pod          ✔ Running     32m  ready:1/1
│  │  └──□ app-1-55c599b68f-pw8kv  Pod          ✔ Running     11m  ready:1/1
│  └──α app-1-55c599b68f-2-2       AnalysisRun  ✔ Successful  32m  ✔ 1
└──# revision:1
   └──⧉ app-1-58dcdc8db            ReplicaSet   • ScaledDown  45m
```

Часть AnalysisRun:

```
kubectl describe analysisrun app-1-57c5db7ccd-3-2
...
Status:
  Message:  metric "not-found-percentage" assessed Failed due to failed (1) > failureLimit (0)
  Metric Results:
    Count:   1
    Failed:  1
    Measurements:
      Finished At:  2021-02-13T15:42:34Z
      Phase:        Failed
      Started At:   2021-02-13T15:42:34Z
      Value:        [0.22925031610593755]
    Name:           not-found-percentage
    Phase:          Failed
  Phase:            Failed
  Started At:       2021-02-13T15:42:34Z
...
```

Обратите внимание:

* Значение превышает 0,1, то есть проверка не пройдена.
* Здесь rollout автоматически отменяется — как мы бы это сделали вручную.
* Чтобы вернуть rollout в состояние Healthy, мы обновляем [*rollout app-1*](https://github.com/larkintuckerllc/hello-argo-rollouts/blob/master/k8s-rollout-analysis-working/app-1-01-rollout.yaml), взяв рабочий образ *0.3.0*.

##


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.konstantinsecurity.com/readme/architect/ci-cd/kubernetes-argo-rollouts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
