Guia de início rápido: compilar e implantar

Nesta página, mostramos como criar um aplicativo Hello World simples, empacotá-lo em uma imagem de contêiner, carregar a imagem do contêiner no Container Registry e, em seguida, implantar a imagem do contêiner no Cloud Run. O exemplo é mostrado em várias linguagens, mas é possível usar outras além das mostradas.

Também é possível seguir este guia de início rápido com uma conta de demonstração no Qwiklabs.

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. Instale e inicialize o SDK do Cloud..

Como gravar o aplicativo de amostra

Para instruções sobre como criar um exemplo do aplicativo hello world que é executado no Cloud Run, clique na guia da sua linguagem:

Go

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

    mkdir helloworld
    cd helloworld
    
  2. Inicialize um arquivo go.mod para declarar o módulo go (em inglês):

    module github.com/GoogleCloudPlatform/golang-samples/run/helloworld
    
    go 1.13
    
  3. Crie um novo arquivo chamado main.go e cole o código a seguir nele:

    
    // Sample run-helloworld is a minimal Cloud Run service.
    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"os"
    )
    
    func main() {
    	log.Print("starting server...")
    	http.HandleFunc("/", handler)
    
    	// Determine port for HTTP service.
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    		log.Printf("defaulting to port %s", port)
    	}
    
    	// Start HTTP server.
    	log.Printf("listening on port %s", port)
    	if err := http.ListenAndServe(":"+port, nil); err != nil {
    		log.Fatal(err)
    	}
    }
    
    func handler(w http.ResponseWriter, r *http.Request) {
    	name := os.Getenv("NAME")
    	if name == "" {
    		name = "World"
    	}
    	fmt.Fprintf(w, "Hello %s!\n", name)
    }
    

    Esse código cria um servidor da Web básico que realiza detecções na porta definida pela variável de ambiente PORT.

O app está concluído, pronto para ficar em contêiner e ser enviado ao Container Registry.

Node.js

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

    mkdir helloworld
    cd helloworld
    
  2. Crie um arquivo package.json com os seguintes conteúdos:

    {
      "name": "helloworld",
      "description": "Simple hello world sample in Node",
      "version": "1.0.0",
      "private": true,
      "main": "index.js",
      "scripts": {
        "start": "node index.js",
        "test": "mocha test/index.test.js --exit",
        "system-test": "NAME=Cloud test/runner.sh mocha test/system.test.js --timeout=30000",
        "lint": "eslint '**/*.js'",
        "fix": "eslint --fix '**/*.js'"
      },
      "engines": {
        "node": ">= 12.0.0"
      },
      "author": "Google LLC",
      "license": "Apache-2.0",
      "dependencies": {
        "express": "^4.17.1"
      },
      "devDependencies": {
        "got": "^11.0.0",
        "mocha": "^8.0.0",
        "supertest": "^6.0.0"
      }
    }
    
  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) => {
      const name = process.env.NAME || 'World';
      res.send(`Hello ${name}!`);
    });
    
    const port = process.env.PORT || 8080;
    app.listen(port, () => {
      console.log(`helloworld: listening on port ${port}`);
    });

    Esse código cria um servidor da Web básico que realiza detecções na porta definida pela variável de ambiente PORT.

O app está concluído, pronto para ficar em contêiner e ser enviado ao Container Registry.

Python

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

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

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

    Esse código responde às solicitações com a saudação "Hello World". A manipulação de HTTP é feita por um servidor da Web Gunicorn no contêiner. Quando invocado diretamente para uso local, este código cria um servidor da Web básico que atende na porta definida pela variável de ambiente PORT.

O app está concluído, pronto para ficar em contêiner e ser enviado ao Container Registry.

Java

