Solução de problemas local

Neste tutorial, mostramos como um desenvolvedor de serviços pode resolver problemas de um serviço do Cloud Run for Anthos no Google Cloud usando ferramentas do Stackdriver para descoberta e um fluxo de trabalho de desenvolvimento local para investigação.

Neste "tutorial de estudo de caso" passo a passo do guia de solução de problemas é usado um projeto de amostra que resulta em erros de ambiente de execução quando implantados, que você soluciona para encontrar e corrigir o problema.

Não é possível usar este tutorial com o Cloud Run for Anthos no local devido às limitações de suporte do pacote de operações do Google Cloud.

Objetivos

  • Gravar, criar e implantar um serviço no Cloud Run for Anthos no Google Cloud
  • Usar o Cloud Logging para identificar um erro
  • Recuperar a imagem do contêiner do Container Registry para uma análise de causa raiz
  • Corrigir o serviço de "produção" e melhorá-lo para reduzir problemas futuros

Custos

Neste tutorial, usamos componentes do Cloud Platform que podem ser cobrados, incluindo estes:

Use a calculadora de preços para gerar uma estimativa de custo com base no uso previsto.

Usuários novos do Cloud Platform podem se qualificar para um teste gratuito.

Antes de começar

  1. Faça login na sua conta do Google.

    Se você ainda não tiver uma, inscreva-se.

  2. No Console do Google Cloud, na página do seletor de projetos, selecione ou crie um projeto do Google Cloud.

    Acessar a página do seletor de projetos

  3. Verifique se o faturamento está ativado para seu projeto na nuvem. Saiba como confirmar se o faturamento está ativado para o projeto.

  4. Ative a API Cloud Run for Anthos no Google Cloud
  5. Instale e inicie o SDK do Cloud.
  6. Instale o componente kubectl:
    gcloud components install kubectl
  7. Instale o componente beta:
    gcloud components install beta
  8. Atualize os componentes:
    gcloud components update
  9. Se você estiver usando o Cloud Run para Anthos no Google Cloud, crie um novo cluster usando as instruções em Como configurar o Cloud Run para Anthos no Google Cloud.
  10. Se você estiver usando o Cloud Run para Anthos no Google Cloud, instale o curl para testar o serviço
  11. Siga as instruções para instalar o Docker localmente

Como configurar padrões do gcloud

Para configurar a gcloud com os padrões do serviço do Cloud Run for Anthos no Google Cloud:

  1. Defina o projeto padrão:

    gcloud config set project PROJECT_ID

    Substitua PROJECT_ID pelo nome do projeto que você usou neste tutorial.

  2. Configure a gcloud para o cluster:

    gcloud config set kuberun/cluster CLUSTER-NAME
    gcloud config set kuberun/cluster_location REGION

    Substitua:

    • CLUSTER-NAME pelo nome que você usou para o cluster;
    • REGION pelo local do cluster compatível de sua escolha.

Como montar o código

