Lançamentos seguros com o Config Sync

Neste documento, mostramos aos operadores de cluster e administradores de plataforma como implantar alterações com segurança em vários ambientes usando o Config Sync. Essa abordagem pode ajudar a evitar erros que afetam todos os seus ambientes simultaneamente.

O Config Sync permite gerenciar clusters únicos, clusters com vários locatários e configurações do Kubernetes de vários clusters usando arquivos armazenados em um repositório Git.

As configurações podem representar várias coisas, incluindo:

O Config Sync é especialmente adequado para implantar configurações, políticas e cargas de trabalho necessárias para executar a plataforma criada com base no Google Kubernetes Engine (GKE) Enterprise, por exemplo, agentes de segurança, de monitoramento e gerenciadores de certificados.

Embora seja possível implantar aplicativos voltados ao usuário com o Config Sync, não recomendamos vincular o ciclo de vida da versão ao ciclo de vida de lançamento das cargas de trabalho administrativas mencionadas anteriormente. Em vez disso, você deve usar uma ferramenta dedicada à implantação de aplicativos, como uma de implantação contínua, para que as equipes de aplicativo possam controlar a programação de lançamentos.

O Config Sync é um produto eficiente que pode gerenciar muitos elementos. Portanto, você precisa de proteções para evitar erros com grande impacto. Este documento descreve vários métodos para criar proteções. A primeira seção abrange lançamentos graduais, e a segunda se concentra em testes e validações. A terceira seção mostra como monitorar suas implantações.

Como implementar lançamentos graduais com o Config Sync

Em um ambiente de vários clusters, que é uma situação comum para usuários do GKE Enterprise, não recomendamos aplicar uma alteração de configuração em todos os clusters ao mesmo tempo. Um lançamento gradual, cluster por cluster, é muito mais seguro porque reduz o possível impacto de qualquer erro.

Há várias maneiras de implementar lançamentos graduais com o Config Sync:

  • Use confirmações ou tags do Git para aplicar manualmente as alterações que você quer aos clusters.
  • Use as ramificações do Git para aplicar automaticamente as alterações quando elas forem mescladas. É possível usar diferentes ramificações para diferentes grupos de clusters.
  • Use os objetos ClusterSelector e NamespaceSelector para aplicar seletivamente alterações a subgrupos de clusters ou namespaces.

Todos os métodos para lançamentos graduais têm vantagens e desvantagens. A tabela a seguir mostra quais desses métodos podem ser usados ao mesmo tempo:

Compatibilidade Tags ou confirmações do Git Ramificações do Git Seletores de cluster Seletores de namespace
Tags ou confirmações do Git Incompatível Compatível Compatível
Ramificações do Git Incompatível Compatível Compatível
Seletores de cluster Compatível Compatível Compatível
Seletores de namespace Compatível Compatível Compatível

A árvore de decisão a seguir pode ajudar você a decidir quando usar um dos métodos de lançamento gradual.

Árvore de decisão para métodos de lançamento.

Usar confirmações ou tags do Git

Em comparação com os outros métodos de lançamento gradual, usar confirmações ou tags do Git oferece mais controle e segurança. Use a página Config Sync no console do Google Cloud para atualizar vários clusters ao mesmo tempo. Use esse método se quiser aplicar alterações aos clusters um por um e controlar exatamente quando isso acontece.

Nesse método, você "fixa" cada cluster a uma versão específica (uma confirmação ou uma tag) do seu repositório. Esse método é semelhante ao uso da confirmação de Git como tag de imagem do contêiner. Para implementar esse método, especifique a confirmação, tag ou hash no campo spec.git.revision do recurso personalizado RootSync ou RepoSync.

Se você gerencia seus recursos personalizados RootSync ou RepoSync com uma ferramenta como o Kustomize, é possível reduzir a quantidade de trabalho manual necessário para lançamentos. Com essa ferramenta, você só precisa alterar o parâmetro revision em um lugar e, em seguida, aplicar seletivamente o novo recurso personalizado RootSync ou RepoSync aos clusters na ordem e no ritmo que você escolher.

