1. はじめに
最終更新日: 2021 年 3 月 5 日
アプリケーションのオブザーバビリティ
オブザーバビリティと OpenTelemetry
オブザーバビリティとは、システムの属性を表す用語です。オブザーバビリティを備えたシステムでは、チームが積極的にシステムをデバッグできます。そこで、オブザーバビリティの 3 本柱について説明します。ログ、指標、トレースは、システムがオブザーバビリティを取得するための基本的な計測手段です。
OpenTelemetry は、オブザーバビリティに必要なテレメトリー データ(ログ、指標、トレース)の計測とエクスポートを高速化する仕様と SDK のセットです。OpenTelemetry は、CNCF に基づくオープン スタンダードでコミュニティ主導のプロジェクトです。プロジェクトとそのエコシステムが提供するライブラリを利用することで、デベロッパーはベンダーに依存しない方法で複数のアーキテクチャに対してアプリケーションを計測できるようになります。
分散トレース
ログ、指標、トレースのうち、トレースはシステム内のプロセスの特定の部分のレイテンシを示すテレメトリーです。特にマイクロサービスの時代において、分散トレースは、分散システム全体のレイテンシのボトルネックを見つける強力な推進力となります。
分散トレースを分析する場合、トレースデータの可視化は、システム全体のレイテンシを一目で把握するための鍵となります。分散トレースでは、システム エントリ ポイントへの 1 つのリクエストを処理する一連の呼び出しを、複数のスパンを含む Trace の形式で処理します。
スパンは分散システムで行われる個々の作業単位を表し、開始時刻と終了時刻が記録されます。スパンは、多くの場合、互いに階層関係にあります。下の図では、すべての小さなスパンが大きな /messages スパンの子スパンであり、1 つのトレースに組み込まれ、システム内の作業パスを示します。
Google Cloud Trace は分散トレース バックエンドのオプションの一つであり、Google Cloud の他のプロダクトと緊密に統合されています。
作成するアプリの概要
この Codelab では、「Shakesapp」というサービスでトレース情報を計測しますGoogle Kubernetes Engine で動作する Kubernetes クラスタ上で動作します。Shakesapp のアーキテクチャは次のとおりです。
- クライアントがクエリ文字列をサーバーに送信する
- サーバーはクライアントからのクエリを受け取り、Google Cloud Storage からすべての Shakespare 作品をテキスト形式で取得して、クエリを含む行を検索し、クライアントに一致した行の番号を返します。
リクエスト全体でトレース情報を計測します。
学習内容
- Python プロジェクトで OpenTelemetry Trace ライブラリの使用を開始する方法
- ライブラリでスパンを作成する方法
- アプリ コンポーネント間のワイヤーを介してスパン コンテキストを伝播する方法
- トレースデータを Google Cloud Trace に送信する方法
- Google Cloud Trace でトレースを分析する方法
この Codelab では、マイクロサービスを計測する方法について説明します。理解しやすいように、この例では 3 つのコンポーネント(負荷生成ツール、クライアント、サーバー)のみが含まれていますが、この Codelab で説明した同じプロセスを、より複雑で大規模なシステムに適用できます。
必要なもの
- Python 3 に関する知識
2. 設定と要件
セルフペース型の環境設定
Google アカウント(Gmail または Google Apps)をお持ちでない場合は、1 つ作成する必要があります。Google Cloud Platform のコンソール(console.cloud.google.com)にログインし、新しいプロジェクトを作成します。
すでにプロジェクトが存在する場合は、コンソールの左上にあるプロジェクト選択プルダウン メニューをクリックします。
[新しいプロジェクト] をクリックします。] ボタンをクリックし、新しいプロジェクトを作成します。
まだプロジェクトが存在しない場合は、次のような最初のプロジェクトを作成するためのダイアログが表示されます。
続いて表示されるプロジェクト作成ダイアログでは、新しいプロジェクトの詳細を入力できます。
プロジェクト ID を忘れないようにしてください。プロジェクト ID は、すべての Google Cloud プロジェクトを通じて一意の名前にする必要があります(上記の名前はすでに使用されているため使用できません)。以降、この Codelab では PROJECT_ID と呼びます。
次に、Google Cloud リソースを使用して Cloud Trace API を有効にするために、Cloud Console で課金を有効にします(まだ有効にしていない場合)。
この Codelab をすべて実行しても費用はかかりませんが、より多くのリソースを使用する場合や実行したままにする場合は、コストが高くなる可能性があります(このドキュメントの最後にある「クリーンアップ」セクションをご覧ください)。Google Cloud Trace、Google Kubernetes Engine、Google Artifacat Registry の料金については、公式ドキュメントに記載されています。
- Google Cloud Observability の料金
- 料金 |Kubernetes Engine のドキュメント
- Artifact Registry の料金 |Artifact Registry のドキュメント
Google Cloud Platform の新規ユーザーの皆さんには、$300 の無料トライアルをご利用いただけます。その場合は、この Codelab を完全に無料でご利用いただけます。
Google Cloud Shell のセットアップ
Google Cloud と Google Cloud Trace はノートパソコンからリモートで操作できますが、この Codelab では Cloud 上で動作するコマンドライン環境である Google Cloud Shell を使用します。
この Debian ベースの仮想マシンには、必要な開発ツールがすべて揃っています。永続的なホーム ディレクトリが 5 GB 用意されており、Google Cloud で稼働するため、ネットワークのパフォーマンスと認証が大幅に向上しています。つまり、この Codelab に必要なのはブラウザだけです(はい、Chromebook で動作します)。
Cloud コンソールから Cloud Shell を有効にするには、「Cloud Shell をアクティブにする」アイコン をクリックします(環境のプロビジョニングと接続には少し時間がかかります)。
Cloud Shell に接続すると、すでに認証は完了しており、プロジェクトに各自の PROJECT_ID
が設定されていることがわかります。
gcloud auth list
コマンド出力
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
コマンド出力
[core] project = <PROJECT_ID>
なんらかの理由でプロジェクトが設定されていない場合は、次のコマンドを実行します。
gcloud config set project <PROJECT_ID>
PROJECT_ID
が見つからない場合は、設定手順で使用した ID を確認するか、Cloud コンソール ダッシュボードで確認します。
Cloud Shell では、デフォルトで環境変数もいくつか設定されます。これらの変数は、以降のコマンドを実行する際に有用なものです。
echo $GOOGLE_CLOUD_PROJECT
コマンドの出力
<PROJECT_ID>
最後に、デフォルトのゾーンとプロジェクト構成を設定します。
gcloud config set compute/zone us-central1-f
さまざまなゾーンを選択できます。詳しくは、リージョンとゾーン。
Python の設定
この Codelab では「詩」を使用します。パッケージのバージョンを厳密に管理できます。Cloud Shell で次のコマンドを実行します。
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 - source $HOME/.poetry/env
Google Kubernetes クラスタを設定する
この Codelab では、Google Kubernetes Engine(GKE)でマイクロサービスのクラスタを実行します。この Codelab のプロセスは次のとおりです。
- ベースライン プロジェクトを Cloud Shell にダウンロードする
- マイクロサービスをコンテナに構築する
- Google Artifact Registry(GAR)にコンテナをアップロードする
- GKE にコンテナをデプロイする
- トレース計測用にサービスのソースコードを変更する
- ステップ 2 に進む
Kubernetes Engine を有効にする
まず、Shakesapp が GKE で実行される Kubernetes クラスタを設定するため、GKE を有効にする必要があります。[Kubernetes Engine] メニューに移動します。[有効にする]ボタンを押します
これで、Kubernetes クラスタを作成する準備が整いました。
Kubernetes クラスタを作成する
Cloud Shell で、次のコマンドを実行して Kubernetes クラスタを作成します。ゾーンの値が Artifact Registry リポジトリの作成に使用したリージョンの下にあることを確認してください。リポジトリ リージョンがゾーンをカバーしていない場合は、ゾーン値 us-central1-f
を変更します。
gcloud container clusters create otel-trace-codelab --zone us-central1-f \ --num-nodes 1 \ --machine-type e2-highcpu-4
コマンド出力
Creating cluster otel-trace-codelab in us-central1-f... Cluster is being health-checked (master is healthy)...done. Created [https://container.googleapis.com/v1/projects/psychic-order-307806/zones/us-central1-f/clusters/otel-trace-codelab]. To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1-f/otel-trace-codelab?project=psychic-order-307806 kubeconfig entry generated for otel-trace-codelab. NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS otel-trace-codelab us-central1-f 1.18.12-gke.1210 104.154.162.176 e2-medium 1.18.12-gke.1210 3 RUNNING
Artifact Registry と skaffold の設定
これで、Kubernetes クラスタをデプロイする準備が整いました。次に、push コンテナとデプロイ コンテナ用の Container Registry を準備します。このステップでは、GAR と skaffold を使用するように設定する必要があります。
Artifact Registry の設定
[Artifact Registry] のメニューに移動します。[有効にする]ボタンを押します
しばらくすると、GAR のリポジトリ ブラウザが表示されます。[リポジトリを作成] をクリックしますリポジトリの名前を入力します。
この Codelab では、新しいリポジトリに trace-codelab
という名前を付けます。アーティファクトの形式は「Docker」です。リージョンは「リージョン」ですGoogle Compute Engine のデフォルト ゾーンに設定したリージョンに近いリージョンを選択します。たとえば、この例では「us-central1-f」を選択しています。ここでは「us-central1 (アイオワ)」を選択します。次に [作成]をクリックして] ボタンを離します。
「trace-codelab」というアクセスできます。
後でここに戻ってレジストリパスを確認します。
Skaffold の設定
Skaffold は、Kubernetes 上でマイクロサービスを実行する場合に便利なツールです。小規模なコマンドセットを使用して、アプリケーションのコンテナのビルド、push、デプロイのワークフローを処理します。Skaffold では、デフォルトでコンテナ レジストリとして Docker Registry が使用されるため、コンテナの push 時に GAR を認識するように skaffold を構成する必要があります。
Cloud Shell をもう一度開き、skaffold がインストールされていることを確認します。(Cloud Shell はデフォルトで skaffold を環境にインストールします)。次のコマンドを実行して、skaffold のバージョンを確認します。
skaffold version
コマンド出力
v1.20.0
これで、skaffold が使用するデフォルトのリポジトリを登録できるようになりました。レジストリパスを取得するには、Artifact Registry ダッシュボードに移動し、前のステップで設定したリポジトリの名前をクリックします。
ページの上部にパンくずリストが表示されます。 アイコンをクリックして、レジストリパスをクリップボードにコピーします。
コピーボタンをクリックすると、ブラウザの下部に次のようなダイアログが表示されます。
"us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab"コピーされました
Cloud Shell に戻ります。ダッシュボードからコピーした値を指定して、skaffold config set default-repo
コマンドを実行します。
skaffold config set default-repo us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab
コマンド出力
set value default-repo to us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab for context gke_stackdriver-sandbox-3438851889_us-central1-b_stackdriver-sandbox
また、レジストリを Docker 構成に構成する必要があります。次のコマンドを実行します。
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
コマンド出力
{ "credHelpers": { "gcr.io": "gcloud", "us.gcr.io": "gcloud", "eu.gcr.io": "gcloud", "asia.gcr.io": "gcloud", "staging-k8s.gcr.io": "gcloud", "marketplace.gcr.io": "gcloud", "us-central1-docker.pkg.dev": "gcloud" } } Adding credentials for: us-central1-docker.pkg.dev
これで、GKE で Kubernetes コンテナを設定する次のステップに進むことができました。
概要
このステップでは、Codelab 環境を設定します。
- Cloud Shell を設定する
- Container Registry 用の Artifact Registry リポジトリを作成する
- Container Registry を使用するように skaffold を設定する
- Codelab マイクロサービスが実行される Kubernetes クラスタを作成した
次のステップ
次のステップでは、マイクロサービスを構築、push、クラスタにデプロイします。
3. マイクロサービスのビルド、push、デプロイ
Codelab の資料をダウンロードする
前のステップで、この Codelab のすべての前提条件を設定しました。これで、その上でマイクロサービス全体を実行する準備が整いました。Codelab の資料は GitHub でホストされているため、次の git コマンドを使用して Cloud Shell 環境にダウンロードします。
cd ~ git clone https://github.com/GoogleCloudPlatform/opentelemetry-trace-codelab-python.git
プロジェクトのディレクトリ構造は次のとおりです。
shakesapp-python ├── LICENSE ├── manifests │ ├── client.yaml │ ├── loadgen.yaml │ └── server.yaml ├── proto │ └── shakesapp.proto ├── skaffold.yaml └── src ├── client ├── loadgen └── server
- マニフェスト: Kubernetes マニフェスト ファイル
- proto: クライアントとサーバー間の通信の proto 定義
- src: 各サービスのソースコードのディレクトリ
- skaffold.yaml: skaffold の構成ファイル
skaffold コマンドを実行
これで、作成した Kubernetes クラスタにコンテンツ全体をビルド、push、デプロイする準備が整いました。これは複数のステップを含むように思われますが、実際には skaffold がすべての処理を行います。次のコマンドを使用して試してみましょう。
cd shakesapp-python skaffold run --tail
このコマンドを実行すると、すぐに docker build
のログ出力が表示され、レジストリに正常に push されたことを確認できます。
コマンド出力
... ---> Running in c39b3ea8692b ---> 90932a583ab6 Successfully built 90932a583ab6 Successfully tagged us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step1 The push refers to repository [us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice] cc8f5a05df4a: Preparing 5bf719419ee2: Preparing 2901929ad341: Preparing 88d9943798ba: Preparing b0fdf826a39a: Preparing 3c9c1e0b1647: Preparing f3427ce9393d: Preparing 14a1ca976738: Preparing f3427ce9393d: Waiting 14a1ca976738: Waiting 3c9c1e0b1647: Waiting b0fdf826a39a: Layer already exists 88d9943798ba: Layer already exists f3427ce9393d: Layer already exists 3c9c1e0b1647: Layer already exists 14a1ca976738: Layer already exists 2901929ad341: Pushed 5bf719419ee2: Pushed cc8f5a05df4a: Pushed step1: digest: sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe size: 2001
すべてのサービス コンテナが push されると、Kubernetes の Deployment が自動的に開始されます。
コマンド出力
sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 size: 1997 Tags used in deployment: - serverservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step4@sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe - clientservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/clientservice:step4@sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 - loadgen -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/loadgen:step4@sha256:eea2e5bc8463ecf886f958a86906cab896e9e2e380a0eb143deaeaca40f7888a Starting deploy... - deployment.apps/clientservice created - service/clientservice created - deployment.apps/loadgen created - deployment.apps/serverservice created - service/serverservice created
注意: 「No push access to specified image repository」のようなエラーが表示される場合は、skaffold のデフォルト リポジトリの構成に関係なく、skaffold コマンドがイメージを Docker Hub(docker.io)に push しようとしているかどうかを確認してください。その場合は、「–default-repo」を追加してみてください。「skaffold run」オプション下にあります
$ skaffold run –tail –default-repo=us-central1-docker.pkg.dev/[プロジェクト ID]/[リポジトリ名]
デプロイ後、各コンテナの stdout に出力された実際のアプリケーション ログが次のように表示されます。
コマンド出力
[server] {"event": "starting server: 0.0.0.0:5050", "severity": "info", "timestamp": "2021-03-17T05:25:56.758575Z"} [client] [2021-03-17 05:25:54 +0000] [1] [INFO] Starting gunicorn 20.0.4 [client] [2021-03-17 05:25:54 +0000] [1] [INFO] Listening at: http://0.0.0.0:8080 (1) [client] [2021-03-17 05:25:54 +0000] [1] [INFO] Using worker: threads [client] [2021-03-17 05:25:54 +0000] [7] [INFO] Booting worker with pid: 7 [client] {"event": "server address is serverservice:5050", "severity": "info", "timestamp": "2021-03-17T05:25:54.888627Z"} [client] {"event": "request to server with query: world", "severity": "info", "timestamp": "2021-03-17T05:26:11.550923Z"} [server] {"event": "query: world", "severity": "info", "timestamp": "2021-03-17T05:26:11.567048Z"} [loadgen] {"event": "check connectivity: http://clientservice:8080/_healthz", "severity": "info", "timestamp": "2021-03-17T05:26:11.533605Z"} [loadgen] {"event": "/_healthz response: ok", "severity": "info", "timestamp": "2021-03-17T05:26:11.544267Z"} [loadgen] {"event": "confirmed connection ot clientservice", "severity": "info", "timestamp": "2021-03-17T05:26:11.544527Z"}
これで、サービスの分散トレースのために OpenTelemetry を使用してアプリケーションを計測する準備が整いました。
概要
このステップでは、ご使用の環境で Codelab の資料を準備し、skaffold が想定どおりに実行されることを確認しました。
次のステップ
次のステップでは、loadgen サービスのソースコードを変更して、トレース情報を計測できるようにします。
4. HTTP のインストルメンテーション
トレースの計測と伝播のコンセプト
ソースコードを編集する前に、分散トレースの仕組みを簡単な図で簡単に説明します。
この例では、トレースとスパンの情報を Cloud Trace にエクスポートし、loadgen サービスからサーバー サービスにリクエスト全体でトレース コンテキストを伝播するようにコードをインストルメント化します。
Cloud Trace が同じトレース ID を持つすべてのスパンを 1 つのトレースにまとめるには、アプリケーションがトレース ID やスパン ID などのトレース メタデータを送信する必要があります。また、アプリケーションは、ダウンストリーム サービスのリクエスト時にトレース コンテキスト(親スパンのトレース ID とスパン ID の組み合わせ)を伝播し、処理しているトレース コンテキストを認識できるようにする必要があります。
OpenTelemetry を使用すると、次のことが可能になります。
- スパン ID とトレース ID を生成できます。
- トレース ID とスパン ID をバックエンドにエクスポートします。
- トレース コンテキストを他のサービスに伝播
最初のスパンを計測する
計測負荷生成サービス
Cloud Shell エディタを開くには、Cloud Shell の右上にあるボタン を押します。左側のペインにあるエクスプローラから src/loadgen/loadgen.py
を開き、main
関数を見つけます。
src/loadgen/loadgen.py
def main():
...
# start request loop to client service
logger.info("start client request loop")
addr = f"http://{target}"
while True:
logger.info("start request to client")
call_client(addr)
logger.info("end request to client")
time.sleep(2.0)
main
関数に、call_client
関数を呼び出すループがあります。現在の実装では、sectoin に関数呼び出しの開始と終了を記録する 2 つのログ行があります。次に、Span 情報をインストルメント化して、関数呼び出しのレイテンシを追跡します。
まず、一意のトレース ID とスパン ID を持つスパンを作成する必要があります。OpenTelemetry には、そのための便利なライブラリが用意されています。次の行を追加して、OpenTelemetry ライブラリをコードにインポートします。
import structlog
+from opentelemetry import propagate, trace
+from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
+from opentelemetry.sdk.trace import TracerProvider
+from opentelemetry.instrumentation.requests import RequestsInstrumentor
+from opentelemetry.sdk.trace.export import SimpleSpanProcessor
+from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
負荷生成ツールは requests
モジュールを介して HTTP でクライアント アプリケーションを呼び出すため、requests
の拡張パッケージを使用して計測を有効にします。
from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
+
+RequestsInstrumentor().instrument()
次に、Trace Contenxt とエクスポータの設定を処理する Tracer インスタンスを設定します。
target = os.environ.get("CLIENT_ADDR", "0.0.0.0:8080")
+ exporter = CloudTraceSpanExporter()
+ trace.get_tracer_provider().add_span_processor(SimpleSpanProcessor(exporter))
+ tracer = trace.get_tracer(__name__)
+ propagate.set_global_textmap(CloudTraceFormatPropagator())
+ trace.set_tracer_provider(TracerProvider())
+
# connectivity check to client service
healthz = f"http://{target}/_healthz"
logger.info(f"check connectivity: {healthz}")
これはトレース計測の仕組みを理解するための Codelab であるため、すべてのリクエストを記録してバックエンドに送信するようにトレーサーを構成します。(SimpleSpanProcessor()
)これは本番環境には適していないため、本番環境アプリケーションを計測可能にする場合はこの部分を必ず変更してください。
Tracer でスパンを計測できるようになりました。ここでのポイントは、スパンを明示的に生成する必要があるということです。Span にイベント メタデータを追加する 2 行がありますが、一意のトレース ID とスパン ID を手動で生成して Span に埋め込む必要はありません。
logger.info("start client request loop")
addr = f"http://{target}"
while True:
- logger.info("start request to client")
- call_client(addr)
- logger.info("end request to client")
+ with tracer.start_as_current_span("loadgen") as root_span:
+ root_span.add_event(name="request_start")
+ logger.info("start request to client")
+ call_client(addr)
+ root_span.add_event(name="request_end")
+ logger.info("end request to client")
time.sleep(2.0)
Docker ビルドに必要な OpenTelemetry パッケージを取得するために、次のコマンドを実行します。
poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0" poetry add "opentelemetry-propagator-gcp=^1.0.0rc0" poetry add "opentelemetry-instrumentation-requests=^0.20b0"
対応する依存関係の説明が pyproject.toml
に記述されていることを確認できます。
クライアント サービスを計測する
前のセクションでは、下の図の赤い長方形で囲まれた部分をインストルメント化しました。負荷生成サービスでスパン情報を計測可能にしました。負荷生成サービスと同様に、クライアント サービスをインストルメント化する必要があります。負荷生成サービスとの違いは、クライアント サービスが HTTP ヘッダー内の負荷生成サービスから伝播したトレース ID 情報を抽出し、その ID を使用してスパンを生成することです。
負荷生成ツールのサービスの場合と同様に、Cloud Shell エディタを開き、必要なモジュールを追加します。
src/client/client.py
import flask
import grpc
import structlog
+from opentelemetry import propagate, trace
+from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
+from opentelemetry.instrumentation.flask import FlaskInstrumentor
+from opentelemetry.sdk.trace import TracerProvider
+from opentelemetry.sdk.trace.export import SimpleSpanProcessor
+from opentelemetry.propagators.cloud_trace_propagator import \
+ CloudTraceFormatPropagator
import shakesapp_pb2
import shakesapp_pb2_grpc
FlaskInstrumentor
をインポートしたところ、ユーザーに代わって Flask アプリケーションの自動計測が有効になり、HTTP ヘッダーを抽出して 1 行のコードでトレース コンテキストを取得できることがわかります。OpenTelemetry コミュニティには、他の主要なライブラリとの同様の便利な統合が用意されています。詳しくは、公式ドキュメントをご覧ください。
app = flask.Flask(__name__)
+FlaskInstrumentor().instrument_app(app)
計測を開始する前に、負荷生成ツールのサービスと同様に、Tracer インスタンスを準備する必要があります。
logger.info(f"server address is {SERVER_ADDR}")
+exporter = CloudTraceSpanExporter()
+trace.get_tracer_provider().add_span_processor(SimpleSpanProcessor(exporter))
+propagate.set_global_textmap(CloudTraceFormatPropagator())
+trace.set_tracer_provider(TracerProvider())
@app.route("/")
def main_handler():
....
これで、ハンドラにインストルメンテーションを追加する準備が整いました。main_handler()
を見つけて、サーバー サービスに gRPC リクエストをスローする部分を変更します。
@app.route("/")
def main_handler():
q, count = random.choice(list(queries.items()))
# get Tracer
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("client") as cur_span:
channel = grpc.insecure_channel(SERVER_ADDR)
stub = shakesapp_pb2_grpc.ShakespeareServiceStub(channel)
logger.info(f"request to server with query: {q}")
cur_span.add_event("server_call_start")
resp = stub.GetMatchCount(shakesapp_pb2.ShakespeareRequest(query=q))
cur_span.add_event("server_call_end")
if count != resp.match_count:
raise UnexpectedResultError(
f"The expected count for '{q}' was {count}, but result was {resp.match_count } obtained"
)
result = str(resp.match_count)
logger.info(f"matched count for '{q}' is {result}")
return result
負荷生成サービスと同様に、次のコマンドを使用して必要なパッケージを pyproject.toml
に追加します。
poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0" poetry add "opentelemetry-propagator-gcp=^1.0.0rc0" poetry add "opentelemetry-instrumentation-flask=^0.20b0"
次に、skaffold run
コマンドを使用してアプリケーションを起動し、Cloud Trace ダッシュボードに何が表示されるかを確認します。
skaffold run --tail
ビルド、push、デプロイのメッセージが表示されると、アプリケーション ログが JSON 形式で表示されます。Cloud Trace に移動する >トレース情報を取得できるかどうかを確認するトレースリスト。負荷生成サービスはクライアント サービスに定期的にリクエストを送信し、すべてのリクエストのトレースを有効にしているため、トレースリストに多くのドットが表示されます。
いずれかをクリックすると、以下のようなウォーターフォール グラフが表示され、リクエストとレスポンスのプロセスにおける各部分のレイテンシを確認できます。[イベントを表示] の横にあるチェックボックスをオンにすると、ウォーターフォール グラフ内にアノテーションが表示されます。これらのアノテーションは、span.add_event()
メソッドによってコード内にインストルメント化されたものです。
サーバー サービスのスパンが表示されない場合があります。正解です。サーバー サービスでスパンを計測することはできません。
概要
このステップでは、負荷生成サービスとクライアント サービスを計測可能にし、サービス間でトレース コンテキストを正常に伝播し、両方のサービスから Cloud Trace にスパン情報をエクスポートできることを確認しました。
次のステップ
次のステップでは、クライアント サービスとサーバー サービスを計測して、gRPC を介してトレース コンテキストを伝播する方法を確認します。
5. gRPC のインストルメンテーション
前のステップでは、リクエストの前半をこのマイクロサービスに計測しました。このステップでは、クライアント サービスとサーバー サービス間の gRPC 通信を計測します。(下の画像の緑色と紫色の長方形)。
gRPC クライアントの自動計測
OpenTelemetry のエコシステムには、デベロッパーがアプリケーションを計測する際に役立つライブラリが多数用意されています。前のステップでは、「requests」に対して自動計測を使用しました。説明します。このステップでは、gRPC を介してトレース コンテキストを伝播するため、そのライブラリを使用します。
src/client/client.py
import flask
import grpc
import structlog
from opentelemetry import propagate, trace
from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
from opentelemetry.instrumentation.flask import FlaskInstrumentor
+from opentelemetry.instrumentation.grpc import GrpcInstrumentorClient
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
from opentelemetry.propagators.cloud_trace_propagator import \
CloudTraceFormatPropagator
import shakesapp_pb2
import shakesapp_pb2_grpc
app = flask.Flask(__name__)
FlaskInstrumentor().instrument_app(app)
+GrpcInstrumentorClient().instrument()
クライアント サービスの場合、計測用に行う必要がある操作はごくわずかです。これから、gRPC を介して現在の Span のトレース ID とスパン ID を組み合わせたトレース コンテキストを伝播します。そのため、ハンドラ関数の gRPC クライアントが、その下の HTTP ヘッダーにトレース コンテキストを埋め込むことができるように、GrpcInstrumentatorClient.instrument()
を呼び出します。
poetry add
コマンドを使用して、新しい依存関係を pyproject.toml
に追加します。
poetry add "opentelemetry-instrumentation-grpc=^0.20b0"
gRPC サーバーの自動計測
gRPC クライアントの場合と同様に、gRPC サーバーの自動計測と呼んでいます。次のようなインポートを追加し、ファイルの先頭で GrpcInstrumentationServer().instrument()
を呼び出します。
注意: 必ず呼び出してください
GrpcInstrumentationServe()
このステップでは、
GrpcInstrumentationClient()
.
src/server/server.py
import grpc
import structlog
from google.cloud import storage
from grpc_health.v1 import health_pb2, health_pb2_grpc
+from opentelemetry import propagate, trace
+from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
+from opentelemetry.instrumentation.grpc import GrpcInstrumentorServer
+from opentelemetry.sdk.trace import TracerProvider
+from opentelemetry.sdk.trace.export import SimpleSpanProcessor
+from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
import shakesapp_pb2
import shakesapp_pb2_grpc
BUCKET_NAME = "dataflow-samples"
BUCKET_PREFIX = "shakespeare/"
+# enable auto gRPC server trace instrumentation
+GrpcInstrumentorServer().instrument()
+
次に、トレース情報を Cloud Trace バックエンドに送信するエクスポータを追加します。serve()
関数に次のコードを追加します。
def serve():
+ # start trace exporter
+ trace.set_tracer_provider(TracerProvider())
+ trace.get_tracer_provider().add_span_processor(
+ SimpleSpanProcessor(CloudTraceSpanExporter())
+ )
+ propagators.set_global_textmap(CloudTraceFormatPropagator())
+
+ # add gRPC services to server
server = grpc.server(futures.ThreadPoolExecutor(max_workers=4))
service = ShakesappService()
shakesapp_pb2_grpc.add_ShakespeareServiceServicer_to_server(service, server)
health_pb2_grpc.add_HealthServicer_to_server(service, server)
新しく追加したパッケージをサーバー サービスに追加してください。
poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0" poetry add "opentelemetry-instrumentation-grpc=^0.20b0" poetry add "opentelemetry-propagator-gcp=^1.0.0rc0" poetry add "opentelemetry-instrumentation=^0.20b0"
マイクロサービスを実行してトレースを確認する
次に、変更したコードを skaffold コマンドを使用して実行します。
skaffold run --tail
ここでも、Cloud Trace のトレースリスト ページに多数のトレースが表示されます。いずれかのトレースをクリックすると、負荷生成サービスからサーバー サービスへのリクエストにまたがっていることがわかります。
概要
このステップでは、OpenTelemetry エコシステム ライブラリのサポートを利用して、gRPC ベースの通信を計測しました。また、負荷生成サービスで生成されたトレース コンテキストがサーバー サービスに正常に配信されていることも確認しました。
6. 完了
OpenTelemery を使用して分散トレースを作成し、Google Cloud Trace でマイクロサービス全体のリクエストのレイテンシを確認できました。
より長い演習が必要な場合は、以下のトピックをご自身で試してください。
- 現在の実装では、ヘルスチェックによって生成されたすべてのスパンが送信されます。Cloud Trace からこうしたスパンを除外するには、どうすればよいでしょうか。こちらのヒントをご覧ください。
- イベントログをスパンと関連付けて、Google Cloud Trace と Google Cloud Logging でどのように機能するかを確認する。こちらのヒントをご覧ください。
- 一部のサービスを別の言語のサービスに置き換えて、その言語の OpenTelemetry で計測してみる
注意: Google Kubernetes Engine と Google Artifact Registry は、このリソースを常に消費します。
クリーンアップ
この Codelab の後、Google Kubernetes Engine、Google Cloud Trace、Google Artifact Registry で予期しない請求が発生しないように、Kubernetes クラスタを停止し、プロジェクトを削除してください。
まず、次のコマンドを使用してクラスタを削除します。
skaffold delete
コマンド出力
Cleaning up... - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
クラスタを削除したら、メニューペインで [IAM と管理>[設定]、[シャットダウン] の順にクリックします] ボタンを離します。
次に、ダイアログのフォームに(プロジェクト名ではなく)プロジェクト ID を入力し、シャットダウンを確認します。