Transfira o tráfego gradualmente para novas versões do Service com base em cabeçalho, cookie ou peso antes do corte total.
Contexto
Tanto os lançamentos graduais (também chamados de canary releases) quanto as implantações blue-green executam uma nova versão simultaneamente à antiga e direcionam parte do tráfego para ela. Após a estabilização, todo o tráfego passa para a nova versão e a versão antiga sai de operação.
O ACK Nginx Ingress Controller oferece suporte a dois métodos de divisão de tráfego baseados em annotations:
|
Método |
Status |
Observações |
|
Annotations |
Ativo |
Método oficial da comunidade. Use este método para todas as novas configurações. |
|
Annotations |
Obsoleto |
Indisponível no Nginx Ingress Controller v1.12 e versões posteriores. Não use. |
Casos de uso
-
Divisão de tráfego com base em requisições do cliente: direcione o tráfego para a nova versão apenas quando uma requisição contiver um cabeçalho ou cookie específico — por exemplo,
foo=bar. As demais requisições seguem para a versão antiga. Após a estabilização, migre todo o tráfego. -
Divisão de tráfego com base no peso do Service: direcione uma porcentagem fixa de tráfego — por exemplo, 20% — para a nova versão. Aumente gradualmente a porcentagem até que todo o tráfego vá para a nova versão.
Dimensões de divisão de tráfego com suporte:
Cabeçalho da requisição — ideal para lançamentos graduais e testes A/B
Cookie — ideal para lançamentos graduais e testes A/B
Parâmetro de query — ideal para lançamentos graduais e testes A/B
Peso do Service — ideal para implantações blue-green
O método de annotation canary-*
Referência de annotations
Todas as configurações canary exigem a annotation nginx.ingress.kubernetes.io/canary: "true". Outras annotations definem a lógica de roteamento.
|
Annotation |
Descrição |
Versão mín. |
|
|
Ativa o recurso canary. Defina como |
>=v0.22.0 |
|
|
Roteia requisições para o Service canary com base em um cabeçalho de requisição. Valores especiais: |
>=v0.22.0 |
|
|
Roteia requisições para o Service canary quando o cabeçalho definido por |
>=v0.30.0 |
|
|
Roteia requisições para o Service canary quando o cabeçalho definido por |
>=v0.44.0 |
|
|
Roteia requisições para o Service canary com base em um cookie, por exemplo, |
>=v0.22.0 |
|
|
Roteia uma porcentagem de requisições para o Service canary com base no peso. Intervalo: |
>=v0.22.0 |
|
|
Define o denominador total do peso. Padrão: |
>=v1.1.2 |
Prioridade das annotations (ordem decrescente):
canary-by-header > canary-by-cookie > canary-weight
Cada regra do Ingress suporta apenas um Ingress canary. O controlador ignora Ingresses canary adicionais.
Etapa 1: Implantar o Service
Implante um Service Nginx e exponha-o para acesso por domínio na camada 7 com o Nginx Ingress Controller.
-
Crie um Deployment e um Service. Salve o seguinte conteúdo em
nginx.yaml.Aplique o manifesto:
kubectl apply -f nginx.yaml -
Crie o Ingress. Salve o seguinte conteúdo em
ingress.yaml.Para clusters da v1.19 e posteriores
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: gray-release spec: ingressClassName: nginx rules: - host: www.example.com http: paths: # Old version of the service. - path: / backend: service: name: old-nginx port: number: 80 pathType: ImplementationSpecificPara clusters anteriores à v1.19
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: gray-release spec: rules: - host: www.example.com http: paths: # Old version of the service. - path: / backend: serviceName: old-nginx servicePort: 80Aplique o manifesto:
kubectl apply -f ingress.yaml -
Verifique a implantação. Obtenha o endereço IP externo:
kubectl get ingressTeste o acesso de roteamento:
curl -H "Host: www.example.com" http://<EXTERNAL_IP>Resultado esperado:
old
Etapa 2: Lançar a nova versão do Service
Implante a nova versão do Nginx e configure as regras de roteamento canary.
-
Crie o novo Deployment e Service. Salve o seguinte conteúdo em
nginx1.yaml.Aplique o manifesto:
kubectl apply -f nginx1.yaml -
Crie um Ingress canary para rotear o tráfego para a nova versão. Três estratégias estão disponíveis. Estratégia A: Roteamento por cabeçalho de requisição Roteie requisições para a nova versão apenas quando o cabeçalho
foofor igual abar. As demais requisições vão para a versão antiga. Salve o seguinte conteúdo emingress1.yaml. Para clusters da v1.19 e posteriores:Com o cabeçalho
foo: bar: 100% do tráfego vai paranew-nginx(controlado porcanary-by-headerecanary-by-header-value).Sem o cabeçalho
foo: bar: 50% do tráfego vai paranew-nginx(controlado porcanary-weight).
Para clusters da v1.19 e posteriores
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: gray-release-canary annotations: # Enable canary routing. nginx.ingress.kubernetes.io/canary: "true" # Route to new-nginx only when the foo header equals bar. nginx.ingress.kubernetes.io/canary-by-header: "foo" nginx.ingress.kubernetes.io/canary-by-header-value: "bar" spec: ingressClassName: nginx rules: - host: www.example.com http: paths: # New version of the service. - path: / backend: service: name: new-nginx port: number: 80 pathType: ImplementationSpecificPara clusters anteriores à v1.19
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: gray-release-canary annotations: nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-by-header: "foo" nginx.ingress.kubernetes.io/canary-by-header-value: "bar" spec: rules: - host: www.example.com http: paths: - path: / backend: serviceName: new-nginx servicePort: 80Aplique o manifesto e verifique:
kubectl apply -f ingress1.yaml kubectl get ingressTeste sem o cabeçalho (roteado para a versão antiga):
curl -H "Host: www.example.com" http://<EXTERNAL_IP>Resposta esperada:
oldTeste com o cabeçalhofoo: bar(roteado para a nova versão):curl -H "Host: www.example.com" -H "foo: bar" http://<EXTERNAL_IP>Resultado esperado:
newEstratégia B: Roteamento por cabeçalho e divisão do tráfego restante por peso
Roteie todas as requisições com
foo=barpara a nova versão e 50% das outras requisições para a nova versão. Atualizeingress1.yamlcom o seguinte conteúdo.Para clusters da v1.19 e posteriores
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: gray-release-canary annotations: nginx.ingress.kubernetes.io/canary: "true" # Route to new-nginx when foo header equals bar. nginx.ingress.kubernetes.io/canary-by-header: "foo" nginx.ingress.kubernetes.io/canary-by-header-value: "bar" # For requests that don't match the header rule, route 50% to new-nginx. nginx.ingress.kubernetes.io/canary-weight: "50" spec: ingressClassName: nginx rules: - host: www.example.com http: paths: - path: / backend: service: name: new-nginx port: number: 80 pathType: ImplementationSpecificPara clusters anteriores à v1.19
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: gray-release-canary annotations: nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-by-header: "foo" nginx.ingress.kubernetes.io/canary-by-header-value: "bar" nginx.ingress.kubernetes.io/canary-weight: "50" spec: rules: - host: www.example.com http: paths: - path: / backend: serviceName: new-nginx servicePort: 80Aplique o manifesto:
kubectl apply -f ingress1.yamlEstratégia C: Roteamento apenas por peso
Roteie 50% do tráfego para a nova versão, independentemente de cabeçalhos ou cookies. Atualize
ingress1.yamlcom o seguinte conteúdo.Para clusters da v1.19 e posteriores
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: gray-release-canary annotations: nginx.ingress.kubernetes.io/canary: "true" # Route 50% of all traffic to new-nginx. Default total weight is 100. nginx.ingress.kubernetes.io/canary-weight: "50" spec: ingressClassName: nginx rules: - host: www.example.com http: paths: - path: / backend: service: name: new-nginx port: number: 80 pathType: ImplementationSpecificPara clusters anteriores à v1.19
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: gray-release-canary annotations: nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-weight: "50" spec: rules: - host: www.example.com http: paths: - path: / backend: serviceName: new-nginx servicePort: 80Aplique o manifesto:
kubectl apply -f ingress1.yamlVerifique: execute este comando várias vezes. Cerca de 50% das respostas devem retornar
new.curl -H "Host: www.example.com" http://<EXTERNAL_IP>
Etapa 3: Concluir a migração de tráfego
Após a estabilização da nova versão, desative a versão antiga.
-
Atualize
nginx.yamlpara redirecionar o Service antigo para o novo Deployment.Aplique a atualização:
kubectl apply -f nginx.yaml -
Verifique se todo o tráfego vai para a nova versão:
kubectl get ingress curl -H "Host: www.example.com" http://<EXTERNAL_IP>Resultado esperado:
new -
Exclua o Ingress canary:
kubectl delete ingress gray-release-canary -
Exclua o Deployment antigo e o novo Service:
kubectl delete deploy old-nginx kubectl delete svc new-nginx
O método de annotation service-*
A annotation service-* não está mais disponível no Nginx Ingress Controller v1.12 e versões posteriores. Não use.
Referência de annotations
|
Annotation |
Descrição |
|
|
|
Define regras de roteamento que mapeiam atributos da requisição para um Service. Sintaxe: |
|
|
|
Define pesos de tráfego entre as versões antiga e nova do Service. Sintaxe: |
|
Etapa 1: Implantar o Service
Implante um Service Nginx e exponha-o para acesso por domínio na camada 7 com o Nginx Ingress Controller.
-
Crie um Deployment e um Service. Salve o seguinte conteúdo em
nginx.yaml.Aplique o manifesto:
kubectl apply -f nginx.yaml -
Crie o Ingress. Salve o seguinte conteúdo em
ingress.yaml.Para clusters da v1.19 e posteriores
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: gray-release spec: ingressClassName: nginx rules: - host: www.example.com http: paths: # Old version of the service. - path: / backend: service: name: old-nginx port: number: 80 pathType: ImplementationSpecificPara clusters anteriores à v1.19
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: gray-release spec: rules: - host: www.example.com http: paths: - path: / backend: serviceName: old-nginx servicePort: 80Aplique o manifesto:
kubectl apply -f ingress.yaml -
Verifique a implantação. Obtenha o endereço IP externo:
kubectl get ingressValide o acesso de roteamento:
curl -H "Host: www.example.com" http://<EXTERNAL_IP>Resultado esperado:
old
Etapa 2: Lançar a nova versão do Service
Implante a nova versão do Nginx e configure as regras de roteamento.
-
Crie o novo Deployment e Service. Salve o seguinte conteúdo em
nginx1.yaml.Aplique o manifesto:
kubectl apply -f nginx1.yaml -
Modifique o Ingress
gray-release. Três estratégias estão disponíveis. Estratégia A: Roteamento por cabeçalho de requisição Roteie requisições para a nova versão apenas quando o cabeçalhofoocorresponder abar. Atualizeingress.yamlcom o seguinte conteúdo. Para clusters da v1.19 e posteriores:Para clusters da v1.19 e posteriores
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: gray-release annotations: # Route to new-nginx when the foo header matches ^bar$. nginx.ingress.kubernetes.io/service-match: | new-nginx: header("foo", /^bar$/) spec: ingressClassName: nginx rules: - host: www.example.com http: paths: # Old version of the service. - path: / backend: service: name: old-nginx port: number: 80 pathType: ImplementationSpecific # New version of the service. - path: / backend: service: name: new-nginx port: number: 80 pathType: ImplementationSpecificPara clusters anteriores à v1.19
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: gray-release annotations: nginx.ingress.kubernetes.io/service-match: | new-nginx: header("foo", /^bar$/) spec: rules: - host: www.example.com http: paths: - path: / backend: serviceName: old-nginx servicePort: 80 - path: / backend: serviceName: new-nginx servicePort: 80Aplique o manifesto e verifique:
kubectl apply -f ingress.yaml kubectl get ingressTeste sem o cabeçalho (roteado para a versão antiga):
curl -H "Host: www.example.com" http://<EXTERNAL_IP>Resposta esperada:
oldTeste com o cabeçalhofoo: bar(roteado para a nova versão):curl -H "Host: www.example.com" -H "foo: bar" http://<EXTERNAL_IP>Resultado esperado:
newEstratégia B: Roteamento por cabeçalho com divisão baseada em peso
Roteie requisições que correspondam a
foo=barpara ambas as versões, sendo 50% para cada uma. Atualizeingress.yamlcom o seguinte conteúdo.Para clusters da v1.19 e posteriores
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: gray-release annotations: nginx.ingress.kubernetes.io/service-match: | new-nginx: header("foo", /^bar$/) # Of the matching requests, route 50% to new-nginx and 50% to old-nginx. nginx.ingress.kubernetes.io/service-weight: | new-nginx: 50, old-nginx: 50 spec: ingressClassName: nginx rules: - host: www.example.com http: paths: - path: / backend: service: name: old-nginx port: number: 80 pathType: ImplementationSpecific - path: / backend: service: name: new-nginx port: number: 80 pathType: ImplementationSpecificPara clusters anteriores à v1.19
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: gray-release annotations: nginx.ingress.kubernetes.io/service-match: | new-nginx: header("foo", /^bar$/) nginx.ingress.kubernetes.io/service-weight: | new-nginx: 50, old-nginx: 50 spec: rules: - host: www.example.com http: paths: - path: / backend: serviceName: old-nginx servicePort: 80 - path: / backend: serviceName: new-nginx servicePort: 80Aplique o manifesto:
kubectl apply -f ingress.yamlExecute o comando de teste várias vezes. Cerca de 50% das requisições com
foo: bardevem retornarnew.Estratégia C: Roteamento apenas por peso
Roteie 50% do tráfego para a nova versão. Atualize
ingress.yamlcom o seguinte conteúdo.Para clusters da v1.19 e posteriores
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: gray-release annotations: # Route 50% of all traffic to new-nginx. nginx.ingress.kubernetes.io/service-weight: | new-nginx: 50, old-nginx: 50 spec: ingressClassName: nginx rules: - host: www.example.com http: paths: - path: / backend: service: name: old-nginx port: number: 80 pathType: ImplementationSpecific - path: / backend: service: name: new-nginx port: number: 80 pathType: ImplementationSpecificPara clusters anteriores à v1.19
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: gray-release annotations: nginx.ingress.kubernetes.io/service-weight: | new-nginx: 50, old-nginx: 50 spec: rules: - host: www.example.com http: paths: - path: / backend: serviceName: old-nginx servicePort: 80 - path: / backend: serviceName: new-nginx servicePort: 80Aplique o manifesto:
kubectl apply -f ingress.yamlVerifique: execute este comando várias vezes. Cerca de 50% das respostas devem retornar
new.curl -H "Host: www.example.com" http://<EXTERNAL_IP>
Etapa 3: Concluir a migração de tráfego
Após a estabilização da nova versão, desative a versão antiga.
-
Aplique a atualização:
Para clusters da v1.19 e posteriores
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: gray-release spec: ingressClassName: nginx rules: - host: www.example.com http: paths: # New version of the service. - path: / backend: service: name: new-nginx port: number: 80 pathType: ImplementationSpecificPara clusters anteriores à v1.19
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: gray-release spec: rules: - host: www.example.com http: paths: - path: / backend: serviceName: new-nginx servicePort: 80kubectl apply -f ingress.yaml -
Verifique se todo o tráfego vai para a nova versão:
kubectl get ingress curl -H "Host: www.example.com" http://<EXTERNAL_IP>Resultado esperado:
new -
Exclua o Deployment e o Service antigos:
kubectl delete deploy <Deployment_name> kubectl delete svc <Service_name>