Liberação Gradual Suave Usando APISIX Ingress Controller com Flagger
Hengliang Tan
January 19, 2023
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.
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
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.
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).
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.
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.