Implantar um app em uma imagem de contêiner em um cluster do GKE


Nesta página, você aprende as seguintes ações com relação à verificação de tempo de atividade:

  1. Criar um aplicativo "Hello World".
  2. Empacotar o aplicativo em uma imagem de contêiner usando o Cloud Build.
  3. Criar um cluster no Google Kubernetes Engine (GKE).
  4. Implantar a imagem de contêiner no cluster.

A amostra é exibida em várias linguagens, mas é possível usar outras além.


Para seguir as instruções da tarefa diretamente no editor do Cloud Shell, clique em Orientação:

Orientações


Antes de começar

  1. Faça login na sua conta do Google Cloud. Se você começou a usar o Google Cloud agora, crie uma conta para avaliar o desempenho de nossos produtos em situações reais. Clientes novos também recebem US$ 300 em créditos para executar, testar e implantar cargas de trabalho.
  2. No console do Google Cloud, na página do seletor de projetos, selecione ou crie um projeto do Google Cloud.

    Acessar o seletor de projetos

  3. Verifique se a cobrança está ativada para o seu projeto do Google Cloud.

  4. Ative as APIs Artifact Registry, Cloud Build, and Google Kubernetes Engine.

    Ative as APIs

  5. Instale a CLI do Google Cloud.
  6. Para inicializar a CLI gcloud, execute o seguinte comando:

    gcloud init
  7. No console do Google Cloud, na página do seletor de projetos, selecione ou crie um projeto do Google Cloud.

    Acessar o seletor de projetos

  8. Verifique se a cobrança está ativada para o seu projeto do Google Cloud.

  9. Ative as APIs Artifact Registry, Cloud Build, and Google Kubernetes Engine.

    Ative as APIs

  10. Instale a CLI do Google Cloud.
  11. Para inicializar a CLI gcloud, execute o seguinte comando:

    gcloud init
  12. kubectl é usado para gerenciar o Kubernetes, o sistema de orquestração de cluster usado pelo GKE. Instale kubectl usando gcloud:
    gcloud components install kubectl

Como escrever o aplicativo de amostra

Para instruções sobre como criar um aplicativo "Hello World" que seja executado no GKE, clique na linguagem usada por você:

Go

  1. Crie um novo diretório com o nome helloworld-gke e altere o diretório nele:

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Crie um novo módulo chamado example.com/helloworld:

    go mod init example.com/helloworld
    
  3. Crie um novo arquivo chamado helloworld.go e cole o código a seguir nele:

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"os"
    )
    
    func main() {
    	http.HandleFunc("/", handler)
    
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    	}
    
    	log.Printf("Listening on localhost:%s", port)
    	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
    }
    
    func handler(w http.ResponseWriter, r *http.Request) {
    	log.Print("Hello world received a request.")
    	target := os.Getenv("TARGET")
    	if target == "" {
    		target = "World"
    	}
    	fmt.Fprintf(w, "Hello %s!\n", target)
    }
    

    Com esse código, você cria um servidor da Web que realiza detecções na porta definida pela variável de ambiente PORT.

Você concluiu seu app. Ele está pronto para ser empacotado em um contêiner do Docker e enviado por upload ao Artifact Registry.

Node.js

  1. Crie um novo diretório chamado helloworld-gke e mude para ele:

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Crie um arquivo package.json com o seguinte conteúdo:

    {
      "name": "gke-helloworld",
      "version": "1.0.0",
      "description": "GKE hello world sample in Node",
      "main": "index.js",
      "scripts": {
        "start": "node index.js"
      },
      "author": "",
      "license": "Apache-2.0",
      "dependencies": {
        "express": "^4.16.4"
      }
    }
    
  3. No mesmo diretório, crie um arquivo index.js e copie as seguintes linhas nele:

    const express = require('express');
    const app = express();
    
    app.get('/', (req, res) => {
      console.log('Hello world received a request.');
    
      const target = process.env.TARGET || 'World';
      res.send(`Hello ${target}!`);
    });
    
    const port = process.env.PORT || 8080;
    app.listen(port, () => {
      console.log('Hello world listening on port', port);
    });

    Com esse código, você cria um servidor da Web que realiza detecções na porta definida pela variável de ambiente PORT.