Crie um aplicativo Spring Boot.

  1. No console, crie um novo projeto da Web vazio usando os comandos cURL e descompactar:

    curl https://start.spring.io/starter.zip \
        -d dependencies=web \
        -d javaVersion=1.8 \
        -d bootVersion=2.3.3.RELEASE \
        -d name=helloworld \
        -d artifactId=helloworld \
        -d baseDir=helloworld \
        -o helloworld.zip
    unzip helloworld.zip
    cd helloworld
    

    Isso cria um projeto Spring Boot.

    Para usar o comando cURL acima no Microscoft Windows, você precisará de uma das linhas de comando a seguir ou terá que usar o Spring Initializr (configuração pré-carregada, link em inglês) para gerar o projeto:

  2. Atualize a classe HelloworldApplication em src/main/java/com/example/helloworld/HelloworldApplication.java ao adicionar um @RestController para processar o mapeamento / e adicione também um campo @Value para fornecer a variável de ambiente NAME:

    
    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("${NAME:World}")
      String name;
    
      @RestController
      class HelloworldController {
        @GetMapping("/")
        String hello() {
          return "Hello " + name + "!";
        }
      }
    
      public static void main(String[] args) {
        SpringApplication.run(HelloworldApplication.class, args);
      }
    }
  3. Configure a porta do servidor para ser definida pela variável de ambiente PORT em application.properties:

    server.port=${PORT:8080}

Esse código cria um servidor da Web básico que realiza detecções na porta definida pela variável de ambiente PORT.

O app está concluído, pronto para ficar em contêiner e ser enviado ao Container Registry.

Para implantar o Java no Cloud Run com outros frameworks, revise as amostras Knative para Spark e Vert.x.

C#

  1. Instale o SDK do .NET Core 3.1. Observe que precisamos fazer isso para criar o novo projeto da Web apenas na próxima etapa: o Dockerfile, descrito posteriormente, carregará todas as dependências no contêiner.

  2. No console, crie um novo projeto da Web vazio usando o comando dotnet:

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

  4. Atualize a definição de CreateHostBuilder em Program.cs para detectar a porta definida pela variável de ambiente PORT:

    using System;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Hosting;
    
    namespace helloworld_csharp
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateHostBuilder(args).Build().Run();
            }
    
            public static IHostBuilder CreateHostBuilder(string[] args)
            {
                string port = Environment.GetEnvironmentVariable("PORT") ?? "8080";
                string url = String.Concat("http://0.0.0.0:", port);
    
                return Host.CreateDefaultBuilder(args)
                    .ConfigureWebHostDefaults(webBuilder =>
                    {
                        webBuilder.UseStartup<Startup>().UseUrls(url);
                    });
            }
        }
    }

    Esse código cria um servidor da Web básico que realiza detecções na porta definida pela variável de ambiente PORT.

  5. Crie um arquivo chamado Startup.cs e cole o seguinte código nele:

    using System;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    
    namespace helloworld_csharp
    {
        public class Startup
        {
            // This method gets called by the runtime. Use this method to add services to the container.
            // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
            public void ConfigureServices(IServiceCollection services)
            {
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app.UseRouting();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapGet("/", async context =>
                    {
                        var target = Environment.GetEnvironmentVariable("TARGET") ?? "World";
                        await context.Response.WriteAsync($"Hello {target}!\n");
                    });
                });
            }
        }
    }

    Esse código responde às solicitações com a saudação "Hello World".

O app está concluído, pronto para ficar em contêiner e ser enviado ao Container Registry.

C++

  1. Crie um novo diretório com o nome helloworld-cpp e altere o diretório para ele:

    mkdir helloworld-cpp
    cd helloworld-cpp
    
  2. Crie um novo arquivo chamado CMakeLists.txt e cole o código a seguir nele:

    cmake_minimum_required(VERSION 3.10)
    
    # Define the project name and where to report bugs.
    set(PACKAGE_BUGREPORT "https://github.com/GoogleCloudPlatform/cpp-samples/issues")
    project(Docker-Run-C++ CXX C)
    
    # Configure the Compiler options, we will be using C++17 features.
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    
    find_package(Boost 1.66 REQUIRED COMPONENTS program_options)
    find_package(Threads)
    
    # When using static libraries the FindgRPC.cmake module does not define the
    # correct dependencies (OpenSSL::Crypto, c-cares, etc) for gRPC::grpc.
    # Explicitly listing these dependencies avoids the undefined symbols problems.
    add_executable(cloud_run_hello cloud_run_hello.cc)
    target_link_libraries(cloud_run_hello PRIVATE Boost::headers
                                                  Boost::program_options
        Threads::Threads)
    
    include(GNUInstallDirs)
    install(TARGETS cloud_run_hello RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
  3. Crie um novo arquivo chamado cloud_run_hello.cpp e cole o código a seguir nele:

    #include <boost/asio/ip/tcp.hpp>
    #include <boost/asio/strand.hpp>
    #include <boost/beast/core.hpp>
    #include <boost/beast/http.hpp>
    #include <boost/beast/version.hpp>
    #include <boost/program_options.hpp>
    #include <cstdlib>
    #include <iostream>
    #include <optional>
    #include <thread>
    
    namespace be = boost::beast;
    namespace asio = boost::asio;
    namespace po = boost::program_options;
    using tcp = boost::asio::ip::tcp;
    
    po::variables_map parse_args(int& argc, char* argv[]) {
      // Initialize the default port with the value from the "PORT" environment
      // variable or with 8080.
      auto port = [&]() -> std::uint16_t {
        auto env = std::getenv("PORT");
        if (env == nullptr) return 8080;
        auto value = std::stoi(env);
        if (value < std::numeric_limits<std::uint16_t>::min() ||
            value > std::numeric_limits<std::uint16_t>::max()) {
          std::ostringstream os;
          os << "The PORT environment variable value (" << value
             << ") is out of range.";
          throw std::invalid_argument(std::move(os).str());
        }
        return static_cast<std::uint16_t>(value);
      }();
    
      // Parse the command-line options.
      po::options_description desc("Server configuration");
      desc.add_options()
          //
          ("help", "produce help message")
          //
          ("address", po::value<std::string>()->default_value("0.0.0.0"),
           "set listening address")
          //
          ("port", po::value<std::uint16_t>()->default_value(port),
           "set listening port");
    
      po::variables_map vm;
      po::store(po::parse_command_line(argc, argv, desc), vm);
      po::notify(vm);
      if (vm.count("help")) {
        std::cout << desc << "\n";
      }
      return vm;
    }
    
    int main(int argc, char* argv[]) try {
      po::variables_map vm = parse_args(argc, argv);
    
      if (vm.count("help")) return 0;
    
      auto address = asio::ip::make_address(vm["address"].as<std::string>());
      auto port = vm["port"].as<std::uint16_t>();
      std::cout << "Listening on " << address << ":" << port << std::endl;
    
      auto handle_session = [](tcp::socket socket) {
        auto report_error = [](be::error_code ec, char const* what) {
          std::cerr << what << ": " << ec.message() << "\n";
        };
    
        be::error_code ec;
        for (;;) {
          be::flat_buffer buffer;
    
          // Read a request
          be::http::request<be::http::string_body> request;
          be::http::read(socket, buffer, request, ec);
          if (ec == be::http::error::end_of_stream) break;
          if (ec) return report_error(ec, "read");
    
          // Send the response
          // Respond to any request with a "Hello World" message.
          be::http::response<be::http::string_body> response{be::http::status::ok,
                                                             request.version()};
          response.set(be::http::field::server, BOOST_BEAST_VERSION_STRING);
          response.set(be::http::field::content_type, "text/plain");
          response.keep_alive(request.keep_alive());
          std::string greeting = "Hello ";
          auto const* target = std::getenv("TARGET");
          greeting += target == nullptr ? "World" : target;
          greeting += "\n";
          response.body() = std::move(greeting);
          response.prepare_payload();
          be::http::write(socket, response, ec);
          if (ec) return report_error(ec, "write");
        }
        socket.shutdown(tcp::socket::shutdown_send, ec);
      };
    
      asio::io_context ioc{/*concurrency_hint=*/1};
      tcp::acceptor acceptor{ioc, {address, port}};
      for (;;) {
        auto socket = acceptor.accept(ioc);
        if (!socket.is_open()) break;
        // Run a thread per-session, transferring ownership of the socket
        std::thread{handle_session, std::move(socket)}.detach();
      }
    
      return 0;
    } catch (std::exception const& ex) {
      std::cerr << "Standard exception caught " << ex.what() << '\n';
      return 1;
    }

    Esse código cria um servidor da Web básico que realiza detecções na porta definida pela variável de ambiente PORT.

O app está concluído, pronto para ficar em contêiner e ser enviado ao Container Registry.

PHP

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

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

    
    $name = getenv('NAME', true) ?: 'World';
    echo sprintf('Hello %s!', $name);
    

    Esse código responde às solicitações com a saudação "Hello World". O processamento de HTTP é feito por um servidor da Web Apache no contêiner.

O app está concluído, pronto para ficar em contêiner e ser enviado ao Container Registry.

Ruby

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

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

    require "sinatra"
    
    set :bind, "0.0.0.0"
    port = ENV["PORT"] || "8080"
    set :port, port
    
    get "/" do
      name = ENV["NAME"] || "World"
      "Hello #{name}!"
    end

    Esse código cria um servidor da Web básico que realiza detecções na porta definida pela variável de ambiente PORT.

  3. Crie um nome de arquivo Gemfile e copie o seguinte nele:

    source "https://rubygems.org"
    
    gem "sinatra", "~>2.0"
    
    group :test do
      gem "rack-test"
      gem "rest-client"
      gem "rspec"
      gem "rspec_junit_formatter"
      gem "rubysl-securerandom"
    end
    
  4. Se você não tiver o Bundler 2.0 ou superior instalado, instale o Bundler.

  5. Gere um arquivo Gemfile.lock executando:

    bundle install

O app está concluído, pronto para ficar em contêiner e ser enviado ao Container Registry.

Shell

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

    mkdir helloworld-shell
    cd helloworld-shell
    
  2. Crie um arquivo script.sh com os seguintes conteúdos:

    
    set -e
    echo "Hello ${NAME:-World}!"
    

    Para executar esse script de shell em todas as solicitações recebidas, esse exemplo usa um pequeno programa Go que inicia um servidor da Web básico e realiza detecções na porta definida pela variável de ambiente PORT.

  3. Crie um arquivo invoke.go com os seguintes conteúdos:

    
    // Sample helloworld-shell is a Cloud Run shell-script-as-a-service.
    package main
    
    import (
    	"log"
    	"net/http"
    	"os"
    	"os/exec"
    )
    
    func main() {
    	http.HandleFunc("/", scriptHandler)
    
    	// Determine port for HTTP service.
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    		log.Printf("Defaulting to port %s", port)
    	}
    
    	// Start HTTP server.
    	log.Printf("Listening on port %s", port)
    	if err := http.ListenAndServe(":"+port, nil); err != nil {
    		log.Fatal(err)
    	}
    }
    
    func scriptHandler(w http.ResponseWriter, r *http.Request) {
    	cmd := exec.CommandContext(r.Context(), "/bin/sh", "script.sh")
    	cmd.Stderr = os.Stderr
    	out, err := cmd.Output()
    	if err != nil {
    		w.WriteHeader(500)
    	}
    	w.Write(out)
    }
    

