透過 Cloud Run 提供動態內容和託管微服務

搭配使用 Cloud Run 和 Firebase 託管,即可產生及提供 動態內容或建構 REST API 做為微服務

使用 Cloud Run 即可 部署封裝在容器映像檔中的應用程式接著使用 Firebase 代管功能可讓你直接透過 HTTPS 要求觸發 容器化應用程式

  • Cloud Run 支援 支援多種語言 包括 Go、Node.js、Python 和 Java 等 您選擇的程式設計語言和架構
  • Cloud Run 自動及水平擴充 處理收到的要求,然後縮減 需求減少
  • 因此您只須支付 CPU 的費用。 處理要求期間耗用的記憶體和網路

透過與 Google Cloud 整合的 Firebase 託管,請造訪我們的 無伺服器總覽


本指南說明如何:

  1. 編寫簡單的 Hello World 應用程式
  2. 將應用程式容器化並上傳至 Container Registry
  3. 將容器映像檔部署至 Cloud Run
  4. 將要求直接託管於容器化應用程式

請注意,為了提高提供動態內容的成效, 視需要調整快取設定

事前準備

使用 Cloud Run 前,您必須先完成幾項初始工作 包括設定 Cloud Billing 帳戶,以及啟用 Cloud Run API,並安裝 gcloud 指令列工具。

設定專案帳單

Cloud Run 提供免費的用量配額。 但您仍必須 Cloud Billing 帳戶 或試用 Cloud Run。

啟用 API 並安裝 SDK

  1. 在 Google API 控制台中啟用 Cloud Run API:

    1. 開啟 Cloud Run API 頁面 也可以前往 Google API 控制台

    2. 系統出現提示時,請選取 Firebase 專案。

    3. 按一下 Cloud Run API 頁面中的「啟用」

  2. 安裝並初始化 Cloud SDK

  3. 檢查是否已為正確的專案設定 gcloud 工具:

    gcloud config list

步驟 1:編寫範例應用程式

請注意,Cloud Run 支援 其他語言 以及以下範例中顯示的語言。

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("helloworld: received a request")
    	target := os.Getenv("TARGET")
    	if target == "" {
    		target = "World"
    	}
    	fmt.Fprintf(w, "Hello %s!\n", target)
    }
    
    func main() {
    	log.Print("helloworld: starting server...")
    
    	http.HandleFunc("/", handler)
    
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    	}
    
    	log.Printf("helloworld: listening on port %s", port)
    	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
    }
    

    這個程式碼會建立一個基本網路伺服器,用於監聽 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.19.2"
      }
    }
    
  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}!\n`);
    });
    
    const port = process.env.PORT || 8080;
    app.listen(port, () => {
      console.log('Hello world listening on port', port);
    });
    

    這個程式碼會建立一個基本網路伺服器,用於監聽 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)))
    

    這個程式碼會建立一個基本網路伺服器,用於監聽 PORT 環境變數定義的連接埠。

您的應用程式已經完成,您可以開始將這個應用程式容器化並上傳到 Container Registry。

Java

  1. 安裝 Java SE 8 以上版本 JDKCURL

    請注意,如要建立新的 Web 專案,只需前往 下一步下半年說明的 Dockerfile 會載入所有 複製到容器中

  2. 在控制台中使用 cURL 建立新的空白網路專案,然後 解壓縮指令:

    curl https://start.spring.io/starter.zip \
        -d dependencies=web \
        -d name=helloworld \
        -d artifactId=helloworld \
        -o helloworld.zip
    unzip helloworld.zip

    這樣就能建立 SpringBoot 專案。

  3. 更新 SpringBootApplication 類別,位於: src/main/java/com/example/helloworld/HelloworldApplication.java 製作 新增 @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);
      }
    }
    

    這個程式碼會建立一個基本網路伺服器,用於監聽 PORT 環境變數定義的連接埠。

您的應用程式已經完成,您可以開始將這個應用程式容器化並上傳到 Container Registry。

步驟 2:將應用程式容器化並上傳至 Container Registry

  1. 將範例應用程式容器化,方法是在Dockerfile 與來源檔案相同的目錄。將下列內容複製到您的 檔案。

    Go

    # Use the official Golang image to create a build artifact.
    # This is based on Debian and sets the GOPATH to /go.
    FROM golang:latest as builder
    
    ARG TARGETOS
    ARG TARGETARCH
    
    # Create and change to the app directory.
    WORKDIR /app
    
    # Retrieve application dependencies using go modules.
    # Allows container builds to reuse downloaded dependencies.
    COPY go.* ./
    RUN go mod download
    
    # Copy local code to the container image.
    COPY . ./
    
    # Build the binary.
    # -mod=readonly ensures immutable go.mod and go.sum in container builds.
    RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -mod=readonly -v -o server
    
    # Use the official Alpine image for a lean production container.
    # https://hub.docker.com/_/alpine
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM alpine:3
    RUN apk add --no-cache ca-certificates
    
    # 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"]
    

    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 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 --only=production
    
    # Copy local code to the container image.
    COPY . ./
    
    # Run the web service on container startup.
    CMD [ "npm", "start" ]
    

    Python

    # Use the official lightweight Python image.
    # https://hub.docker.com/_/python
    FROM python:3.7-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 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 the Official OpenJDK image for a lean production stage of our multi-stage build.
    # https://hub.docker.com/_/openjdk
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM openjdk:8-jre-alpine
    
    # 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"]
    

  2. 執行下列指令,透過 Cloud Build 建構容器映像檔 指令:

    gcloud builds submit --tag gcr.io/PROJECT_ID/helloworld

    成功後,您會看到含有映像檔名稱的「SUCCESS」(成功) 訊息。
    (gcr.io/PROJECT_ID/helloworld)。

容器映像檔現已儲存在 Container Registry 中,如有下列情況,就可以重複使用

請注意,您可以使用本機安裝的版本,而非 Cloud Build 將 Docker 容器 在本機上建構容器

步驟 3:將容器映像檔部署至 Cloud Run

  1. 使用下列指令進行部署:

    gcloud run deploy --image gcr.io/PROJECT_ID/helloworld

  2. 出現提示時:

為獲得最佳效能,請在下列區域將 Cloud Run 服務與「託管」存放在相同位置:

  • us-west1
  • us-central1
  • us-east1
  • europe-west1
  • asia-east1

下列區域:

  • asia-east1
  • asia-east2
  • asia-northeast1
  • asia-northeast2
  • asia-northeast3
  • asia-south1
  • asia-south2
  • asia-southeast1
  • asia-southeast2
  • australia-southeast1
  • australia-southeast2
  • europe-central2
  • europe-north1
  • europe-southwest1
  • europe-west1
  • europe-west12
  • europe-west2
  • europe-west3
  • europe-west4
  • europe-west6
  • europe-west8
  • europe-west9
  • me-central1
  • me-west1
  • northamerica-northeast1
  • northamerica-northeast2
  • southamerica-east1
  • southamerica-west1
  • us-central1
  • us-east1
  • us-east4
  • us-east5
  • us-south1
  • us-west1
  • us-west2
  • us-west3
  • us-west4
  • us-west1
  • us-central1
  • us-east1
  • europe-west1
  • asia-east1
  1. 請稍待片刻,等待部署作業完成。成功之後,指令列 會顯示服務網址例如:https://helloworld-RANDOM_HASH-us-central1.a.run.app

  2. 在網路瀏覽器中開啟服務網址,以造訪您所部署的容器。

下一個步驟會逐步引導您在 Firebase 託管網址,這樣系統才能為 Firebase 代管的網站。

步驟 4:直接向容器化應用程式託管要求

取代為 重新編寫規則,就可以將要求設為 會將特定模式比對到單一目的地。

以下範例說明如何導向來自網頁的所有要求 代管網站上的 /helloworld,以便觸發 helloworld 容器執行個體。

  1. 請確認下列事項:

    如需安裝 CLI 和初始化的詳細操作說明 託管,請參閱 代管入門指南

  2. 開啟 firebase.json 檔案

  3. hosting 區段下方新增下列 rewrite 設定:

    "hosting": {
      // ...
    
      // Add the "rewrites" attribute within "hosting"
      "rewrites": [ {
        "source": "/helloworld",
        "run": {
          "serviceId": "helloworld",  // "service name" (from when you deployed the container image)
          "region": "us-central1",    // optional (if omitted, default is us-central1)
          "pinTag": true              // optional (see note below)
        }
      } ]
    }
    
  4. 執行下列指令,將代管設定部署至網站 指令:

    firebase deploy --only hosting

您現在可以透過下列網址連上您的容器:

  • 您的 Firebase 子網域:
    PROJECT_ID.web.app/」和 PROJECT_ID.firebaseapp.com/

  • 任何已連結的自訂網域
    CUSTOM_DOMAIN/

前往「託管」設定頁面: 進一步瞭解重寫規則。你可以 還可以查看 回應的優先順序 提供多種託管設定選項。

在本機測試

開發期間,您可以在本機執行及測試容器映像檔。適用對象 如需詳細操作說明,請參閱 Cloud Run 說明文件

後續步驟