Passo a passo para criar um novo serviço do Cloud Run for Anthos no Google Cloud. Lembre-se de que esse serviço cria um erro de ambiente de execução de propósito para o exercício de solução de problemas.

  1. Crie um novo projeto:

    Node.js

    Crie um projeto Node.js definindo o pacote de serviços, as dependências iniciais e algumas operações comuns.

    1. Crie um novo diretório hello-service:

      mkdir hello-service
      cd hello-service
      
    2. Crie um novo projeto Node.js gerando um arquivo package.json:

      npm init --yes
      npm install --save express@4
      
    3. Abra o novo arquivo package.json no seu editor e configure um script start para executar node index.js. Quando terminar, o arquivo terá esta aparência:

      {
        "name": "hello-service",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
            "start": "node index.js",
            "test": "echo \"Error: no test specified\" && exit 1"
        },
        "keywords": [],
        "author": "",
        "license": "ISC",
        "dependencies": {
            "express": "^4.17.1"
        }
      }

    Se você continuar a evoluir esse serviço além do tutorial imediato, preencha a descrição, o autor e avalie a licença. Para mais detalhes, leia a documentação do package.json.

    Python

    1. Crie um novo diretório hello-service:

      mkdir hello-service
      cd hello-service
      
    2. Crie um arquivo requirements.txt e copie suas dependências para ele:

      Flask==1.1.2
      pytest==5.3.0; python_version > "3.0"
      pytest==4.6.6; python_version < "3.0"
      gunicorn==20.0.4
      

    Go

    1. Crie um novo diretório hello-service:

      mkdir hello-service
      cd hello-service
      
    2. Crie um projeto em Go inicializando um novo módulo go:

      go mod init example.com/hello-service
      

    É possível atualizar o nome específico como você quiser: atualize o nome se o código for publicado em um repositório de código acessível pela web.

    Java

    1. Crie um novo projeto de instrução:

      mvn archetype:generate \
        -DgroupId=com.example \
        -DartifactId=hello-service \
        -DarchetypeArtifactId=maven-archetype-quickstart \
        -DinteractiveMode=false
      
    2. Copie as dependências para sua lista de dependências pom.xml (entre os elementos <dependencies>):

      <dependency>
        <groupId>com.sparkjava</groupId>
        <artifactId>spark-core</artifactId>
        <version>2.9.3</version>
      </dependency>
      <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.3.0-alpha5</version>
      </dependency>
      <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.30</version>
      </dependency>
      <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.7.30</version>
      </dependency>
      
    3. Copie a configuração de build para o pom.xml (nos elementos <dependencies>):

      <build>
        <plugins>
          <plugin>
            <groupId>com.google.cloud.tools</groupId>
            <artifactId>jib-maven-plugin</artifactId>
            <version>2.7.0</version>
            <configuration>
              <to>
                <image>gcr.io/PROJECT_ID/hello-service</image>
              </to>
            </configuration>
          </plugin>
        </plugins>
      </build>
      

  2. Crie um serviço HTTP para lidar com solicitações de entrada:

    Node.js

    const express = require('express');
    const app = express();
    
    app.get('/', (req, res) => {
      console.log('hello: received request.');
    
      const {NAME} = process.env;
      if (!NAME) {
        // Plain error logs do not appear in Stackdriver Error Reporting.
        console.error('Environment validation failed.');
        console.error(new Error('Missing required server parameter'));
        return res.status(500).send('Internal Server Error');
      }
      res.send(`Hello ${NAME}!`);
    });
    const port = process.env.PORT || 8080;
    app.listen(port, () => {
      console.log(`hello: listening on port ${port}`);
    });

    Python

    import json
    import os
    
    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route("/", methods=["GET"])
    def index():
        print("hello: received request.")
    
        NAME = os.getenv("NAME")
    
        if not NAME:
            print("Environment validation failed.")
            raise Exception("Missing required service parameter.")
    
        return f"Hello {NAME}"
    if __name__ == "__main__":
        PORT = int(os.getenv("PORT")) if os.getenv("PORT") else 8080
    
        # This is used when running locally. Gunicorn is used to run the
        # application on KubeRun. See entrypoint in Dockerfile.
        app.run(host="127.0.0.1", port=PORT, debug=True)

    Go

    
    // Sample hello demonstrates a difficult to troubleshoot service.
    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"os"
    )
    
    func main() {
    	log.Print("hello: service started")
    
    	http.HandleFunc("/", helloHandler)
    
    	http.HandleFunc("/improved", improvedHandler)
    
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    		log.Printf("Defaulting to port %s", port)
    	}
    
    	log.Printf("Listening on port %s", port)
    	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
    }
    
    func helloHandler(w http.ResponseWriter, r *http.Request) {
    	log.Print("hello: received request")
    
    	name := os.Getenv("NAME")
    	if name == "" {
    		log.Printf("Missing required server parameter")
    		// The panic stack trace appears in Cloud Error Reporting.
    		panic("Missing required server parameter")
    	}
    
    	fmt.Fprintf(w, "Hello %s!\n", name)
    }
    

    Java

    import static spark.Spark.get;
    import static spark.Spark.port;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class App {
    
      private static final Logger logger = LoggerFactory.getLogger(App.class);
    
      public static void main(String[] args) {
        int port = Integer.parseInt(System.getenv().getOrDefault("PORT", "8080"));
        port(port);
    
        get(
            "/",
            (req, res) -> {
              logger.info("Hello: received request.");
              String name = System.getenv("NAME");
              if (name == null) {
                // Standard error logs do not appear in Stackdriver Error Reporting.
                System.err.println("Environment validation failed.");
                String msg = "Missing required server parameter";
                logger.error(msg, new Exception(msg));
                res.status(500);
                return "Internal Server Error";
              }
              res.status(200);
              return String.format("Hello %s!", name);
            });
      }
    }

  3. Crie um Dockerfile para definir a imagem do contêiner usada para implantar o serviço:

    Node.js

    
    # Use the official lightweight Node.js 10 image.
    # https://hub.docker.com/_/node
    FROM node:12-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 copying both package.json AND package-lock.json (when available).
    # Copying this first prevents re-running npm install on every code change.
    COPY package*.json ./
    
    # Install production dependencies.
    # If you add a package-lock.json, speed your build by switching to 'npm ci'.
    # RUN npm ci --only=production
    RUN npm install --only=production
    
    # Copy local code to the container image.
    COPY . ./
    
    # Run the web service on container startup.
    CMD [ "npm", "start" ]
    

    Python

    
    # Use the official Python image.
    # https://hub.docker.com/_/python
    FROM python:3.9
    
    # Allow statements and log messages to immediately appear in the KubeRun logs
    ENV PYTHONUNBUFFERED True
    
    # Copy application dependency manifests to the container image.
    # Copying this separately prevents re-running pip install on every code change.
    COPY requirements.txt ./
    
    # Install production dependencies.
    RUN pip install -r requirements.txt
    
    # Copy local code to the container image.
    ENV APP_HOME /app
    WORKDIR $APP_HOME
    COPY . ./
    
    # Run the web service on container startup.
    # Use 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 --timeout 0 main:app
    

    Go

    
    # Use the offical golang image to create a binary.
    # This is based on Debian and sets the GOPATH to /go.
    # https://hub.docker.com/_/golang
    FROM golang:1.15-buster as builder
    
    # Create and change to the app directory.
    WORKDIR /app
    
    # Retrieve application dependencies.
    # This allows the container build to reuse cached dependencies.
    # Expecting to copy go.mod and if present go.sum.
    COPY go.* ./
    RUN go mod download
    
    # Copy local code to the container image.
    COPY . ./
    
    # Build the binary.
    RUN go build -mod=readonly -v -o server
    
    # Use the official Debian slim image for a lean production container.
    # https://hub.docker.com/_/debian
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM debian:buster-slim
    RUN set -x && apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
        ca-certificates && \
        rm -rf /var/lib/apt/lists/*
    
    # Copy the binary to the production image from the builder stage.
    COPY --from=builder /app/server /server
    
    # Run the web service on container startup.
    CMD ["/server"]
    

    Java

    Esta amostra usa o Jib (em inglês) para criar imagens do Docker usando ferramentas comuns do Java. O Jib otimiza builds de contêiner sem a necessidade de um Dockerfile ou de ter o Docker (em inglês) instalado. Saiba mais sobre como criar contêineres Java com o Jib.

    <plugin>
      <groupId>com.google.cloud.tools</groupId>
      <artifactId>jib-maven-plugin</artifactId>
      <version>2.7.0</version>
      <configuration>
        <to>
          <image>gcr.io/PROJECT_ID/hello-service</image>
        </to>
      </configuration>
    </plugin>
    

Como enviar o código

O código de envio consiste em três etapas: criar uma imagem de contêiner com o Cloud Build, fazer upload da imagem de contêiner no Container Registry e implantar a imagem de contêiner no Cloud Run for Anthos no Google Cloud.

Para enviar o código, siga estas etapas:

  1. Compile seu contêiner e publique no Container Registry.

    Node.js

    gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service

    Em que PROJECT_ID é o ID do seu projeto do GCP. Verifique o ID do projeto atual com gcloud config get-value project.

    Após a conclusão, você verá uma mensagem de "SUCESSO" contendo o ID, a hora da criação e o nome da imagem. A imagem é armazenada no Container Registry e poderá ser reutilizada, se você quiser.

    Python

    gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service

    Em que PROJECT_ID é o ID do seu projeto do GCP. Verifique o ID do projeto atual com gcloud config get-value project.

    Após a conclusão, você verá uma mensagem de "SUCESSO" contendo o ID, a hora da criação e o nome da imagem. A imagem é armazenada no Container Registry e poderá ser reutilizada, se você quiser.

    Go

    gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service

    Em que PROJECT_ID é o ID do seu projeto do GCP. Verifique o ID do projeto atual com gcloud config get-value project.

    Após a conclusão, você verá uma mensagem de "SUCESSO" contendo o ID, a hora da criação e o nome da imagem. A imagem é armazenada no Container Registry e poderá ser reutilizada, se você quiser.

    Java

    mvn compile jib:build -Dimage=gcr.io/PROJECT_ID/hello-service

    Em que PROJECT_ID é o ID do seu projeto do GCP. Verifique o ID do projeto atual com gcloud config get-value project.

    Após a conclusão, você verá uma mensagem "BUILD SUCCESS". A imagem é armazenada no Container Registry e poderá ser reutilizada, se você quiser.

  2. Execute o comando a seguir para implantar seu aplicativo:

    gcloud kuberun core services create hello-service --image gcr.io/PROJECT_ID/hello-service

    Substitua PROJECT_ID pelo ID do projeto do GCP. hello-service é o nome da imagem do contêiner e do serviço Cloud Run for Anthos no Google Cloud. Observe que a imagem do contêiner é implantada no serviço e no cluster que você configurou anteriormente em Como configurar o gcloud.

    Aguarde até que a implantação esteja concluída. Isso pode levar cerca de 30 segundos. Em caso de sucesso, a linha de comando exibe o URL de serviço.

Testar

Teste o serviço para confirmar que o implantou. As solicitações falham com um erro HTTP 500 ou 503 (membros da classe Erros de servidor 5xx). O tutorial explica a solução de problemas dessa resposta de erro.

Se o cluster estiver configurado com um domínio padrão roteável, ignore as etapas acima e copie o URL para o navegador da Web.

Se você não usa certificados TLS automáticos e mapeamento de domínio, não recebe um URL navegável para seu serviço.

Em vez disso, use o URL fornecido e o endereço IP do gateway de entrada do serviço para criar um comando curl que possa fazer solicitações ao seu serviço:

  1. Para receber o IP externo do gateway de entrada do Istio:
    kubectl get svc istio-ingress -n gke-system
    
    A saída resultante é algo semelhante a:
    NAME            TYPE           CLUSTER-IP     EXTERNAL-IP  PORT(S)
    istio-ingress   LoadBalancer   XX.XX.XXX.XX   pending      80:32380/TCP,443:32390/TCP,32400:32400/TCP
    
    O EXTERNAL-IP do balanceador de carga é o endereço IP que você precisa usar.
  2. Execute um comando curl usando este endereço GATEWAY_IP no URL.

     curl -G -H "Host: SERVICE-DOMAIN" https://EXTERNAL-IP/

    Substitua SERVICE-DOMAIN pelo domínio padrão atribuído ao seu serviço. Para isso, use o URL padrão e remova o protocolo http://.

  3. Veja a mensagem de erro HTTP 500 ou HTTP 503.

Como investigar o problema

Veja que o erro HTTP 5xx encontrado acima em Como testar foi encontrado como um erro de ambiente de execução de produção. Este tutorial aborda um processo formal para lidar com ele. Embora os processos de resolução de erros de produção variem muito, este tutorial apresenta uma sequência específica de etapas para mostrar a aplicação de ferramentas e técnicas úteis.

Para investigar esse problema, siga estas etapas:

  • Colete mais detalhes sobre o erro relatado para ajudar na investigação e definir uma estratégia de mitigação.
  • Alivie o impacto do usuário decidindo avançar em uma correção ou reversão para uma versão íntegra conhecida.
  • Reproduza o erro para confirmar se os detalhes corretos foram coletados e se o erro não é uma falha única.
  • Realize uma análise de causa-raiz no bug para encontrar o código, a configuração ou o processo que criou o erro.

No início da investigação, há um URL, um carimbo de data/hora e a mensagem "Erro interno do servidor".

Como coletar mais detalhes

Reúna mais informações sobre o problema para entender o que aconteceu e determinar as próximas etapas.

Use as ferramentas disponíveis para coletar mais detalhes:

  1. Veja os registros para mais detalhes.

  2. Use o Cloud Logging para analisar a sequência de operações que levam ao problema, incluindo mensagens de erro.

Reverter para uma versão íntegra

Se tiver uma revisão que você sabe que estava funcionando, poderá reverter seu serviço para usar essa revisão. Por exemplo, não será possível fazer uma reversão no novo serviço hello-service implantado neste tutorial, porque ele contém apenas uma revisão.

Para localizar uma revisão e reverter o serviço:

  1. Liste todas as revisões do serviço.

  2. Migre todo o tráfego para a revisão íntegra.

Como reproduzir o erro

Usando os detalhes que você recebeu anteriormente, confirme se o problema ocorre de forma consistente nas condições de teste.

Envie a mesma solicitação HTTP testando-a novamente e veja se o mesmo erro e detalhes são relatados. Pode levar algum tempo para que os detalhes do erro sejam exibidos.

Como o serviço de amostra neste tutorial é somente leitura e não aciona efeitos secundários de complicações, a reprodução de erros na produção é segura. No entanto, para muitos serviços reais, isso não acontecerá: talvez seja necessário reproduzir erros em um ambiente de teste ou limitar essa etapa à investigação local.

A reprodução do erro estabelece o contexto para trabalhos futuros. Por exemplo, se os desenvolvedores não conseguirem reproduzir o erro, investigações adicionais podem exigir instrumentação adicional do serviço.

Como realizar uma análise de causa raiz

A análise da causa raiz é uma etapa importante na solução de problemas eficaz para garantir que você corrija o problema em vez do sintoma.

Anteriormente neste tutorial, você reproduziu o problema no Cloud Run for Anthos no Google Cloud, que confirma que o problema está ativo quando o serviço é hospedado no Cloud Run for Anthos no Google Cloud. Agora, reproduza o problema localmente para determinar se ele está isolado do código ou se ele só aparece na hospedagem de produção.

  1. Se você não tiver usado a CLI do Docker localmente com o Container Registry, faça a autenticação com o gcloud:

    gcloud auth configure-docker

    Para abordagens alternativas, consulte Métodos de autenticação do Container Registry.

  2. Se o nome da imagem do contêiner usado mais recentemente não estiver disponível, a descrição do serviço terá as informações da imagem do contêiner implantada mais recentemente:

    gcloud kuberun core services describe hello-service

    Encontre o nome da imagem do contêiner dentro do objeto spec. Um comando mais segmentado pode recuperá-lo diretamente:

    gcloud kuberun core services describe hello-service \
       --format="value(spec.template.spec.containers.image)"

    Esse comando revela um nome de imagem de contêiner como gcr.io/PROJECT_ID/hello-service.

  3. Extraia a imagem do contêiner do Container Registry para seu ambiente. Essa etapa pode levar alguns minutos para fazer o download da imagem do contêiner:

    docker pull gcr.io/PROJECT_ID/hello-service

    Atualizações posteriores na imagem do contêiner que reutilizam esse nome podem ser recuperadas com o mesmo comando. Se você pular esta etapa, o comando docker run abaixo extrairá uma imagem de contêiner se ela não estiver presente na máquina local.

  4. Execute localmente para confirmar que o problema não é exclusivo do Cloud Run for Anthos no Google Cloud:

    PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \
       gcr.io/PROJECT_ID/hello-service

    Analisando os elementos do comando acima:

    • A variável de ambiente PORT é usada pelo serviço para determinar a porta a ser ouvida no contêiner.
    • O comando run inicia o contêiner, assumindo como padrão o comando entrypoint definido no Dockerfile ou em uma imagem de contêiner pai.
    • A sinalização --rm exclui a instância do contêiner na saída.
    • A sinalização -e atribui um valor a uma variável de ambiente. -e PORT=$PORT está propagando a variável PORT do sistema local para o contêiner com o mesmo nome de variável.
    • A sinalização -p publica o contêiner como um serviço disponível no localhost na porta 9000. Solicitações para localhost:9000 serão roteadas para o contêiner na porta 8080. Isso significa que a saída do serviço sobre o número da porta em uso não corresponde à forma como o serviço é acessado.
    • O argumento final gcr.io/PROJECT_ID/hello-service é um caminho do repositório que aponta para a versão mais recente da imagem do contêiner. Se não estiver disponível localmente, o docker tentará recuperar a imagem de um registro remoto.

    No navegador, abra http://localhost:9000. Verifique se há mensagens de erro na saída do terminal que correspondem às mensagens do pacote de operações do Google Cloud.

    Se o problema não puder ser reproduzido localmente, ele pode ser exclusivo para o Cloud Run for Anthos no ambiente do Google Cloud. Consulte o guia de solução de problemas do Cloud Run for Anthos no Google Cloud para conhecer as áreas específicas de investigação.

    Nesse caso, o erro é reproduzido localmente.

Agora que o erro foi confirmado duplamente como persistente e causado pelo código de serviço em vez da plataforma de hospedagem, é hora de investigar o código mais de perto.

Para os fins deste tutorial, é seguro presumir que o código dentro do contêiner e o código no sistema local sejam idênticos.

Node.js

Encontre a origem da mensagem de erro no arquivo index.js ao redor do número de linha chamado no rastreamento de pilha mostrado nos registros:
const {NAME} = process.env;
if (!NAME) {
  // Plain error logs do not appear in Stackdriver Error Reporting.
  console.error('Environment validation failed.');
  console.error(new Error('Missing required server parameter'));
  return res.status(500).send('Internal Server Error');
}

Python

Encontre a origem da mensagem de erro no arquivo main.py ao redor do número de linha chamado no rastreamento de pilha mostrado nos registros:
NAME = os.getenv("NAME")

if not NAME:
    print("Environment validation failed.")
    raise Exception("Missing required service parameter.")

Go

Encontre a origem da mensagem de erro no arquivo main.go ao redor do número de linha chamado no rastreamento de pilha mostrado nos registros:

name := os.Getenv("NAME")
if name == "" {
	log.Printf("Missing required server parameter")
	// The panic stack trace appears in Cloud Error Reporting.
	panic("Missing required server parameter")
}

Java

Encontre a origem da mensagem de erro no arquivo App.java ao redor do número de linha chamado no rastreamento de pilha mostrado nos registros:

String name = System.getenv("NAME");
if (name == null) {
  // Standard error logs do not appear in Stackdriver Error Reporting.
  System.err.println("Environment validation failed.");
  String msg = "Missing required server parameter";
  logger.error(msg, new Exception(msg));
  res.status(500);
  return "Internal Server Error";
}

Ao examinar esse código, as seguintes ações são realizadas quando a variável de ambiente NAME não está definida:

  • Um erro é registrado no pacote de operações do Google Cloud
  • Uma resposta de erro HTTP é enviada

O problema é causado por uma variável ausente, mas a causa raiz é mais específica: a alteração de código que adiciona a dependência de uma variável de ambiente não inclui alterações relacionadas aos scripts de implantação e documentação de requisitos de ambiente de execução.

Como corrigir a causa raiz

Agora que coletamos o código e identificamos a possível causa raiz, podemos tomar medidas para corrigi-lo.

  • Verifique se o serviço funciona localmente com o ambiente NAME disponível no local:

    1. Execute o contêiner localmente com a variável de ambiente adicionada:

      PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \
       -e NAME="Local World!" \
       gcr.io/PROJECT_ID/hello-service
    2. Navegue para http://localhost:9000.

    3. Consulte "Hello Local World!" que aparece na página.

  • Modifique o ambiente de serviço em execução no Cloud Run para Anthos no Google Cloud para incluir essa variável:

    1. Execute o comando de atualização de serviços com o parâmetro --update-env-vars para adicionar uma variável de ambiente:

      gcloud kuberun core services update hello-service \
        --update-env-vars NAME=Override
      
    2. Aguarde alguns segundos enquanto o Cloud Run para Anthos no Google Cloud cria uma nova revisão com base na revisão anterior com a nova variável de ambiente adicionada.

  • Confirme se o serviço foi corrigido:

    1. Navegue até o URL do serviço do Cloud Run para Anthos no Google Cloud.
    2. Consulte "Hello Override!" que aparece na página.
    3. Verifique se são exibidas mensagens ou erros inesperados no Cloud Logging.

Como melhorar a velocidade das futuras soluções de problemas

Neste exemplo de problema de produção, o erro estava relacionado à configuração operacional. Há alterações de código que minimizam o impacto desse problema no futuro.

  • Melhore o registro de erros para incluir detalhes mais específicos.
  • Em vez de retornar um erro, faça com que o serviço retorne a um padrão seguro. Se o uso de um padrão representar uma alteração na funcionalidade normal, use uma mensagem de aviso para fins de monitoramento.

Vamos remover a variável de ambiente NAME como uma dependência forçada.

  1. Remova o código de manipulação NAME atual:

    Node.js

    const {NAME} = process.env;
    if (!NAME) {
      // Plain error logs do not appear in Stackdriver Error Reporting.
      console.error('Environment validation failed.');
      console.error(new Error('Missing required server parameter'));
      return res.status(500).send('Internal Server Error');
    }

    Python

    NAME = os.getenv("NAME")
    
    if not NAME:
        print("Environment validation failed.")
        raise Exception("Missing required service parameter.")

    Go

    name := os.Getenv("NAME")
    if name == "" {
    	log.Printf("Missing required server parameter")
    	// The panic stack trace appears in Cloud Error Reporting.
    	panic("Missing required server parameter")
    }

    Java

    String name = System.getenv("NAME");
    if (name == null) {
      // Standard error logs do not appear in Stackdriver Error Reporting.
      System.err.println("Environment validation failed.");
      String msg = "Missing required server parameter";
      logger.error(msg, new Exception(msg));
      res.status(500);
      return "Internal Server Error";
    }

  2. Adicione o novo código que define um valor substituto:

    Node.js

    const NAME = process.env.NAME || 'World';
    if (!process.env.NAME) {
      console.log(
        JSON.stringify({
          severity: 'WARNING',
          message: `NAME not set, default to '${NAME}'`,
        })
      );
    }

    Python

    NAME = os.getenv("NAME")
    
    if not NAME:
        NAME = "World"
        error_message = {
            "severity": "WARNING",
            "message": f"NAME not set, default to {NAME}",
        }
        print(json.dumps(error_message))

    Go

    name := os.Getenv("NAME")
    if name == "" {
    	name = "World"
    	log.Printf("warning: NAME not set, default to %s", name)
    }

    Java

    String name = System.getenv().getOrDefault("NAME", "World");
    if (System.getenv("NAME") == null) {
      logger.warn(String.format("NAME not set, default to %s", name));
    }

  3. Teste localmente recriando e executando o contêiner por meio dos casos de configuração afetados:

    Node.js

    docker build --tag gcr.io/PROJECT_ID/hello-service .

    Python

    docker build --tag gcr.io/PROJECT_ID/hello-service .

    Go

    docker build --tag gcr.io/PROJECT_ID/hello-service .

    Java

    mvn compile jib:build

    Confirme se a variável de ambiente NAME ainda funciona:

    PORT=8080 && docker run --rm -e $PORT -p 9000:$PORT \
     -e NAME="Robust World" \
     gcr.io/PROJECT_ID/hello-service

    Confirme se o serviço funciona sem a variável NAME:

    PORT=8080 && docker run --rm -e $PORT -p 9000:$PORT \
     gcr.io/PROJECT_ID/hello-service

    Se o serviço não retornar um resultado, confirme a remoção do código na primeira etapa que não removeu linhas extras, como aquelas usadas para gravar a resposta.

  4. Implemente esse recurso revisitando a seção Implantar seu código.

    Cada implantação em um serviço cria uma nova revisão e inicia automaticamente o tráfego de serviço quando estiver pronto.

    Para limpar as variáveis de ambiente definidas anteriormente:

    gcloud kuberun core services update hello-service --clear-env-vars

Adicione a nova funcionalidade do valor padrão à cobertura de teste automatizada do serviço.

Como encontrar outros problemas nos registros

Talvez você veja outros problemas no Visualizador de registros deste serviço. Por exemplo, uma chamada de sistema incompatível aparecerá nos registros como uma "Limitação do sandbox de contêiner".

Por exemplo, os serviços do Node.js às vezes resultam nesta mensagem de registro:

Container Sandbox Limitation: Unsupported syscall statx(0xffffff9c,0x3e1ba8e86d88,0x0,0xfff,0x3e1ba8e86970,0x3e1ba8e86a90). Please, refer to https://gvisor.dev/c/linux/amd64/statx for more information.

Nesse caso, a falta de suporte não afeta o serviço de amostra hello-service.

Limpeza

Se você criou um novo projeto para este tutorial, exclua o projeto. Se você usou um projeto atual e quer mantê-lo sem as alterações incluídas neste tutorial, exclua os recursos criados para o tutorial.

Como excluir o projeto

O jeito mais fácil de evitar cobranças é excluindo o projeto que você criou para o tutorial.

Para excluir o projeto:

  1. No Console do 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.

Como excluir recursos do tutorial

  1. Exclua o serviço do Cloud Run para Anthos no Google Cloud que você implantou neste tutorial:

    gcloud kuberun core services delete SERVICE-NAME

    SERVICE-NAME é o nome escolhido do serviço.

    Também é possível excluir o Cloud Run para Anthos nos serviços do Google Cloud no Console do Google Cloud.

  2. Remova as configurações padrão da gcloud que você adicionou durante a configuração do tutorial:

     gcloud config unset kuberun/cluster
     gcloud config unset kuberun/cluster_location
    
  3. Remova a configuração do projeto:

     gcloud config unset project
    
  4. Exclua outros recursos do Google Cloud criados neste tutorial:

A seguir

  • Saiba mais sobre como usar o Cloud Logging para ter insights sobre o comportamento de produção.
  • Para mais informações sobre o Cloud Run for Anthos no Google Cloud, consulte [/kuberun/docs/troubleshooting#sandbox).
  • Teste outros recursos do Google Cloud. Veja nossos tutoriais.