O app está concluído, pronto para ficar em contêiner e ser enviado ao Container Registry.

Outra

O Cloud Run é compatível com a maioria das linguagens. Para amostras simples em linguagens diferentes das que aparecem nesta tabela, consulte estes links (em inglês):

No entanto, em todas essas amostras, ignore e omita o material sobre service.yaml e o Docker Hub porque o Cloud Run não utiliza isso.

Como colocar um aplicativo em contêiner e enviá-lo ao Container Registry

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 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 /app/server

# Run the web service on container startup.
CMD ["/app/server"]

Adicione um arquivo .dockerignore para excluir arquivos da imagem do contêiner.

# The .dockerignore file excludes files from the container build process.
#
# https://docs.docker.com/engine/reference/builder/#dockerignore-file

# Exclude locally vendored dependencies.
vendor/

# Exclude "build-time" ignore files.
.dockerignore
.gcloudignore

# Exclude git history and configuration.
.gitignore

Node.js


# Use the official lightweight Node.js 12 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 [ "node", "index.js" ]

Adicione um arquivo .dockerignore para excluir arquivos da imagem do contêiner.

Dockerfile
.dockerignore
node_modules
npm-debug.log

Python

O Dockerfile do Python inicia um servidor da Web do Gunicorn que detecta na porta definida pela variável de ambiente PORT:


