ログのクエリと表示

Google Distributed Cloud(GDC)エアギャップのログクエリを使用すると、ログを収集した後に、プロジェクト ワークロード全体の運用イベントと監査イベントを検査できます。Grafana ログパネルで、Log Query Language(LogQL)式を使用してログストリームをフィルタ、可視化、エクスポートできます。プログラムによるワークフローの場合は、標準の API アクセス方法に従って、HTTP または gRPC 経由で組織の Log Query API にクエリを実行します。

始める前に

ログをクエリして可視化するには、必要な権限が必要です。

IAM 組織ロールをリクエストする

IAM 組織管理者に連絡して、次のロールをリクエストしてください。

  • 組織 Grafana 閲覧者(organization-grafana-viewer): Grafana モニタリング インスタンスのダッシュボードで、組織に関連するオブザーバビリティ データを可視化します。
  • ログクエリ(log-query-api-querier-pa): Log Query API にアクセスして、platform-obs プロジェクトのプラットフォーム ログをクエリします。

IAM プロジェクト ロールをリクエストする

IAM プロジェクト管理者に連絡して、次のロールをリクエストしてください。

  • プロジェクト Grafana 閲覧者(project-grafana-viewer): プロジェクトの名前空間にある Grafana モニタリング インスタンスのダッシュボードで、プロジェクト関連のオブザーバビリティ データを可視化します。
  • ログクエリ(log-query-api-querier): Log Query API にアクセスして、プロジェクトの名前空間内のアプリケーション ログをクエリします。

次の表に、PA と AO のペルソナの Role 要件をまとめます。

ペルソナ オブジェクト クラスタ ロール 名前空間 グループ / ユーザー
PA grafana 管理 API サーバー project-grafana-viewer platform-obs グループ
PA log-query-api 管理 API サーバー log-query-api-querier-pa platform-obs グループ
PA grafana 管理 API サーバー project-grafana-viewer platform-obs ユーザー
PA log-query-api 管理 API サーバー log-query-api-querier-pa platform-obs ユーザー
AO grafana 管理 API サーバー project-grafana-viewer PROJECT_NAMESPACE グループ
AO log-query-api 管理 API サーバー log-query-api-querier PROJECT_NAMESPACE グループ
AO grafana 管理 API サーバー project-grafana-viewer PROJECT_NAMESPACE ユーザー
AO log-query-api 管理 API サーバー log-query-api-querier PROJECT_NAMESPACE ユーザー

次のいずれかの構成を選択して、管理 API サーバーのユーザー グループ(Config 1)または個々のユーザー(Config 2)に Grafana へのアクセス権を付与します。構成ごとに、kubectl コマンドを実行して RoleBinding を直接作成するか、RoleBinding YAML マニフェストを指定された Infrastructure as Code(IaC)ファイルパスに保存して GitOps を介して適用できます。

構成 1

この構成では、Management API サーバー上の PA と AO Grafana にアクセスする権限をユーザー グループに付与します。この構成を設定したら、このドキュメントの Grafana ダッシュボード セクションを参照して、Grafana でログを表示します。

  • kubectl コマンド

    次のコマンドを実行して、RoleBinding を直接作成します。

    kubectl --kubeconfig KUBECONFIG create rolebinding RULE_NAME -n platform-obs --group=GROUP_NAME --role=project-grafana-viewer
    

    例:

    kubectl --kubeconfig KUBECONFIG_PATH create rolebinding project-grafana-viewers-binding --role=project-grafana-viewer --group=my-team --namespace=platform-obs
    
  • IaC ファイルパス

    または、IaC を使用して RoleBinding を管理するには、次のパスに YAML ファイルを作成します。

    /infrastructure/zonal/zones/ZONE/org-admin/rolebindings/GROUP_NAME/YAML_FILE
    
  • YAML ファイル

    次の RoleBinding マニフェストを IaC ファイルパスの YAML ファイルに保存します。

    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: RULE_NAME
      namespace: platform-obs
    subjects:
    - kind: Group
      name: GROUP_NAME
      apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: Role
      name: project-grafana-viewer
      apiGroup: rbac.authorization.k8s.io
    

構成 2

この構成により、ユーザーは Management API サーバー上の PA と AO Grafana にアクセスする権限が付与されます。この構成を設定したら、このドキュメントの Grafana ダッシュボード セクションを参照して、Grafana でログを表示します。

  • kubectl コマンド

    次のコマンドを実行して、RoleBinding を直接作成します。

    kubectl --kubeconfig KUBECONFIG create rolebinding RULE_NAME -n platform-obs --user=EMAIL_ADDRESS --role=project-grafana-viewer
    

    例:

    kubectl --kubeconfig KUBECONFIG_PATH create rolebinding project-grafana-viewers-binding --role=project-grafana-viewer --user=my-email@example.com --namespace=platform-obs
    
  • IaC ファイルパス

    または、IaC を使用して RoleBinding を管理するには、次のパスに YAML ファイルを作成します。

    /infrastructure/zonal/zones/ZONE/org-admin/rolebindings/EMAIL_ADDRESS/YAML_FILE
    
  • YAML ファイル

    次の RoleBinding マニフェストを IaC ファイルパスの YAML ファイルに保存します。

    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: RULE_NAME
      namespace: platform-obs
    subjects:
    - kind: User
      name: EMAIL_ADDRESS
      apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: Role
      name: project-grafana-viewer
      apiGroup: rbac.authorization.k8s.io
    

次のように置き換えます。

  • KUBECONFIG: この RoleBinding が適用される NAMESPACE を含む特定のクラスタの kubeconfig ファイルのパス。
  • KUBECONFIG_PATH: サンプル コマンドの kubeconfig ファイルのパス。
  • RULE_NAME: Namespace 内のこの RoleBinding リソースの一意の名前(pa-project-grafana-viewer など)。
  • NAMESPACE: この RoleBinding が作成され、適用される Kubernetes Namespace。前の表の Namespace 列を探します。
  • EMAIL_ADDRESS: ロールを付与するユーザーの ID(application-operator@example.com など)。
  • ROLE: ユーザーに付与する権限を含む Role の名前。前の表で使用可能なロールを探します。
  • GROUP_NAME: PA ユーザーが属する Group の名前(pa-group など)。
  • ZONE: ゾーンの名前。
  • YAML_FILE: RoleBinding リソースの YAML ファイルの名前。

これらのロールの詳細については、IAM 権限を準備するをご覧ください。

ログのクエリとフィルタ

次のいずれかの方法を選択して、クエリを作成し、プロジェクト ワークロードからログをフィルタします。

Grafana ログパネル

このセクションでは、Grafana の [Log] パネルを使用してログにアクセスする方法について説明します。

Grafana エンドポイントを特定する

次の URL は、プロジェクトの Grafana インスタンスのエンドポイントです。

  https://GDC_URL/PROJECT_NAMESPACE/grafana

次のように置き換えます。

  • GDC_URL: GDC の組織の URL。
  • PROJECT_NAMESPACE: プロジェクトの名前空間。

    たとえば、org-1 組織の platform-obs プロジェクトの Grafana エンドポイントは https://org-1/platform-obs/grafana です。

Grafana ユーザー インターフェースでログを表示する

Grafana ユーザー インターフェースでログをクエリします。

  1. GDC コンソールで、プロジェクトを選択します。
  2. ナビゲーション メニューで、[オペレーション] > [ロギング] を選択します。
  3. [View all in Grafana Loki] をクリックします。

    新しいページが開き、Grafana エンドポイントとユーザー インターフェースが表示されます。

  4. ユーザー インターフェースで、ナビゲーション メニューから explore [Explore] をクリックして、[Explore] ページを開きます。

  5. [Explore] バーのメニューから、ユニバース タイプに応じて、ログを取得するデータソースを選択します。

    • シングルゾーン ユニバース: 次のいずれかのデータソースを選択して、ユニバースのシングルゾーンのロギングデータを表示します。

      • オペレーション ログ: オペレーション ログを表示します。
      • 監査ログ: 監査ログを表示します。
    • マルチゾーン ユニバース: Grafana は、異なるゾーンに接続して、ゾーン間のデータを表示できます。次のいずれかのデータソースを選択して、ログインしているゾーンに関係なく、ユニバースの任意のゾーンのロギングデータを表示します。

      • オペレーション ログ ZONE_NAME: 特定のゾーンのオペレーション ログを表示します。
      • 監査ログ ZONE_NAME: 特定のゾーンの監査ログを表示します。

      また、1 つのダッシュボードでゾーン間のデータ可視化を行い、クエリに複数のゾーンを追加するには、データソースとして [混合] を選択します。

  6. LogQL(Log Query Language)式を使用して、[ログ] パネルからログを検索するクエリを入力します。この手順は、次のいずれかの方法で行います。

    • インタラクティブなクエリビルダー インターフェースを使用します。[クエリを実行] をクリックします。
    • テキスト フィールドにクエリを直接入力し、Shift+Enter キーを押してクエリを実行します。

    クエリに一致するログがページに表示されます。ログをクエリした後、ログをエクスポートできます。[エクスポート] をクリックして、ログを書式なしテキスト形式または CSV 形式でダウンロードします。ログの期間を選択することもできます。

    監査ログを取得するために、[Explore] ページで [Audit logs] オプションが選択されている。

    図 1. Grafana ユーザー インターフェースから監査ログをクエリするメニュー オプション。

    図 1 の [監査ログ] オプションには、Grafana からクエリを作成して監査ログを取得できるインターフェースが表示されます。

    さまざまなログをクエリするためのラベルと値の例については、サンプルクエリとラベルをご覧ください。

ログの期間を選択する

特定の期間のログをクエリする手順は次のとおりです。

  1. Grafana で [Time Picker] メニューをクリックします。

  2. メニューから、次のいずれかの操作を行います。

    • 相対的な期間オプション(過去 30 分など)を選択します。
    • カレンダーから特定の日時を選択し、[期間を適用] をクリックして、カスタムの絶対期間を設定します。
  3. 必要に応じて、[時間設定を変更] をクリックし、期間コントロールから [タイムゾーン] と [会計年度] の設定を変更します。

    時間設定はダッシュボードごとに保存されます。一定期間にわたるクエリの詳細については、https://grafana.com/docs/loki/latest/reference/api/#query-loki-over-a-range-of-time をご覧ください。

Log Query API

このセクションでは、Log Query API を使用してログにアクセスする方法について説明します。

Log Query API エンドポイントを特定する

Log Query API は、監査ログと運用ログをクエリするために、次の 2 つのエンドポイントを公開します。

  • 監査ログ エンドポイント:

    audit-log-query-api.ORG_DOMAIN
    
  • オペレーション ログのエンドポイント:

    operational-log-query-api.ORG_DOMAIN
    

ORG_DOMAIN は、組織のドメイン名に置き換えます。このプロパティを表示するには、gdcloud config list コマンドを使用します。ドメイン名は org-name.zone.google.gdch.com の構文に従う必要があります。たとえば、zone1 ゾーンのテスト環境にある org-1 という名前の組織には、org-1.zone1.google.gdch.test のようなドメインがあります。

Log Query API には、次の 3 つのエンドポイント オプションがあります。

  • labels: プロジェクトのすべてのラベルを一覧表示します。
  • labels/labels/LABEL/values: プロジェクトの特定のラベル値を一覧表示します。
  • logs: 特定のプロジェクトのログを一覧表示します。

詳細については、API ドキュメントをご覧ください。

クエリを送信する

HTTP または gRPC クライアントを使用して、Log Query API エンドポイントにクエリを送信します。

HTTP

HTTP クライアントを使用して API に直接アクセスするの手順に沿って操作します。kubectl を使用して認証を管理することも、認証を自分で処理することもできます。

curl、wget などの HTTP クライアント、または作成して管理する HTTP クライアントを使用して、Log Query API にクエリを実行します。次の例では、curl ツールを使用して API をクエリします。wget コマンドでも同様の形式を使用できます。

  1. cURL リクエストを認証します。

    1. gdcloud CLI をダウンロードしてインストールします。
    2. gdcloud core/organization_console_url プロパティを設定します。

      gdcloud config set core/organization_console_url https://GDC_URL
      

      GDC_URL は、GDC の組織の URL に置き換えます。

    3. 構成済みの ID プロバイダでログインする:

      gdcloud auth login
      
    4. ユーザー名とパスワードを使用して認証し、ログインします。

    5. 指定したアカウントの ID トークンを環境変数にエクスポートします。

      export TOKEN="$($HOME/gdcloud auth print-identity-token --audiences=https://LOG_QUERY_API_ENDPOINT)"
      

      LOG_QUERY_API_ENDPOINT は、ログをクエリする Log Query API エンドポイントと、接続するドメインに置き換えます。したがって、audiences フラグの値は https://operational-log-query-api.org-1.zone1.google.gdch.test などになります。

      ログインが成功すると、gdcloud auth print-identity-token コマンドを使用して cURL リクエストで認証ヘッダーを使用できます。詳細については、gdcloud auth print-identity-token をご覧ください。

  2. プロジェクトのすべてのラベルを一覧表示するには、次のクエリを送信します。

    curl -H "Authorization: Bearer ${TOKEN}" \
    https://LOG_QUERY_API_ENDPOINT/v1/projects/PROJECT_NAMESPACE/labels \
    -H "Content-Type: application/json" -v
    

    次のように置き換えます。

  3. プロジェクトの特定のラベル値を一覧表示するには、次のクエリを送信します。

    curl -H "Authorization: Bearer ${TOKEN}" \
    https://LOG_QUERY_API_ENDPOINT/v1/projects/PROJECT_NAMESPACE/labels/labels/LABEL/values \
    -H "Content-Type: application/json" -v
    

    次のように置き換えます。

    • LOG_QUERY_API_ENDPOINT: ログをクエリする Log Query API エンドポイント。
    • PROJECT_NAMESPACE: プロジェクトの名前空間。
    • LABEL: 値をクエリする特定のラベル。
  4. 特定のプロジェクトのログをクエリする場合は、logs_filter クエリを作成してリクエストの本文に含めます。

    curl -X GET -H "Authorization: Bearer ${TOKEN}" \
    https://LOG_QUERY_API_ENDPOINT/v1/projects/PROJECT_NAMESPACE/logs \
    -H "Content-Type: application/json" -d \
    '{"logs_filter": {"labels_equal": {"LABEL": "LABEL_VALUE"}}}' -v
    

    次のように置き換えます。

    • LOG_QUERY_API_ENDPOINT: ログをクエリする Log Query API エンドポイント。
    • PROJECT_NAMESPACE: プロジェクトの名前空間。
    • LABEL: ログをクエリする特定のラベル。
    • LABEL_VALUE: ログをクエリするラベル値。

    logs_filter クエリを作成するためのすべてのオプションについては、API ドキュメントをご覧ください。

gRPC

gRPC はプログラミング言語全体で広くサポートされており、HTTP クライアントと比較してより効率的な通信方法を提供します。

gRPC を使用してログをクエリするには、次の前提条件を満たす必要があります。

  • Google が提供するプロトコル バッファに基づいて独自のクライアント ライブラリを作成する。
  • クライアントに認証を実装します。
  • 再試行を実装する。

プロトコル バッファの詳細については、API ドキュメントをご覧ください。

次の例は、認証されていない gRPC クライアントを使用して Go プログラムからログをクエリする方法を示しています。この例では、コードの依存関係をインポートする Bazel ビルドファイルを含む golang パッケージを作成したことを前提としています。

  1. 次のコードを client.go という名前の Go プログラムに保存します。

    package main
    import (
            "context"
            "crypto/tls"
            "flag"
            "fmt"
            "google.golang.org/grpc/credentials"
            "google.golang.org/grpc/metadata"
            pb "<import path to generated log query api protos>/pkg/apis/public/logging/v1/proto"
            "google.golang.org/grpc"
    )
    
    var serverAddr = flag.String("server", "localhost:8080", "server address")
    
    func main() {
            flag.Parse()
            tc := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})
            conn, err := grpc.Dial(*serverAddr, grpc.WithTransportCredentials(tc))
    
            if err != nil {
                    panic(error.Error(fmt.Errorf("create client connection failed: %v", err)))
            }
            defer conn.Close()
    
            c := pb.NewLogsClient(conn)
            md := metadata.Pairs("clienttest", "test")
            ctx := metadata.NewOutgoingContext(context.Background(), md)
    
            err = listLabels(ctx, c, "project-foo")
            if err != nil {
                    panic(error.Error(err))
            }
    
            if err := listLabelValues(ctx, c, "project-foo", "resource-bar"); err != nil {
                    panic(error.Error(err))
            }
    
            if err := listLogs(ctx, c, "project-foo", &pb.ListLogsFilter{
                    LabelsEqual:    map[string]string{"resource-bar": "resource-bar-value"},
                    OrderAscending: true,
            }); err != nil {
                    panic(error.Error(err))
            }
    }
    
    // List all labels for a project.
    
    func listLabels(ctx context.Context, c pb.LogsClient, project string) error {
            lbr := &pb.ListLabelsRequest{
                    Parent:   project,
                    PageSize: 1000, // PageSize can be configured to limit the number of responses per page.
            }
            resp, err := c.ListLabels(ctx, lbr)
            if err != nil {
                    return fmt.Errorf("list labels: %v", err)
            }
            fmt.Printf("%v", resp)
            return nil
    }
    
    // List specific label values for a project.
    
    func listLabelValues(ctx context.Context, c pb.LogsClient, project string, label string) error {
            lbr := &pb.ListLabelValuesRequest{
                    Parent:   project,
                    Label:    label,
                    PageSize: 1000, // PageSize can be configured to limit the number of responses per page.
            }
            resp, err := c.ListLabelValues(ctx, lbr)
            if err != nil {
                    return fmt.Errorf("list label values: %v", err)
            }
            fmt.Printf("%v", resp)
            return nil
    }
    
    // List logs for a specific project.
    
    func listLogs(ctx context.Context, c pb.LogsClient, project string, lf *pb.ListLogsFilter) error {
            lbr := &pb.ListLogsRequest{
                    Parent:     project,
                    LogsFilter: lf,
                    PageSize:   5, // PageSize can be configured to limit the number of responses per page.
            }
            resp, err := c.ListLogs(ctx, lbr)
            if err != nil {
                    return fmt.Errorf("list logs: %v", err)
            }
            fmt.Printf("logs: %v", resp)
            return nil
    }
    
  2. Go プログラムを実行します。

    go run PATH_TO_API/client.go -server=LOG_QUERY_API_ENDPOINT:443
    

    次のように置き換えます。

    サーバーフラグが指定されていない場合、デフォルトのリクエストは localhost に送信されます。

サンプルクエリとラベル

ログのクエリに使用できるデフォルトのラベルの一部を次に示します。

  • cluster: クラスタの名前。
  • namespace: プロジェクトの名前空間。
  • node: ノード名。
  • pod: Pod 名。
  • container: コンテナ名。

次のコードサンプルは、ラベルと値を使用してさまざまなログをクエリする方法を示しています。

  • サーバーログを選択します。

    {cluster="admin", namespace="kube-system", resources="k8s_container", container="kube-apiserver"}
    
  • クラスタ監査ログを選択します。

    {cluster="admin", resources="k8s_audit"}