Pub/Sub 経由で Google Cloud ログにアクセスする
Cloud Logging シンクを使用してアプリケーション ログをフィルタリングし、Pub/Sub、Cloud Run、DataKit を通じて Guance に送信します。この記事では、プライベート ネットワーク ホストにデプロイされたスタンドアロン DataKit を使用しており、GKE は必要ありません。フォワーダーは jsonPayload および textPayload をサポートしますが、監査ログ protoPayload はサポートしません。
Cloud Logging シンク → Pub/Sub → Cloud Run Forwarder → Private DataKit → Guance。
トランスポンダのソースコードとREADME は、Apache License 2.0 に基づいて公開されています。 DataWay のアドレスとトークンは DataKit にのみ保存され、フォワーダーはこれらの資格情報を必要としません。
準備¶
- Cloud Shell を使用するか、
gcloudと Git をインストールして Google Cloud にログインします。プロジェクトでは課金を有効にする必要があります。 - 現在のアカウントには、API の有効化、サービス アカウントの作成、ログの読み取りと書き込み、シンク、Pub/Sub、ファイアウォール ルールの管理、Cloud Run のデプロイ、IAM の構成を行うための権限が必要です。また、以下で作成するアカウントのビルド、実行、プッシュに対する
iam.serviceAccounts.actAs権限も必要です。 - Cloud Run が配置されているリージョンに
/26以上の VPC サブネットを準備し、プライベート ネットワーク経由で DataKit ホストにアクセスできるようにします。ネットワーク要件については、Direct VPC egress を参照してください。 - ファイアウォールの例では、同じプロジェクトの同じ VPC 内の Compute Engine 仮想マシンを使用します。他のプライベート ネットワーク ホストを使用する場合は、最初にネットワーク管理者に対応するルーティング ルールとファイアウォール ルールを構成してもらいます。
次の変数を置き換えます。すべての gcloud コマンドは同じ端末で実行され、DataKit のインストールと構成はホスト マシン上で完了します。この例では、同じプロジェクト内に新しいリソースを作成します。空いている名前を使用するか、記事内のリソース名を統一して変更してください。
PROJECT_ID="my-project"
REGION="us-central1"
NETWORK="my-vpc"
SUBNET="cloud-run-subnet"
DATAKIT_IPV4="10.0.1.10"
DATAKIT_VM="datakit-vm"
DATAKIT_ZONE="us-central1-a"
gcloud services enable run.googleapis.com pubsub.googleapis.com \
logging.googleapis.com cloudbuild.googleapis.com artifactregistry.googleapis.com \
compute.googleapis.com iam.googleapis.com --project "$PROJECT_ID"
PROJECT_NUMBER=$(gcloud projects describe "$PROJECT_ID" --format='value(projectNumber)')
1. DataKit の設定¶
Guance ワークスペースからインストール コマンドを取得し、プライベート ネットワーク ホスト DataKitをインストールする で実行します。ホストは、ワークスペースに対応する DataWay アドレスにアクセスできる必要があります。
datakit.conf で、[http_api] の既存のリスニング アドレスをホストのプライベート IPv4 アドレスに変更します。
このアドレスは DATAKIT_IPV4 と一致している必要があります。 DataKitを再起動します を保存した後。 TCP 9529 は、Cloud Run サブネットと指定された管理ソースからのアクセスのみを許可し、パブリック ネットワークには公開しません。
ターゲット タグを Compute Engine VM に追加し、Cloud Run サブネットを許可します。
SUBNET_CIDR=$(gcloud compute networks subnets describe "$SUBNET" \
--project "$PROJECT_ID" --region "$REGION" --format='value(ipCidrRange)')
gcloud compute instances add-tags "$DATAKIT_VM" \
--project "$PROJECT_ID" --zone "$DATAKIT_ZONE" --tags pubsub-datakit
gcloud compute firewall-rules create allow-pubsub-datakit \
--project "$PROJECT_ID" --network "$NETWORK" --direction INGRESS \
--action ALLOW --rules tcp:9529 --target-tags pubsub-datakit \
--source-ranges "${SUBNET_CIDR:?Subnet CIDR is required}"
ホスト ファイアウォールが有効になっている場合は、同じサブネットを許可し、既存のルールで他のソースが許可されているかどうかを確認する必要もあります。 DataKit ホストで次のコマンドを実行してリスニングを確認し、例の IP を置き換えます。 HTTP 200 を返すことが期待されています。ステップ 5 では、Cloud Run の DataKit への接続を確認します。
フォワーダーは、ログストリーミング コレクターをさらに開かずに、/v1/write/logging を通じて JSON レコードを書き込みます。宛先アドレスは、10.0.0.0/8、172.16.0.0/12、または 192.168.0.0/16 ネットワーク セグメント内にある必要があります。
2. フォワーダーのデプロイ¶
gcloud が実行されたターミナルに戻り、ビルド、実行、プッシュのアカウントをそれぞれ作成します。 roles/run.builder のみをビルド アカウントに付与し、デプロイ時に明示的に指定します。導入担当者に必要な権限については、「サービスアカウントを作成する」を参照してください。
gcloud iam service-accounts create forwarder-build --project "$PROJECT_ID"
gcloud iam service-accounts create forwarder-run --project "$PROJECT_ID"
gcloud iam service-accounts create forwarder-push --project "$PROJECT_ID"
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
--member "serviceAccount:forwarder-build@${PROJECT_ID}.iam.gserviceaccount.com" \
--role roles/run.builder
git clone https://github.com/TrueWatchTech/google-cloud-log-forwarder.git
cd google-cloud-log-forwarder
cat > env.yaml <<EOF
DATAKIT_URL: "http://${DATAKIT_IPV4}:9529/v1/write/logging"
EXPECTED_PROJECT_ID: "${PROJECT_ID}"
EXPECTED_SUBSCRIPTION: "projects/${PROJECT_ID}/subscriptions/application-logs-push"
MEASUREMENT: "gcp_pubsub"
EOF
gcloud run deploy pubsub-log-forwarder \
--source . --project "$PROJECT_ID" --region "$REGION" \
--no-allow-unauthenticated \
--build-service-account "projects/${PROJECT_ID}/serviceAccounts/forwarder-build@${PROJECT_ID}.iam.gserviceaccount.com" \
--service-account "forwarder-run@${PROJECT_ID}.iam.gserviceaccount.com" \
--network "$NETWORK" --subnet "$SUBNET" --vpc-egress private-ranges-only \
--cpu 1 --memory 512Mi --min-instances 0 --max-instances 1 --concurrency 1 \
--env-vars-file env.yaml
デプロイが成功し、サービス URL が表示されるまで待ちます。認可の直後に権限エラーが発生した場合は、IAM の変更が有効になるまで数分間待ってから、デプロイメント コマンドを実行してください。 env.yaml に認証情報を追加しないでください。上記の CPU、メモリ、およびインスタンスの番号は単なる開始構成であり、運用環境で測定された最小仕様ではないため、実際の負荷テストに基づいて調整する必要があります。
3. 認証付きプッシュの設定¶
この Cloud Run サービスに対する呼び出し者権限のみを付与します。 Pub/Sub サービス プロキシが作成されていることを確認し、プッシュ アカウントのトークンの作成を許可してから、サブスクリプションを作成します。
SERVICE_URL=$(gcloud run services describe pubsub-log-forwarder \
--project "$PROJECT_ID" --region "$REGION" --format='value(status.url)')
gcloud run services add-iam-policy-binding pubsub-log-forwarder \
--project "$PROJECT_ID" --region "$REGION" \
--member "serviceAccount:forwarder-push@${PROJECT_ID}.iam.gserviceaccount.com" \
--role roles/run.invoker
gcloud pubsub topics create application-logs --project "$PROJECT_ID"
gcloud beta services identity create \
--service pubsub.googleapis.com --project "$PROJECT_ID"
gcloud iam service-accounts add-iam-policy-binding \
"forwarder-push@${PROJECT_ID}.iam.gserviceaccount.com" \
--project "$PROJECT_ID" \
--member "serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com" \
--role roles/iam.serviceAccountTokenCreator
gcloud pubsub subscriptions create application-logs-push \
--project "$PROJECT_ID" --topic application-logs --ack-deadline 60 \
--push-endpoint "${SERVICE_URL}/pubsub" \
--push-auth-service-account "forwarder-push@${PROJECT_ID}.iam.gserviceaccount.com" \
--push-auth-token-audience "$SERVICE_URL"
ペイロードのラップ解除をオフに保つため、フォワーダーは完全な Pub/Sub JSON メッセージのカプセル化を必要とします。 OIDC トークンは Cloud Run によって検証され、ID 認証と Invoker IAM チェックをオンにする必要があります。詳細については、「認証プッシュの要件」を参照してください。
4. テスト用 Sink の作成¶
まず、テスト中に無関係なログが転送されないように、専用のログ ID pubsub-guide-demo にのみアクセスします。
gcloud logging sinks create application-logs \
"pubsub.googleapis.com/projects/${PROJECT_ID}/topics/application-logs" \
--project "$PROJECT_ID" \
--log-filter="logName=\"projects/${PROJECT_ID}/logs/pubsub-guide-demo\" AND (jsonPayload:* OR textPayload:*)"
SINK_WRITER=$(gcloud logging sinks describe application-logs \
--project "$PROJECT_ID" --format='value(writerIdentity)')
gcloud pubsub topics add-iam-policy-binding application-logs \
--project "$PROJECT_ID" --member "$SINK_WRITER" --role roles/pubsub.publisher
シンクの構成が完了すると、条件を満たす新しいログが送信され、過去のログは再生されません。まず次のサンプル検証を完了してから、実際のアプリケーション ログを選択します。詳細については、「ログルーティング」を参照してください。
5. ログの取り込みの確認¶
JSON とプレーン テキストのログをテスト ログに書き込みます。
TEST_ID="pubsub-$(date -u +%Y%m%dT%H%M%SZ)"
gcloud logging write pubsub-guide-demo \
"{\"message\":\"${TEST_ID}-json\"}" \
--payload-type=json --severity=INFO --project "$PROJECT_ID"
gcloud logging write pubsub-guide-demo "${TEST_ID}-text" \
--payload-type=text --severity=INFO --project "$PROJECT_ID"
テスト ログとフォワーダー処理レコードを読み取ります。
gcloud logging read \
"logName=\"projects/${PROJECT_ID}/logs/pubsub-guide-demo\" AND SEARCH(\"${TEST_ID}\")" \
--project "$PROJECT_ID" --freshness=1h --limit=10 --format=json
gcloud logging read \
"resource.type=\"cloud_run_revision\" AND resource.labels.service_name=\"pubsub-log-forwarder\" AND resource.labels.location=\"${REGION}\" AND jsonPayload.receipt:*" \
--project "$PROJECT_ID" --freshness=1h --limit=20 --format=json
- 最初のコマンドは 2 つのテスト ログを返します。それぞれの
insertId、timestamp、およびログの内容に注意してください。まだ結果がない場合は、しばらく待ってからもう一度試してください。 - 2 番目のコマンドによって返された
jsonPayloadで対応するgoogle_insert_idを見つけ、http_statusが 204 であり、datakit_statusが 2xx であることを確認します。失敗した場合は、reasonおよび FAQ の表に従ってトラブルシューティングを行ってください。 - Guance の ログ ページで、ソース
gcp_pubsubと対象となるテスト時間の範囲を選択し、google_insert_idを押してそれぞれレコードを検索します。 - 2 つのレコードのメッセージの内容が正しいこと、および
log_timestampが元の時刻と一致していることを確認します。 JSONログのmessageはJSON文字列であり、プレーンテキストログは元のテキストを保持します。
Cloud Run が 204 を返したり、DataKit が 2xx を返したりしても、データベースに保存されていることを意味するものではありません。 Guance で 2 つのログを見つける必要があります。運用環境で使用する前に、スループット、信頼性、リソース仕様、およびアプリケーションのオーバーヘッドを実際の負荷の下でテストする必要があります。
6. 実際のアプリケーションログへの切り替え¶
Cloud Logging でアプリケーション ログをクエリできることを確認し、テスト フィルタ条件を置き換えます。次の GKE の例では、アプリケーション コンテナの stdout と stderr にのみアクセスします。ビジネス コンテナのみを選択し、DataKit を除外するには、クラスター、名前空間、およびコンテナーの名前を置き換えてください。 k8s_container 条件では Cloud Run フォワーダーも除外されます。
APP_FILTER=$(cat <<'EOF'
resource.type="k8s_container"
resource.labels.cluster_name="my-cluster"
resource.labels.namespace_name="my-namespace"
resource.labels.container_name="my-app"
(log_id("stdout") OR log_id("stderr"))
(jsonPayload:* OR textPayload:*)
EOF
)
gcloud logging read "$APP_FILTER" \
--project "$PROJECT_ID" --freshness=1h --limit=5 --format=json
クエリ結果に予期されるアプリケーション ログのみが含まれていることを確認します。結果がない場合は、まずアプリケーションにログを生成させ、ログ エクスプローラーでフィルターを確認します。 GKE 以外のアプリケーションは、代わりに対応するリソース タイプとアプリケーション タグを使用する必要があります。確認後にシンクを更新します。
更新が有効になったら、アプリケーションで新しいログを生成し、APP_FILTER を使用して Cloud Logging でログを検索し、ステップ 5 に従って、Guance のレコードで ID、時刻、メッセージの内容を確認します。現時点では、pubsub-guide-demo テスト ログはシンクと一致しなくなります。フィルター スコープでは、転送ループを避けるために、フォワーダーと DataKit 自体のログを常に除外する必要があります。
フィールドのマッピング¶
各 Cloud Logging ログは DataKit ログに変換されます。デフォルトのソースは gcp_pubsub で、MEASUREMENT によって設定されます。
| Cloud Logging のコンテンツ | DataKitのコンテンツ |
|---|---|
jsonPayload または textPayload |
message: コンパクトな JSON 文字列または生のテキスト |
timestamp |
Unix ナノ秒の記録時間と元の文字列を log_timestamp に保存 |
receiveTimestamp |
存在する場合は receive_timestamp を書き込みます |
insertId |
タグ google_insert_id |
logName のプロジェクト ID |
タグ project、EXPECTED_PROJECT_ID と一致する必要があります |
logNameのログID |
タグ log_name、URL デコード済み |
resource.type |
タグ resource_type、またはない場合は unknown |
severity |
タグ severity およびフィールド status |
status では、DEFAULT および INFO は info に、EMERGENCY は emerg に変換され、その他のレベルは小文字に変換されます。 JSON コンテンツは、独立したフィールドに自動的に展開されず、リsource ラベルはマップされません。
よくある質問¶
| 現象 | チェック項目 |
|---|---|
| Cloud Run のデプロイに失敗しました | ビルド権限、サブネットゾーン、残りのアドレス |
| プッシュすると 401 または 403 が返されます | プッシュサービスアカウント、サービスレベルの呼び出し側権限、OIDC オーディエンス、およびトークン作成権限。フォワーダーが 403 を返した場合は、reason、EXPECTED_PROJECT_ID、EXPECTED_SUBSCRIPTION も確認する必要があります。 |
| フォワーダーは 400 または 413 を返します | ログのタイプとサイズ、必要な insertId、logName、timestamp、およびペイロード アンラップ設定 |
| フォワーダーは 502 を返します | DataKit リスニング アドレス、VPC ルート、TCP 9529 ファイアウォール ルール、および DataKit 書き込み応答 |
| ワークスペースにログがありません | シンク フィルターと公開権限、サブスクリプションの配信ステータス、DataKit から DataWay への接続、ワークスペースとクエリの時間範囲 |
プッシュ リクエストの本文は 1 MiB に制限され、変換されたレコードは 512 KiB に制限されます。 Pub/Sub は少なくとも 1 回の配信を使用するため、再試行すると重複レコードが生成される可能性があります。 google_insert_id は関連付けを容易にするために保持されますが、自動的には重複排除されません。
未確認のメッセージは、サブスクリプションの保持期間を超えると期限切れになる場合があります。サブスクリプションのバックログを監視し、繰り返し配信に失敗するメッセージを処理するために、必要に応じて デッドレターのトピック を構成する必要があります。