O Cloud Service Mesh é uma ferramenta poderosa para gerir e monitorizar aplicações distribuídas. Para tirar o máximo partido do Cloud Service Mesh, é útil compreender as suas abstrações subjacentes, incluindo contentores e o Kubernetes. Este tutorial explica como preparar uma aplicação para a Cloud Service Mesh a partir do código fonte para um contentor em execução no GKE, até ao ponto imediatamente antes de instalar a Cloud Service Mesh.
Se já conhece os conceitos do Kubernetes e da malha de serviços, pode ignorar este tutorial e aceder diretamente ao guia de instalação da malha de serviços da Google Cloud.
Objetivos
- Explore uma aplicação "hello world" simples com vários serviços.
- Execute a aplicação a partir da origem
- Contentorize a aplicação.
- Crie um cluster do Kubernetes.
- Implemente os contentores no cluster.
Antes de começar
Siga os passos abaixo para ativar a API Cloud Service Mesh:- Visite a página do Kubernetes Engine na Google Cloud consola.
- Crie ou selecione um projeto.
- Aguarde até que a API e os serviços relacionados sejam ativados. Esta ação pode demorar vários minutos.
-
Verify that billing is enabled for your Google Cloud project.
Este tutorial usa o Cloud Shell, que aprovisiona uma máquina virtual g1-small do Compute Engine que executa um sistema operativo Linux baseado em Debian.
Prepare o Cloud Shell
As vantagens da utilização do Cloud Shell são:
- Os ambientes de desenvolvimento do Python 2 e Python 3 (incluindo
virtualenv
) estão todos configurados. - As ferramentas de linhas de comando
gcloud
,docker
,git
ekubectl
usadas neste tutorial já estão instaladas. Tem à sua escolha editores de texto:
Editor de código, ao qual acede clicando em na parte superior da janela do Cloud Shell.
Emacs, Vim ou Nano, aos quais acede a partir da linha de comandos no Cloud Shell.
In the Google Cloud console, activate Cloud Shell.
Transfira o exemplo de código
Transfira o código-fonte
helloserver
:git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samples
Altere para o diretório do exemplo de código:
cd anthos-service-mesh-samples/docs/helloserver
Explore a aplicação multiserviços
A aplicação de exemplo está escrita em Python e tem dois componentes que comunicam através de REST:
server
: Um servidor simples com um ponto finalGET
,/
, que imprime "hello world" na consola.loadgen
: um script que envia tráfego para oserver
, com um número configurável de pedidos por segundo (RPS).
Execute a aplicação a partir da origem
Para se familiarizar com a aplicação de exemplo, execute-a no Cloud Shell.
A partir do diretório
sample-apps/helloserver
, execute o comandoserver
:python3 server/server.py
No arranque, o
server
apresenta o seguinte:INFO:root:Starting server...
Abra outra janela de terminal para poder enviar pedidos para
server
. Clique em para abrir outra sessão.Envie um pedido ao
server
:curl http://localhost:8080
O
server
responde:Hello World!
No diretório onde transferiu o exemplo de código, mude para o diretório que contém o ficheiro
loadgen
:cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/loadgen
Crie as seguintes variáveis de ambiente:
export SERVER_ADDR=http://localhost:8080 export REQUESTS_PER_SECOND=5
Início
virtualenv
:virtualenv --python python3 env
Ative o ambiente virtual:
source env/bin/activate
Instale os requisitos para
loadgen
:pip3 install -r requirements.txt
Execute o comando
loadgen
:python3 loadgen.py
No arranque, o
loadgen
produz uma mensagem semelhante à seguinte:Starting loadgen: 2019-05-20 10:44:12.448415 5 request(s) complete to http://localhost:8080
Na outra janela do terminal, o
server
escreve mensagens na consola semelhantes às seguintes:127.0.0.1 - - [21/Jun/2019 14:22:01] "GET / HTTP/1.1" 200 - INFO:root:GET request, Path: / Headers: Host: localhost:8080 User-Agent: python-requests/2.22.0 Accept-Encoding: gzip, deflate Accept: */*
Do ponto de vista da rede, toda a aplicação está agora a ser executada no mesmo anfitrião. Por este motivo, pode usar o
localhost
para enviar pedidos para oserver
.Para parar o
loadgen
e oserver
, introduzaCtrl-c
em cada janela do terminal.Na
loadgen
janela de terminal, desative o ambiente virtual:deactivate
Contentorize a aplicação
Para executar a aplicação no GKE, tem de empacotar a aplicação de exemplo, tanto server
como loadgen
, em contentores. Um contentor é uma forma de embalar uma aplicação de modo que fique isolada do ambiente subjacente.
Para colocar a aplicação num contentor, precisa de um Dockerfile
. Um Dockerfile
é um ficheiro de texto que define os comandos necessários para montar o código-fonte da aplicação e as respetivas dependências numa imagem Docker. Depois de criar a imagem, carregue-a para um registo de contentores, como o Docker Hub ou o registo de contentores.
O exemplo inclui um Dockerfile
para o server
e o loadgen
com todos os comandos necessários para criar as imagens. Seguem-se os
Dockerfile
para o server
:
- O comando
FROM python:3-slim as base
indica ao Docker que use a imagem do Python 3 mais recente como imagem de base. - O comando
COPY . .
copia os ficheiros de origem no diretório de trabalho atual (neste caso, apenasserver.py
) para o sistema de ficheiros do contentor. - O elemento
ENTRYPOINT
define o comando que é usado para executar o contentor. Neste caso, o comando é quase igual ao que usou para executarserver.py
a partir do código fonte. - O comando
EXPOSE
especifica que oserver
é responsável pela deteção na porta8080
. Este comando não expõe nenhuma porta, mas serve como documentação de que tem de abrir a porta8080
quando executar o contentor.
Prepare-se para colocar a aplicação em contentores
Defina as seguintes variáveis de ambiente. Substitua
PROJECT_ID
pelo ID do seu Google Cloud projeto.export PROJECT_ID="PROJECT_ID"
export GCR_REPO="asm-ready"
Usa o valor de
PROJECT_ID
eGCR_REPO
para etiquetar a imagem do Docker quando a cria e, em seguida, a envia para o seu registo de contentores privado.Defina o projeto Google Cloud predefinido para a CLI do Google Cloud.
gcloud config set project $PROJECT_ID
Defina a zona predefinida para a CLI gcloud.
gcloud config set compute/zone us-central1-b
Certifique-se de que o serviço Container Registry está ativado no seu Google Cloud projeto.
gcloud services enable containerregistry.googleapis.com
Coloque o server
num contentor
Mude para o diretório onde se encontra o exemplo
server
:cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/server/
Crie a imagem com o comando
Dockerfile
e as variáveis de ambiente que definiu anteriormente:docker build -t gcr.io/$PROJECT_ID/$GCR_REPO/helloserver:v0.0.1 .
A flag
-t
representa a etiqueta do Docker. Este é o nome da imagem que usa quando implementa o contentor.Envie a imagem para o Container Registry:
docker push gcr.io/$PROJECT_ID/$GCR_REPO/helloserver:v0.0.1
Coloque o loadgen
num contentor
Mude para o diretório onde se encontra o exemplo
loadgen
:cd ../loadgen
Crie a imagem:
docker build -t gcr.io/$PROJECT_ID/$GCR_REPO/loadgen:v0.0.1 .
Envie a imagem para o Container Registry:
docker push gcr.io/$PROJECT_ID/$GCR_REPO/loadgen:v0.0.1
Indica as imagens
Obtenha uma lista das imagens no repositório para confirmar que as imagens foram enviadas:
gcloud container images list --repository gcr.io/$PROJECT_ID/asm-ready
O comando responde com os nomes das imagens que acabou de enviar:
NAME gcr.io/PROJECT_ID/asm-ready/helloserver gcr.io/PROJECT_ID/asm-ready/loadgen
Crie um cluster do GKE
Pode executar estes contentores na VM do Cloud Shell usando o comando docker run
. No entanto, na produção, tem de orquestrar os contentores de uma forma mais unificada. Por exemplo, precisa de um sistema que garanta que os contentores estão sempre em execução e de uma forma de aumentar e iniciar instâncias adicionais de um contentor para processar aumentos de tráfego.
Pode usar o GKE para executar aplicações contentorizadas. O GKE é uma plataforma de orquestração de contentores que funciona através da ligação de VMs a um cluster. Cada MV é referida como um nó. Os clusters do GKE são baseados no sistema de gestão de clusters de código aberto Kubernetes. O Kubernetes fornece os mecanismos através dos quais interage com o seu cluster.
Para criar um cluster do GKE:
Crie o cluster:
gcloud container clusters create asm-ready \ --cluster-version latest \ --machine-type=n1-standard-4 \ --num-nodes 4
O comando
gcloud
cria um cluster no Google Cloud projeto e na zona que definiu anteriormente. Para executar o Cloud Service Mesh, recomendamos, pelo menos, 4 nós e o tipo de máquina n1-standard-4.O comando para criar o cluster demora alguns minutos a ser concluído. Quando o cluster estiver pronto, o comando produz uma mensagem semelhante à seguinte:
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS asm-ready us-central1-b 1.13.5-gke.10 203.0.113.1 n1-standard-2 1.13.5-gke.10 4 RUNNING
Forneça credenciais à ferramenta de linha de comandos
kubectl
para que a possa usar para gerir o cluster:gcloud container clusters get-credentials asm-ready
Agora, pode usar o
kubectl
para comunicar com o Kubernetes. Por exemplo, pode executar o seguinte comando para obter o estado dos nós:kubectl get nodes
O comando responde com uma lista dos nós, semelhante à seguinte:
NAME STATUS ROLES AGE VERSION gke-asm-ready-default-pool-dbeb23dc-1vg0 Ready <none> 99s v1.13.6-gke.13 gke-asm-ready-default-pool-dbeb23dc-36z5 Ready <none> 100s v1.13.6-gke.13 gke-asm-ready-default-pool-dbeb23dc-fj7s Ready <none> 99s v1.13.6-gke.13 gke-asm-ready-default-pool-dbeb23dc-wbjw Ready <none> 99s v1.13.6-gke.13
Compreenda os principais conceitos do Kubernetes
O diagrama seguinte representa a aplicação em execução no GKE:
Antes de implementar os contentores no GKE, recomendamos que reveja alguns conceitos-chave do Kubernetes. No final deste tutorial, são disponibilizados links para que possa saber mais sobre cada conceito.
Nós e clusters: no GKE, um nó é uma VM. Noutras plataformas Kubernetes, um nó pode ser uma máquina física ou virtual. Um cluster é um conjunto de nós que podem ser tratados em conjunto como uma única máquina, na qual implementa uma aplicação contentorizada.
Pods: no Kubernetes, os contentores são executados num pod. Um pod é a unidade atómica no Kubernetes. Um pod contém um ou mais contentores. Implementa os contentores
server
eloadgen
, cada um no seu próprio pod. Quando um Pod executa vários contentores (por exemplo, um servidor de aplicações e um servidor proxy), os contentores são geridos como uma única entidade e partilham os recursos do Pod.Implementações: uma implementação é um objeto do Kubernetes que representa um conjunto de pods idênticos. Uma implementação executa várias réplicas dos pods distribuídos entre os nós de um cluster. Uma implementação substitui automaticamente todos os pods que falham ou deixam de responder.
Serviço Kubernetes: a execução do código da aplicação no GKE altera a rede entre o
loadgen
e oserver
. Quando executou os serviços numa VM do Cloud Shell, podia enviar pedidos para oserver
através do endereçolocalhost:8080
. Depois de implementar no GKE, os pods são agendados para serem executados nos nós disponíveis. Por predefinição, não pode controlar em que nó o pod está a ser executado, pelo que os pods não têm endereços IP estáveis.Para obter um endereço IP para o
server
, tem de definir uma abstração de rede acima dos pods denominada serviço Kubernetes. Um serviço do Kubernetes fornece um ponto final de rede estável para um conjunto de pods. Existem vários tipos de serviços. Oserver
usa umLoadBalancer
, que expõe um endereço IP externo para que possa alcançar oserver
a partir do exterior do cluster.O Kubernetes também tem um sistema DNS incorporado, que atribui nomes DNS (por exemplo,
helloserver.default.cluster.local
) aos serviços. Isto permite que os pods no cluster alcancem outros pods no cluster com um endereço estável. Não pode usar este nome DNS fora do cluster, como a partir do Cloud Shell.
Manifestos do Kubernetes
Quando executou a aplicação a partir do código-fonte, usou um comando
imperativo: python3 server.py
Imperativo significa orientado por verbos: "faz isto".
Por outro lado, o Kubernetes opera num modelo declarativo. Isto significa que, em vez de dizer exatamente ao Kubernetes o que fazer, fornece ao Kubernetes um estado desejado. Por exemplo, o Kubernetes inicia e termina os pods conforme necessário para que o estado real do sistema corresponda ao estado desejado.
Especifica o estado pretendido num conjunto de manifestos ou ficheiros YAML. Um ficheiro YAML contém a especificação de um ou mais objetos do Kubernetes.
O exemplo contém um ficheiro YAML para o server
e o loadgen
. Cada ficheiro YAML especifica o estado pretendido para o objeto de implementação do Kubernetes e o serviço.
Servidor
kind
indica o tipo de objeto.metadata.name
especifica o nome da implementação.- O primeiro campo
spec
contém uma descrição do estado pretendido. spec.replicas
especifica o número de pods desejados.- A secção
spec.template
define um modelo de agrupamento. A especificação dos pods inclui o campoimage
, que é o nome da imagem a extrair do registo de contentores.
O Serviço é definido da seguinte forma:
LoadBalancer
: os clientes enviam pedidos para o endereço IP de um balanceador de carga de rede, que tem um endereço IP estável e é acessível fora do cluster.targetPort
: lembre-se de que o comandoEXPOSE 8080
emDockerfile
não expõe realmente nenhuma porta. Expõe a porta8080
para poder aceder ao contentorserver
fora do cluster. Neste caso,hellosvc.default.cluster.local:80
(nome abreviado:hellosvc
) é mapeado para a porta8080
do IP do agrupamentohelloserver
.port
: este é o número da porta que outros serviços no cluster usam quando enviam pedidos.
Gerador de carga
O objeto de implementação em loadgen.yaml
é semelhante a server.yaml
. Uma diferença
notável é que o objeto Deployment contém uma secção denominada env
. Esta secção define as variáveis de ambiente necessárias para o loadgen
, que definiu anteriormente quando executou a aplicação a partir da origem.
Uma vez que o loadgen
não aceita pedidos recebidos, o campo type
está definido como ClusterIP
. Este tipo fornece um endereço IP estável que os serviços no cluster podem usar, mas o endereço IP não é exposto a clientes externos.
Implemente os contentores no GKE
Mude para o diretório onde se encontra o exemplo
server
:cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/server/
Abra
server.yaml
num editor de texto.Substitua o nome no campo
image
pelo nome da sua imagem do Docker.image: gcr.io/PROJECT_ID/asm-ready/helloserver:v0.0.1
Substitua
PROJECT_ID
pelo ID do seu Google Cloud projeto.Guardar e fechar
server.yaml
.Implemente o ficheiro YAML no Kubernetes:
kubectl apply -f server.yaml
Em caso de êxito, o comando responde com o seguinte:
deployment.apps/helloserver created service/hellosvc created
Altere para o diretório onde se encontra
loadgen
.cd ../loadgen
Abra
loadgen.yaml
num editor de texto.Substitua o nome no campo
image
pelo nome da sua imagem do Docker.image: gcr.io/PROJECT_ID/asm-ready/loadgen:v0.0.1
Substitua
PROJECT_ID
pelo ID do seu Google Cloud projeto.Guarde e feche
loadgen.yaml
e feche o editor de texto.Implemente o ficheiro YAML no Kubernetes:
kubectl apply -f loadgen.yaml
Em caso de êxito, o comando responde com o seguinte:
deployment.apps/loadgenerator created service/loadgensvc created
Verifique o estado dos Pods:
kubectl get pods
O comando responde com um estado semelhante ao seguinte:
NAME READY STATUS RESTARTS AGE helloserver-69b9576d96-mwtcj 1/1 Running 0 58s loadgenerator-774dbc46fb-gpbrz 1/1 Running 0 57s
Obtenha os registos da aplicação do
loadgen
Pod. SubstituaPOD_ID
pelo identificador da saída anterior.kubectl logs loadgenerator-POD_ID
Obtenha os endereços IP externos de
hellosvc
:kubectl get service
A resposta do comando é semelhante à seguinte:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hellosvc LoadBalancer 10.81.15.158 192.0.2.1 80:31127/TCP 33m kubernetes ClusterIP 10.81.0.1 <none> 443/TCP 93m loadgensvc ClusterIP 10.81.15.155 <none> 80/TCP 4m52s
Envie um pedido para
hellosvc
. SubstituaEXTERNAL_IP
pelo endereço IP externo do seuhellosvc
.curl http://EXTERNAL_IP
Tudo pronto para o Cloud Service Mesh
Agora, tem a aplicação implementada no GKE. O loadgen
pode usar o DNS do Kubernetes (hellosvc:80
) para enviar pedidos para oserver
e
pode enviar pedidos para o server
com um endereço IP externo. Embora o Kubernetes lhe ofereça muitas funcionalidades, faltam algumas informações sobre os serviços:
- Como é que os serviços interagem? Qual é a relação entre os serviços? Como flui o tráfego entre os serviços? Sabe que o
loadgen
envia pedidos para oserver
, mas imagine que não conhece a aplicação. Não pode responder a estas perguntas consultando a lista de pods em execução no GKE. - Métricas: quanto tempo demora o
server
a responder a pedidos recebidos? Quantos pedidos por segundo (RPS) são recebidos noserver
? Existem respostas de erro? - Informações de segurança: o tráfego entre
loadgen
eserver
é simplesHTTP
ou mTLS?
O Cloud Service Mesh pode fornecer respostas a estas perguntas. O Cloud Service Mesh é uma versão Google Cloudgerida do projeto Istio de código aberto. O Cloud Service Mesh funciona através da colocação de um proxy sidecar do Envoy em cada Pod. O proxy Envoy
interceta todo o tráfego de entrada e saída para os contentores de aplicações. Isto significa que o server
e o loadgen
recebem cada um um proxy sidecar do Envoy e todo o tráfego do loadgen
para o server
é mediado pelos proxies do Envoy. As ligações entre estes proxies Envoy formam a malha de serviços. Esta arquitetura de malha de serviço fornece uma camada de controlo acima do Kubernetes.
Uma vez que os proxies Envoy são executados nos respetivos contentores, pode instalar o Cloud Service Mesh sobre um cluster do GKE sem alterações substanciais ao código da aplicação. No entanto, existem algumas formas importantes de preparar a aplicação para ser instrumentada com a Cloud Service Mesh:
- Serviços para todos os contentores: as implementações
server
eloadgen
têm um serviço Kubernetes anexado. Mesmo oloadgen
, que não recebe pedidos de entrada, tem um serviço. - As portas nos serviços têm de ter um nome: embora o GKE lhe permita definir portas de serviço sem nome, o Cloud Service Mesh requer que forneça um nome para uma porta que corresponda ao protocolo da porta. No ficheiro YAML, a porta para o
server
tem o nomehttp
porque oserver
usa o protocolo de comunicaçãoHTTP
. Se oservice
usado forgRPC
, deve dar o nomegrpc
à porta. - As implementações estão etiquetadas: isto permite-lhe usar funcionalidades de gestão de tráfego da Cloud Service Mesh, como dividir o tráfego entre versões do mesmo serviço.
Instale o Cloud Service Mesh
Visite o guia de instalação do Cloud Service Mesh e siga as instruções para instalar o Cloud Service Mesh no seu cluster.
Limpar
Para evitar incorrer em custos na sua conta do Google Cloud pelos recursos usados neste tutorial, elimine o projeto que contém os recursos ou mantenha o projeto e elimine os recursos individuais.
Para limpar, elimine o cluster do GKE. A eliminação do cluster elimina todos os recursos que compõem o cluster de contentores, como as instâncias de computação, os discos e os recursos de rede.
gcloud container clusters delete asm-ready
O que se segue?
Saiba mais sobre as tecnologias usadas neste tutorial:
Saiba mais sobre as ferramentas:
Saiba mais sobre os conceitos do Kubernetes: