1. Visão geral
Este laboratório demonstra recursos e funcionalidades projetados para simplificar o fluxo de trabalho de desenvolvimento de engenheiros de software encarregados de desenvolver aplicativos Python em um ambiente conteinerizado. O desenvolvimento típico de contêineres exige que o usuário entenda os detalhes dos contêineres e do processo de build deles. Além disso, os desenvolvedores geralmente precisam interromper o fluxo de trabalho, saindo do ambiente de desenvolvimento integrado para testar e depurar os aplicativos em ambientes remotos. Com as ferramentas e tecnologias mencionadas neste tutorial, os desenvolvedores podem trabalhar de forma eficaz com aplicativos contêinerizados sem sair do ambiente de desenvolvimento integrado.
O que você vai aprender
Neste laboratório, você vai aprender métodos para desenvolver com contêineres no GCP, incluindo:
- Como criar um novo aplicativo inicial em Python
- Explicar o processo de desenvolvimento
- Desenvolver um serviço REST CRUD simples
2. Configuração e requisitos
Configuração de ambiente personalizada
- Faça login no Console do Google Cloud e crie um novo projeto ou reutilize um existente. Crie uma conta do Gmail ou do Google Workspace, se ainda não tiver uma.



- O Nome do projeto é o nome de exibição para os participantes do projeto. Ele é uma string de caracteres que não é usada pelas APIs do Google e pode ser atualizada a qualquer momento.
- O ID do projeto precisa ser exclusivo em todos os projetos do Google Cloud e não pode ser alterado após a definição. O Console do Cloud gera automaticamente uma string única, geralmente não importa o que seja. Na maioria dos codelabs, você precisará fazer referência ao ID do projeto, que geralmente é identificado como
PROJECT_ID. Então, se você não gostar dele, gere outro ID aleatório ou crie um próprio e veja se ele está disponível. Em seguida, ele fica "congelado" depois que o projeto é criado. - Há um terceiro valor, um Número de projeto, que algumas APIs usam. Saiba mais sobre esses três valores na documentação.
- Em seguida, você precisará ativar o faturamento no Console do Cloud para usar os recursos/APIs do Cloud. A execução deste codelab não será muito cara, se tiver algum custo. Para encerrar os recursos e não gerar cobranças além deste tutorial, siga as instruções de "limpeza" encontradas no final do codelab. Novos usuários do Google Cloud estão qualificados para o programa de US$ 300 de avaliação sem custos.
Iniciar o editor do Cloud Shell
Este laboratório foi projetado e testado para uso com o editor do Google Cloud Shell. Para acessar o editor,
- Acesse seu projeto do Google em https://console.cloud.google.com.
- No canto superior direito, clique no ícone do editor do Cloud Shell.

- Um novo painel será aberto na parte de baixo da janela
- Clique no botão "Abrir editor".

