快速入门:构建和部署

本页面介绍了如何创建简单的 Hello World 应用,将该应用打包到容器映像中,然后将该映像上传到 Container Registry 并部署到 Cloud Run。示例以多种语言提供,但请注意,除了所提供的语言以外,您还可以使用其他语言。

准备工作

  1. 登录您的 Google 帐号。

    如果您还没有 Google 帐号,请注册新帐号

  2. 选择或创建 Google Cloud Platform 项目。

    转到“管理资源”页面

  3. 确保您的 Google Cloud Platform 项目已启用结算功能。

    了解如何启用结算功能

  4. 启用 Cloud Run API
  5. 安装并初始化 Cloud SDK。
  6. 安装 gcloud beta 组件:
    gcloud components install beta
  7. 更新组件:
    gcloud components update

编写示例应用

如需了解如何创建在 Cloud Run 上运行的示例 hello world 应用,请点击与您的语言对应的标签页:

Go

  1. 创建一个名为 helloworld-go 的新目录,并将目录更改为此目录:

    mkdir helloworld-go
    cd helloworld-go
    
  2. 创建一个名为 helloworld.go 的新文件,并将以下代码粘贴到其中:

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"os"
    )
    
    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)
    }
    
    func main() {
    	log.Print("Hello world sample started.")
    
    	http.HandleFunc("/", handler)
    
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    	}
    
    	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
    }
    

    此代码会创建一个基本 Web 服务器,以侦听由 PORT 环境变量定义的端口。

您的应用已编写完毕,可以进行容器化并上传到 Container Registry。

Node.js

  1. 创建一个名为 helloworld-nodejs 的新目录,并将目录更改为此目录:

    mkdir helloworld-nodejs
    cd helloworld-nodejs
    
  2. 创建一个包含以下内容的 package.json 文件:

    {
      "name": "knative-serving-helloworld",
      "version": "1.0.0",
      "description": "Simple hello world sample in Node",
      "main": "index.js",
      "scripts": {
        "start": "node index.js"
      },
      "author": "",
      "license": "Apache-2.0",
      "dependencies": {
        "express": "^4.16.4"
      }
    }
    
  3. 在同一目录中,创建一个 index.js 文件,并将以下行复制到其中:

    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);
    });
    

    此代码会创建一个基本 Web 服务器,以侦听由 PORT 环境变量定义的端口。

您的应用已编写完毕,可以进行容器化并上传到 Container Registry。

Python

  1. 创建一个名为 helloworld-python 的新目录,并将目录更改为此目录:

    mkdir helloworld-python
    cd helloworld-python
    
  2. 创建一个名为 app.py 的文件,并将以下代码粘贴到其中:

    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)))
    

    此代码会创建一个基本 Web 服务器,以侦听由 PORT 环境变量定义的端口。

您的应用已编写完毕,可以进行容器化并上传到 Container Registry。

Java

创建一个 Spring Boot 应用。

  1. 安装 Java SE 8 或更高版本 JDKCURL。请注意,我们只需执行此操作,即可在下一步中创建新的网页项目。Dockerfile(稍后将进行介绍)会将所有依赖项加载到容器中。

  2. 在 Console 中,使用 cURL 和 unzip 命令新建一个空网页项目:

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

    上述命令将创建一个 Spring Boot 项目。

  3. 更新 src/main/java/com/example/helloworld/HelloworldApplication.java 中的 HelloworldApplication 类,方法是添加 @RestController 以处理 / 映射,并添加 @Value 字段以提供 TARGET 环境变量:

    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);
    	}
    }
    

    此代码会创建一个基本 Web 服务器,以侦听由 PORT 环境变量定义的端口。

您的应用已编写完毕,可以进行容器化并上传到 Container Registry。

要使用其他框架将 Java 部署到 Cloud Run,请查看 SparkVert.x 版 Knative 示例。