Você concluiu seu app. Ele está pronto para ser empacotado em um contêiner do Docker e enviado por upload ao Artifact Registry.

Python

  1. Crie um novo diretório chamado helloworld-gke e mude para ele:

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Crie um arquivo chamado app.py e cole o seguinte código nele:

    import os
    
    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        target = os.environ.get('TARGET', 'World')
        return 'Hello {}!\n'.format(target)
    
    if __name__ == "__main__":
        app.run(debug=True,host='0.0.0.0',port=int(os.environ.get('PORT', 8080)))

Java

Crie um aplicativo Spring Boot.

  1. Instale JDK Java SE 8 ou superior e cURL (links em inglês). O Java SE e cURL são necessários apenas para criar o novo projeto da Web na próxima etapa. O Dockerfile, descrito posteriormente, carrega todas as dependências no contêiner.

  2. No terminal, crie um novo projeto da Web vazio:

    curl https://start.spring.io/starter.zip \
        -d dependencies=web \
        -d javaVersion=1.8 \
        -d type=maven-project \
        -d bootVersion=2.6.6 \
        -d name=helloworld \
        -d artifactId=helloworld \
        -d baseDir=helloworld-gke \
        -o helloworld-gke.zip
    unzip helloworld-gke.zip
    cd helloworld-gke
    

    Agora você tem um novo projeto de inicialização do Spring em helloworld-gke.

  3. No arquivo src/main/java/com/example/helloworld/HelloworldApplication.java, atualize a classe HelloworldApplication adicionando um @RestController para manipular o mapeamento /.

    package com.example.helloworld;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    public class HelloworldApplication {
    
    	@Value("${TARGET:World}")
    	String target;
    
    	@RestController
    	class HelloworldController {
    		@GetMapping("/")
    		String hello() {
    			return "Hello " + target + "!";
    		}
    	}
    
    	public static void main(String[] args) {
    		SpringApplication.run(HelloworldApplication.class, args);
    	}
    }

    Com esse código, você cria um servidor da Web que realiza detecções na porta definida pela variável de ambiente PORT.

Você concluiu seu app. Ele está pronto para ser empacotado em um contêiner do Docker e enviado por upload ao Artifact Registry.

C#

  1. Instale o SDK .NET. O SDK .NET será necessário apenas para criar o novo projeto da Web na próxima etapa. O Dockerfile, que é descrito posteriormente, carrega todas as dependências no contêiner.

  2. No terminal, crie um novo projeto da Web vazio:

    dotnet new web -o helloworld-gke
    
  3. Altere o diretório para helloworld-gke.

    cd helloworld-gke
    
  4. Atualize o Program.cs para detectar a atividade na porta 8080:

    var builder = WebApplication.CreateBuilder(args);
    
    // Google Cloud Run sets the PORT environment variable to tell this
    // process which port to listen to.
    var port = Environment.GetEnvironmentVariable("PORT") ?? "8080";
    var url = $"http://0.0.0.0:{port}";
    var target = Environment.GetEnvironmentVariable("TARGET") ?? "World";
    
    var app = builder.Build();
    
    app.MapGet("/", () => $"Hello {target}!");
    
    app.Run(url);

Você concluiu seu app. Ele está pronto para ser empacotado em um contêiner do Docker e enviado por upload ao Artifact Registry.

PHP

  1. Crie um novo diretório chamado helloworld-gke e mude para ele:

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Crie um arquivo chamado index.php e cole o seguinte código nele:

    <?php
    $target = getenv('TARGET', true) ?: 'World';
    echo sprintf("Hello %s!", $target);
    ?>

Você concluiu seu app. Ele está pronto para ser empacotado em um contêiner do Docker e enviado por upload ao Artifact Registry.

Como contentorizar um aplicativo com o Cloud Build

  1. Para contentorizar o aplicativo de amostra, crie um novo arquivo chamado Dockerfile no mesmo diretório dos arquivos de origem e copie o seguinte conteúdo:

    Go

    # Use the offical Go image to create a build artifact.
    # This is based on Debian and sets the GOPATH to /go.
    # https://hub.docker.com/_/golang
    FROM golang:1.21.0 as builder
    WORKDIR /app
    
    # Initialize a new Go module.
    RUN go mod init quickstart-go
    
    # Copy local code to the container image.
    COPY *.go ./
    
    # Build the command inside the container.
    RUN CGO_ENABLED=0 GOOS=linux go build -o /quickstart-go
    
    # Use a Docker multi-stage build to create a lean production image.
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM gcr.io/distroless/base-debian11
    
    # Change the working directory.
    WORKDIR /
    
    # Copy the binary to the production image from the builder stage.
    COPY --from=builder /quickstart-go /quickstart-go
    
    # Run the web service on container startup.
    USER nonroot:nonroot
    ENTRYPOINT ["/quickstart-go"]

    Node.js

    # Use the official lightweight Node.js 16 image.
    # https://hub.docker.com/_/node
    FROM node:17-slim
    
    # Create and change to the app directory.
    WORKDIR /usr/src/app
    
    # Copy application dependency manifests to the container image.
    # A wildcard is used to ensure both package.json AND package-lock.json are copied.
    # Copying this separately prevents re-running npm install on every code change.
    COPY package*.json ./
    
    # Install production dependencies.
    RUN npm install --omit=dev
    
    # Copy local code to the container image.
    COPY . ./
    
    # Run the web service on container startup.
    CMD [ "npm", "start" ]

    Adicione outro arquivo .dockerignore para garantir que os arquivos locais não afetem o processo de criação do contêiner:

    Dockerfile
    README.md
    node_modules
    npm-debug.log
    

    Python

    # Use the official lightweight Python image.
    # https://hub.docker.com/_/python
    FROM python:3.7-slim
    
    # Copy local code to the container image.
    ENV APP_HOME /app
    WORKDIR $APP_HOME
    COPY . ./
    
    # Install production dependencies.
    RUN pip install Flask gunicorn
    
    # Run the web service on container startup. Here we use the gunicorn
    # webserver, with one worker process and 8 threads.
    # For environments with multiple CPU cores, increase the number of workers
    # to be equal to the cores available.
    CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app

    Adicione um arquivo .dockerignore para garantir que os arquivos locais não afetem o processo de criação do contêiner:

    Dockerfile
    README.md
    *.pyc
    *.pyo
    *.pyd
    __pycache__
    

    Java

    # Use the official maven/Java 8 image to create a build artifact.
    # https://hub.docker.com/_/maven
    FROM maven:3.5-jdk-8-alpine as builder
    
    # Copy local code to the container image.
    WORKDIR /app
    COPY pom.xml ./
    COPY src ./src/
    
    # Build a release artifact.
    RUN mvn package -DskipTests
    
    # Use AdoptOpenJDK for base image.
    # It's important to use OpenJDK 8u191 or above that has container support enabled.
    # https://hub.docker.com/r/adoptopenjdk/openjdk8
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM adoptopenjdk/openjdk8:jdk8u202-b08-alpine-slim
    
    # Copy the jar to the production image from the builder stage.
    COPY --from=builder /app/target/helloworld-*.jar /helloworld.jar
    
    # Run the web service on container startup.
    CMD ["java","-Djava.security.egd=file:/dev/./urandom","-Dserver.port=${PORT}","-jar","/helloworld.jar"]

    C#

    # Use Microsoft's official lightweight .NET images.
    FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
    WORKDIR /app
    
    # Install production dependencies.
    # Copy csproj and restore as distinct layers.
    COPY *.csproj ./
    RUN dotnet restore
    
    # Copy local code to the container image.
    COPY . ./
    
    # Build a release artifact.
    RUN dotnet publish -c Release -o out
    
    # Run the web service on container startup in a lean production image.
    FROM mcr.microsoft.com/dotnet/aspnet:6.0
    WORKDIR /app
    COPY --from=build /app/out .
    
    # Start the .dll (will have the same name as your .csproj file)
    ENTRYPOINT ["dotnet", "helloworld-gke.dll"]

    Adicione um arquivo .dockerignore para garantir que os arquivos locais não afetem o processo de criação do contêiner:

    Dockerfile
    README.md
    **/obj/
    **/bin/
    

    PHP

    # Use the official PHP 7.4 image.
    # https://hub.docker.com/_/php
    FROM php:7.4-apache
    
    # Copy local code to the container image.
    COPY index.php /var/www/html/
    
    # Use port 8080 in Apache configuration files.
    RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
    
    # Configure PHP for development.
    # Switch to the production php.ini for production operations.
    # RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
    # https://hub.docker.com/_/php#configuration
    RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

    Adicione um arquivo .dockerignore para garantir que os arquivos locais não afetem o processo de criação do contêiner:

    Dockerfile
    README.md
    vendor
    
  2. Receba seu ID do projeto do Google Cloud:

    gcloud config get-value project
    
  3. Neste guia de início rápido, você armazenará o contêiner no Artifact Registry e o implantará no cluster a partir do registro. Execute o seguinte comando para criar um repositório chamado hello-repo no mesmo local do cluster:

    gcloud artifacts repositories create hello-repo \
        --project=PROJECT_ID \
        --repository-format=docker \
        --location=us-central1 \
        --description="Docker repository"
    

    Substitua os seguintes valores:

    • PROJECT_ID é o ID do projeto do Google Cloud.
  4. Crie sua imagem de contêiner usando Cloud Build, que é semelhante à execução de docker build e docker push, mas isso acontece no Google Cloud:

    gcloud builds submit \
      --tag us-central1-docker.pkg.dev/PROJECT_ID/hello-repo/helloworld-gke .
    

    A imagem é armazenada no Artifact Registry.

crie um cluster do GKE;

Um cluster do GKE é um conjunto gerenciado de máquinas virtuais do Compute Engine que operam como uma única unidade.

  1. Crie o cluster.

    gcloud container clusters create-auto helloworld-gke \
      --location us-central1
    
  2. Verifique se você tem acesso ao cluster. O comando a seguir lista os nós no cluster do contêiner que estão em execução e indica que você tem acesso ao cluster.

    kubectl get nodes
    

    Se ocorrerem erros, consulte o Guia de solução de problemas do Kubernetes.

Como implantar no GKE

Para implantar o aplicativo no cluster do GKE que você criou, são necessários dois objetos do Kubernetes.

  1. A Implantação para definir o aplicativo.
  2. O objeto Service para definir como acessar o aplicativo.

Implantar um aplicativo

O aplicativo tem um servidor de front-end que processa as solicitações da Web. Defina os recursos de cluster necessários para executar o front-end em um novo arquivo chamado deployment.yaml. Eles são conhecidos como implantação. Use Implantações para criar e atualizar um ReplicaSet (em inglês) e os pods associados.

  1. Crie o arquivo deployment.yaml no mesmo diretório dos outros arquivos e copie o conteúdo a seguir. Substitua os seguintes valores no seu arquivo:

    • $GCLOUD_PROJECT é o ID do projeto do Google Cloud:
    • $LOCATION é o local do repositório, como us-central1.
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: helloworld-gke
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: hello
      template:
        metadata:
          labels:
            app: hello
        spec:
          containers:
          - name: hello-app
            # Replace $LOCATION with your Artifact Registry location (e.g., us-west1).
            # Replace $GCLOUD_PROJECT with your project ID.
            image: $LOCATION-docker.pkg.dev/$GCLOUD_PROJECT/hello-repo/helloworld-gke:latest
            # This app listens on port 8080 for web traffic by default.
            ports:
            - containerPort: 8080
            env:
              - name: PORT
                value: "8080"
            resources:
              requests:
                memory: "1Gi"
                cpu: "500m"
                ephemeral-storage: "1Gi"
              limits:
                memory: "1Gi"
                cpu: "500m"
                ephemeral-storage: "1Gi"
  2. Implante o recurso no cluster:

    kubectl apply -f deployment.yaml
    
  3. Acompanhe o status da implantação:

    kubectl get deployments
    

    A implantação é concluída quando todas as implantações AVAILABLE são READY.

    NAME              READY   UP-TO-DATE   AVAILABLE   AGE
    helloworld-gke    1/1     1            1           20s
    

    Se a implantação tiver um erro, execute kubectl apply -f deployment.yaml novamente para atualizar a implantação com alterações.

  4. Depois que a implantação for concluída, veja os pods criados por ela

    kubectl get pods
    

