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

O diagrama a seguir mostra 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. Os projetos são a unidade de faturamento e permitem que os administradores associem os 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. É possível aplicar políticas mais granulares e estritas aos projetos que contêm os dados e cargas de trabalho mais críticos e confidenciais, ao mesmo tempo que aplica políticas de permissão flexíveis para os desenvolvedores do ambiente test-dev fazerem experiências.

Clusters

Um projeto pode conter vários clusters. Se você tiver várias cargas de trabalho para implantar, poderá optar por 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 convenção atual de gerenciamento de endereços IP (IPAM, na sigla em inglês). Aplique, então, as 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 que o tráfego passe entre as sub-redes. Use a sinalização --tags durante a criação do cluster ou do pool de nós para marcar corretamente 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 nodes 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 nodes 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, e os de várias zonas apenas um. Nos dois casos, o tráfego entre nodes nas zonas é cobrado.

No momento da criação do cluster, você escolhe se ele será de várias zonas ou regional. Você pode 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

A seção anterior mostrou que é possível vincular papéis de IAM a usuários no nível do projeto. Além de conceder papéis a usuários individuais, também é possível usar 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 para um projeto dev que está configurado para que desenvolvedores desenvolvam e testem os próximos recursos e correções de bugs, bem como um projeto prod para o 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 Pode criar recursos do Kubernetes para os clusters existentes 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, uma conta de serviço extra é fornecida ao papel container.developer de prod, concedendo permissão para criar, listar e excluir recursos no cluster. As contas de serviço podem ser usadas para proporcionar 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 precisam 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, garantindo 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 versões posteriores 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 adicionadas vinculações individuais de papel (em nível de namespace e de cluster) por meio do RBAC para conceder 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, mas, como administrador de cluster, é possível criar o próprio mapa, mais específico às necessidades organizacionais. Veja abaixo um papel de exemplo que permite aos usuários apenas ver, editar e atualizar o 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, é possível aplicá-los 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 saber 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, abordaremos duas maneiras de compartilhar imagens. Uma delas é tornando-as públicas, a outra é compartilhando-as entre projetos.

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.

Acessar imagens entre projetos

É possível compartilhar imagens de contêiner entre projetos, basta garantir 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. Esse identificador possibilita conceder a ele acesso de storage.viewer em projetos em que você 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ço 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.

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 toda a vida do serviço. Ao enviar tráfego a 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ço 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 se alternam para facilitar a propagação da carga em vários pods. Algumas ferramentas de resolução de DNS do lado do cliente podem armazenar respostas de DNS em cache, tornando ineficaz a alternância do registro A. As vantagens do uso do ClusterIP estão listadas na documentação do Kubernetes.

Um caso de uso típico para 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 IP do pod pode mudar, mas a entrada DNS do nome do host permanecerá atualizada e poderá ser resolvida.

Fluxo de pacotes: ClusterIP

O diagrama a seguir mostra 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, acesse a documentação do Kubernetes. Para ter uma compreensão mais aprofundada sobre a 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 que aumenta a segurança das cargas de trabalho em execução no seu cluster. Por exemplo, você pode criar uma política de rede para garantir que um serviço comprometido de front-end no aplicativo não possa se comunicar diretamente com um serviço de cobrança 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, você pode fornecer multilocação segura definindo um modelo de locatário por namespace. Nesse modelo, as regras de política de rede podem garantir que pods e serviços em um determinado namespace não acessem outros pods ou serviços em um namespace diferente.

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 versões posteriores, configure 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 você tem servidores DNS autorizados que devem ser consultados em relação 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 retornarão um registro CNAME que você escolher. Isso precisa ser usado se você tiver apenas alguns registros dos quais quer fazer o mapeamento retroativo aos serviços DNS existentes.

Serviços sem seletores

Você pode criar serviços sem seletor e depois adicionar a eles os pontos de extremidade manualmente para preencher a descoberta de serviço com os valores corretos. Com isso, você pode usar o mesmo mecanismo de descoberta de serviço para os serviços internos ao cluster, ao mesmo tempo em que assegura que os sistemas sem descoberta de serviço por meio do DNS ainda estão 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.

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 nodes 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), é recomendável utilizar 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. Como alternativa, é 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, possibilitando 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, é necessário 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. Também é necessário criar uma regra de firewall correspondente, uma verificação de integridade, um serviço de back-end e uma regra de encaminhamento para configurar o balanceador de carga a fim de começar a rotear o tráfego para os 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 seguem 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. Adicione 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

O exemplo a seguir mostra como marcar um cluster para que o tráfego da Internet possa acessar nodes na porta 30000 enquanto o outro cluster é marcado para permitir o tráfego da VPN para a porta 40000. Isso é útil ao expor um serviço por meio de um NodePort que só deve ser acessível por redes com privilégio, como uma VPN, em direção a um data center corporativo ou 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, é possível combiná-las 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 de 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 particular do Compute Engine.

A seguir