Cloud Run 服務教學課程中的 gcloud 指令列


在本教學課程中,您將使用 Cloud Run 服務內的 Google Cloud CLI,建立 Cloud Run 服務的清單。您可以將本教學課程所學內容套用至現有的 Cloud 運算作業指令碼,或在透過用戶端程式庫建構更穩健的服務之前,先建構概念驗證。

您可以在網路服務中使用 gcloud CLI,就像使用任何殼層指令碼一樣,例如殼層快速入門導覽課程所示。在 Cloud Run 上,這兩項工具都會與服務搭配運作,方法是自動透過 Cloud Run 服務身分進行驗證。 Google Cloudgcloud CLI 可以使用授予服務身分的任何權限。

gcloud CLI 能夠廣泛收集資訊,並管理 Google Cloud 資源,因此在網路服務中使用時,必須盡量降低呼叫端濫用這些功能的風險。如果沒有安全控管措施,您可能會允許意外或蓄意的惡意活動,進而對在同一專案中執行的其他服務或資源造成風險。這類風險的例子包括:

  • 啟用私人虛擬機器的 IP 位址探索功能
  • 允許存取同一專案中資料庫的私人資料
  • 啟用刪除其他執行中服務

本教學課程的幾個步驟會說明如何強制執行控管措施,盡量降低風險,例如指定要在程式碼中執行的 gcloud 指令,而不是將其開放為使用者輸入內容。

在 Cloud Run 服務中使用指令列工具編寫指令碼,與在本機使用指令列類似。主要差異在於您應在主要指令碼邏輯周圍新增額外限制。

目標

  • 使用 Dockerfile 撰寫並建構自訂容器
  • 撰寫、建構及部署 Cloud Run 服務
  • 在網路服務中安全地使用 gcloud CLI
  • 產生 Cloud Run 服務報表並儲存至 Cloud Storage

費用

在本文件中,您會使用 Google Cloud的下列計費元件:

如要根據預測用量估算費用,請使用 Pricing Calculator

初次使用 Google Cloud 的使用者可能符合免費試用資格。

事前準備

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  5. Verify that billing is enabled for your Google Cloud project.

  6. Enable the Artifact Registry, Cloud Build, Cloud Run, and Cloud Storage APIs.

    Enable the APIs

  7. 安裝並初始化 gcloud CLI
  8. 必要的角色

    如要取得完成本教學課程所需的權限,請要求管理員為您授予專案的下列 IAM 角色:

    如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和機構的存取權」。

    您或許還可透過自訂角色或其他預先定義的角色取得必要權限。

設定 gcloud 預設值

如要針對 Cloud Run 服務設定 gcloud 的預設值:

  1. 設定您的預設專案:

    gcloud config set project PROJECT_ID

    PROJECT_ID 改為您為本教學課程建立的專案名稱。

  2. 為所選區域設定 gcloud:

    gcloud config set run/region REGION

    REGION 改為您所選擇的支援 Cloud Run 地區

Cloud Run 位置

Cloud Run 具有「地區性」,這表示執行 Cloud Run 服務的基礎架構位於特定地區,並由 Google 代管,可為該地區內所有區域提供備援功能。

選擇 Cloud Run 服務的執行地區時,請將延遲時間、可用性或耐用性需求做為主要考量。一般而言,您可以選擇最靠近使用者的地區,但您應考量 Cloud Run 服務所使用的其他 Google Cloud 產品位置。使用分散在不同位置的 Google Cloud 產品,可能會影響服務的延遲時間和費用。

Cloud Run 可在下列地區使用:

採用級別 1 定價

採用級別 2 定價

如果您已建立 Cloud Run 服務,即可在 Google Cloud 控制台的 Cloud Run 資訊主頁中查看地區。

擷取程式碼範例

如要擷取要使用的程式碼範例:

  1. 將應用程式存放區範例複製到本機電腦中:

    git clone https://github.com/GoogleCloudPlatform/cloud-run-samples.git

    您也可以 下載 zip 格式的範例,然後解壓縮該檔案。

  2. 變更為包含 Cloud Run 程式碼範例的目錄:

    cd cloud-run-samples/gcloud-report/

檢查程式碼

這個部分包含您擷取的程式碼範例相關資訊。

產生報表並上傳至 Cloud Storage

這個 Shell 指令碼會產生目前專案和區域中 Cloud Run 服務的報表,並將結果上傳至 Cloud Storage。列出名稱包含所提供字串 search 引數的服務。

這個指令碼會使用 gcloud run services list 指令、gcloud 進階格式選項,以及gcloud 串流傳輸複製模式。

set -eo pipefail

# Check for required environment variables.
requireEnv() {
  test "${!1}" || (echo "gcloud-report: '$1' not found" >&2 && exit 1)
}
requireEnv GCLOUD_REPORT_BUCKET

# Prepare formatting: Default search term to include all services.
search=${1:-'.'}
limits='spec.template.spec.containers.resources.limits.flatten("", "", " ")'
format='table[box, title="Cloud Run Services"](name,status.url,metadata.annotations.[serving.knative.dev/creator],'${limits}')'

# Create a specific object name that will not be overridden in the future.
obj="gs://${GCLOUD_REPORT_BUCKET}/report-${search}-$(date +%s).txt"

# Write a report containing the service name, service URL, service account or user that
# deployed it, and any explicitly configured service "limits" such as CPU or Memory.
gcloud run services list \
  --format "${format}" \
  --filter "metadata.name~${search}" | gsutil -q cp -J - "${obj}"

# /dev/stderr is sent to Cloud Logging.
echo "gcloud-report: wrote to ${obj}" >&2
echo "Wrote report to ${obj}"

這個指令碼可安全地以服務形式執行,因為重複叫用指令碼時,系統會更新報表,不會產生額外費用。如果其他指令碼使用 gcloud CLI,且重複叫用這些指令碼 (例如建立新的雲端資源或執行耗費資源的工作),可能會產生更多費用。冪等指令碼在重複呼叫時會產生相同結果,因此以服務形式執行較安全。

在 HTTP 要求中叫用指令碼

這段 Go 程式碼會設定網路服務,執行 Shell 指令碼來產生報表。 由於搜尋查詢是使用者輸入內容,程式碼會驗證查詢,確保查詢只包含英文字母、數字或連字號,避免輸入惡意指令。這組字元範圍夠窄,可防止指令注入攻擊

網路服務會將搜尋參數做為引數傳遞至 Shell 指令碼。


// Service gcloud-report is a Cloud Run shell-script-as-a-service.
package main

import (
	"log"
	"net/http"
	"os"
	"os/exec"
	"regexp"
)

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) {
	search := r.URL.Query().Get("search")
	re := regexp.MustCompile(`^[a-z]+[a-z0-9\-]*$`)
	if !re.MatchString(search) {
		log.Printf("invalid search criteria %q, using default", search)
		search = "."
	}

	cmd := exec.CommandContext(r.Context(), "/bin/bash", "script.sh", search)
	cmd.Stderr = os.Stderr
	out, err := cmd.Output()
	if err != nil {
		log.Printf("Command.Output: %v", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	w.Write(out)
}

go.mod 檔案會在 Go 模組中宣告應用程式依附元件:

module github.com/GoogleCloudPlatform/cloud-run-samples/gcloud-report

go 1.19

定義容器環境

Dockerfile 會定義服務的環境組合方式。 這與殼層版 Hello World 快速入門導覽課程中的 Dockerfile 類似,但最終容器映像檔是以 gcloud Google Cloud CLI 映像檔為基礎。這樣一來,您的服務就能使用 gcloud,而不必自訂 Google Cloud CLI 的安裝和設定步驟。


# Use the official 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.20-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 a gcloud image based on debian:buster-slim for a lean production container.
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
FROM gcr.io/google.com/cloudsdktool/cloud-sdk:slim

WORKDIR /app

# Copy the binary to the production image from the builder stage.
COPY --from=builder /app/server /app/server
COPY *.sh /app/
RUN chmod +x /app/*.sh

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

建立 Artifact Registry 標準存放區

建立 Artifact Registry 標準存放區,用於儲存容器映像檔:

gcloud artifacts repositories create REPOSITORY \
    --repository-format=docker \
    --location=REGION

取代:

  • REPOSITORY,並為存放區指定專屬名稱。
  • REGION,其中 Google Cloud 是 Artifact Registry 的區域。

設定 Cloud Storage bucket

建立 Cloud Storage bucket,用於上傳報表:

gcloud storage buckets create gs://REPORT_ARCHIVE_BUCKET

REPORT_ARCHIVE_BUCKET 替換成全域不重複的值區名稱。

設定服務身分

為限制服務對其他基礎架構的權限,您可以建立服務身分,並自訂執行工作所需的特定 IAM 權限。

在本例中,必要權限為讀取 Cloud Run 服務的權限,以及從 Cloud Storage bucket 讀取和寫入資料的權限。

  1. 建立服務帳戶:

    gcloud iam service-accounts create gcloud-report-identity

  2. 授予服務帳戶讀取 Cloud Run 服務的權限:

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member=serviceAccount:gcloud-report-identity@PROJECT_ID.iam.gserviceaccount.com \
      --role roles/run.viewer
  3. 授予服務帳戶讀取及寫入 Cloud Storage bucket 的權限:

    gcloud storage buckets add-iam-policy-binding gs://REPORT_ARCHIVE_BUCKET \
      --member=serviceAccount:gcloud-report-identity@PROJECT_ID.iam.gserviceaccount.com \
      --role=roles/storage.objectUser

這個自訂服務身分具有有限的存取權,因此服務無法存取其他 Google Cloud 資源。

運送服務

運送代碼的產生流程包含三個步驟:

  • 使用 Cloud Build 建構容器映像檔
  • 將容器映像檔上傳至 Artifact Registry
  • 將容器映像檔部署至 Cloud Run。

如要推送程式碼:

  1. 建構容器並發布至 Artifact Registry:

    gcloud builds submit --tag REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/gcloud-report

    取代:

    • PROJECT_ID 替換為您的 Google Cloud 專案 ID
    • REPOSITORY 替換為 Artifact Registry 存放區的名稱。
    • REGION,其中 Google Cloud 是 Artifact Registry 的區域。

    gcloud-report 是服務名稱。

    若成功執行,系統會顯示「SUCCESS」(成功) 訊息,當中包含 ID、建立時間和映像檔名稱。映像檔會儲存在 Artifact Registry 中,日後如有需要,可以重複使用。

  2. 執行下列指令來部署服務:

    gcloud run deploy gcloud-report \
       --image REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/gcloud-report \
       --update-env-vars GCLOUD_REPORT_BUCKET=REPORT_ARCHIVE_BUCKET \
       --service-account gcloud-report-identity \
       --no-allow-unauthenticated

    取代:

    • PROJECT_ID 改成您的專案 ID。 Google Cloud
    • REPOSITORY 替換為 Artifact Registry 存放區的名稱。
    • REGION 替換為服務的 Google Cloud 區域。

    gcloud-report 是容器名稱和服務名稱的一部分。 容器映像檔會部署到您先前在「設定 gcloud」中設定的服務和地區 (Cloud Run)。

    --no-allow-unauthenticated 旗標會限制未經驗證的服務存取權。不公開服務可讓您依靠 Cloud Run 的內建驗證功能,封鎖未經授權的要求。如要進一步瞭解以身分與存取權管理 (IAM) 為基礎的驗證,請參閱「使用 IAM 管理存取權」。

    等待部署作業完成。這項作業可能要花半分鐘的時間。成功完成後,指令列會顯示服務網址。

  3. 如果您要將程式碼更新部署到服務,請重複上述步驟。每次部署到服務都會建立一個新的修訂版本,並會在就緒時自動開始處理流量。

如要授予 Google Cloud 使用者叫用這項服務的權限,請參閱使用 IAM 管理存取權。專案編輯者和擁有者會自動取得這項存取權。

產生報表

如要產生 Cloud Run 服務的報表,請按照下列步驟操作:

  1. 使用 curl 傳送已驗證的要求:

    curl -H "Authorization: Bearer $(gcloud auth print-identity-token)" SERVICE_URL

    SERVICE_URL 替換為 Cloud Run 在部署完成後提供的網址。

    如果您建立新專案並按照本教學課程操作,輸出內容會類似於:

    Wrote report to gs://REPORT_ARCHIVE_BUCKET/report-.-DATE.txt

    檔案名稱中的 . 是預設搜尋引數,如原始碼中所述。

    如要使用搜尋功能,請在要求中加入 search 引數:

    curl -H "Authorization: Bearer $(gcloud auth print-identity-token)" SERVICE_URL?search=gcloud

    這項查詢會傳回類似下列內容的輸出內容:

    Wrote report to gs://REPORT_ARCHIVE_BUCKET/report-gcloud-DATE.txt
  2. 在本機使用 gcloud CLI 擷取檔案:

    gcloud storage cp gs://REPORT_FILE_NAME .

    指令中的 . 代表目前的工作目錄。

    REPORT_FILE_NAME 替換為上一步輸出的 Cloud Storage 物件名稱。

開啟檔案即可查看報表。內容應該會類似這樣:

螢幕截圖:專案中的 Cloud Run 服務清單,包含四個服務屬性的資料欄。
這四個資料欄會從服務說明中擷取。包括服務的「名稱」、首次部署時指派的「網址」、服務的初始「建立者」,以及 CPU 和記憶體上限的服務「限制」

提升未來穩定性

如果您打算進一步開發這項服務,建議以更穩健的程式設計語言重新編寫,並使用 Cloud Run Admin APICloud Storage 用戶端程式庫

您可以在 gcloud CLI 指令中加入 --log-http,檢查發出的 API 呼叫 (並查看部分驗證詳細資料)。

自動執行這項作業

現在,HTTP 要求可以觸發 Cloud Run 服務的報表,因此您可以在需要時使用自動化功能產生報表:

清除所用資源

如果您是為了這個教學課程建立新專案,請刪除專案。如果您使用現有專案,並想保留專案,但不要在本教學課程中新增的變更,請刪除為本教學課程建立的資源

刪除專案

如要避免付費,最簡單的方法就是刪除您為了本教學課程所建立的專案。

如要刪除專案:

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

刪除教學課程資源

  1. 刪除您在本教學課程中部署的 Cloud Run 服務:

    gcloud run services delete SERVICE-NAME

    其中 SERVICE-NAME 是您選擇的服務名稱。

    您也可以從Google Cloud 控制台刪除 Cloud Run 服務。

  2. 移除您在教學課程設定期間新增的 gcloud 預設區域設定:

     gcloud config unset run/region
    
  3. 移除專案設定:

     gcloud config unset project
    
  4. 刪除在本教學課程中建立的其他 Google Cloud 資源:

後續步驟