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

將「Cloud Run」與「Firebase Hosting」配對,即可產生及提供 動態內容或建構 REST API 做為微服務

使用 Cloud Run 可讓您 部署封裝在容器映像檔中的應用程式接著使用 Firebase Hosting,您可以指示 HTTPS 要求以觸發 容器化應用程式

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

使用與以下服務整合的 Cloud Run 應用實例和範例 Firebase Hosting,請造訪我們的 無伺服器總覽


本指南說明如何:

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

請注意,如要改善動態內容的放送效能,您可以視需要調整快取設定

事前準備

使用 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.20.0"
      }
    }
    
  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 服務與 Hosting 並用:

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

您可以在Cloud RunHosting 下列區域:

  • 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 Hosting 網址,這樣系統才能針對以下項目產生動態內容: Firebase 代管的網站。

步驟 4:將代管要求直接傳送至容器化應用程式

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

以下範例說明如何導向來自網頁的所有要求 Hosting 網站上的 /helloworld,觸發系統啟動及執行 helloworld 容器執行個體。

  1. 請確認下列事項:

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

  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/

,瞭解如何調查及移除這項存取權。

請參閱 Hosting 設定頁面,進一步瞭解重寫規則的詳細資訊。你可以 還可以查看 回應的優先順序 適用於各種 Hosting 設定。

在本機測試

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

後續步驟