- O editor será aberto com um explorador à direita e o editor na área central.
- Um painel de terminal também vai estar disponível na parte de baixo da tela.
- Se o terminal NÃO estiver aberto, use a combinação de teclas "ctrl+`" para abrir uma nova janela do terminal.
Configuração do ambiente
No Cloud Shell, defina o ID e o número do projeto. Salve-as como variáveis PROJECT_ID e PROJECT_ID.
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
--format='value(projectNumber)')
Conseguir o código-fonte
- O código-fonte deste laboratório está localizado no container-developer-workshop em GoogleCloudPlatform no GitHub. Clone com o comando abaixo e mude para o diretório.
git clone https://github.com/GoogleCloudPlatform/container-developer-workshop.git &&
cd container-developer-workshop/labs/python
mkdir music-service && cd music-service
cloudshell workspace .
Se o terminal NÃO estiver aberto, use a combinação de teclas "ctrl+`" para abrir uma nova janela do terminal.
Provisionar a infraestrutura usada neste laboratório
Neste laboratório, você vai implantar código no GKE e acessar dados armazenados em um banco de dados do Spanner. O script de configuração abaixo prepara essa infraestrutura para você. O processo de provisionamento vai levar mais de 10 minutos. Você pode continuar com as próximas etapas enquanto a configuração é processada.
../setup.sh
3. Criar um novo aplicativo inicial em Python
- Crie um arquivo chamado
requirements.txte copie o conteúdo a seguir nele:
Flask
gunicorn
google-cloud-spanner
ptvsd==4.3.2
- Crie um arquivo chamado
app.pye cole o seguinte código nele:
import os
from flask import Flask, request, jsonify
from google.cloud import spanner
app = Flask(__name__)
@app.route("/")
def hello_world():
message="Hello, World!"
return message
if __name__ == '__main__':
server_port = os.environ.get('PORT', '8080')
app.run(debug=False, port=server_port, host='0.0.0.0')
- Crie um arquivo chamado Dockerfile e cole o seguinte nele:
FROM python:3.8
ARG FLASK_DEBUG=0
ENV FLASK_DEBUG=$FLASK_DEBUG
ENV FLASK_APP=app.py
WORKDIR /app
COPY requirements.txt .
RUN pip install --trusted-host pypi.python.org -r requirements.txt
COPY . .
ENTRYPOINT ["python3", "-m", "flask", "run", "--port=8080", "--host=0.0.0.0"]
Observação: FLASK_DEBUG=1 permite recarregar automaticamente as mudanças de código em um app Python Flask. Esse Dockerfile permite transmitir esse valor como um argumento de build.
Gerar manifestos
No terminal, execute o comando a seguir para gerar um skaffold.yaml e um deployment.yaml padrão.
- Inicialize o Skaffold com o seguinte comando:
skaffold init --generate-manifests
Quando solicitado, use as setas para mover o cursor e a barra de espaço para selecionar as opções.
Opções disponíveis:
8080para a portaypara salvar a configuração
Atualizar configurações do Skaffold
- Mudar o nome do aplicativo padrão
- Abrir
skaffold.yaml - Selecione o nome da imagem definido como
dockerfile-image. - Clique com o botão direito do mouse e escolha "Mudar todas as ocorrências".
- Digite o novo nome como
python-app - Edite ainda mais a seção de build para
- adicionar
docker.buildArgsao cartãoFLASK_DEBUG=1 - Sincronize as configurações para carregar as mudanças nos arquivos
*.pydo ambiente de desenvolvimento integrado para o contêiner em execução.
Após as edições, a seção de build no arquivo skaffold.yaml ficaria assim:
build:
artifacts:
- image: python-app
docker:
buildArgs:
FLASK_DEBUG: 1
dockerfile: Dockerfile
sync:
infer:
- '**/*.py'
Modificar o arquivo de configuração do Kubernetes
- Mudar o nome padrão
- Abrir arquivo
deployment.yaml - Selecione o nome da imagem definido como
dockerfile-image. - Clique com o botão direito do mouse e escolha "Mudar todas as ocorrências".
- Digite o novo nome como
python-app
4. Como percorrer o processo de desenvolvimento
Com a lógica de negócios adicionada, agora você pode implantar e testar seu aplicativo. A seção a seguir vai destacar o uso do plug-in Cloud Code. Entre outras coisas, esse plug-in se integra ao skaffold para simplificar o processo de desenvolvimento. Ao implantar no GKE nas etapas a seguir, o Cloud Code e o Skaffold vão criar automaticamente a imagem do contêiner, enviá-la para um Container Registry e implantar o aplicativo no GKE. Isso acontece nos bastidores, abstraindo os detalhes do fluxo do desenvolvedor.
Implantar no Kubernetes
- No painel na parte de baixo do editor do Cloud Shell, selecione Cloud Code 

- No painel que aparece na parte de cima, selecione Executar no Kubernetes. Se solicitado, selecione "Sim" para usar o contexto atual do Kubernetes.

Esse comando inicia um build do código-fonte e executa os testes. A criação e os testes vão levar alguns minutos para serem executados. Eles incluem testes de unidade e uma etapa de validação que verifica as regras definidas para o ambiente de implantação. Essa etapa de validação já está configurada e garante que você receba avisos sobre problemas de implantação enquanto ainda está trabalhando no ambiente de desenvolvimento.
- Na primeira vez que você executar o comando, uma solicitação vai aparecer na parte de cima da tela perguntando se você quer o contexto atual do Kubernetes. Selecione "Sim" para aceitar e usar o contexto atual.
- Em seguida, uma solicitação vai aparecer perguntando qual registro de contêiner usar. Pressione "Enter" para aceitar o valor padrão fornecido.
- Selecione a guia "Saída" no painel de baixo para conferir o progresso e as notificações.

- Selecione "Kubernetes: Run/Debug - Detailed" no menu suspenso do canal à direita para conferir mais detalhes e registros transmitidos ao vivo dos contêineres.

Quando o build e os testes forem concluídos, a guia "Saída" vai mostrar: Attached debugger to container "python-app-8476f4bbc-h6dsl" successfully., e o URL http://localhost:8080 será listado.
- No terminal do Cloud Code, passe o cursor sobre o primeiro URL na saída (http://localhost:8080) e, na dica de ferramenta que aparece, selecione "Abrir visualização na Web".
- Uma nova guia do navegador será aberta e vai mostrar a mensagem
Hello, World!
Recarga automática
- Abra o arquivo
app.py. - Mude a mensagem de saudação para
Hello from Python
Na janela Output, na visualização Kubernetes: Run/Debug, o observador sincroniza os arquivos atualizados com o contêiner no Kubernetes.
Update initiated Build started for artifact python-app Build completed for artifact python-app Deploy started Deploy completed Status check started Resource pod/python-app-6f646ffcbb-tn7qd status updated to In Progress Resource deployment/python-app status updated to In Progress Resource deployment/python-app status completed successfully Status check succeeded ...
- Se você mudar para a visualização
Kubernetes: Run/Debug - Detailed, vai notar que ela reconhece as mudanças no arquivo, cria e reimplanta o app.
files modified: [app.py]
Syncing 1 files for gcr.io/veer-pylab-01/python-app:3c04f58-dirty@sha256:a42ca7250851c2f2570ff05209f108c5491d13d2b453bb9608c7b4af511109bd
Copying files:map[app.py:[/app/app.py]]togcr.io/veer-pylab-01/python-app:3c04f58-dirty@sha256:a42ca7250851c2f2570ff05209f108c5491d13d2b453bb9608c7b4af511109bd
Watching for changes...
[python-app] * Detected change in '/app/app.py', reloading
[python-app] * Restarting with stat
[python-app] * Debugger is active!
[python-app] * Debugger PIN: 744-729-662
- Atualize o navegador para ver os resultados atualizados.
Depuração
- Acesse a visualização de depuração e pare a linha de execução atual
. - Clique em
Cloud Codeno menu da parte de baixo e selecioneDebug on Kubernetespara executar o aplicativo no mododebug.
- Na visualização
Kubernetes Run/Debug - Detailedda janelaOutput, observe que o Skaffold vai implantar esse aplicativo no modo de depuração.
- Na primeira vez que isso for executado, uma solicitação vai perguntar onde a origem está dentro do contêiner. Esse valor está relacionado aos diretórios no Dockerfile.
Pressione "Enter" para aceitar o padrão

A criação e a implantação do aplicativo levam alguns minutos.
- Quando o processo for concluído. Você vai notar um depurador anexado.
Port forwarding pod/python-app-8bd64cf8b-cskfl in namespace default, remote port 5678 -> http://127.0.0.1:5678
- A barra de status na parte de baixo muda de azul para laranja, indicando que está no modo de depuração.
- Na visualização
Kubernetes Run/Debug, observe que um contêiner depurável é iniciado.
**************URLs***************** Forwarded URL from service python-app: http://localhost:8080 Debuggable container started pod/python-app-8bd64cf8b-cskfl:python-app (default) Update succeeded ***********************************
Usar pontos de interrupção
- Abra o arquivo
app.py. - Localize a instrução que diz
return message. - Adicione um ponto de interrupção a essa linha clicando no espaço em branco à esquerda do número da linha. Um indicador vermelho vai aparecer para mostrar que o ponto de interrupção foi definido.
- Recarregue o navegador e observe que o depurador interrompe o processo no ponto de interrupção e permite investigar as variáveis e o estado do aplicativo que está sendo executado remotamente no GKE.
- Clique na seção "VARIÁVEIS".
- Clique em "Locais" para encontrar a variável
"message". - Clique duas vezes no nome da variável "message" e, no pop-up, mude o valor para algo diferente, como
"Greetings from Python". - Clique no botão "Continuar" no painel de controle de depuração
. - Revise a resposta no navegador, que agora mostra o valor atualizado que você acabou de inserir.
- Pare o modo "Debug" pressionando o botão de parada
e remova o ponto de interrupção clicando nele novamente.
5. Como desenvolver um serviço REST CRUD simples
Neste ponto, seu aplicativo está totalmente configurado para desenvolvimento em contêineres, e você já passou pelo fluxo de trabalho de desenvolvimento básico com o Cloud Code. Nas seções a seguir, você vai praticar o que aprendeu adicionando endpoints de serviço REST que se conectam a um banco de dados gerenciado no Google Cloud.
Codificar o serviço restante
O código abaixo cria um serviço REST simples que usa o Spanner como o banco de dados que oferece suporte ao aplicativo. Crie o aplicativo copiando o código a seguir nele.
- Crie o aplicativo principal substituindo
app.pypelo conteúdo a seguir:
import os
from flask import Flask, request, jsonify
from google.cloud import spanner
app = Flask(__name__)
instance_id = "music-catalog"
database_id = "musicians"
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
@app.route('/singer', methods=['POST'])
def create():
try:
request_json = request.get_json()
singer_id = request_json['singer_id']
first_name = request_json['first_name']
last_name = request_json['last_name']
def insert_singers(transaction):
row_ct = transaction.execute_update(
f"INSERT Singers (SingerId, FirstName, LastName) VALUES" \
f"({singer_id}, '{first_name}', '{last_name}')"
)
print("{} record(s) inserted.".format(row_ct))
database.run_in_transaction(insert_singers)
return {"Success": True}, 200
except Exception as e:
return e
@app.route('/singer', methods=['GET'])
def get_singer():
try:
singer_id = request.args.get('singer_id')
def get_singer():
first_name = ''
last_name = ''
with database.snapshot() as snapshot:
results = snapshot.execute_sql(
f"SELECT SingerId, FirstName, LastName FROM Singers " \
f"where SingerId = {singer_id}",
)
for row in results:
first_name = row[1]
last_name = row[2]
return (first_name,last_name )
first_name, last_name = get_singer()
return {"first_name": first_name, "last_name": last_name }, 200
except Exception as e:
return e
@app.route('/singer', methods=['PUT'])
def update_singer_first_name():
try:
singer_id = request.args.get('singer_id')
request_json = request.get_json()
first_name = request_json['first_name']
def update_singer(transaction):
row_ct = transaction.execute_update(
f"UPDATE Singers SET FirstName = '{first_name}' WHERE SingerId = {singer_id}"
)
print("{} record(s) updated.".format(row_ct))
database.run_in_transaction(update_singer)
return {"Success": True}, 200
except Exception as e:
return e
@app.route('/singer', methods=['DELETE'])
def delete_singer():
try:
singer_id = request.args.get('singer')
def delete_singer(transaction):
row_ct = transaction.execute_update(
f"DELETE FROM Singers WHERE SingerId = {singer_id}"
)
print("{} record(s) deleted.".format(row_ct))
database.run_in_transaction(delete_singer)
return {"Success": True}, 200
except Exception as e:
return e
port = int(os.environ.get('PORT', 8080))
if __name__ == '__main__':
app.run(threaded=True, host='0.0.0.0', port=port)
Adicionar configurações de banco de dados
Para se conectar ao Spanner com segurança, configure o aplicativo para usar identidades da carga de trabalho. Isso permite que seu aplicativo atue como uma conta de serviço própria e tenha permissões individuais ao acessar o banco de dados.
- Atualize o
deployment.yaml. Adicione o seguinte código ao final do arquivo (mantenha os recuos de tabulação no exemplo abaixo):
serviceAccountName: python-ksa
nodeSelector:
iam.gke.io/gke-metadata-server-enabled: "true"
Implantar e validar o aplicativo
- No painel na parte de baixo do editor do Cloud Shell, selecione
Cloud Codee depoisDebug on Kubernetesna parte de cima da tela. - Quando o build e os testes forem concluídos, a guia "Saída" vai mostrar:
Resource deployment/python-app status completed successfully, e um URL será listado: "URL encaminhado do serviço python-app: http://localhost:8080" - Adicione algumas entradas.
No terminal do Cloud Shell, execute o comando abaixo:
curl -X POST http://localhost:8080/singer -H 'Content-Type: application/json' -d '{"first_name":"Cat","last_name":"Meow", "singer_id": 6}'
- Teste o GET executando o comando abaixo no terminal:
curl -X GET http://localhost:8080/singer?singer_id=6
- Teste de exclusão: agora tente excluir uma entrada executando o seguinte comando. Mude o valor de item-id, se necessário.
curl -X DELETE http://localhost:8080/singer?singer_id=6
This throws an error message
500 Internal Server Error
Identificar e corrigir o problema
- Modo de depuração e encontrar o problema. Veja algumas dicas:
- Sabemos que há algo errado com o DELETE, já que ele não está retornando o resultado desejado. Portanto, você definiria o ponto de interrupção em
app.pyno métododelete_singer. - Execute a execução passo a passo e observe as variáveis em cada passo para ver os valores das variáveis locais na janela à esquerda.
- Para observar valores específicos, como
singer_iderequest.args, adicione essas variáveis à janela "Watch".
- O valor atribuído a
singer_idéNone. Mude o código para corrigir o problema.
O snippet de código corrigido ficaria assim.
@app.route('/delete-singer', methods=['DELETE', 'GET'])
def delete_singer():
try:
singer_id = request.args.get('singer_id')
- Depois que o aplicativo for reiniciado, tente excluir de novo.
- Clique no quadrado vermelho na barra de ferramentas de depuração
para interromper a sessão.
6. Limpeza
Parabéns! Neste laboratório, você criou um novo aplicativo Python do zero e o configurou para funcionar de maneira eficaz com contêineres. Em seguida, você implantou e depurou o aplicativo em um cluster do GKE remoto seguindo o mesmo fluxo de desenvolvedor encontrado em stacks de aplicativos tradicionais.
Para fazer a limpeza depois de concluir o laboratório:
- Excluir os arquivos usados no laboratório
cd ~ && rm -rf container-developer-workshop
- Exclua o projeto para remover toda a infraestrutura e os recursos relacionados.