Além disso, é possível usar o console do Google Cloud para atualizar o parâmetro revision de vários clusters pertencentes à mesma frota ao mesmo tempo. No entanto, se você tiver um sistema automatizado para atualizar suas configurações, não recomendamos usar o console do Google Cloud para fazer alterações na configuração.

Por exemplo, a seguinte definição do RootSync configura o Config Sync para usar a tag 1.2.3:

apiVersion: configsync.gke.io/v1
kind: RootSync
metadata:
  name: root-sync
  namespace: config-sync-system
spec:
  sourceType: git
  sourceFormat: unstructured
  git:
    repo: git@example.com:gke/config-sync.git
    revision: 1.2.3
    auth: ssh

Se você aplicar essa configuração ao cluster, o Config Sync usará a tag 1.2.3 do repositório example.com:gke/config-sync.git.

Para atualizar um cluster, altere o campo spec.git.revision para o novo valor do cluster. Isso permite que você defina quais clusters serão atualizados e quando. Se precisar reverter uma alteração, mude o campo spec.git.revision de volta para o valor anterior.

O diagrama a seguir ilustra o processo de lançamento desse método. Primeiro, você confirma as alterações no repositório do Config Sync e, em seguida, atualiza as definições do RootSync em todos os clusters:

Processo de lançamento para confirmações e tags do Git.

Recomendamos o seguinte:

  • Use IDs de confirmação do Git em vez de tags. Devido à maneira como o Git funciona, você tem uma garantia de que eles nunca serão alterados. Por exemplo, um git push --force não pode alterar a confirmação que o Config Sync está usando. Essa abordagem é útil para fins de auditoria e para monitorar qual confirmação você está usando nos registros. Além disso, ao contrário das tags, não há mais uma etapa para confirmar os IDs.
  • Se você preferir usar tags do Git em vez de IDs de confirmação do Git, proteja-as se estiver usando uma solução Git compatível com proteção.
  • Para atualizar vários clusters ao mesmo tempo, use o console do Google Cloud. Para atualizar vários clusters de uma só vez, eles precisam fazer parte da mesma frota e estar no mesmo projeto.

Usar ramificações do Git

Se você quiser que as alterações sejam aplicadas aos clusters assim que eles forem mesclados no repositório do Git, configure o Config Sync para usar ramificações do Git em vez de confirmações ou tags. Nesse método, você cria várias ramificações de longa duração no repositório Git e configura o Config Sync em clusters diferentes para ler a configuração de diferentes ramificações.

Por exemplo, um padrão simples tem duas ramificações:

  • Uma ramificação staging para clusters que não sejam de produção.
  • Uma ramificação main para clusters de produção.

Para clusters que não sejam de produção, crie o objeto RootSync ou RepoSync com o campo spec.git.branch definido como staging. Para clusters de produção, crie o objeto RootSync ou RepoSync com o parâmetro spec.git.branch definido como main.

Por exemplo, a seguinte definição do RootSync configura o Config Sync para usar a ramificação main:

apiVersion: configsync.gke.io/v1
kind: RootSync
metadata:
  name: root-sync
  namespace: config-sync-system
spec:
  git:
    repo: git@example.com:gke/config-sync.git
    branch: main
    auth: ssh

O diagrama abaixo ilustra o processo de lançamento desse método:

Processo de lançamento de ramificações do Git.

Você pode adaptar esse padrão a necessidades específicas, usando mais de duas ramificações ou ramificações mapeadas para outros itens, que não seja os ambientes. Se precisar reverter uma alteração, use o comando git revert para criar uma nova confirmação na mesma ramificação que reverte as alterações anteriores.