C#

  1. 安装 .NET Core SDK 2.2。请注意,我们只需执行此操作,即可在下一步中创建新的网页项目。Dockerfile(稍后将进行介绍)会将所有依赖项加载到容器中。

  2. 在 Console 中,使用 dotnet 命令新建一个空网页项目:

    dotnet new web -o helloworld-csharp
    
  3. 将目录更改为 helloworld-csharp

  4. 更新 Program.cs 中的 CreateWebHostBuilder 定义,方法是为 .UseUrls() 指定端口网址,以定义服务端口。示例中显示的端口是 8080,但您可以使用其他端口。您的服务器必须侦听您在此处指定的端口:

    using System;
    using Microsoft.AspNetCore;
    using Microsoft.AspNetCore.Hosting;
    
    namespace helloworld_csharp
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateWebHostBuilder(args).Build().Run();
            }
    
            public static IWebHostBuilder CreateWebHostBuilder(string[] args)
            {
                string port = Environment.GetEnvironmentVariable("PORT") ?? "8080";
                string url = String.Concat("http://0.0.0.0:", port);
    
                return WebHost.CreateDefaultBuilder(args)
                    .UseStartup<Startup>().UseUrls(url);
            }
        }
    }
    
  5. 更新 app.Run(...) 语句(包含在 Startup.cs 中),以读取并返回 TARGET 环境变量:

    using System;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.DependencyInjection;
    
    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, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app.Run(async (context) =>
                {
                    var target = Environment.GetEnvironmentVariable("TARGET") ?? "World";
                    await context.Response.WriteAsync($"Hello {target}\n");
                });
            }
        }
    }
    

    此代码会创建一个基本 Web 服务器,以侦听由 PORT 环境变量定义的端口。

您的应用已编写完毕,可以进行容器化并上传到 Container Registry。

PHP

  1. 创建一个名为 helloworld-php 的新目录,并将目录更改为此目录:

    mkdir helloworld-php
    cd helloworld-php
    
  2. 创建一个名为 index.php 的文件,并将以下代码粘贴到其中:

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

    此代码会创建一个基本 Web 服务器,以侦听由 PORT 环境变量定义的端口。

您的应用已编写完毕,可以进行容器化并上传到 Container Registry。

Ruby

  1. 创建一个名为 helloworld-ruby 的新目录,并将目录更改为此目录:

    mkdir helloworld-ruby
    cd helloworld-ruby
    
  2. 创建一个名为 app.rb 的文件,并将以下代码粘贴到其中:

    require 'sinatra'
    
    set :bind, '0.0.0.0'
    
    get '/' do
      target = ENV['TARGET'] || 'World'
      "Hello #{target}!\n"
    end
    

    此代码会创建一个基本 Web 服务器,以侦听由 PORT 环境变量定义的端口。

  3. 创建一个名为 Gemfile 的文件,并将以下内容复制到其中:

    source 'https://rubygems.org'
    
    gem 'sinatra'
    gem 'rack', '>= 2.0.6'
    
  4. 创建一个名为 Gemfile.lock 的文件,并将以下内容复制到其中:

    GEM
      remote: https://rubygems.org/
      specs:
        mustermann (1.0.2)
        rack (2.0.6)
        rack-protection (2.0.3)
          rack
        sinatra (2.0.3)
          mustermann (~> 1.0)
          rack (~> 2.0)
          rack-protection (= 2.0.3)
          tilt (~> 2.0)
        tilt (2.0.8)
    
    PLATFORMS
      ruby
    
    DEPENDENCIES
      rack (>= 2.0.6)
      sinatra
    
    BUNDLED WITH
       1.17.1
    

您的应用已编写完毕,可以进行容器化并上传到 Container Registry。

Shell

  1. 创建一个名为 helloworld-shell 的新目录,并将目录更改为此目录:

    mkdir helloworld-shell
    cd helloworld-shell
    
  2. 创建一个包含以下内容的 script.sh 文件:

    #!/bin/sh
    echo Hello ${TARGET:=World}
    
    

    为了对每个传入请求执行此 shell 脚本,本示例使用一个小型 Go 程序,该程序会启动一个基本 Web 服务器并侦听 PORT 环境变量所定义的端口。

  3. 创建一个包含以下内容的 invoke.go 文件:

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"os"
    	"os/exec"
    )
    
    func handler(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)
    }
    
    func main() {
    	http.HandleFunc("/", handler)
    
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    	}
    
    	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
    }
    

您的应用已编写完毕,可以进行容器化并上传到 Container Registry。

其他

Cloud Run 支持大多数语言。如需查看以此表中未显示的语言提供的简单示例,请参阅以下部分:

但在所有这些示例中,请忽略并省略有关 service.yaml 和 Docker Hub 的资料,因为 Cloud Run 不使用这些内容。

将应用容器化并将其上传到 Container Registry

要将示例应用容器化,请在与源文件相同的目录中创建一个名为 Dockerfile 的新文件,并复制以下内容:

Go

# Use the offical Golang 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.12 as builder

# Copy local code to the container image.
WORKDIR /go/src/github.com/knative/docs/helloworld
COPY . .

# Build the command inside the container.
# (You may fetch or manage dependencies here,
# either manually or with a tool like "godep".)
RUN CGO_ENABLED=0 GOOS=linux go build -v -o helloworld

# 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 alpine

# Copy the binary to the production image from the builder stage.
COPY --from=builder /go/src/github.com/knative/docs/helloworld/helloworld /helloworld

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

Node.js

# Use the official Node.js 10 image.
# https://hub.docker.com/_/node
FROM node:10

# 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 package*.json ./

# Install production dependencies.
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.7

# 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

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 .NET image.
# https://hub.docker.com/r/microsoft/dotnet
FROM microsoft/dotnet:2.2-sdk

# Install production dependencies.
# Copy csproj and restore as distinct layers.
WORKDIR /app
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.
CMD ["dotnet", "out/helloworld-csharp.dll"]

PHP

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

# Copy local code to the container image.
COPY index.php /var/www/html/

# Use the PORT environment variable 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"

Ruby

# Use the official Ruby image.
# https://hub.docker.com/_/ruby
FROM ruby:2.5

# Install production dependencies.
WORKDIR /usr/src/app
COPY Gemfile Gemfile.lock ./
ENV BUNDLE_FROZEN=true
RUN bundle install

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

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

Shell

FROM golang:1.11

WORKDIR /go/src/invoke

COPY invoke.go .
RUN go install -v

COPY . .

CMD ["invoke"]

其他

Cloud Run 支持大多数语言。如需查看以此表中未显示的语言提供的示例 Dockerfile,请参阅以下部分:

但在这些示例中,请忽略并省略有关 service.yaml 和 Docker Hub 的资料,因为 Cloud Run 不使用这些内容。

使用 Cloud Build 构建容器映像,方法是从包含 Dockerfile 的目录中运行以下命令:

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

其中 [PROJECT-ID] 是您的 GCP 项目 ID。运行 gcloud config get-value project 即可获取该 ID。

成功完成后,您将看到一条包含映像名称 (gcr.io/[PROJECT-ID]/helloworld) 的 SUCCESS 消息。该映像存储在 Container Registry 中,并可根据需要重复使用。

将容器映像部署到 Cloud Run

要部署容器映像,请执行以下操作:

  1. 使用以下命令进行部署:

    默认

    gcloud beta run deploy --image gcr.io/[PROJECT-ID]/helloworld
    

    Java

    gcloud beta run deploy --image gcr.io/[PROJECT-ID]/helloworld \
          --set-env-vars="JAVA_TOOL_OPTIONS=-XX:MaxRAM=256m"
    

    JAVA_TOOL_OPTIONS=-XX:MaxRAM=256m 环境变量赋值旨在解决已知 JVM 内存问题

    其中 [PROJECT-ID] 是您的 GCP 项目 ID。运行 gcloud config get-value project 即可获取该 ID。

    当系统提示时,请选择一个区域(例如 us-central1),确认服务名称,并针对允许未通过身份验证的调用回复 y

    然后等待部署完成。成功完成时,命令行会显示服务网址。

  2. 通过在网络浏览器中打开该服务网址来访问已部署的容器。

恭喜!您刚刚将容器映像中打包的应用部署到了 Cloud Run。Cloud Run 会在需要处理收到的请求时自动横向扩容您的容器映像,并在需要处理的请求数量减少时自动缩减您的映像。您只需为在请求处理期间消耗的 CPU、内存和网络流量付费。

清理

移除测试项目

虽然 Cloud Run 不会对未在使用中的服务计费,但您可能仍然需要支付将容器映像存储在 Container Registry 中而产生的相关费用。为避免产生费用,您可以删除映像或删除 GCP 项目。删除 GCP 项目后,系统即会停止对该项目中使用的所有资源计费。

  1. 在 GCP Console 中,转到项目页面。

    转到“项目”页面

  2. 在项目列表中,选择您要删除的项目,然后点击删除 delete
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

后续步骤

如需详细了解如何使用代码源构建容器并推送到 Container Registry,请参阅以下内容:

此页内容是否有用?请给出您的反馈和评价:

发送以下问题的反馈:

此网页
Cloud Run