Liberação Gradual Suave Usando APISIX Ingress Controller com Flagger

Hengliang Tan

January 19, 2023

Ecosystem

Autor: Hengliang Tan, Gerente de Engenharia na XPENG

No processo de desenvolvimento de projetos, as atualizações de serviços são frequentemente um desafio. Para proporcionar a melhor experiência ao usuário, precisamos evitar ao máximo o risco de indisponibilidade do serviço. Assim, nasceu a entrega contínua, aceita como uma prática de software empresarial e uma evolução natural dos princípios bem estabelecidos de integração contínua. No entanto, a implantação contínua ainda é muito rara devido à complexidade de gerenciamento e ao medo de que falhas na implantação afetem a disponibilidade do sistema. O lançamento canário é provavelmente o cenário mais clássico no sistema de entrega contínua. Com base nisso, podemos descobrir rapidamente serviços problemáticos e não saudáveis e reverter para a versão anterior sem esforço.

Lançamento Canário

O lançamento canário também é conhecido como lançamento em escala de cinza. Geralmente, a nova versão do aplicativo é lançada e implantada como um "canário" para testar o desempenho. A versão antiga permanece para operações normais no mesmo estágio. Durante a atualização, alguns usuários serão direcionados para usar a nova versão, enquanto outros continuarão a usar a versão antiga. Sob a premissa de garantir a estabilidade geral do sistema, ele permite a detecção precoce de bugs e ajustes oportunos.

O lançamento canário não libera diretamente a atualização. Ele orienta lentamente uma certa porcentagem de tráfego para um pequeno número de usuários. Se nenhum erro for detectado, ele será promovido para todos os usuários, e a versão antiga será gradualmente eliminada. Esse método reduz o risco de introduzir novas funções no ambiente de produção.

Este artigo apresentará como alcançar um lançamento canário suave através do Apache APISIX Ingress e Flagger, melhorar a eficiência de lançamento e reduzir os riscos de lançamento.

Sobre o Apache APISIX Ingress

O Apache APISIX Ingress é realizado pelo Kubernetes Ingress Controller que usa o Apache APISIX como o proxy do plano de dados. Ele fornece centenas de funções, como balanceamento de carga, upstream dinâmico, lançamento canário, roteamento granular, limitação de taxa, degradação de serviço, interrupção de serviço, autenticação e observabilidade. Ele foi adotado por empresas e organizações nacionais e internacionais, incluindo Zoom, Tencent Cloud, Jiakaobaodian, Horizon Robotics, European Copernicus Reference System, etc.

Sobre o Flagger

O Flagger é um projeto da CNCF (Cloud Native Computing Foundation) e parte da família de ferramentas GitOps do Flux. Recentemente, a CNCF também anunciou a graduação oficial do Flux, o que é um bom indicador do sucesso e do futuro promissor da tecnologia nativa em nuvem. Como uma ferramenta de entrega progressiva, o Flagger automatiza o processo de lançamento para aplicativos em execução no Kubernetes. Ele reduz o risco de introduzir uma nova versão de software em produção, deslocando gradualmente o tráfego para a nova versão enquanto mede métricas analíticas e executa testes de conformidade.

Após esforços contínuos das comunidades Apache APISIX e Flux, o Flagger lançou recentemente a versão v1.27.0, que suporta lançamentos canários automatizados usando Apache APISIX Ingress e Flagger.

featured-<Flagger and Apache APISIX Ingress>.jpg

Vamos experimentar juntos esse processo suave de lançamento canário.

Ambiente

Requer um cluster Kubernetes v1.19 ou mais recente, que você pode instalar via kind.

Instalação de Componentes

Use o Helm V3 para instalar o Apache APISIX e o Apache APISIX Ingress Controller

helm repo add apisix https://charts.apiseven.com
kubectl create ns apisix


helm upgrade -i apisix apisix/apisix --version=0.11.3 \
--namespace apisix \
--set apisix.podAnnotations."prometheus\.io/scrape"=true \
--set apisix.podAnnotations."prometheus\.io/port"=9091 \
--set apisix.podAnnotations."prometheus\.io/path"=/apisix/prometheus/metrics \
--set pluginAttrs.prometheus.export_addr.ip=0.0.0.0 \
--set pluginAttrs.prometheus.export_addr.port=9091 \
--set pluginAttrs.prometheus.export_uri=/apisix/prometheus/metrics \
--set pluginAttrs.prometheus.metric_prefix=apisix_ \
--set ingress-controller.enabled=true \
--set ingress-controller.config.apisix.serviceNamespace=apisix

Instale os componentes Flagger e Prometheus no namespace apisix.

helm repo add flagger https://flagger.app


helm upgrade -i flagger flagger/flagger \
--namespace apisix \
--set prometheus.install=true \
--set meshProvider=apisix

Nota: se você precisar personalizar o Prometheus ou o Prometheus Operator, pode pesquisar artigos relacionados para modificação.

Inicialização do Aplicativo

O Flagger pode ser aplicado a implantações do Kubernetes e outras cargas de trabalho, e também pode ser combinado com HPA. Ele criará uma série de objetos: implantações do Kubernetes, serviços ClusterIP e ApisixRoute. Esses objetos podem expor aplicativos para fora dos clusters para fornecer serviços e são usados para a análise do processo de lançamento canário.

Crie um novo namespace de teste:

kubectl create ns test

Crie uma nova implantação e HPA. Aqui extraímos o exemplo de código oficial do Flagger.

kubectl apply -k https://github.com/fluxcd/flagger//kustomize/podinfo?ref=main

Implante o serviço de teste de carga do Flagger para gerar tráfego durante o lançamento canário para análise.

helm upgrade -i flagger-loadtester flagger/loadtester \ --namespace=test

Crie o ApisixRoute do Apache APISIX, e então o Flagger fará referência ao recurso criado e gerará o ApisixRoute do Apache APISIX Ingress na versão canário. (Substitua app.example.com no exemplo abaixo pelo seu domínio real)

apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
  name: podinfo
  namespace: test
spec:
  http:
    - backends:
        - serviceName: podinfo
          servicePort: 80
      match:
        hosts:
          - app.example.com
        methods:
          - GET
        paths:
          - /*
      name: method
      plugins:
        - name: prometheus
          enable: true
          config:
            disable: false
            prefer_name: true

Salve como podinfo-apisixroute.yaml e envie para o cluster:

kubectl apply -f ./podinfo-apisixroute.yaml

Crie um recurso personalizado Canary do Flagger. (Substitua app.example.com no exemplo pelo seu domínio real)

apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: podinfo
  namespace: test
spec:
  provider: apisix
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: podinfo
  # Referencie a rota apisix
  routeRef:
    apiVersion: apisix.apache.org/v2
    kind: ApisixRoute
    name: podinfo
  progressDeadlineSeconds: 60
  service:
    port: 80
    targetPort: 9898
  analysis:
    interval: 10s
    # número máximo de falhas para reversão
    threshold: 10
    # porcentagem máxima de tráfego para a versão canário
    # (0-100)
    maxWeight: 50
    # tamanho do passo da análise canário
    # (0-100)
    stepWeight: 10
    # use Prometheus para verificar as informações de tráfego do APISIX
    metrics:
      - name: request-success-rate
        # taxa mínima de sucesso (nenhuma resposta 5xx)
        # (0-100)
        thresholdRange:
          min: 99
        interval: 1m
      - name: request-duration
        # P99 é o maior atraso de solicitação(ms)
        thresholdRange:
          max: 500
        interval: 30s
    webhooks:
        # tráfego automatizado para análise canário, modificado com base no cenário real
      - name: load-test
        url: http://flagger-loadtester.test/
        timeout: 5s
        type: rollout
        metadata:
          cmd: |-
            hey -z 1m -q 10 -c 2 -h2 -host app.example.com http://apisix-gateway.apisix/api/info

Salve como podinfo-canary.yaml e envie para o cluster:

kubectl apply -f ./podinfo-canary.yaml

O Flagger gerará automaticamente os recursos relacionados:

# Enviado deployment.apps/podinfo horizontalpodautoscaler.autoscaling/podinfo apisixroute/podinfo canary.flagger.app/podinfo

# Gerado automaticamente deployment.apps/podinfo-primary horizontalpodautoscaler.autoscaling/podinfo-primary service/podinfo service/podinfo-canary service/podinfo-primary apisixroute/podinfo-podinfo-canary

featured-<version 1>.jpg

Neste ponto, você pode acessar o aplicativo através do domínio app.example.com (Substitua app.example.com no exemplo pelo seu domínio real), e você verá a versão atual do aplicativo.

Automação do Lançamento Canário

O Flagger implementa um loop de controle que gradualmente desloca o tráfego para os nós canário enquanto mede métricas-chave de desempenho, como taxa de sucesso de solicitações HTTP, duração média de solicitação e saúde do pod. De acordo com a análise dos indicadores relevantes, libere ou interrompa a implantação canário e publique os resultados da análise em plataformas relevantes como Slack, MS Teams ou Prometheus Alert Manager, etc.

Flagger Control Loop

Disparar um lançamento canário atualizando a versão da imagem do contêiner

kubectl -n test set image deployment/podinfo \ podinfod=stefanprodan/podinfo:6.0.1

O Flagger detecta que há uma nova versão da implantação e iniciará uma execução de teste da análise canário.

kubectl -n test describe canary/podinfo

Status:
  Canary Weight:  0
  Conditions:
    Message:               Análise canário concluída com sucesso, promoção finalizada.
    Reason:                Succeeded
    Status:                True
    Type:                  Promoted
  Failed Checks:           1
  Iterations:              0
  Phase:                   Succeeded

Events:
  Type     Reason  Age                    From     Message
  ----     ------  ----                   ----     -------
  Warning  Synced  2m59s                  flagger  podinfo-primary.test não está pronto: aguardando a finalização da implantação: geração de implantação observada menor que a geração desejada
  Warning  Synced  2m50s                  flagger  podinfo-primary.test não está pronto: aguardando a finalização da implantação: 0 de 1 (limiar de prontidão 100%) réplicas atualizadas estão disponíveis
  Normal   Synced  2m40s (x3 over 2m59s)  flagger  todos os provedores de métricas estão disponíveis!
  Normal   Synced  2m39s                  flagger  Inicialização concluída! podinfo.test
  Normal   Synced  2m20s                  flagger  Nova revisão detectada! Escalando podinfo.test
  Warning  Synced  2m (x2 over 2m10s)     flagger  implantação canário podinfo.test não está pronta: aguardando a finalização da implantação: 0 de 1 (limiar de prontidão 100%) réplicas atualizadas estão disponíveis
  Normal   Synced  110s                   flagger  Iniciando análise canário para podinfo.test
  Normal   Synced  109s                   flagger  Avançando peso canário podinfo.test 10
  Warning  Synced  100s                   flagger  Interrompendo avanço, nenhum valor encontrado para a métrica apisix request-success-rate, provavelmente podinfo.test não está recebendo tráfego: execução da consulta falhou: nenhum valor encontrado
  Normal   Synced  90s                    flagger  Avançando peso canário podinfo.test 20
  Normal   Synced  80s                    flagger  Avançando peso canário podinfo.test 30
  Normal   Synced  69s                    flagger  Avançando peso canário podinfo.test 40
  Normal   Synced  59s                    flagger  Avançando peso canário podinfo.test 50
  Warning  Synced  30s (x2 over 40s)      flagger  podinfo-primary.test não está pronto: aguardando a finalização da implantação: 1 réplica antiga está pendente de término
  Normal   Synced  9s (x3 over 50s)       flagger  (combinado de eventos semelhantes): Promoção concluída! Reduzindo podinfo.test

Durante o processo de lançamento canário, você receberá respostas diferentes ao acessar o aplicativo através do domínio app.example.com (Substitua app.example.com pelo seu domínio real).

featured-<version 2>.jpg

Ao visualizar o recurso ApisixRoute podinfo-podinfo-canary do Apache APISIX criado automaticamente pelo Flagger, você descobrirá que os pesos do serviço podinfo-primary e do serviço podinfo-canary mudam junto com o processo de publicação.

spec:
  http:
    - backends:
        - serviceName: podinfo-primary
          servicePort: 80
          # Ajustado automaticamente pelo Flagger
          weight: 80
        - serviceName: podinfo-canary
          servicePort: 80
          # Ajustado automaticamente pelo Flagger
          weight: 20

Você verá a versão estável mais recente quando a liberação final estiver concluída.

featured-<version 3>.jpg

Nota: O Flagger reexecutará a análise canário se você alterar a implantação novamente durante o lançamento canário.

Você pode observar todos os lançamentos canário com este comando:

watch kubectl get canaries --all-namespaces

NAMESPACE   NAME      STATUS      WEIGHT   LASTTRANSITIONTIME
test        podinfo-2   Progressing   10       2022-11-23T05:00:54Z
test        podinfo     Succeeded     0        2022-11-23T06:00:54Z

Reversão

Durante a análise de lançamento canário, você pode testar o Flagger para suspender o lançamento canário e reverter para a versão antiga gerando um HTTP 500 Bad Request.

Disparar outro lançamento canário:

kubectl -n test set image deployment/podinfo \ podinfod=stefanprodan/podinfo:6.0.2

Entre no contêiner do testador de carga

kubectl -n test exec -it deploy/flagger-loadtester bash

Gere erro HTTP 500:

hey -z 1m -c 5 -q 5 -host app.example.com http://apisix-gateway.apisix/status/500

Simule atraso no servidor:

watch -n 1 curl -H \"host: app.example.com\" http://apisix-gateway.apisix/delay/1

Quando o número de falhas detectadas atingir o limiar da análise canário, o tráfego é automaticamente redirecionado para o nó principal, o nó canário é reduzido para zero e o processo de lançamento canário é marcado como falho.

kubectl -n apisix logs deploy/flagger -f | jq .msg

"Nova revisão detectada! Escalando podinfo.test"
"implantação canário podinfo.test não está pronta: aguardando a finalização da implantação: 0 de 1 (limiar de prontidão 100%) réplicas atualizadas estão disponíveis"
"Iniciando análise canário para podinfo.test"
"Avançando peso canário podinfo.test 10"
"Interrompendo avanço podinfo.test taxa de sucesso 0.00% < 99%"
"Interrompendo avanço podinfo.test taxa de sucesso 26.76% < 99%"
"Interrompendo avanço podinfo.test taxa de sucesso 34.19% < 99%"
"Interrompendo avanço podinfo.test taxa de sucesso 37.32% < 99%"
"Interrompendo avanço podinfo.test taxa de sucesso 39.04% < 99%"
"Interrompendo avanço podinfo.test taxa de sucesso 40.13% < 99%"
"Interrompendo avanço podinfo.test taxa de sucesso 48.28% < 99%"
"Interrompendo avanço podinfo.test taxa de sucesso 50.35% < 99%"
"Interrompendo avanço podinfo.test taxa de sucesso 56.92% < 99%"
"Interrompendo avanço podinfo.test taxa de sucesso 67.70% < 99%"
"Revertendo podinfo.test limiar de verificações falhas atingido 10"
"Canário falhou! Reduzindo podinfo.test"

Personalização de Métricas para Análise Canário

A análise canário pode ser estendida consultando métricas do Prometheus. Personalizamos com base em cenários de negócios reais. Crie um modelo de métrica e envie para o cluster.

apiVersion: flagger.app/v1beta1
kind: MetricTemplate
metadata:
  name: not-found-percentage
  namespace: test
spec:
  provider:
    type: prometheus
    address: http://flagger-prometheus.apisix:9090
  query: |
    sum(
      rate(
        apisix_http_status{
          route=~"{{ namespace }}_{{ route }}-{{ target }}-canary_.+",
          code!~"4.."
        }[{{ interval }}]
      )
    )
    /
    sum(
      rate(
        apisix_http_status{
          route=~"{{ namespace }}_{{ route }}-{{ target }}-canary_.+"
        }[{{ interval }}]
      )
    ) * 100
# Modifique a análise no lançamento canário e adicione o modelo de indicador criado acima.
  analysis:
    metrics:
      - name: "404s percentage"
        templateRef:
          name: not-found-percentage
        thresholdRange:
          max: 5
        interval: 1m

A configuração acima valida o canário verificando se o QPS (Consultas por segundo) de solicitações HTTP 404 é maior que 5% do tráfego total. O lançamento canário falha se as solicitações HTTP 404 excederem o limiar de 5%.

Resumo

O processo acima pode ser estendido com mais verificações de métricas personalizadas, Webhook, aprovações manuais e notificações no Slack ou MS Teams.

Um lançamento canário muito suave é alcançado através da integração do Apache APISIX e Flagger, o que melhora a eficiência de lançamento e reduz os riscos de lançamento. No futuro, as duas comunidades cooperarão mais de perto para realizar mais capacidades de publicação, como Espelhamento Azul/Verde e Testes A/B.

Tags: