本教學課程說明服務開發人員如何使用 Google Cloud Observability 工具來發現問題,並透過本機開發工作流程進行調查,以排解 Cloud Run 服務故障問題。
這份逐步操作的「個案研究」是疑難排解指南的輔助資料,其中使用了會在部署時導致執行階段錯誤的範例專案,您可以排解問題來找出並修正問題。
目標
- 撰寫、建構及部署至 Cloud Run 的服務
- 使用錯誤回報和 Cloud Logging 找出錯誤
- 從 Container Registry 擷取容器映像檔,進行根本原因分析
- 修正「正式版」服務,然後改善服務,以減輕日後的問題
費用
在本文件中,您會使用 Google Cloud的下列計費元件:
您可以使用 Pricing Calculator 根據預測用量產生預估費用。
事前準備
- 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.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
- 啟用 Cloud Run Admin API
- 安裝並初始化 gcloud CLI。
- 更新元件:
gcloud components update
- 按照操作說明在本機安裝 Docker
-
Cloud Build 編輯器 (
roles/cloudbuild.builds.editor
) -
Cloud Run 管理員 (
roles/run.admin
) -
Error Reporting Viewer (
roles/errorreporting.viewer
) -
記錄檔檢視存取者 (
roles/logging.viewAccessor
) -
專案 IAM 管理員 (
roles/resourcemanager.projectIamAdmin
) -
服務帳戶使用者 (
roles/iam.serviceAccountUser
) -
服務用量消費者 (
roles/serviceusage.serviceUsageConsumer
) -
儲存空間管理員 (
roles/storage.admin
)
必要的角色
如要取得完成本教學課程所需的權限,請要求管理員為您授予專案的下列 IAM 角色:
如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和機構的存取權」。
設定 gcloud 預設值
如要針對 Cloud Run 服務設定 gcloud 的預設值:
設定您的預設專案:
gcloud config set project PROJECT_ID
將 PROJECT_ID 改為您為本教學課程建立的專案名稱。
為所選地區設定 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 定價
asia-east1
(臺灣)asia-northeast1
(東京)asia-northeast2
(大阪)asia-south1
(印度孟買)europe-north1
(芬蘭)低二氧化碳
europe-north2
(斯德哥爾摩)低二氧化碳
europe-southwest1
(馬德里)二氧化碳排放量低2
europe-west1
(比利時)二氧化碳排放量低
europe-west4
(荷蘭)二氧化碳排放量低
europe-west8
(米蘭)europe-west9
(巴黎)二氧化碳排放量低
me-west1
(特拉維夫)northamerica-south1
(墨西哥)us-central1
(愛荷華州)二氧化碳排放量低
us-east1
(南卡羅來納州)us-east4
(北維吉尼亞州)us-east5
(哥倫布)us-south1
(達拉斯)二氧化碳排放量低
us-west1
(奧勒岡州)二氧化碳排放量低
採用級別 2 定價
africa-south1
(約翰尼斯堡)asia-east2
(香港)asia-northeast3
(韓國首爾)asia-southeast1
(新加坡)asia-southeast2
(雅加達)asia-south2
(印度德里)australia-southeast1
(雪梨)australia-southeast2
(墨爾本)europe-central2
(波蘭華沙)europe-west10
(柏林)二氧化碳排放量低
europe-west12
(都靈)europe-west2
(英國倫敦)二氧化碳排放量低
europe-west3
(德國法蘭克福)二氧化碳排放量低
europe-west6
(瑞士蘇黎世)二氧化碳排放量低
me-central1
(杜哈)me-central2
(達曼)northamerica-northeast1
(蒙特婁)二氧化碳排放量低
northamerica-northeast2
(多倫多)二氧化碳排放量低
southamerica-east1
(巴西聖保羅)二氧化碳排放量低
southamerica-west1
(智利聖地牙哥)二氧化碳排放量低
us-west2
(洛杉磯)us-west3
(鹽湖城)us-west4
(拉斯維加斯)
如果您已建立 Cloud Run 服務,即可在 Google Cloud 控制台的 Cloud Run 資訊主頁中查看地區。
彙整程式碼
逐步建構新的 Cloud Run 問候服務。提醒您,這項服務會刻意為排解問題練習建立執行階段錯誤。
建立新專案:
Node.js
定義服務套件、初始依附元件和一些常見作業,建立 Node.js 專案。建立新的
hello-service
目錄:mkdir hello-service cd hello-service
產生
package.json
檔案,建立新的 Node.js 專案:npm init --yes npm install express@4
在編輯器中開啟新的
package.json
檔案,並設定start
指令碼來執行node index.js
。完成後,檔案會如下所示:
如果您在完成本教學課程後,仍想繼續改良這項服務,建議您填入說明、作者資訊,並評估授權。詳情請參閱 package.json 說明文件。
Python
建立新的
hello-service
目錄:mkdir hello-service cd hello-service
建立 requirements.txt 檔案,並將依附元件複製到其中:
Go
建立新的
hello-service
目錄:mkdir hello-service cd hello-service
初始化新的 go 模組,建立 Go 專案:
go mod init example.com/hello-service
您可以視需要更新特定名稱:如果程式碼已發布至可透過網際網路存取的程式碼存放區,則應更新名稱。
Java
建立新的 Maven 專案:
mvn archetype:generate \ -DgroupId=com.example.cloudrun \ -DartifactId=hello-service \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false
將依附元件複製到
pom.xml
依附元件清單 (<dependencies>
元素之間):將建構設定複製到
pom.xml
(位於<dependencies>
元素下方):
建立 HTTP 服務來處理傳入的要求:
Node.js
Python
Go
Java
建立
Dockerfile
來定義用於部署服務的容器映像檔:Node.js
Python
Go
Java
這個範例使用 Jib 建構 Docker 映像檔,並使用常見的 Java 工具。Jib 可在不需要 Dockerfile 或安裝 Docker 的情況下,最佳化容器建構作業。進一步瞭解如何使用 Jib 建構 Java 容器。
推送程式碼
推送程式碼包含三個步驟:使用 Cloud Build 建構容器映像檔、將容器映像檔上傳到 Container Registry,然後將容器映像檔部署到 Cloud Run。
如要推送程式碼:
建構容器並發布至 Container Registry:
Node.js
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
其中 PROJECT_ID 是您的 Google Cloud 專案 ID。您可以使用
gcloud config get-value project
查看目前的專案 ID。若成功執行,您應會看到包含 ID、建立時間和映像檔名稱的「SUCCESS」(成功) 訊息。映像檔儲存在 Container Registry 中,日後如有需要,可以重複使用。
Python
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
其中 PROJECT_ID 是您的 Google Cloud 專案 ID。您可以使用
gcloud config get-value project
查看目前的專案 ID。若成功執行,您應會看到包含 ID、建立時間和映像檔名稱的「SUCCESS」(成功) 訊息。映像檔儲存在 Container Registry 中,日後如有需要,可以重複使用。
Go
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
其中 PROJECT_ID 是您的 Google Cloud 專案 ID。您可以使用
gcloud config get-value project
查看目前的專案 ID。若成功執行,您應會看到包含 ID、建立時間和映像檔名稱的「SUCCESS」(成功) 訊息。映像檔儲存在 Container Registry 中,日後如有需要,可以重複使用。
Java
- 使用 gcloud 憑證輔助程式授權 Docker 推送至 Container Registry。
gcloud auth configure-docker
- 使用 Jib Maven 外掛程式建構容器,並將容器推送至 Container Registry。
mvn compile jib:build -Dimage=gcr.io/PROJECT_ID/hello-service
其中 PROJECT_ID 是您的 Google Cloud 專案 ID。您可以使用
gcloud config get-value project
查看目前的專案 ID。成功後,您應該會看到「BUILD SUCCESS」(建構成功) 訊息。映像檔儲存在 Container Registry 中,日後如有需要,可以重複使用。
- 使用 gcloud 憑證輔助程式授權 Docker 推送至 Container Registry。
執行下列指令來部署您的應用程式:
gcloud run deploy hello-service --image gcr.io/PROJECT_ID/hello-service
將 PROJECT_ID 替換為您的 Google Cloud 專案 ID。
hello-service
是容器映像檔名稱和 Cloud Run 服務名稱。請注意,容器映像檔是部署到您之前在「設定 gcloud」中設定的服務和地區。在出現「allow unauthenticated」(允許未經驗證) 提示時,回覆
y
或「是」。如要進一步瞭解以 IAM 為基礎的驗證,請參閱「管理存取權」一文。請等待部署完成,這可能需要半分鐘的時間。成功完成後,指令列會顯示服務網址。
立即體驗
請試用服務,確認您已成功部署服務。要求應以 HTTP 500 或 503 錯誤失敗 (5xx 伺服器錯誤類別的成員)。本教學課程將逐步說明如何排解這項錯誤回應問題。
系統會自動指派可瀏覽的網址給這項服務。
使用網路瀏覽器前往以下網址:
開啟網路瀏覽器
找出先前部署指令的輸出內容中所列的服務網址。
如果部署指令未提供網址,則表示發生錯誤。查看錯誤訊息並採取相應行動:如果沒有可操作的指引,請參閱疑難排解指南,並嘗試重新執行部署指令。
複製網址並貼到瀏覽器的網址列中,然後按下 Enter 鍵,即可前往該網址。
查看 HTTP 500 或 HTTP 503 錯誤。
如果您收到 HTTP 403 錯誤,表示您可能已在部署提示中拒絕
allow unauthenticated invocations
。如要修正這個問題,請授予服務未經驗證的存取權:gcloud run services add-iam-policy-binding hello-service \ --member="allUsers" \ --role="roles/run.invoker"
詳情請參閱「允許公開 (未經驗證) 存取權」。
調查問題
請注意,上方「試用」一節中發生的 HTTP 5xx 錯誤,是實際執行時發生的錯誤。本教學課程將逐步說明處理這類問題的正式程序。雖然實際工作環境的錯誤解決程序差異很大,但本教學課程會提供特定的步驟順序,說明如何應用實用的工具和技巧。
如要調查這個問題,您需要完成以下階段:
- 收集更多有關回報錯誤的詳細資料,以便進一步調查並設定緩解策略。
- 決定是否要推送修復版本,或回復至已知正常運作的版本,以減輕對使用者的影響。
- 重現錯誤,確認已收集正確的詳細資料,且錯誤並非一次性的故障
- 針對錯誤執行根本原因分析,找出造成這項錯誤的程式碼、設定或程序
在調查開始時,您會收到網址、時間戳記和「Internal Server Error」訊息。
收集更多詳細資料
收集更多有關問題的資訊,瞭解發生的情況並決定後續步驟。
使用 Google Cloud Observability 工具收集更多詳細資料:
使用錯誤回報控制台,這個控制台提供資訊主頁,可針對有已辨識堆疊追蹤的錯誤提供詳細資料和重複發生情形追蹤。
已記錄的錯誤清單。系統會依修訂版本、服務和平台,將錯誤訊息分門別類。 按一下錯誤即可查看堆疊追蹤詳細資料,並注意在錯誤發生前所做的函式呼叫。
錯誤詳細資料頁面中的「堆疊追蹤範例」會顯示單一錯誤例項。您可以查看個別事件。 使用 Cloud Logging 查看導致問題的作業順序,包括因缺少已辨識的錯誤堆疊追蹤而未包含在 Error Reporting 主控台中的錯誤訊息:
在第一個下拉式方塊中,依序選取「Cloud Run 修訂版本」>「hello-service」。這會篩選出由服務產生的記錄項目。
進一步瞭解如何在 Cloud Run 中查看記錄檔
復原至正常版本
如果這是已知可運作的既有服務,Cloud Run 上會有該服務的先前修訂版本。本教學課程使用的是沒有舊版的全新服務,因此您無法進行回溯。
不過,如果您有可回溯至先前版本的服務,請按照「查看修訂版本詳細資料」中的步驟,擷取建立服務新工作部署作業所需的容器名稱和設定詳細資料。
重現錯誤
根據先前取得的詳細資料,確認問題在測試條件下持續發生。
再次測試相同的 HTTP 要求,看看是否會回報相同的錯誤和詳細資料。錯誤詳細資料可能需要一段時間才會顯示。
由於本教學課程中的範例服務為唯讀,且不會觸發任何複雜的副作用,因此在實際工作環境中重現錯誤是安全的。不過,許多實際服務並非如此:您可能需要在測試環境中重現錯誤,或將此步驟限制為本機調查。
重現錯誤可為後續工作建立背景資訊。舉例來說,如果開發人員無法重現錯誤,可能需要對服務進行額外的檢測,才能進一步調查。
執行根本原因分析
根本原因分析是有效疑難排解的重要步驟,可確保您修正的是問題,而非症狀。
在本教學課程的先前步驟中,您已在 Cloud Run 上重現問題,確認服務在 Cloud Run 上代管時,問題仍會發生。現在請在本機重現問題,判斷問題是否只發生在程式碼中,或是只發生在實際工作代管服務中。
如果您尚未在本機使用 Docker CLI 搭配 Container Registry,請使用 gcloud 進行驗證:
gcloud auth configure-docker
如需其他方法,請參閱「Container Registry 驗證方法」。
如果最近使用的容器映像檔名稱無法使用,服務說明會提供最近部署的容器映像檔資訊:
gcloud run services describe hello-service
在
spec
物件中找出容器映像檔名稱。更精準的指令可以直接擷取該資訊:gcloud run services describe hello-service \ --format="value(spec.template.spec.containers.image)"
這個指令會顯示容器映像檔名稱,例如
gcr.io/PROJECT_ID/hello-service
。將容器映像檔從 Container Registry 提取到您的環境,這個步驟可能需要幾分鐘的時間,因為它會下載容器映像檔:
docker pull gcr.io/PROJECT_ID/hello-service
您可以使用相同的指令,擷取重複使用此名稱的容器映像檔後續更新內容。如果您略過這個步驟,當本機電腦上沒有容器映像檔時,下方的
docker run
指令會提取該映像檔。在本機上執行應用程式,確認問題並非 Cloud Run 特有:
PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \ gcr.io/PROJECT_ID/hello-service
將上述指令的元素分解如下:
- 服務會使用
PORT
環境變數,判斷要監聽容器內的哪個通訊埠。 run
指令會啟動容器,預設為 Dockerfile 或父項容器映像檔中定義的進入點指令。--rm
標記會在退出時刪除容器執行個體。-e
旗標會為環境變數指派值。-e PORT=$PORT
會將PORT
變數從本機系統傳播至同名變數的容器。-p
標記會將容器發布為可在 localhost 上透過通訊埠 9000 使用的服務。系統會將要求 localhost:9000 轉送至通訊埠 8080 上的容器。也就是說,服務針對目前使用的連接埠編號所產生的輸出內容,與服務的存取方式不符。- 最後一個引數
gcr.io/PROJECT_ID/hello-service
是容器映像檔tag
,這是容器映像檔 sha256 雜湊 ID 的易讀標籤。如果本機沒有可用的映像檔,Docker 會嘗試從遠端登錄檔擷取映像檔。
在瀏覽器中開啟 http://localhost:9000。查看終端機輸出內容,找出與 {ops_name} 相符的錯誤訊息。
如果無法在本機重現問題,則可能是 Cloud Run 環境特有的情況。如要瞭解應調查的具體領域,請參閱 Cloud Run 疑難排解指南。
在這種情況下,本機會重現錯誤。
- 服務會使用
既然已確認錯誤持續發生,且是由服務程式碼而非代管平台造成,現在是時候仔細調查程式碼了。
為了本教學課程的目的,我們可以假設容器內的程式碼與本機系統中的程式碼相同。
請再次查看錯誤報表的堆疊追蹤,並與程式碼交叉參照,找出錯誤的特定行。
Node.js
在記錄中顯示的堆疊追蹤中,找出呼叫的行號附近index.js
檔案中的錯誤訊息來源:
Python
在記錄中顯示的堆疊追蹤中,找出錯誤訊息來源所在的main.py
檔案,並查看該檔案中附近的行號:
Go
在記錄中顯示的堆疊追蹤記錄中,找出錯誤訊息來源所在的 main.go
檔案,並在該檔案中查看該行號附近的內容:
Java
在記錄中顯示的堆疊追蹤中,找出錯誤訊息來源所在的 App.java
檔案,並在該檔案中找出呼叫的行號:
檢查這段程式碼後,我們發現在未設定 NAME
環境變數時,系統會採取以下動作:
- 系統會將錯誤記錄到 Google Cloud Observability
- 傳送 HTTP 錯誤回應
這個問題是因為缺少變數,但實際上的原因更為具體:程式碼變更會在環境變數上新增硬式依附元件,但未納入部署指令碼和執行階段需求文件的相關變更。
修正根本原因
我們已收集程式碼並找出潛在的根本原因,因此可以採取措施加以修正。
確認服務是否可在本機環境中搭配現有的
NAME
環境運作:在本機執行已新增環境變數的容器:
PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \ -e NAME="Local World!" \ gcr.io/PROJECT_ID/hello-service
前往瀏覽器的 http://localhost:9000
查看頁面上是否顯示「Hello Local World!」
修改執行中的 Cloud Run 服務環境,加入這個變數:
執行服務更新指令來新增環境變數:
gcloud run services update hello-service \ --set-env-vars NAME=Override
請稍候幾秒,Cloud Run 會根據先前的修訂版本建立新修訂版本,並新增新的環境變數。
確認服務現已修正:
- 在瀏覽器中前往 Cloud Run 服務網址。
- 請查看頁面上顯示的「Hello Override!」。
- 確認 Cloud Logging 或 Error Reporting 中沒有顯示任何非預期的訊息或錯誤。
改善日後疑難排解的速度
在這個實際工作環境問題中,錯誤與作業設定有關。我們已進行程式碼變更,以便在日後盡量減少此問題的影響。
- 改善錯誤記錄,加入更多具體詳細資料。
- 請讓服務改為使用安全的預設值,而非傳回錯誤。如果使用預設值代表變更為正常功能,請使用警告訊息進行監控。
讓我們逐步移除 NAME
環境變數做為硬式依附元件。
移除現有的
NAME
處理程式碼:Node.js
Python
Go
Java
新增設定備用值的程式碼:
Node.js
Python
Go
Java
透過重新建構並執行容器,針對受影響的設定案例進行本機測試:
Node.js
docker build --tag gcr.io/PROJECT_ID/hello-service .
Python
docker build --tag gcr.io/PROJECT_ID/hello-service .
Go
docker build --tag gcr.io/PROJECT_ID/hello-service .
Java
mvn compile jib:build
確認
NAME
環境變數仍可正常運作:PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \ -e NAME="Robust World" \ gcr.io/PROJECT_ID/hello-service
確認服務在沒有
NAME
變數的情況下能正常運作:PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \ gcr.io/PROJECT_ID/hello-service
如果服務未傳回結果,請確認在第一個步驟中移除的程式碼並未移除其他行,例如用於寫入回應的行。
請參閱「部署程式碼」一節,瞭解如何部署這項服務。
每次部署到服務都會建立一個新的修訂版本,並會在就緒時自動開始處理流量。
如要清除先前設定的環境變數,請按照下列步驟操作:
gcloud run services update hello-service --clear-env-vars
將預設值的新功能新增至服務的自動化測試涵蓋率。
在記錄中找出其他問題
您可能會在這項服務的記錄檢視器中看到其他問題。舉例來說,如果系統不支援某項系統呼叫,就會在記錄檔中顯示為「容器沙箱限制」。
舉例來說,Node.js 服務有時會產生以下記錄訊息:
Container Sandbox Limitation: Unsupported syscall statx(0xffffff9c,0x3e1ba8e86d88,0x0,0xfff,0x3e1ba8e86970,0x3e1ba8e86a90). Please, refer to https://gvisor.dev/c/linux/amd64/statx for more information.
在這種情況下,缺乏支援不會影響 hello-service 範例服務。
Terraform 疑難排解
如有 Terraform 相關疑難排解問題,請參閱「Terraform 政策驗證疑難排解」或洽詢 Terraform 支援團隊。
清除所用資源
如果您是為了這個教學課程建立新專案,請刪除專案。如果您使用現有專案,且希望保留該專案而不採用本教學課程中的變更,請刪除為教學課程建立的資源。
刪除專案
如要避免付費,最簡單的方法就是刪除您為了本教學課程所建立的專案。
如要刪除專案:
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
刪除教學課程資源
刪除您在本教學課程中部署的 Cloud Run 服務:
gcloud run services delete SERVICE-NAME
其中 SERVICE-NAME 是您選擇的服務名稱。
您也可以從 Google Cloud 控制台刪除 Cloud Run 服務。
移除您在教學課程設定期間新增的 gcloud 預設區域設定:
gcloud config unset run/region
移除專案設定:
gcloud config unset project
刪除本教學課程中建立的其他 Google Cloud 資源:
- 從 Container Registry 刪除名為
gcr.io/<var>PROJECT_ID</var>/hello-service
的容器映像檔。
- 從 Container Registry 刪除名為
後續步驟
- 進一步瞭解如何使用 Cloud Logging 和錯誤回報,深入瞭解實際工作環境的行為。
- 如要進一步瞭解如何排解 Cloud Run 問題,請參閱疑難排解指南。
- 探索 Google Cloud 的參考架構、圖表和最佳做法。歡迎瀏覽我們的雲端架構中心。