Recomendamos o seguinte:

  • Ao trabalhar com vários clusters, use pelo menos duas ramificações do Git para distinguir os clusters de produção e os de não-produção.
  • A maioria das soluções do Git permite que você use o recurso de ramificações protegidas para evitar exclusões ou alterações não analisadas dessas ramificações. Para mais informações, consulte a documentação do GitHub, do GitLab e do Bitbucket (links em inglês).

Usar objetos ClusterSelector e NamespaceSelector

As ramificações do Git são uma boa maneira de fazer um lançamento gradual de alterações em vários clusters que futuramente terão as mesmas políticas. No entanto, se você quiser lançar uma alteração apenas em um subconjunto de clusters ou namespaces, use os objetos ClusterSelector e NamespaceSelector. Esses objetos têm um propósito semelhante: permitem que você aplique objetos apenas a clusters ou namespaces com rótulos específicos.

Exemplo:

  • Com o uso de objetos ClusterSelector, é possível aplicar políticas diferentes aos clusters, dependendo do país em que estejam localizados, para vários sistemas de compliance.
  • Ao usar objetos NamespaceSelector, você pode aplicar políticas diferentes a namespaces usados por uma equipe interna e por um fornecedor externo.

Os objetos ClusterSelector e NamespaceSelector também permitem implementar avançadas metodologias de teste e lançamento, como as seguintes:

  • Versões canário de políticas, em que você implanta uma nova política em um pequeno subconjunto de clusters e namespaces por um longo tempo para estudar o impacto da política.
  • Testes A/B, em que você implanta diferentes versões da mesma política em diferentes clusters para avaliar o impacto dessas versões e escolher a melhor para uma implantação global.

Por exemplo, imagine uma organização com vários clusters de produção. A equipe de plataforma já criou duas categorias de clusters de produção, chamados canary-prod e prod, usando os objetos Cluster e ClusterSelector. Consulte Usar ClusterSeletors.

A equipe da plataforma quer lançar uma política com o Policy Controller para impor a presença de um rótulo de equipe em namespaces e identificar a qual equipe cada namespace pertence. Ela já implantou uma versão dessa política no modo de teste e agora quer aplicá-la a um pequeno número de clusters. Usando objetos ClusterSelector, eles criam dois recursos K8sRequiredLabels diferentes aplicados a diferentes clusters.

  • O recurso K8sRequiredLabels é aplicado a clusters do tipo prod, com um parâmetro enforcementAction definido como dryrun:

    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sRequiredLabels
    metadata:
      name: ns-must-have-team
      annotations:
        configmanagement.gke.io/cluster-selector: prod
    Spec:
      enforcementAction: dryrun
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Namespace"]
      parameters:
        labels:
          - key: "team"
    
  • O recurso K8sRequiredLabels é aplicado a clusters do tipo canary-prod, sem o parâmetro enforcementAction, o que significa que a política é realmente aplicada:

    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sRequiredLabels
    metadata:
      name: ns-must-have-team
      annotations:
        configmanagement.gke.io/cluster-selector: canary-prod
    spec:
      match:
        kinds:
          - apiGroups: [""]
        kinds: ["Namespace"]
      parameters:
        labels:
          - key: "team"
    

A anotação configmanagement.gke.io/cluster-selector permite que a equipe aplique a política somente em clusters do tipo canary-prod, impedindo que efeitos colaterais indesejados se espalhem para toda a frota de produção. Para mais informações sobre o recurso de teste do Policy Controller, consulte Como criar restrições.

Recomendamos o seguinte:

  • Use objetos ClusterSelector e NamespaceSelector se precisar aplicar uma alteração de configuração apenas a um subconjunto de clusters ou namespaces indefinidamente ou por um longo período.
  • Se você implementar uma alteração usando seletores, tenha muito cuidado. Se você usar as confirmações do Git, qualquer erro vai afetar apenas um cluster por vez, porque você vai implantar um cluster por vez. Mas, se você usar ramificações do Git, qualquer erro poderá afetar todos os clusters que usam essa ramificação. Se você usar seletores, o erro poderá afetar todos os clusters de uma só vez.

Como implementar avaliações, testes e validações

Uma vantagem do Config Sync é que ele gerencia tudo de maneira declarativa: recursos do Kubernetes, recursos da nuvem e políticas. Isso significa que os arquivos em um sistema de gerenciamento de controle de origem representam os recursos (arquivos Git, no caso do Config Sync). Essa característica permite implementar fluxos de trabalho de desenvolvimento que você já usa para o código-fonte de um aplicativo: avaliações e testes automatizados.

Implementar avaliações

Como o Config Sync é baseado no Git, é possível usar sua solução Git preferida para hospedar o repositório do Config Sync. Sua solução Git provavelmente tem um recurso de revisão de código que pode ser usado para analisar as alterações feitas no repositório do Config Sync.

As práticas recomendadas para revisar alterações no repositório são as mesmas de uma revisão de código normal, como a seguir:

Devido à sensibilidade da base de código do Config Sync, também recomendamos que, se possível com sua solução Git, você faça as seguintes configurações:

Ao usar esses recursos diferentes, é possível aplicar aprovações para cada solicitação de alteração à sua base de código. Por exemplo, você pode garantir que cada alteração seja aprovada pelo menos por um membro da equipe de plataforma (que opera a frota de clusters) e por um membro da equipe de segurança (responsável por definir e implementar políticas de segurança).

Recomendamos a seguinte ação:

  • Aplique avaliações de colegas ao seu repositório e proteja as ramificações do Git usadas pelos clusters.

Implementar testes automatizados

Uma prática recomendada comum quando se trabalha em uma codebase é implementar a integração contínua. Isso significa que você configura testes automatizados para serem executados quando uma solicitação de alteração é criada ou atualizada. Os testes automatizados podem detectar muitos erros antes de uma pessoa analisar a solicitação de mudança. Isso aumenta o loop de feedback para o desenvolvedor. É possível implementar a mesma ideia usando as mesmas ferramentas no repositório do Config Sync.

Por exemplo, um bom ponto de partida é executar o comando nomos vet automaticamente em novas alterações. Esse comando valida que a sintaxe do repositório do Config Sync é válida. É possível implementar esse teste usando o Cloud Build seguindo o tutorial de validação de configs. Integre o Cloud Build com as seguintes opções:

  • Bitbucket, usando gatilhos de compilação.
  • com o GitHub usando o aplicativo Google Cloud Build GitHub. Gatilhos de compilação também estão disponíveis para o GitHub, mas o aplicativo do GitHub é o método preferencial de integração.

Como você pode ver no tutorial Como validar configurações, o teste é feito usando uma imagem de contêiner. Portanto, é possível implementar o teste em qualquer solução de integração contínua que execute contêineres, e não apenas no Cloud Build.

Para aumentar ainda mais o loop de feedback, solicite que os usuários executem o comando nomos vet como um gancho de pré-confirmação do Git. Uma ressalva é que alguns usuários podem não ter acesso aos clusters do Kubernetes gerenciados pelo Config Sync e talvez não consigam executar a validação completa na estação de trabalho. Execute o comando nomos vet --clusters "" para restringir a validação a verificações semânticas e sintáticas.

Recomendamos a seguinte ação:

  • Implemente testes em um pipeline de integração contínua.
  • Execute pelo menos o comando nomos vet em todas as alterações sugeridas.

Como monitorar lançamentos

Mesmo que você implemente todas as proteções abordadas neste documento, ainda podem ocorrer erros. Veja a seguir dois tipos comuns de erros:

  • Erros que não representam um problema para o Config Sync em si, mas impedem que as cargas de trabalho funcionem corretamente, como um NetworkPolicy excessivamente restritivo que afeta a comunicação dos componentes da carga de trabalho.
  • Erros que impedem que o Config Sync aplique alterações a um cluster, como um manifesto do Kubernetes inválido ou um objeto rejeitado por um controlador de admissão. Os métodos explicados anteriormente devem detectar a maioria desses erros.

Detectar os erros descritos no primeiro item anterior é quase impossível no Config Sync porque isso exige a compreensão do estado de cada uma das cargas de trabalho. Por esse motivo, a detecção desses erros é mais eficaz pelo sistema de monitoramento existente, que avisa quando um aplicativo apresenta um comportamento inadequado.

A detecção dos erros descritos no segundo item (que deve ser baixa se você tiver implementado todas as proteções), requer uma configuração específica. Por padrão, o Config Sync grava erros nos registros, que você encontrará, por padrão, no Cloud Logging. Os erros também são exibidos na página do console do Config Sync do Google Cloud. Geralmente, nem os registros nem o console são suficientes para detectar erros, porque você provavelmente não os monitora o tempo todo. A maneira mais simples de automatizar a detecção de erros é executar o comando nomos status, que informa se há um erro em um cluster.

Você também pode configurar uma solução mais avançada com alertas automáticos para erros. O Config Sync expõe métricas no formato do Prometheus. Para mais informações, consulte Como monitorar o Config Sync.

Depois de inserir as métricas do Config Sync no sistema de monitoramento, crie um alerta para receber notificações quando a métrica gkeconfig_monitor_errors for maior que 0. Para mais informações, consulte como gerenciar políticas de alertas do Cloud Monitoring ou regras de alerta para o Prometheus.

Resumo dos mecanismos para lançamentos seguros com o Config Sync

A tabela a seguir resume os vários mecanismos descritos anteriormente neste documento. Nenhum desses mecanismos é exclusivo. É possível usar alguns deles ou todos para diferentes propósitos.

Mecanismo Indicações de uso Não é bom para Exemplo de caso de uso:
IDs e tags de confirmação do Git Use IDs ou tags de confirmação Git específicas para controlar com precisão quais alterações de cluster serão aplicadas. Não use IDs de confirmação do Git ou tags para diferenças de longa duração entre clusters. Use seletores de cluster. Todos os clusters estão configurados para aplicar a confirmação 12345 do Git. Você faz uma alteração com uma nova confirmação, abcdef, que pretende testar. Você altera a configuração de um único cluster para usar essa nova confirmação e validar a alteração.
Ramificações do Git Use várias ramificações do Git quando quiser implantar a mesma alteração em vários ambientes, um após o outro. Não use várias ramificações do Git para diferenças de longa duração entre os clusters. As ramificações irão divergir e será difícil mesclá-las novamente. Primeiro, mescle a alteração na ramificação de preparação, que será escolhida pelos clusters de preparo.
Em seguida, mescle a alteração na ramificação mestre, onde ela será selecionada por clusters de produção.
Seletores de cluster e seletores de namespace Use seletores para diferenças de longa duração entre clusters e namespaces. Não use seletores para um lançamento gradual em vários ambientes. Se você quiser, primeiro, testar uma modificação na preparação para, depois, implantá-la na produção, use ramificações do Git separadas. Se as equipes de aplicativo precisarem de acesso total aos clusters de desenvolvimento, mas tiverem somente acesso de leitura a clusters de produção, use o objeto ClusterSelector para aplicar as políticas de RBAC corretas apenas aos clusters relevantes.
Avaliações de peering Use avaliações de peering para garantir que as equipes relevantes aprovem as alterações. Revisores humanos não detectam todos os erros, especialmente itens como erros de sintaxe. Sua organização exige que a equipe de segurança avalie alterações de configuração que afetam vários sistemas. Peça para um membro da equipe de segurança avaliar as alterações.
Testes automatizados no pipeline de integração contínua Use testes automatizados para detectar erros nas alterações sugeridas. Os testes automatizados não podem substituir totalmente um revisor humano. Use os dois A execução de um comando nomos vet em todas as alterações sugeridas confirma que o repositório é uma configuração válida do Config Sync.
Monitorar erros de sincronização Verifique se o Config Sync realmente aplica alterações aos clusters. Os erros de sincronização ocorrerão somente se o Config Sync tentar aplicar um repositório inválido ou se o servidor da API Kubernetes rejeitar alguns dos objetos. Um usuário ignora todos os testes e revisões e confirma uma alteração inválida no repositório do Config Sync. Essa alteração não pode ser aplicada aos clusters. Se você estiver monitorando erros de sincronização, será alertado caso ocorra um erro.

Exemplo de estratégia de lançamento

Nesta seção, usamos os conceitos apresentados no restante deste artigo para ajudar você a criar uma estratégia de implantação completa em todos os clusters da sua organização. Essa estratégia pressupõe que você tenha frotas separadas para desenvolvimento, preparação e produção (como mostrado no Exemplo de frota 1 da abordagem 1).

.

Neste cenário, você configura cada cluster para sincronizar com o repositório Git usando uma confirmação Git específica. A implantação de uma alteração em uma determinada frota é um processo de quatro etapas:

  1. Atualize um único cluster (o "canário") na frota para usar a nova confirmação primeiro.
  2. Você valida que tudo funciona conforme esperado executando testes e monitorando o lançamento.
  3. Atualize o restante dos clusters na frota.
  4. Confirme novamente que tudo está funcionando conforme esperado.

Para implantar uma alteração em todos os clusters, repita esse processo para cada frota. Tecnicamente, é possível aplicar esse método a qualquer confirmação do Git de qualquer ramificação. No entanto, sugerimos que você adote o seguinte processo para identificar problemas no início do processo de revisão:

  1. Quando alguém abrir uma solicitação de alteração no repositório Git do Config Sync, implante essa alteração em um dos clusters de desenvolvimento.
  2. Se a solicitação de alteração for aceita e mesclada na ramificação principal, execute a implantação completa em todas as frotas, conforme descrito anteriormente.

Embora algumas alterações possam segmentar apenas uma frota específica, recomendamos que você implante todas as alterações posteriormente em todas as frotas. Essa estratégia elimina o problema de rastrear qual frota precisa ser sincronizada com qual confirmação. Preste atenção especial às alterações que visam apenas a frota de produção porque testes adequados não terão sido realizados nas frotas anteriores. Por exemplo, isso significa esperar mais para que os problemas apareçam entre a implantação nos clusters canário e no restante dos clusters.

Em suma, uma implantação completa tem a seguinte aparência:

  1. Alguém abre uma solicitação de alteração.
  2. Testes e validações automatizados são executados, e uma revisão manual é feita.
  3. Você aciona um job manualmente para implantar a alteração no cluster canário na frota de desenvolvimento. Testes automatizados de ponta a ponta são executados neste cluster.
  4. Se estiver tudo certo, você deve mesclar a solicitação de mudança na ramificação principal.
  5. A mescla aciona um job automatizado para implantar a confirmação nova da ramificação principal no cluster canário na frota de desenvolvimento. Testes automatizados de ponta a ponta são executados neste cluster para detectar possíveis incompatibilidades entre duas solicitações de alteração que foram criadas e mescladas aproximadamente ao mesmo tempo.
  6. Os jobs a seguir são executados um após o outro (você os aciona manualmente ou após um horário predefinido para permitir os relatórios de regressões dos usuários):
    1. Implante em todos os clusters da frota de desenvolvimento.
    2. Execute testes e validações nos clusters da frota de desenvolvimento.
    3. Implante no cluster canário da frota de preparo.
    4. Execute testes e validações no cluster canário da frota de preparo.
    5. Implante em todos os clusters da frota de preparo.
    6. Execute testes e validações nos clusters da frota de preparo.
    7. Implante no cluster canário da frota de produção.
    8. Execute testes e validações no cluster canário da frota de produção.
    9. Implante em todos os clusters da frota de produção.
    10. Execute testes e validações nos clusters da frota de produção.

Processo completo de lançamento.

A seguir