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.