# Use the official lightweight Python image.
# https://hub.docker.com/_/python
FROM python:3.9-slim

# Allow statements and log messages to immediately appear in the Knative logs
ENV PYTHONUNBUFFERED True

# 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 --timeout 0 main:app

Adicione um arquivo .dockerignore para excluir arquivos da imagem do contêiner.

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

Java


# Use the official maven/Java 8 image to create a build artifact.
# https://hub.docker.com/_/maven
FROM maven:3.6-jdk-11 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/openjdk11: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", "-jar", "/helloworld.jar"]

Adicione um arquivo .dockerignore para excluir arquivos da imagem do contêiner.

Dockerfile
.dockerignore
target/

C#

# Use Microsoft's official build .NET image.
# https://hub.docker.com/_/microsoft-dotnet-core-sdk/
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-alpine 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 . ./
WORKDIR /app

# Build a release artifact.
RUN dotnet publish -c Release -o out

# Use Microsoft's official runtime .NET image.
# https://hub.docker.com/_/microsoft-dotnet-core-aspnet/
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-alpine AS runtime
WORKDIR /app
COPY --from=build /app/out ./

# Run the web service on container startup.
ENTRYPOINT ["dotnet", "helloworld-csharp.dll"]

Para excluir arquivos produzidos por meio de operações de compilação dotnet locais do upload para o Cloud Build, adicione um arquivo .gcloudignore ao mesmo diretório dos arquivos de origem do app de amostra:

# The .gcloudignore file excludes file from upload to Cloud Build.
# If this file is deleted, gcloud will default to .gitignore.
#
# https://cloud.google.com/cloud-build/docs/speeding-up-builds#gcloudignore
# https://cloud.google.com/sdk/gcloud/reference/topic/gcloudignore

**/obj/
**/bin/

# Exclude git history and configuration.
.git/
.gitignore

Se essas linhas estiverem em um arquivo .gitignore, pule esta etapa porque .gitignore é uma fonte padrão para a configuração .gcloudignore.

Copie essas linhas para um arquivo .dockerignore para builds de contêiner locais com a CLI docker.

C++

O Dockerfile C++ inicia o aplicativo ao detectar na porta definida pela variável de ambiente PORT:

# We chose Alpine to build the image because it has good support for creating
# statically-linked, small programs.
ARG DISTRO_VERSION=edge
FROM alpine:${DISTRO_VERSION} AS base

# Create separate targets for each phase, this allows us to cache intermediate
# stages when using Google Cloud Build, and makes the final deployment stage
# small as it contains only what is needed.
FROM base AS devtools

# Install the typical development tools and some additions:
#   - ninja-build is a backend for CMake that often compiles faster than
#     CMake with GNU Make.
#   - Install the boost libraries.
RUN apk update && \
    apk add \
        boost-dev \
        boost-static \
        build-base \
        cmake \
        git \
        gcc \
        g++ \
        libc-dev \
        nghttp2-static \
        ninja \
        openssl-dev \
        openssl-libs-static \
        tar \
        zlib-static

# Copy the source code to /v/source and compile it.
FROM devtools AS build
COPY . /v/source
WORKDIR /v/source