Implantar um serviço

O objeto Service fornece um único ponto de acesso a um conjunto de pods. É possível acessar um único pod, mas eles são efêmeros, e o acesso só é confiável quando feito usando um endereço de serviço. Em seu aplicativo Hello World, o serviço "hello" "define um balanceador de carga (em inglês) para acessar os conjuntos hello-app a partir de um único endereço IP. Este serviço é definido no arquivo service.yaml.

  1. Crie o arquivo service.yaml no mesmo diretório que seus outros arquivos de origem com o seguinte conteúdo:

    # The hello service provides a load-balancing proxy over the hello-app
    # pods. By specifying the type as a 'LoadBalancer', Kubernetes Engine will
    # create an external HTTP load balancer.
    apiVersion: v1
    kind: Service
    metadata:
      name: hello
    spec:
      type: LoadBalancer
      selector:
        app: hello
      ports:
      - port: 80
        targetPort: 8080

    Os pods são definidos separadamente do serviço que os usa. No Kubernetes, você usa identificadores para selecionar os pods abrangidos por um serviço. Com isso, é possível ter um serviço que atende pods de diferentes conjuntos de réplicas e ter vários serviços que apontam para um pod específico.

  2. Crie o serviço "Hello World":

    kubectl apply -f service.yaml
    
  3. Encontre o endereço IP externo do serviço:

    kubectl get services
    

    Pode levar até 60 segundos para alocar o endereço IP. O endereço IP externo é listado na coluna EXTERNAL-IP do serviço hello.

    NAME         TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
    hello        LoadBalancer   10.22.222.222   35.111.111.11   80:32341/TCP   1m
    kubernetes   ClusterIP      10.22.222.1     <none>          443/TCP        20m
    

Ver um aplicativo implantado

Agora você implantou todos os recursos necessários para executar o app "Hello World" no GKE.

Use o endereço IP externo da etapa anterior para carregar o app no navegador da Web e vê-lo em execução:

 http://EXTERNAL_IP

Também é possível fazer uma chamada curl para o endereço IP externo do serviço:

curl EXTERNAL_IP

O resultado exibido é:

Hello World!

Limpar

Para evitar cobranças na conta do Google Cloud pelos recursos usados nesta página, siga estas etapas.

Você é cobrado pelas instâncias do Compute Engine em execução no cluster, bem como pela imagem de contêiner no Artifact Registry.

Excluir o projeto

A exclusão do projeto do Google Cloud interrompe o faturamento de todos os recursos usados no projeto.

  1. No Console do Google Cloud, acesse a página Gerenciar recursos.

    Acessar "Gerenciar recursos"

  2. Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir .
  3. Na caixa de diálogo, digite o ID do projeto e clique em Encerrar para excluí-lo.

Excluir o cluster e o contêiner

Se quiser manter o projeto, mas excluir apenas os recursos usados neste tutorial, remova o cluster e a imagem.

Para excluir um cluster usando a Google Cloud CLI, execute o comando a seguir no modo usado:

gcloud container clusters delete helloworld-gke \
    --location us-central1

Para excluir uma imagem no repositório do Artifact Registry, execute o seguinte comando:

gcloud artifacts docker images delete \
    us-central1-docker.pkg.dev/PROJECT_ID/hello-repo/helloworld-gke

A seguir

Para mais informações sobre o Kubernetes, consulte:

Para mais informações sobre como fazer implantações no GKE, consulte:

Para mais informações sobre como criar, desenvolver e executar aplicativos no GKE diretamente do seu ambiente de desenvolvimento integrado com o Cloud Code, consulte: