Como preparar um ambiente do Google Kubernetes Engine para produção

Nesta solução, apresentamos um esquema e uma metodologia para integrar as cargas de trabalho ao Google Kubernetes Engine de maneira mais segura, confiável e econômica. Ela orienta na configuração do acesso administrativo e de rede aos clusters. Neste artigo, pressupomos uma compreensão prática dos recursos e da administração de cluster do Kubernetes, além de familiaridade com os recursos de rede do Google Cloud.

Como estruturar projetos, redes de nuvem privada virtual (VPC) e clusters

No diagrama a seguir, mostramos a melhor estrutura de projetos, redes VPC, regiões, sub-redes, zonas e clusters.

Estrutura de projeto, rede e cluster

Projetos

O Google Cloud cria todos os recursos próprios em uma entidade de projeto. Sendo a unidade de faturamento, os projetos permitem que os administradores associem papéis do Cloud Identity and Access Management (Cloud IAM) aos usuários. Quando aplicados no nível do projeto, os papéis são pertinentes a todos os recursos encapsulados no projeto.

Use projetos para encapsular vários ambientes operacionais. Por exemplo, pode haver os projetos production e staging para equipes de operações e um projeto test-dev para desenvolvedores. Você aplica políticas mais granulares e rigorosas aos projetos que contêm os dados e cargas de trabalho mais importantes e confidenciais, ao mesmo tempo que aplica políticas permissivas e flexíveis para desenvolvedores no ambiente test-dev para testar.

Clusters

Um projeto pode conter vários clusters. Se você tiver várias cargas de trabalho para implantar, poderá usar um único cluster compartilhado ou clusters separados para essas cargas de trabalho. Para tomar a melhor decisão, veja nossas práticas recomendadas no artigo sobre como escolher o tamanho e o escopo de um cluster do GKE.

Redes e sub-redes

Dentro de cada projeto, é possível ter uma ou mais redes VPC, que são versões virtuais de redes físicas. Cada rede VPC é um recurso global que contém outros recursos relacionados à rede, como sub-redes, endereços IP externos, regras de firewall, rotas, VPN e o Cloud Router. Em uma rede VPC, é possível usar sub-redes, que são recursos regionais, para isolar e controlar o tráfego recebido ou enviado por cada região entre os clusters do GKE.

Cada projeto inclui uma única rede padrão. É possível criar e configurar uma rede extra para mapear para a convenção atual de gerenciamento de endereços IP (IPAM, na sigla em inglês). Portanto, aplique regras de firewall à rede para filtrar o tráfego de entrada e saída dos nós do GKE. Por padrão, todo o tráfego da Internet recebido pelos nós do GKE é negado.

Para controlar a comunicação entre sub-redes, é necessário criar regras de firewall que permitam a passagem de tráfego entre as sub-redes. Use asinalização --tags durante a criação do cluster ou do pool de nós para marcar devidamente os nós do GKE e efetivar as regras de firewall. Também é possível usar tags para criar rotas entre as sub-redes, se necessário.

Clusters de várias zonas e regionais

Por padrão, um cluster cria os respectivos mestre e nós em uma única zona, que você especifica no momento da criação. Para melhorar a disponibilidade e a resiliência dos clusters, crie clusters de várias zonas ou regionais. Eles distribuem os recursos do Kubernetes em várias zonas dentro de uma região.

Os clusters de várias zonas:

  • criam um único mestre em uma zona;
  • criam nodes em várias zonas.

Os clusters regionais:

  • criam três mestres em três zonas;
  • por padrão, criam nós em três zonas, mas podem criar em quantas você quiser.

A principal diferença entre eles é que os clusters regionais criam três mestres, os de várias zonas, apenas um. Nos dois casos, o tráfego entre nós nas zonas é cobrado.

No momento da criação do cluster, você escolhe se ele será de várias zonas ou regional. É possível adicionar novas zonas a um cluster existente para torná-lo de várias zonas. No entanto, não é possível modificar um cluster atual para ser regional. Também não é possível transformar um cluster regional em não regional.

Para saber mais sobre clusters regionais e de várias zonas, consulte a documentação do GKE.

Como gerenciar identidades e acesso

Acesso no nível do projeto

Na seção anterior, você viu que pode vincular papéis de IAM a usuários no nível do projeto. Além de conceder papéis a usuários individuais, você também usa grupos para simplificar a aplicação de papéis.

Veja abaixo uma ilustração do layout da política de IAM que fornece o princípio do menor privilégio a um projeto dev que está configurado para desenvolvedores desenvolverem e testarem os próximos recursos e correções de bugs, bem como um projeto prod para tráfego de produção:

Gerenciamento de identidade e acesso

Como mostra a tabela a seguir, há quatro grupos de usuários dentro da organização com diferentes níveis de permissões, concedidas por meio de papéis de IAM entre os dois projetos:

Equipe Papel de IAM Projeto Permissões
Desenvolvedores container.developer dev Criar recursos do Kubernetes para os clusters atuais no projeto, sem permissão para criar ou excluir clusters.
Operações container.admin prod Acesso administrativo completo aos clusters e recursos do Kubernetes em execução no projeto.
Segurança container.viewer
security.admin
prod Criar, modificar e excluir regras de firewall e certificados SSL, bem como ver os recursos que foram criados dentro de cada cluster, incluindo os registros dos pods em execução.
Rede network.admin prod Criar, modificar e excluir recursos de rede, exceto regras de firewall e certificados SSL.

Além das três equipes com acesso ao projeto prod, um conta de serviço extra é fornecida ao papel container.developer de prod, dando permissão para criar, listar e excluir recursos no cluster. As contas de serviço podem ser usadas para dar a scripts de automação ou frameworks de implantação a capacidade de agir por você. As implantações no projeto de produção e nos clusters devem passar por um pipeline automatizado.

No projeto dev, há vários desenvolvedores trabalhando no mesmo aplicativo no mesmo cluster. Isso é facilitado pelos namespaces, que o usuário do cluster pode criar. Cada desenvolvedor pode criar recursos dentro do próprio namespace, o que evita conflitos de nome. Eles também podem reutilizar os mesmos arquivos de configuração YAML nas implantações para manter a maior semelhança possível entre as configurações durante as iterações de desenvolvimento. Os namespaces também podem ser usados para criar cotas para uso de CPU, memória e armazenamento no cluster, assegurando que um desenvolvedor não use recursos demais no cluster. A próxima seção aborda a restrição à operação de certos namespaces por parte dos usuários.

Autorização RBAC

Os clusters do GKE que executam o Kubernetes 1.6 e posterior podem utilizar outras restrições relativas ao que os usuários estão autorizados a fazer em clusters individuais. O Cloud IAM pode fornecer aos usuários acesso a clusters completos e aos recursos dentro deles. No entanto, o controle de acesso baseado em papéis do Kubernetes (RBAC, na sigla em inglês) permite usar a API do Kubernetes para limitar ainda mais as ações que os usuários podem executar nos próprios clusters.

Com o RBAC, os administradores de cluster aplicam políticas detalhadas a namespaces individuais dentro dos próprios clusters ou ao cluster como um todo. A interface de linha de comando do Kubernetes, kubectl, usa as credenciais ativas da ferramenta gcloud, permitindo que os administradores de cluster mapeiem papéis para identidades do Google Cloud (usuários e contas de serviço) como entidades em RoleBindings.

Por exemplo, na figura abaixo, há dois usuários, user-a e user-b, que receberam os papéis config-reader e pod-reader no namespace app-a.

Autorização RBAC

Como em outro exemplo, o Google Cloud tem papéis de IAM em nível do projeto que dão a certos usuários acesso a todos os clusters de um projeto. Além disso, são incluídas vinculações individuais de papel (em nível de namespace e de cluster) por meio do RBAC para dar acesso detalhado a recursos dentro de clusters ou namespaces específicos.

Vinculações de papéis de IAM

O Kubernetes inclui alguns papéis padrão, porém, como administrador de cluster, você mesmo pode criá-los para atender às suas necessidades organizacionais com mais precisão. Veja abaixo um papel de exemplo que permite aos usuários apenas ver, editar e atualizar ConfigMaps, mas não excluí-los, porque o verbo delete não está incluído:

kind: Role
    apiVersion: rbac.authorization.k8s.io/v1beta1
    metadata:
      namespace: default
      name: config-editor
    rules:
    - apiGroups: [""]
      resources: ["configmaps"]
      verbs: ["get", "list", "watch", "create", "update", "patch"]
    

Depois de definir papéis, você os aplica ao cluster ou namespace por meio de vinculações. As vinculações associam os papéis aos respectivos usuários, grupos ou contas de serviço. Veja abaixo um exemplo de vinculação do papel criado anteriormente (config-editor) ao usuário bob@example.org e ao namespace development.

kind: RoleBinding
    apiVersion: rbac.authorization.k8s.io/v1beta1
    metadata:
      name: config-editors
      namespace: development
    subjects:
    - kind: User
      name: bob@example.org
      apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: ClusterRole
      name: config-editor
      apiGroup: rbac.authorization.k8s.io
    

Para mais informações sobre o RBAC, consulte a documentação do GKE.

Acesso e compartilhamento de imagens

As imagens no Container Registry são armazenadas no Cloud Storage. Nesta seção, abordamos duas maneiras de compartilhar imagens. Uma delas é tornando-as públicas, a outra é compartilhando-as entre projetos.

Como tornar públicas as imagens

Para tornar públicas as imagens, torne públicos os objetos e buckets que as sustentam. Para instruções mais detalhadas, consulte a documentação de controle de acesso do Container Registry.

Como acessar imagens entre projetos

Para compartilhar imagens de contêiner entre projetos, garanta que os nós do Kubernetes usem uma conta de serviço. A conta de serviço padrão associada ao seu projeto está no formato [PROJECT_ID]-compute@developer.gserviceaccount.com. Com esse identificador, é possível conceder a ele acesso de storage.viewer em projetos em que quer usar o Container Registry. Portanto, use uma conta de serviço personalizada que tenha permissões restritas, já que a conta padrão tem acesso de editor no projeto inteiro.

Para usar outra conta de serviço com seus clusters, forneça a conta de serviço na criação do cluster ou do pool de nós usando a sinalização --service-account. Por exemplo, para usar a conta de serviço gke-sa no projeto my-project:

gcloud container clusters create west --service-account \
      gke-sa@my-project.google.com.iam.gserviceaccount.com
    

Como configurar a rede

O Kubernetes fornece a abstração de serviço que proporciona o balanceamento de carga e a descoberta de serviços em conjuntos de pods dentro de um cluster, bem como em sistemas legados executados fora do cluster. As seções abaixo descrevem as práticas recomendadas para a comunicação entre os pods do Kubernetes e com outros sistemas, incluindo outros clusters do Kubernetes.

Como comunicar-se no mesmo cluster

Descoberta de serviço

O Kubernetes permite definir serviços que agrupam pods em execução no cluster com base em um conjunto de rótulos. Esse grupo de pods pode ser descoberto no cluster usando DNS. Para mais informações sobre a descoberta de serviços no Kubernetes, acesse a documentação Como conectar aplicativos a serviços(em inglês).

DNS

Um servidor DNS de cluster local, kube-dns, é implantado em cada cluster do GKE que manipula o mapeamento de nomes de serviço para IPs de pods íntegros. Por padrão, o servidor DNS do Kubernetes retorna o endereço IP do cluster do serviço. Esse endereço IP é estático por todo o ciclo de vida do serviço. Quando há envio de tráfego para esse IP, os iptables no nó farão o balanceamento de carga dos pacotes pelos pods prontos que correspondem aos seletores do serviço. Esses iptables são programados automaticamente pelo serviço kube-proxy em execução em cada nó.

Se você quer a descoberta de serviços e o monitoramento de integridade, mas prefere que o serviço DNS retorne os IPs dos pods em vez de um IP virtual, provisione o serviço com o campo ClusterIP definido com "None", o que torna o serviço sem comando. Nesse caso, o servidor DNS retorna uma lista de registros A que mapeiam o nome DNS do serviço para os registros A dos pods prontos que correspondem aos seletores de rótulo definidos pelo serviço. Os registros da resposta são revezados para facilitar a propagação da carga nos diversos pods. Alguns resolvedores de DNS do lado do cliente podem armazenar respostas DNS em cache, tornando ineficaz o revezamento de registros A. As vantagens do uso do ClusterIP estão listadas na documentação do Kubernetes(em inglês).

Um caso de uso típico de serviços sem comando é StatefulSets. StatefulSets é ideal para executar aplicativos com estado que exigem estabilidade de armazenamento e rede entre as réplicas. Esse tipo de implantação provisiona pods que têm uma identidade de rede estável, o que significa que os respectivos nomes de host podem ser resolvidos no cluster. O endereço IP do pod pode mudar, mas a entrada DNS do nome do host permanecerá atualizada e passível de resolução.

Fluxo de pacotes: ClusterIP

No diagrama a seguir, veja a resposta DNS e o fluxo de pacotes de um serviço padrão do Kubernetes. Os endereços IP do pod são roteáveis de fora do cluster, mas o endereço IP do cluster de um serviço só é acessível dentro do cluster. Esses endereços IP virtuais são implementados por meio da conversão de endereços de rede de destino (DNAT, na sigla em inglês) em cada nó do Kubernetes. O serviço kube-proxy em execução nos nós mantém as regras de encaminhamento atualizadas em cada nó que mapeia o endereço IP do cluster para os endereços IP de pods íntegros no cluster. Se houver um pod do serviço em execução no nó local, esse pod será usado. Caso contrário, será escolhido um pod aleatório no cluster.

Serviço de IP de cluster

Para mais informações sobre como os IPs de serviço são implementados, consulte a documentação do Kubernetes (em inglês). Para se aprofundar na rede do GKE, assista à palestra do Next 2017 no YouTube:

Serviços sem comando

Veja abaixo um exemplo da resposta DNS e do padrão de tráfego referente a um serviço sem comando. Os endereços IP do pod podem ser roteados por meio das tabelas de rotas da sub-rede do GCP padrão e são acessados diretamente pelo seu aplicativo.

Exemplo de resposta DNS e padrão de tráfego do serviço sem comando

Políticas de rede

Use a aplicação da política de rede do Kubernetes Engine para controlar a comunicação entre os pods e os serviços do cluster. Para definir uma política de rede no Kubernetes Engine, é possível usar a API Kubernetes Network Policy para criar regras de firewall no nível do pod. Essas regras de firewall determinam quais pods e serviços podem acessar um ao outro dentro do cluster.

As políticas de rede são um tipo de defesa profunda que aumenta a segurança das cargas de trabalho em execução no seu cluster. Por exemplo, é possível criar uma política de rede para impedir que um serviço comprometido de front-end no aplicativo se comunique diretamente com um serviço de faturamento ou contabilidade vários níveis abaixo.

As políticas de rede também podem ser usadas para isolar cargas de trabalho pertencentes a locatários diferentes. Por exemplo, é possível fornecer multilocação segura definindo um modelo de locatário por namespace. Nesse modelo, as regras de política de rede podem impedir que pods e serviços em um determinado namespace acessem outros pods ou serviços em outro namespace.

Para saber mais sobre as políticas de rede, consulte a documentação do GKE.

Como se conectar a um cluster do GKE usando o Google Cloud

Para se conectar aos serviços de fora do cluster, mas dentro do espaço IP particular da rede do GCP, use o balanceamento de carga interno. Durante a criação de um serviço com type: Load Balancer e de uma anotação cloud.google.com/load-balancer-type: Internal no Kubernetes, um balanceador de carga de rede interno é criado no projeto do GCP e configurado para distribuir tráfego TCP e UDP entre os pods.

Como se conectar a serviços externos de dentro de um cluster

Em muitos casos, pode ser necessário conectar os aplicativos em execução dentro do Kubernetes a um serviço, banco de dados ou aplicativo que esteja fora do cluster. Há três opções, descritas abaixo.

Domínios stub

No Kubernetes 1.6 e posterior, você configura o serviço DNS interno do cluster (kube-dns) para encaminhar consultas DNS referentes a um determinado domínio a um servidor DNS externo. Isso é útil quando há servidores DNS confiáveis que precisam ser consultados quanto a um domínio que os pods do Kubernetes precisarão aproveitar.

Serviços de nomes externos

Os serviços de nomes externos permitem mapear um registro DNS para um nome de serviço dentro do cluster. Nesse caso, as buscas DNS quanto ao serviço no cluster retornam um registro CNAME de sua escolha. Isso precisa ser usado se você tiver apenas alguns registros que queira mapear para serviços DNS atuais.

Serviços sem seletores

Você cria serviços sem seletor e depois adiciona endpoints a eles manualmente para preencher a descoberta de serviços com os valores corretos. Com isso, é possível usar o mesmo mecanismo de descoberta de serviços para os serviços internos ao cluster, garantindo que os sistemas sem descoberta de serviços por meio de DNS ainda estejam acessíveis. Essa abordagem é a mais flexível, mas também requer mais configuração e manutenção a longo prazo.

Para mais informações sobre o DNS, acesse a página de documentação em Pods e serviços DNS do Kubernetes (em inglês).

Como receber tráfego da Internet para o cluster

O tráfego da Internet pode ser direcionado para os serviços executados no Kubernetes usando dois métodos diferentes: balanceamento de carga de rede ou HTTP(s).

Os serviços do Kubernetes precisam ser criados como o tipo LoadBalancer para balanceamento de carga TCP/UDP externa. O Kubernetes cria um balanceador de carga de rede no projeto do GCP e o mapeia para os nós do cluster do Kubernetes Engine. Assim, fica fácil ter balanceamento de carga para as cargas de trabalho TCP e UDP com configuração mínima. O balanceador de carga de rede tem escopo regional, portanto, só pode balancear o tráfego em relação aos nós em execução na mesma região.

Balanceador de carga de rede na região us-west1

No caso do balanceamento de carga HTTP(S), você precisa aproveitar o balanceador de carga HTTP(S) global do Google, que pode fazer o balanceamento de carga do tráfego entre várias regiões usando um único endereço IP anycast. Para balancear o tráfego para um único cluster, crie um recurso de entrada no Kubernetes que permita mapear nomes de host e caminhos para os serviços dentro do cluster. O Kubernetes cria um balanceador de carga HTTP(S) e o configura para encaminhar tráfego para os nós no seu cluster GKE. Para que a entrada funcione corretamente, é preciso criar os serviços com type: NodePort. Opcionalmente, é possível adicionar a anotação cloud.google.com/neg: '{"ingress": true}' para ativar o balanceamento de carga nativo do contêiner, o que permite ao balanceador de carga direcionar o tráfego diretamente para os pods em execução no cluster, permitindo uma distribuição mais uniforme do tráfego.

balanceamento de carga para um único cluster

Para balancear o tráfego em várias regiões, recomendamos criar e configurar um balanceador de carga HTTP(S) para direcionar tráfego para grupos de endpoints da rede autônomos que expõem serviços nos clusters. Para o balanceamento de carga multirregional, você precisa criar seus serviços com type: ClusterIP e incluir a anotação cloud.google.com/neg para especificar qual serviço e porta associar a um grupo de endpoints de rede. Você também precisa criar uma regra de firewall correspondente, uma verificação de integridade, um serviço de back-end e uma regra de encaminhamento para configurar seu balanceador de carga a fim de começar a rotear o tráfego para seus serviços de back-end.

balanceamento de carga em várias regiões

Firewall

Os nós do GKE são provisionados como instâncias no Compute Engine. Portanto, eles adotam o mesmo mecanismo de firewall com estado que outras instâncias. Essas regras de firewall são aplicadas dentro da rede a instâncias com o uso de tags. Cada pool de nós recebe o próprio conjunto de tags que pode ser usado nas regras. Por padrão, cada instância pertencente a um pool de nós recebe uma tag que identifica um cluster específico do Kubernetes Engine do qual esse pool de nós faz parte. Essa tag é usada em regras de firewall criadas automaticamente pelo Kubernetes Engine. Você adiciona suas próprias tags personalizadas no momento de criação do pool de nós ou do cluster usando a sinalização --tags na linha de comando do gcloud.

Por exemplo, para permitir que um balanceador de carga interno acesse a porta 8080 em todos os nós, use os comandos a seguir:

gcloud compute firewall-rules create \
      allow-8080-fwr --target-tags allow-8080 --allow tcp:8080 \
      --network gke --source-range 130.211.0.0/22
    gcloud container clusters create my-cluster --tags allow-8080
    

No exemplo a seguir, veja como marcar um cluster para que o tráfego da Internet possa acessar nós na porta 30000 enquanto o outro cluster é marcado para permitir tráfego da VPN para a porta 40000. Isso é útil ao expor um serviço por meio de um NodePort que só precisa ser acessível por redes com privilégio, como uma VPN, em direção a um data center corporativo ou a partir de outro cluster no projeto.

como marcar dois clusters de maneira diferente

Como se conectar a um data center local

O Cloud Interconnect oferece várias opções para a conexão com data centers locais. Por não serem mutuamente excludentes, elas podem ser combinadas de acordo com a carga de trabalho e os requisitos:

  1. Internet para cargas de trabalho sem uso intenso de dados ou relacionadas à latência. O Google tem mais de 100 pontos de presença (PoPs, na sigla em inglês) que se conectam a provedores de serviços em todo o mundo.
  2. O peering direto para cargas de trabalho que exigem largura de banda dedicada é sensível à latência e precisa de acesso a todos os serviços do Google, incluindo o pacote completo de produtos do Google Cloud. O peering direto é uma conexão de camada 3, efetuada pela troca de rotas BGP e, portanto, requer um ASN registrado.
  3. Peering por operadora é o mesmo que peering direto, só que feito por meio de um provedor de serviços. É uma ótima opção quando você não tem um ASN registrado ou tem relações atuais com um provedor de serviços preferencial.
  4. O Cloud VPN é configurado na interconexão de camada 3 e nas opções de Internet (1, 2 e 3) caso a criptografia IPsec seja obrigatória ou caso você queira estender a rede privada à rede privada do Compute Engine.

A seguir