# Run the CMake configuration step, setting the options to create
# a statically linked C++ program
RUN cmake -S/v/source -B/v/binary -GNinja \
    -DCMAKE_BUILD_TYPE=Release \
    -DBoost_USE_STATIC_LIBS=ON \
    -DCMAKE_EXE_LINKER_FLAGS=-static

# Compile the binary and strip it to reduce its size.
RUN cmake --build /v/binary
RUN strip /v/binary/cloud_run_hello

# Create the final deployment image, using `scratch` (the empty Docker image)
# as the starting point. Effectively we create an image that only contains
# our program.
FROM scratch AS cloud-run-hello
WORKDIR /r

# Copy the program from the previously created stage and make it the entry point.
COPY --from=build /v/binary/cloud_run_hello /r

ENTRYPOINT [ "/r/cloud_run_hello" ]

PHP

O Dockerfile do PHP inicia um servidor da Web Apache que detecta na porta definida pela variável de ambiente PORT:


# Use the official PHP image.
# https://hub.docker.com/_/php
FROM php:7.4-apache

# Configure PHP for Cloud Run.
# Precompile PHP code with opcache.
RUN docker-php-ext-install -j "$(nproc)" opcache
RUN set -ex; \
  { \
    echo "; Cloud Run enforces memory & timeouts"; \
    echo "memory_limit = -1"; \
    echo "max_execution_time = 0"; \
    echo "; File upload at Cloud Run network limit"; \
    echo "upload_max_filesize = 32M"; \
    echo "post_max_size = 32M"; \
    echo "; Configure Opcache for Containers"; \
    echo "opcache.enable = On"; \
    echo "opcache.validate_timestamps = Off"; \
    echo "; Configure Opcache Memory (Application-specific)"; \
    echo "opcache.memory_consumption = 32"; \
  } > "$PHP_INI_DIR/conf.d/cloud-run.ini"

# Copy in custom code from the host machine.
WORKDIR /var/www/html
COPY . ./

# Use the PORT environment variable in Apache configuration files.
# https://cloud.google.com/run/docs/reference/container-contract#port
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://github.com/docker-library/docs/blob/master/php/README.md#configuration
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

Adicione um arquivo .dockerignore para excluir arquivos da imagem do contêiner.

# The .dockerignore file excludes files from the container build process.
#
# https://docs.docker.com/engine/reference/builder/#dockerignore-file

# Exclude locally vendored dependencies.
vendor/

# Exclude "build-time" ignore files.
.dockerignore
.gcloudignore

# Exclude git history and configuration.
.gitignore

Ruby


# Use the official lightweight Ruby image.
# https://hub.docker.com/_/ruby
FROM ruby:2.7-slim

# Install production dependencies.
WORKDIR /usr/src/app
COPY Gemfile Gemfile.lock ./
ENV BUNDLE_FROZEN=true
RUN gem install bundler && bundle install --without test

# Copy local code to the container image.
COPY . ./

# Run the web service on container startup.
CMD ["ruby", "./app.rb"]

Adicione um arquivo .dockerignore para excluir arquivos da imagem do contêiner.

Dockerfile
README.md
.ruby-version
.bundle/
vendor/

Shell


# 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.14-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 invoke.go ./

# 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 \
    --no-install-recommends \
    ca-certificates && \
    rm -rf /var/lib/apt/lists/*

# Copy the binary to the production image from the builder stage.
COPY --from=builder /app/server /app/server
COPY script.sh ./

# Run the web service on container startup.
CMD ["/app/server"]

Outra

O Cloud Run é compatível com a maioria das linguagens. Para amostras do Dockerfiles em linguagens diferentes das que aparecem na tabela, consulte estes links (em inglês):

No entanto, nessas amostras, ignore e omita o material sobre service.yaml e o Docker Hub porque o Cloud Run não os usa.

Compile a imagem de contêiner usando o Cloud Build. Para isso, execute o comando a seguir no diretório que contém seu Dockerfile:

gcloud builds submit --tag gcr.io/PROJECT-ID/helloworld

em que PROJECT-ID é o ID do projeto do GCP. É possível consegui-lo executando gcloud config get-value project.

Após a conclusão, você verá uma mensagem de "SUCESSO" contendo o nome da imagem (gcr.io/PROJECT-ID/helloworld). A imagem é armazenada no Container Registry e pode ser reutilizada, se você quiser.

Como implantar no Cloud Run

Para implantar a imagem do contêiner, siga estas etapas:

  1. Implante usando o comando a seguir:

    gcloud run deploy --image gcr.io/PROJECT-ID/helloworld --platform managed

    Substitua PROJECT-ID pelo ID do projeto do GCP. Para ver o ID do projeto, execute o comando gcloud config get-value project.

    1. O nome do serviço será solicitado: pressione Enter para aceitar o nome padrão, helloworld.
    2. Você receberá uma solicitação de região: selecione a região de sua escolha, por exemplo, us-central1.
    3. Você receberá uma solicitação para permitir chamadas não autenticadas: responda y.

    Aguarde alguns instantes até a conclusão da implantação. Em caso de sucesso, a linha de comando exibe o URL de serviço.

  2. Consulte o contêiner implantado. Para isso, abra o URL de serviço em um navegador da Web.

Locais do Cloud Run

O Cloud Run é regional, o que significa que a infraestrutura que executa seus serviços do Cloud Run está localizada em uma região específica e é gerenciada pelo Google para estar disponível de maneira redundante em todas as zonas da região.

Atender aos seus requisitos de latência, disponibilidade ou durabilidade são os principais fatores para selecionar a região em que seus serviços do Cloud Run são executados. Geralmente, é possível selecionar a região mais próxima de seus usuários, mas considere a localização dos outros produtos do Google Cloud usados pelo serviço do Cloud Run. O uso de produtos do Google Cloud em vários locais pode afetar a latência e o custo do serviço.

O Cloud Run está disponível nas regiões a seguir:

Sujeitas aos preços do nível 1

  • asia-east1 (Taiwan)
  • asia-northeast1 (Tóquio)
  • asia-northeast2 (Osaka)
  • europe-north1 (Finlândia)
  • europe-west1 (Bélgica)
  • europe-west4 (Países Baixos)
  • us-central1 (Iowa)
  • us-east1 (Carolina do Sul)
  • us-east4 (Norte da Virgínia)
  • us-west1 (Oregon)

Sujeitas aos preços do nível 2

  • asia-east2 (Hong Kong)
  • asia-northeast3 (Seul, Coreia do Sul)
  • asia-southeast1 (Singapura)
  • asia-southeast2 (Jacarta)
  • asia-south1 (Mumbai, Índia)
  • australia-southeast1 (Sydney)
  • europe-west2 (Londres, Reino Unido)
  • europe-west3 (Frankfurt, Alemanha)
  • europe-west6 (Zurique, Suíça)
  • northamerica-northeast1 (Montreal)
  • southamerica-east1 (São Paulo, Brasil)

Se você já criou um serviço do Cloud Run, poderá ver a região no painel do Cloud Run no Console do Cloud.

Parabéns! Você acabou de implantar um aplicativo empacotado em uma imagem de contêiner no Cloud Run. O Cloud Run escalona de maneira automática e horizontal a imagem de contêiner para processar as solicitações recebidas e reduz o escalonamento quando a demanda diminui. Você paga apenas pela CPU, memória e rede consumidas durante o processamento da solicitação.

Limpar

Como remover seu projeto de teste

Ainda que o Cloud Run não gere custos quando o serviço não estiver em uso, é possível receber cobranças pelo armazenamento da imagem do contêiner no Container Registry. É possível excluir sua imagem ou excluir seu projeto do Cloud para evitar cobranças. A exclusão do projeto do Cloud interrompe o faturamento de todos os recursos usados nesse projeto.

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

    Acessar a página "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.

A seguir

Para mais informações sobre como compilar um contêiner da origem do código e enviar para o Container Registry, consulte estes tópicos: