このチュートリアルでは、サービス デベロッパーが Google Cloud Observability ツールを使用して Cloud Run サービスの問題を検出し、ローカル開発ワークフローで調査を行う方法を説明します。
このトラブル シューティング ガイドの詳細な「ケーススタディ」では、デプロイ時にランタイム エラーが発生するサンプル プロジェクトを使用して、問題を発見および修正します。
目標
- Cloud Run でサービスを書き込み、作成、ビルド、デプロイする
- Error Reporting と Cloud Logging を使用してエラーを特定する
- 根本原因を分析するため Container Registry からコンテナ イメージを取得する
- 「本番環境」のサービスを修正し、今後の問題を軽減するためにサービスを改善する
費用
このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。
料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。
始める前に
- 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 をローカルにインストールします。
必要なロール
チュートリアルを完了するために必要な権限を取得するには、プロジェクトに対して次の IAM ロールを付与するよう管理者に依頼してください。
-
Cloud Build 編集者(
roles/cloudbuild.builds.editor
) -
Cloud Run 管理者(
roles/run.admin
) -
Error Reporting 閲覧者(
roles/errorreporting.viewer
) -
ログ表示アクセス者(
roles/logging.viewAccessor
) -
プロジェクト IAM 管理者(
roles/resourcemanager.projectIamAdmin
) -
サービス アカウント ユーザー(
roles/iam.serviceAccountUser
) -
Service Usage ユーザー(
roles/serviceusage.serviceUsageConsumer
) -
ストレージ管理者(
roles/storage.admin
)
ロールの付与については、プロジェクト、フォルダ、組織へのアクセスを管理するをご覧ください。
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
(フィンランド) 低 CO2europe-southwest1
(マドリッド) 低 CO2europe-west1
(ベルギー) 低 CO2europe-west4
(オランダ) 低 CO2europe-west8
(ミラノ)europe-west9
(パリ) 低 CO2me-west1
(テルアビブ)us-central1
(アイオワ) 低 CO2us-east1
(サウスカロライナ)us-east4
(北バージニア)us-east5
(コロンバス)us-south1
(ダラス) 低 CO2us-west1
(オレゴン) 低 CO2
ティア 2 料金を適用
africa-south1
(ヨハネスブルグ)asia-east2
(香港)asia-northeast3
(ソウル、韓国)asia-southeast1
(シンガポール)asia-southeast2
(ジャカルタ)asia-south2
(デリー、インド)australia-southeast1
(シドニー)australia-southeast2
(メルボルン)europe-central2
(ワルシャワ、ポーランド)europe-west10
(ベルリン) 低 CO2europe-west12
(トリノ)europe-west2
(ロンドン、イギリス) 低 CO2europe-west3
(フランクフルト、ドイツ) 低 CO2europe-west6
(チューリッヒ、スイス) 低 CO2me-central1
(ドーハ)me-central2
(ダンマーム)northamerica-northeast1
(モントリオール) 低 CO2northamerica-northeast2
(トロント) 低 CO2southamerica-east1
(サンパウロ、ブラジル) 低 CO2southamerica-west1
(サンティアゴ、チリ) 低 CO2us-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 --save express@4
エディタで新しい
package.json
ファイルを開き、node index.js
を実行するようにstart
スクリプトを構成します。完了すると、ファイルは次のような状態になります。
このサービスをこのチュートリアルからさらに進化させる場合は、説明、作成者を入力してライセンスを評価します。詳しくは、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 を使用して一般的な Java ツールにより Docker イメージをビルドします。Jib は、Dockerfile や Docker をインストールせずにコンテナのビルドを最適化します。Jib を使用して Java コンテナを構築する方法の詳細を確認します。
コードを配布する
コードの配布は、Cloud Build でコンテナ イメージをビルドする、Container Registry にコンテナ イメージをアップロードする、Cloud Run にコンテナ イメージをデプロイするという 3 つのステップで構成されます。
コードを配布するには、次の手順を行います。
コンテナをビルドして、Container Registry に公開します。
Node.js
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
ここで PROJECT_ID は、Google Cloud プロジェクト ID です。 現在のプロジェクト ID は、
gcloud config get-value project
で確認できます。ビルドが成功すると、ID、作成時間、イメージ名を含む SUCCESS メッセージが表示されます。イメージが Container Registry に保存されます。このイメージは必要に応じて再利用できます。
Python
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
ここで PROJECT_ID は、Google Cloud プロジェクト ID です。 現在のプロジェクト ID は、
gcloud config get-value project
で確認できます。ビルドが成功すると、ID、作成時間、イメージ名を含む SUCCESS メッセージが表示されます。イメージが Container Registry に保存されます。このイメージは必要に応じて再利用できます。
Go
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
ここで PROJECT_ID は、Google Cloud プロジェクト ID です。 現在のプロジェクト ID は、
gcloud config get-value project
で確認できます。ビルドが成功すると、ID、作成時間、イメージ名を含む SUCCESS メッセージが表示されます。イメージが Container Registry に保存されます。このイメージは必要に応じて再利用できます。
Java
- Docker を承認して Container Registry に push するには、gcloud 認証ヘルパーを使用します。
gcloud auth configure-docker
- Jib Maven プラグインを使用して、コンテナをビルドして Container Registry に push します。
mvn compile jib:build -Dimage=gcr.io/PROJECT_ID/hello-service
ここで PROJECT_ID は、Google Cloud プロジェクト ID です。 現在のプロジェクト ID は、
gcloud config get-value project
で確認できます。ビルドが成功すると、BUILD SUCCESS メッセージが表示されます。イメージが Container Registry に保存されます。このイメージは必要に応じて再利用できます。
- Docker を承認して Container Registry に push するには、gcloud 認証ヘルパーを使用します。
次のコマンドを実行して、アプリをデプロイします。
gcloud run deploy hello-service --image gcr.io/PROJECT_ID/hello-service
PROJECT_ID を Google Cloud プロジェクト ID に置き換えます。
hello-service
は、コンテナ イメージ名と Cloud Run サービスの名前の両方です。コンテナ イメージは、gcloud の設定で構成したサービスとリージョンにデプロイされることに注意してください。未認証の許可を求めるプロンプトに対して
y
(はい)と答えます。IAM ベースの認証の詳細については、アクセスの管理をご覧ください。デプロイが完了するまで待ちます。30 秒ほどかかる場合があります。成功すると、コマンドラインにサービス URL が表示されます。
試してみる
サービスを試してみて、サービスが正常にデプロイされたことを確認します。リクエストは HTTP 500 エラーまたは HTTP 503 エラー(クラス 5xx サーバーエラーのメンバー)で失敗します。このチュートリアルでは、このエラー レスポンスのトラブルシューティングについて説明します。
サービスにはナビゲーション可能な URL が自動的に割り当てられます。
ウェブブラウザで次の URL に移動します。
ウェブブラウザを開きます。
前に実行した deploy コマンドで出力されたサービス URL を見つけます。
deploy コマンドが URL を提供しなかった場合、何か問題が発生しています。エラーメッセージを確認し、その内容に応じて対処します。対処可能なガイダンスがない場合は、トラブルシューティング ガイドを確認し、デプロイ コマンドを再試行します。
この URL をブラウザのアドレスバーにコピーして、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 エラーが、本番環境ランタイム エラーとして発生したことを表示で確認してください。このチュートリアルでは、正式な処理プロセスを説明します。本番環境でのエラー解決プロセスは大きく異なりますが、このチュートリアルでは、有用なツールとテクニックを利用するための特定の手順を示します。
この問題を調査するには、以下のフェーズを実施します。
- 報告されたエラーの詳細を収集し、さらに調査を進め、軽減策を策定します。
- 修正を進めるか、既知の正常なバージョンにロールバックして、ユーザーへの影響を軽減させます。
- 正確な詳細が収集されたことと、1 回限りのエラーではないことを確認するために、エラーを再現します。
- バグの根本原因を分析して、このエラーの原因となったコード、構成、プロセスを特定します。
調査を開始すると、URL、タイムスタンプ、「Internal Server Error」というメッセージが表示されます。
詳細の収集
問題の詳細情報を収集して何が起きたのかを理解し、次のステップを決定します。
利用可能な Google Cloud Observability ツールを使用して詳細を収集します。
Error Reporting コンソールを使用します。これにより、認識されたスタック トレースを含むエラーの詳細と繰り返しトラッキングがダッシュボードに表示されます。
スタック トレースの詳細を表示するには、エラーをクリックします。このとき、関数呼び出しはエラーの直前であることに留意します。
Cloud Logging を使用して、問題につながる一連の操作を確認します。確認対象には、確認されたエラースタック トレースが存在しないために Error Reporting コンソールに表示されないエラー メッセージが含まれます。
最初のプルダウン ボックスで、[Cloud Run のリビジョン] > [hello-service] の順に選択します。これにより、ログエントリはサービスによって生成されたものに絞り込まれます。
Cloud Run でのログの表示に関する詳細をご覧ください。
正常なバージョンへのロールバック
これが確立されたサービスであり、動作することがわかっている場合は、Cloud Run のサービスの以前のリビジョンがあります。このチュートリアルでは、以前のバージョンを使用しない新しいサービスを使用するため、ロールバックはできません。
ただし、ロールバックできる以前のバージョンのサービスを利用している場合は、リビジョンの詳細の表示に従って、サービスの新しいワーキング デプロイを作成するために必要なコンテナ名と構成の詳細を抽出します。
エラーを再現する
以前に取得した詳細を使用して、テスト条件で一貫して問題が発生していることを確認します。
同じ HTTP リクエストをもう一度試すことで送信し、同じエラーと詳細が報告されるかどうかを確認します。エラーの詳細が表示されるまでに時間がかかることがあります。
このチュートリアルのサンプル サービスは読み取り専用であり、複雑な副次的影響をトリガーしないため、本番環境でのエラーの再現は安全です。ただし、実際のサービスの多くには上記が当てはまりません。テスト環境でエラーを再現するか、ローカル調査に限定する必要があります。
エラーを再現することで、後続作業のコンテキストが明確になります。たとえば、デベロッパーがエラーを再現できない場合、サービスに対してインストゥルメンテーションの追加が必要になる場合があります。
根本原因の分析を行う
根本原因の分析は、効果的なトラブルシューティングにおいて、症状ではなく問題を解決するための重要なステップです。
このチュートリアルでは、Cloud Run で問題を再現し、Cloud Run でサービスがホストされているときに問題がアクティブであることを確認しました。次に、問題をローカルで再現させてみて、問題がコードに限定されているか、本番環境のホスティングでのみ発生しているかを判断します。
Container Registry で Docker CLI をローカルで使用していない場合は、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 から環境に pull します。この手順では、コンテナ イメージをダウンロードするため、数分かかることがあります。
docker pull gcr.io/PROJECT_ID/hello-service
この名前を再利用するコンテナ イメージに対するその後の更新は、同じコマンドで取得できます。この手順をスキップすると、次の
docker run
コマンドはコンテナ イメージを pull します(ローカルマシンにない場合)。ローカルで実行して、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
フラグは、ローカルホストのポート 9,000 でコンテナをサービスとして公開します。localhost: 9000 へのリクエストは、ポート 8080 でコンテナにルーティングされます。つまり、使用中のポート番号に関するサービスからの出力は、サービスへのアクセス方法と一致しません。- 最後の引数
gcr.io/PROJECT_ID/hello-service
はコンテナ イメージtag
です。これは、コンテナ イメージの SHA256 ハッシュ識別子を表す、人が読める形式のラベルです。ローカルで入手できない場合、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 サービスの URL に移動します。
- ページに「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
サービスの自動テスト カバレッジに、デフォルト値の新しい機能を追加します。
ログ内でその他の問題を検索
このサービスのログビューアには、その他の問題がある場合があります。たとえば、サポートされていないシステムコールは、「Container Sandbox Limitation」(コンテナ サンドボックスの制限)としてログに表示されます。
たとえば、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 は、選択したサービス名です。
Cloud Run サービスは Google Cloud コンソール から削除することもできます。
チュートリアルの設定時に追加した gcloud のデフォルト リージョン構成を削除します。
gcloud config unset run/region
プロジェクト構成を削除します。
gcloud config unset project
このチュートリアルで作成した他の Google Cloud リソースを削除します。
gcr.io/<var>PROJECT_ID</var>/hello-service
という名前のコンテナ イメージを Container Registry から削除します。
次のステップ
- Cloud Logging と Error Reporting を使用して本番環境の動作をより深く理解する方法を学ぶ。
- トラブルシューティング ガイドで、Cloud Run のトラブルシューティングの詳細を確認する。
- Google Cloud に関するリファレンス アーキテクチャ、図、チュートリアル、ベスト プラクティスを確認する。Cloud アーキテクチャ センターをご覧ください。