TECH PLAY

株式会社G-gen

株式会社G-gen の技術ブログ

744

当記事は みずほリサーチ&テクノロジーズ × G-gen エンジニアコラボレーション企画 で執筆されたものです。 G-gen の佐々木です。当記事では、Google Cloud (旧称 GCP) でマネージドな Kubernetes クラスタを使用することができる Google Kubernetes Engine (GKE) を解説します。Amazon Elastic Kubernetes Service (EKS) や Azure Kubernetes Service (AKS)など、kubenetes をマネージドに提供するサービスは存在しますが GKE はそれらの中でもよい評判を耳にします。例えばマスターノードの料金が不要、起動が早いといった具合です。GKE は Google Cloud 採択の理由たりえるサービスのため、優先的に仕様を調査することにしました。 Google Kubernetes Engine とは GKE クラスタのアーキテクチャ コントロールプレーン ノード クラスタの運用モード (クラスタタイプ) Autopilot モード Standard モード クラスタの可用性 クラスタのネットワークモード VPC ネイティブクラスタ ルートベースクラスタ クラスタのスケーリング ノードプールとは ノードのスケーリング Pod のスケーリング ストレージ マネージドオプション Kubernetes のストレージ抽象化 バックアップ Kubernetes ボリュームスナップショット Backup for GKE セキュリティ GKE クラスタの認証と認可 限定公開クラスタ Workload Identity クラスタのアップグレード リリースチャンネル アップグレードによるクラスタへの影響 モニタリング クラスタ設計時の考慮事項 GKE Enterprise 料金 クラスタ管理手数料 運用モードごとの利用料 Autopilot モード Standard モード Amazon EKS との違い クラスタのアップグレードについて 自動アップグレードの提供有無 アップグレードのスケジュール リリースまでのスケジュール サポート終了のスケジュール Ingress で使用されるロードバランサについて クラスタのモニタリングについて クラスタの料金について Google Kubernetes Engine とは Google Kubernetes Engine (以下、GKE) は、Google Cloud のインフラストラクチャ上で、コンテナ化されたアプリケーションのデプロイ、運用管理を行うためのマネージドな Kubernetes クラスタを利用することができるサービスです。 GKE では、Google Cloud が提供するクラスタ管理機能により、Kubernetes クラスタの管理負荷を大幅に削減することができます。 なお当記事の内容は、 Kubernetes の基本的な用語の理解を前提としています。Kubernetes の基本については以下の記事で解説しているので、こちらをご一読ください。 blog.g-gen.co.jp GKE クラスタのアーキテクチャ GKE クラスタを作成すると、 コントロールプレーン (マスターノード) と ノード (ワーカーノード) の 2 種類のコンポーネントが自動で構築されます。 これらのコンポーネントはそれぞれ Kubernetes のコントロールプレーン、ノードに対応しています。 GKE クラスタのアーキテクチャ コントロールプレーン GKE クラスタのコントロールプレーンは Google Cloud のマネージド VPC 内に作成され、ユーザに構築、運用の負荷は発生しません。 kube-apiserver プロセスによってクラスタの統合エンドポイントが提供され、Kubernetes API 経由でクラスタの操作を行います。 ノード クラスタには、ワークロードを実行する 1 つ以上のノードが含まれます。 GKE クラスタでは、ノードは Compute Engine インスタンスによって構成され、クラスタ作成時に自動的に作成されます。 ノードでは自動修復機能がデフォルトで有効となっており、クラスタ内の各ノードのヘルスチェックが定期的に行われます。 ノードの運用管理に関するユーザ側の責任範囲については、後述の 運用モード によって異なります。 クラスタの運用モード (クラスタタイプ) GKE では、 Autopilot モード 、 Standard モード という 2 種類の 運用モード で マネージド Kubernetes クラスタが提供され、それぞれクラスタに対する構成の柔軟性、ユーザが持つ権限、ユーザによる管理の範囲などが異なります。 GKE クラスタの運用モード 運用モードの詳細な比較については、 ドキュメント に一覧表があるので、こちらをご一読ください。 Autopilot モード GKE では、 基本的に Autopilot モードの使用が推奨されています。 GKE クラスタを Autopilot モード で作成した場合、 GKE のベストプラクティスと推奨事項を遵守した、本番環境ワークロード向けにあらかじめ最適化されたクラスタ構成が提供されます。 Autopilot モードを使用した場合、ワークロードが実行されるノードは Google Cloud によって管理され、 必要に応じてスケーリング、修復、セキュリティパッチの適用などが自動的に行われます。 また、Autopilot モードでは、 ワークロードが使用しているコンピューティングリソースに対してのみ料金が発生します。 ノードの未使用のコンピューティングリソースや OS 実行のコスト、実行中のワークロードに関係しないリソースの使用などの料金は発生しません。 Standard モード Standard モードでは、コントロールプレーンのみ Google Cloud によって管理され、クラスタとノードの構成および管理についてはユーザが行います。 ユーザが管理する必要がある主な設定は次の通りです。 管理対象 内容 ノードプール 同様の構成設定をもつノードをグループ化して管理する。 セキュリティ Workload Identity や Shielded GKE ノード など、GKE で利用することができるセキュリティ機能を手動で有効化/無効化する。 スケジューリング ビンパッキングなどを行い、未使用のリソースを最小限に抑えるようにワークロードを設計する。 スケーリング ノードのプロビジョニング、スケーリング設定を調整し、ノードが適切な範囲でスケーリングされるように設計する。 バージョン管理 GKE クラスタのバージョンや、自動アップグレードに関する設定を手動で行う。 また、Standard モードでは、 ノード上で実行されているワークロードにかかわらず、各ノードのコンピューティングリソースに対して料金が発生します、 そのため、スケジューリング、スケーリングを上手く設計し、リソース消費を最小限に抑える必要があります。 先述したように、GKE では基本的には Autopilot モードの使用が推奨されていますが、以下のようなケースにおいて Standard モードを使用することになります。 クラスタ構成を詳細に制御する必要がある。 Autopilot モードの制約 を満たさないワークロードを実行する必要がある。 クラスタの可用性 GKE では、コントロールプレーンとノードの可用性について、3 種類の 可用性タイプ から選択します。 Autopilot モードでは、自動的に リージョンクラスタ として設定されます。 可用性タイプ コントロールプレーンの可用性 ノードの可用性 シングルゾーンクラスタ 1 つのゾーンで単一のコントロールプレーンが実行される。 すべてのノードがコントロールプレーンと同一ゾーンで実行される。 マルチゾーンクラスタ 1 つのゾーンで単一のコントロールプレーンが実行される。 リージョン内の複数のゾーンで各ノードが実行される。 リージョンクラスタ リージョン内の複数のゾーンでコントロールプレーンが実行される。 リージョン内の複数のゾーンで各ノードが実行される。 シングルおよびマルチゾーンクラスタでは、コントロールプレーンが動作するゾーンに障害があった場合や、コントロールプレーンのアップグレードなどがあった場合にワークロードが停止する可能性があります。 したがって、 本番環境ワークロードの実行には、リージョンクラスタの使用が推奨されます。 ただし、リージョンクラスタでは構成の変更を行った際、変更がすべてのコントロールプレーンに反映される必要があるため、変更にかかる時間が長くなるという欠点があります。 可用性の重要度が比較的低く、また構成変更を柔軟に行う必要があるワークロードの実行では、シングルおよびマルチゾーンクラスタの使用も検討します。 また、コントロールプレーンの冗長化は料金に影響しませんが、例えばゾーンクラスタで 1 ノードで実行するようなワークロードをマルチゾーンクラスタやリージョンクラスタで構成すると、複数ゾーンにノードを冗長化するために、3 ノードぶん (ゾーンあたり 1 ノード) の料金が発生してしまいます。 ゾーンの異なるノード間で通信を行う場合にネットワーク料金が発生する ことにも注意する必要があります。 クラスタの可用性タイプはクラスタ作成後に変更することはできない ため、Standard モードで GKE を利用する場合、上記のトレードオフを考慮しつつ、慎重に選択する必要があります。 クラスタのネットワークモード GKE では、Pod 間のトラフィックをルーティングする方法によって、 VPC ネイティブクラスタ と ルートベースクラスタ の 2 つの ネットワークモード が存在します。 基本的には VPC ネイティブクラスタの使用が推奨されており 、Autopilot モードのクラスタでは VPC ネイティブクラスタが使用されるようになっています。 クラスタのネットワークモードについても、クラスタの作成後に変更することはできません。 VPC ネイティブクラスタ VPC ネイティブクラスタでは、GKE クラスタに対して、ノードを作成する VPC ネットワークのサブネットを関連付けます。 クラスタの作成時に、以下の 3 つの IP アドレス範囲を設定します (重複不可)。 クラスタ内のすべてのノードに対して割り当てる、サブネットのプライマリ IP アドレス範囲 すべての Pod に使用される、サブネットのセカンダリ IP アドレス範囲 すべての Service ( Cluster IP ) に使用される、サブネットの別のセカンダリ IP アドレス範囲 このように、各リソースに対して VPC のサブネットを割り当てることで、Pod が VPC ピアリング接続や Cloud VPN で接続された他のネットワークに接続することができます。 また、ネットワークエンドポイントグループ ( NEG ) を使用した コンテナネイティブの負荷分散 やファイアウォールルール、共有 VPC など、 VPC に紐付いた機能を利用することができます。 VPC ネイティブクラスタを使用する注意点としては、クラスタ内部で使用されるエイリアス IP 範囲と、VPC で既に使用している IP 範囲が重複しないようにネットワーク設計をする必要があります。 ルートベースクラスタ ルートベースクラスタでは、クラスタに対して RFC 1918 ブロックから任意の IP アドレスを指定します。 ここで指定した IP アドレス範囲から、クラスタ内のノードごとに IP アドレス範囲が割り振られ、それが Pod と Service に対して使用されます。 Pod や Service に使用される IP アドレス範囲は、ノードが作成される VPC ネットワークとは別のネットワークとなる ため、ノードが存在する VPC に対して、ノード内ネットワークへのカスタムルートが自動で追加されます。 そのため、ノードのスケーリングによりルート数の上限値に達しないように設計する必要があります。 元々 GKE ではルートベースクラスタのみ作成することができました。 VPC ネイティブクラスタでは Pod が VPC に紐づくリソースとなることで得られるメリットが多いことから、現在はルートベースクラスタの利用は推奨されていません。 クラスタのスケーリング Autopilot モードのクラスタでは、ワークロードで使用されるリソースを需要に応じて自動で確保しますが、Standard モードのクラスタの場合、ワークロードを実行する Pod が適切な数だけ展開できるように、クラスタに対してスケーリングの設定を行う必要があります。 ノードプールとは ノードプール とは、 Standard モードのクラスタで使用する、クラスタ内で 同じ構成を持つノードのグループ です。 クラスタの作成時に、起動するノード数や、ノードが使用する OS イメージ、ローカル SSD 、CPU プラットフォーム、マシンタイプなどを設定し、ノードプールを作成します。 ノードプール内のノードはすべて同一の構成になり、ノードプール単位でスケーリングの設定をすることができます。 ノードプールは後から追加することもでき、例えば Spot VM を使用するノードプールなど、クラスタ内に別の構成のノードプールを混在させることができます。 ノードのスケーリング GKE では、ワークロードの需要に基づいて、クラスタ内のノード数を自動でスケーリングすることができます。 スケーリングの種類 スケーリング対象 説明 クラスタオートスケーラー ノード ノードプールに対してノードの最大数と最小数を事前に設定しておくことで、ワークロードの需要に基づいて、適切なノード数になるようにスケーリングする。 スケーリングは実際のリソース使用率ではなく、ノードプール内のノードで実行されている Pod のリソースリクエスト数に基づいて行われる。 既存のノードに Pod を起動するだけのリソースがなければ新たにノードを追加し、ノードのリソースが余っている状態が続く場合はノードを削除する。 ノードの自動プロビジョニング ノードプール ワークロードの需要に基づき、 ノードプールを 追加/削除する。 CPU 、メモリなどのリソースリクエストに基づいてスケーリングが行われる。 クラスタ内の Pod の要件に合わせて、最適なノードを起動できるように設定されたノードプールが追加される。 Pod のスケーリング ワークロードの CPU やメモリなどの リソース使用量 、Kubernetes から報告される カスタム指標 、Kubernetes 外部にあるアプリケーションのパフォーマンスに基づいた 外部指標 などを用いて、Pod の自動スケーリングを設定することができます。 スケーリングの種類 スケーリング対象 説明 水平 Pod 自動スケーリング Pod 数 指標に基づいて Pod の数を自動的に増減する。 垂直 Pod 自動スケーリング Pod のリソースリクエスト 指標に基づいて Pod に必要な CPU とメモリリソースを分析し、最適なリソース量を推奨値として算出する。 推奨値を使用した Pod を自動で起動するように設定することもできる。 多次元 Pod 自動スケーリング Pod の数 Pod のリソースリクエスト 2023 年 2 月現在プレビュー 水平 Pod 自動スケーリングと垂直 Pod 自動スケーリングを同時に実現することができる。 リソース使用量の指標で垂直 Pod 自動スケーリングと水平 Pod 自動スケーリングを併用すると、それぞれのオートスケーラーが需要の変化に対応するため、競合が発生します。 多次元 Pod 自動スケーリングでは、このようなオートスケーラーの競合を回避しながら、水平と垂直の両方向のスケーリングを実現することができます。 ストレージ GKE クラスタでストレージを利用する場合、 マネージドオプション として Google Cloud のストレージプロダクトを GKE クラスタの外部で使用するか、Kubernetes の ストレージ抽象化 によって、一部の Google Cloud ストレージプロダクトを Kubernetes リソースとして管理することができます。 マネージドオプション Compute Engine などのコンピュートプロダクトで使用するときと同様に、Google Cloud のストレージプロダクトを作成し、GKE クラスタから接続することができます。 この場合、Kubernetes のライフサイクルとは関係なくリソースが作成されるため、クラスタの削除後もストレージとして利用していたリソースが残り続けます。 以下は、GKE から接続できるストレージプロダクトの抜粋となります。 ストレージの種類 対応するプロダクト データベース Cloud SQL Datastore Cloud Spanner オブジェクトストレージ Cloud Storage ブロックストレージ Persistent Disk コンテナイメージレジストリ Artifact Registry Container Registry ファイルサーバ Cloud Filestore Kubernetes のストレージ抽象化 Kubernetes のストレージ抽象化では、Kubernetes のリソースである Volume および PersistentVolume リソースを使用し、ストレージリソースを Pod や Kubernetes のライフサイクルに組み込むことができます。 Volume で使用できる emptyDir では、Pod 内に読み書き可能の空のディレクトリが作成され、 Pod の削除とともにディレクトリ内のデータも削除されます。 PersistentVolume では Google Cloud のプロダクトである Compute Engine の Persistent Disk や Filestore などを Kubernetes のリソースとして抽象化 して管理できます。 Kubernetes のライフサイクルでリソースが管理されるため、クラスタの削除後もデータを保持したい場合は、リソースのマニフェストで 再利用ポリシー を設定します。 バックアップ Kubernetes ボリュームスナップショット 通常、GKE では Kubernetes リソースである PersistentVolume に Compute Engine の Persistent Disk が使用されます。 Kubernetes ボリュームスナップショット を使用することで、GKE クラスタ内の PersistestVolume リソース のスナップショットを取得することができます。 Backup for GKE GKE のアドオンとして Backup for GKE を使用することで、GKE クラスタ全体をバックアップすることができます。 取得したバックアップからは、クラスタ全体を復元したり、クラスタ内の単一のワークロードのみロールバックしたりすることが可能です。 バックアップはスケジュール実行することができ、最小間隔は 10 分となっています。 セキュリティ GKE クラスタの認証と認可 GKE では、Kubernetes のユーザアカウントは Google Cloud で管理されます。 Kubernetes ユーザアカウントには以下の 2 種類のいずれかが使用されます。 Google アカウント / グループ Google Cloud サービスアカウント プロダクトとしての GKE に対するプロジェクトレベルのアクセス制御は、他の Google Cloud プロダクト同様に IAM で行います。 クラスタレベルや Kubernetes 名前空間 (Namespace) レベルで Kubernetes リソースへのアクセス制御を行う場合は、 Kubernetes のロールベースのアクセス制御 ( Kubernetes RBAC ) を使用します。 Kubernetes のリソースとして Role または ClusterRole を作成し、 RoleBinding または ClusterRoleBinding リソースを使用してユーザアカウントにロールを割り当てます。 限定公開クラスタ 通常の GKE クラスタは、ノードに対してパブリック IP アドレスが付与されており、 Nodeport を利用してワークロードを公開することで、外部からアクセスすることができます。 コントロールプレーンに対しては パブリックエンドポイント が提供されており、インターネットからクラスタに対する kubectl による管理操作を行うことができます。 コントロールプレーンに 承認済みネットワーク を設定し、パブリックエンドポイントに対するアクセス元 IP を制限することができます。 VPC ネイティブクラスタのみ 、GKE クラスタを 限定公開クラスタ として構成することで、コントロールプレーンとノードをインターネット接続から分離することができます。 限定公開クラスタは、クラスタ作成時のみ設定することができます。 限定公開クラスタでは、 ノードにはプライベート IP アドレスのみが付与されます。 コントロールプレーンが存在するマネージド VPC と、ノードが作成される VPC が接続され、コントロールプレーンとノード間のルーティングにプライベート IP アドレスが使用されます。 外部ネットワークからノード上のワークロードにアクセスする場合は、LoadBalancer や Ingress などの Service を作成し、ロードバランサを使用してワークロードを公開できるように設定します。 コントロールプレーンに対してはパブリックエンドポイントと プライベートエンドポイント が提供され、 必要に応じてパブリックエンドポイントを無効化することができます。 プライベートエンドポイント経由で kubectl による管理操作を行う場合、VPC に作成した踏み台サーバから行うか、Cloud VPN または Cloud Interconnect を使用します。 限定公開クラスタに対するアクセスの例 Workload Identity GKE クラスタ内の Pod から Google Cloud 内の他のリソースにアクセスする場合、クラスタに設定した IAM サービスアカウントの認証情報を使用することができますが、その場合、クラスタ内のすべての Pod が IAM サービスアカウントの認証情報を使用することができてしまいます。 GKE では、より安全な方法として Workload Identity の使用が推奨されます。 Workload Identity では、 Kubernetes のリソースである ServiceAccount と IAM サービスアカウントを紐付ける ことで、その Kubernetes の ServiceAccount を使用する Pod だけが Google Cloud のリソースにアクセスすることができます。 blog.g-gen.co.jp また、Workload Identity のより簡略化された方法として、Kubernetes の ServiceAccount に IAM ロールを直接紐づけることもできます。 blog.g-gen.co.jp クラスタのアップグレード リリースチャンネル Kubernetes では、セキュリティの更新や既知の問題の修正、新機能導入のため、頻繁にアップデートがリリースされています。 GKE では、クラスタを リリースチャンネル に登録することで、クラスタのアップグレードを自動で管理することができます。 リリースチャンネルは 3 種類あり、Kubernetes のアップデートが GKE クラスタにリリースされるまでの早さを制御することができます。 リリースチャンネル Kubernetes のアップデートから GKE にリリースされるまでの期間 備考 Rapid 数週間 GKE の SLA 対象外のため、検証環境での使用が推奨される。 Regular Rapid チャンネルのリリースから 2 ~ 3 ヶ月後 デフォルトの設定 Stable Regular チャンネルのリリースから 2 ~ 3 ヶ月後 特定のバージョンの Kubernetes を使用したい場合は、Standard モードのクラスタのみ、手動アップグレードが可能となっています。 アップグレードによるクラスタへの影響 マルチゾーンおよびゾーンクラスタを使用している場合、コントロールプレーンが冗長化されていないため、アップグレード中はコントロールプレーンに依存するクラスタの操作が不可能になります。 ノードについては、以下の アップグレード戦略 が使用されるため、実行中のワークロードが停止することなくアップグレードを実施できます。 アップグレード戦略 特徴 サージアップグレード ローリング方式を使用してノードをアップグレードする。 設定によってはワークロードが一時的に縮退運転となるが、コストを抑えてアップグレードを行うことができる。 Blue/Green アップグレード Blue/Green 方式を使用してノードをアップグレードする。 一時的にノードリソースが 2 倍になるためコストが高くなるが、迅速なロールバックが必要な場合はこちらを使用する。 モニタリング GKE は Cloud Monitoring や Cloud Logging と統合されており、クラスタの作成時にデフォルトで有効化されます。 Cloud Monitoring では、Pod やノードにおける CPU 、メモリ、ストレージのリソース使用状況やネットワーク送受信量などの システム指標 が利用できるほか、オプションでコントロールプレーンに対するリクエスト数やリクエストのレイテンシ、スケジューラのレイテンシなどの コントロールプレーンの指標 を利用することができます。 Cloud Logging では、以下のログがデフォルトで収集されます。 ログの種類 説明 監査ログ コンソールや gcloud コマンド、SDK などを使用した、GKE クラスタの作成、削除、構成変更などの API 操作、管理アクションのログが収集される。 また、kubectl コマンドを使用した、コントロールプレーンに対する Kubernetes API 操作のログも収集される。 システムログ 自動で作成される Kubernetes のシステム用コンテナなど、ワークロードとは関係ないコンテナのログや、コンテナランタイムなどのコンテナ化されていない重要なサービスのログ、各ノードのシリアルポートの出力などが収集される。 アプリケーションログ ノードで実行しているワークロードで、 STDOUT または STDERR に書き込まれたログが自動的に収集される。 また、 Google Cloud Managed Service for Prometheus を使用することで、フルマネージドの Prometheus を使用して GKE クラスタで実行されるワークロードをモニタリングすることができます。 クラスタ設計時の考慮事項 ここまで解説してきたように、GKE を使用する際には様々な要素を考慮する必要があります。 クラスタ設計時に特に気をつけなければならない点としては、以下のような クラスタ作成後に変更できない 設定項目があります。 項目 検討内容 運用モード まずは構築・運用負荷の低い Autopilot モードを検討し、Autopilot モードでは達成できない要件がある場合に Standard モードを選択します。 可用性タイプ Autopilot モードの場合は自動的にリージョンクラスタとして構成されます。 Standard モードのクラスタを使用する場合は、当記事で解説したコントロールプレーンおよびノードの冗長化に伴うトレードオフを考慮します。 ネットワークモード Pod が VPC に紐づく多数の機能を利用することができる VPC ネイティブクラスタの利用が推奨されます。 VPC ネイティブクラスタでは Service や Pod が VPC で使用できる IP アドレスを消費するため、それが許容できない場合はルートベースクラスタを検討します。 GKE Enterprise GKE Enterprise は、マルチクラスタ管理機能を強化した GKE の上位エディションです。 Enterprise エディションとも呼ばれ、これに対して基本の GKE は Standard エディションと呼ばれます。 GKE Enterprise は、従来の Anthos の後継サービス(上位互換)です。GKE Enterprise では Anthos 同様に複数の GKE や Google Cloud 以外の Kubernetes クラスタを フリート と呼ばれる論理グループにまとめます。 また大規模なマルチクラスタの管理に役立つ以下のような機能が提供されます。 フリート全体で同じクラスタ構成、機能、セキュリティポリシーを自動的に構成するポリシー管理ツール マルチクラスタ Ingress 、マネージドなサービスメッシュなどのマルチクラスタに対応したネットワーク管理機能 フリート全体で一貫した ID 管理機能 フリート内のクラスタやアプリケーションのモニタリング、トラブルシューティングを可能にするオブザーバビリティ機能 Teams 機能(クラスタを管理する単位 "Team" を提供) これらの機能は Anthos で提供されているものですが、Anthos では独立したメニュー画面からこれらの機能にアクセスする必要がありました。GKE Enterprise では統合された UI で GKE と Anthos の管理操作を行うことができるようになっています。 GKE Enterprise はクラスタタイプ(Standard / Autopilot)を問わず使用することができます。 参考 : GKE エディション 料金 GKE の利用料金は、 クラスタ管理手数料 + 運用モードごとの利用料 で決まります。 クラスタ管理手数料 GKE では、運用モードや可用性タイプ、クラスタの規模に関係なく、1 クラスタあたり $0.10 / 時間 のクラスタ管理手数料が発生します ( 1 秒単位の課金 )。 シングルゾーンクラスタもしくは Autopilot モードのクラスタの場合、 月額 $74.40 の無料枠 があり、請求先アカウントごとに提供されます。 クラスタが 1 つであれば、クラスタの管理手数料は無料枠ですべてカバーされます。 運用モードごとの利用料 Autopilot モード Autopilot モードのクラスタでは、ノード上で実行中の Pod でリクエストされている CPU 、メモリ、エフェメラルストレージリソースに対して料金が発生します。 ノードの未使用のコンピューティングリソースや OS 実行のコスト、実行中のワークロードに関係しないリソースの使用などの料金は発生しません。 また、 Spod Pod や 確約利用割引 を使用することで、料金を節約することができます。 以下は asia-northeast1 (東京) リージョンにおける Autopilot モードのクラスタの料金 (月額) です。 課金項目 通常料金 スポット Pod 料金 1 年間の確約利用割引 3 年間の確約利用割引 vCPU ( vCPU 数 / 月 ) $41.68 $12.48 $33.35 $22.93 メモリ ( GB / 月 ) $4.61 $1.38 $3.69 $2.54 エフェメラルストレージ ( GB / 月 ) $0.05 $0.05 $0.04 $0.03 Standard モード Standard モードのクラスタでは、ノードを構成する Compute Engine インスタンスに対して料金が発生します。 例えば、asia-northeast1 (東京) リージョンにおいて、デフォルトのマシンタイプ e2-medium を使用した場合、 ノード 1 つあたり $31.38 / 月 の課金が発生します。 Compute Engine 同様、1 年または 3 年の確約利用割引で料金を節約することも可能です。 Compute Engine の料金の詳細については、 Compute Engine のドキュメント を参照してください。 Amazon EKS との違い Amazon Elastic Kubernetes Service ( Amazon EKS ) は Amazon Web Service ( AWS ) が提供するマネージドな Kubernetes のプロダクトです。 Kubernetes はオープンソースのため、クラスタで使用できる Kubernetes の機能にほとんど差はありませんが、パブリッククラウドのプロダクトとしての差はいくつか存在します。 クラスタのアップグレードについて 自動アップグレードの提供有無 GKE では、リリースチャンネルを使用することで、Kubernetes のアップグレードを自動化することができ、また必要に応じて手動でアップグレードを実施することもできます。 GKE には、今後のアップグレードで非推奨となる API を検出でき、現在利用している Kubernetes API の中にアップグレードに伴って削除されるものがあった場合に、自動アップグレードを一時停止できる機能が提供されています。 それに対して、Amazon EKS は自動アップグレードに対応しておらず、コントロールプレーンとノードのアップグレードをそれぞれ実施する必要があります。 アップグレードのスケジュール GKE と Amazon EKS とでは、Kubernetes の新しいバージョンがリリースされてから利用できるようになるまでの期間と、バージョンごとのサポート終了のタイミングが異なります。 最新のスケジュールについては以下のドキュメントを参照してください。 GKE リリーススケジュール EKS リリーススケジュール リリースまでのスケジュール GKE のほうが、比較的短い期間で Kubernetes の新しいバージョンに対応する傾向があります。 Rapid のリリースチャンネルでは SLA が適用されないことには注意が必要ですが、早い段階から新バージョンの検証を行うことができます。 Kubernetes のバージョン Kubernetes のリリース日 GKE ( Rapid ) GKE (Regular) GKE ( Stable ) Amazon EKS 1.27 2023-04-11 2023-05-08 2023-06-14 2023-07-05 2023−05-24 1.26 2022-12-06 2023-01-13 2023-04-14 2023-06-14 2023-04-11 1.25 2022-08-23 2022-09-13 2023-12-08 2023-05-08 2023-02-22 1.24 2022-05-03 2022-06-13 2022-08-19 2022-11-30 2022-11-15 1.23 2021-12-14 2022-01-27 2022-04-29 2022-07-22 2022-08-11 サポート終了のスケジュール Kubernetes の旧バージョンのサポート終了タイミングは、Amazon EKS のほうが比較的後になっています。 リリースのタイミングも勘案すると、Amazon EKS のほうがサポート期間が長いというわけではない点には注意が必要です。 Kubernetes のバージョン GKE Amazon EKS 1.27 2024-08-31 2024-07 1.26 2024-06-30 2024-06 1.25 2024-02-29 2024-05 1.24 2023-10-31 2024-01 1.23 2023-07-31 2023-10 Ingress で使用されるロードバランサについて ワークロードに対する レイヤ 7 のトラフィックを負荷分散したい場合、Kubernetes の Ingress リソースを利用します。 Ingress リソースで使用されるロードバランサは、GKE では HTTP(S) Loadbalancer 、Amamzon EKS では Application Load Balancer ( ALB ) となっています。 AWS の ALB では、トラフィックのスパイクが予測される場合に、事前にロードバランサをスケーリングしておく Pre-warming (暖機運転) を行う必要があり、これは AWS のサポートに対してリクエストを送ることで実現できます。 これは、AWS 側で作業が発生するため、数日前には申請しておく必要があります。 それに対して、Google Cloud の HTTP(S) Loadbalancer は常にトラフィックのスパイクに対応できるようになっており、 Pre-warming の必要がありません。 したがって、HTTP(S) LoadBalancer のほうが、予想外のスパイクに対応できる仕様になっています。 このように、Amazon EKS では、クラスタでワークロードのスケーリングが適切に行われていても、ロードバランサがボトルネックとなりトラフィックを処理しきれない可能性があります。 クラスタのモニタリングについて リソースのモニタリングについて、GKE では、Cloud Monitoring との統合がデフォルトで有効となっていますが、Amazon EKS では Amazon CloudWatch の Container Insights を手動で設定するか、サードパーティツールを使用する必要があります。 クラスタの料金について EKS では、GKE 同様に 1 クラスタあたり $0.10 / 時間 の料金が発生します。 GKE の場合、クラスタの可用性モードにもよりますが、無料枠によって 1 クラスタぶんの料金が相殺されるため、EKS よりも料金が安くなる傾向があります。 佐々木 駿太 (記事一覧) G-gen最北端、北海道在住のクラウドソリューション部エンジニア 2022年6月にG-genにジョイン。Google Cloud Partner Top Engineer 2025 Fellowに選出。好きなGoogle CloudプロダクトはCloud Run。 趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。 Follow @sasashun0805
アバター
G-gen の藤岡です。当記事では、 Google Cloud(旧称 GCP)の予算アラートの設定方法を紹介します。 概要 設定 1. 通知チャンネルの準備 ①メールアドレスの場合 ②Slack の場合 2. 通知チャンネルの設定 必要な権限と設定画面 3. 予算とアラートの設定 確認 概要 予算アラートを設定することで、指定した期間の中で請求額がしきい値を超えた場合に、メールを使って通知することができます。通知を設定しておけば、予期しない請求に早めに気が付くことができます。 また Slack のメールインテグレーション機能を用いれば、Slack チャンネルへ通知することも可能です。 今回は以下の図のように、1つのプロジェクトの予算を ¥10,000 とし、3つの各しきい値を超えた場合にアラート通知をする設定をします。 今回ご紹介する通知先は以下の2つです。環境に合わせて適切な通知先を選択し、後述の設定の項をご覧ください。 ①メール ②Slack (メールインテグレーション) 構成 予算アラートは 2023年2月時点で メール通知のみをサポート しています。Cloud Monitoring の「通知チャンネル」機能では Slack や SMS 等も設定できますが、そのチャンネルを予算アラートから使うことはできません。当記事では、後述する Slack のメールインテグレーション機能を利用することで、Slack の DM やチャンネルへの通知を実現しています。 また、前提となる Google Cloud の請求の仕組みについては以下の記事をご参照ください。 blog.g-gen.co.jp 設定 以下の流れで設定を行います。今回は Google Cloud コンソールから設定をしますが、 コンソールの表記は変わる可能性がある ため、参考リンクも確認しながら設定してください。 通知チャンネルの準備 通知チャンネルの設定 予算とアラートの設定 1. 通知チャンネルの準備 通知チャンネルとは、Cloud Monitoring のアラート機能の通知先として選択可能な、連絡先のことです。メールアドレスや Slack、Web hook を指定することができます。 ①メールアドレスの場合 事前に通知先メールアドレスを用意しておきます。通知先としては、個人アドレスではなくグループアドレスが便利でしょう。 ②Slack の場合 Slack 通知用のメールアドレスを事前に作成しておきます。Slack では、チャンネルへの通知用メールアドレスを簡単に作成可能です。 作成方法は チャンネルまたは DM 用メールアドレスを作成する をご覧ください。 2. 通知チャンネルの設定 必要な権限と設定画面 通知チャンネルの作成に必要な権限は ドキュメント をご参照ください。 コンソールで [モニタリング] > [アラート] へ進みます。 コンソール画面 [EDIT NOTIFICATION CHANNELS] をクリックします。 EDIT NOTIFICATION CHANNELS [メール] セクションで [ADD NEW] をクリックします。 通知チャンネルの作成① Email Address にメールアドレス、 Display Name は表示名を入力し [SAVE] をクリックします。 通知チャンネルの作成② 保存すると、以下のように通知先が追加されます。 通知チャンネルの作成③ 参考: 通知チャンネルを作成する 3. 予算とアラートの設定 予算とアラートの設定に必要な権限は ドキュメント をご参照ください。 コンソールから [予算とアラート] ページへ進みます。 検索ボックス 請求先アカウント で予算を設定する請求先アカウントを選択し、 [予算とアラートのページに移動] をクリックします。 予算とアラート 以下の項目を入力し、[次へ] をクリックします。用途に合わせて設定項目は変更してください。 項目 設定値 備考 名前 Monthly-Billing-Alert 任意の名前 期間 月別 期間を指定することも可能 プロジェクト 対象プロジェクト 予算を設定するプロジェクトを選択 予算の作成(範囲) 目標金額 に今回は ¥10,000 を入力し、[次へ] をクリックします。 予算の作成(金額) Set alert threshold rules にアラート通知をするしきい値を入力します。 通知の管理 で モニタリング メール通知チャネルをこの予算にリンクする にチェックを入れ、 プロジェクト に対象のプロジェクト、 Nortification Channels に 2. 通知チャンネルの設定 で設定をした通知先を選択し、 [終了] をクリックします。 予算の作成(操作) 参考: 予算と予算アラートを作成、編集、削除する 確認 例として、② Slack では予算のしきい値に達すると以下のような通知がきます。送信者は Google Cloud Billing Alerts <CloudPlatform-noreply@google.com> です。 Slack アラート通知画面 藤岡 里美 (記事一覧) クラウドソリューション部 接客業からエンジニアへ。2022年9月 G-gen にジョイン。Google Cloud 認定資格は全冠。2023 夏アニメのオススメは、ダークギャザリング。箏を習っています :) Follow @fujioka57621469
アバター
G-gen の杉村です。当記事では Google Cloud (旧称 GCP) のサービスである Managed Service for Microsoft Active Directory (マネージド Microsoft AD) をご紹介したいと思います。 概要 Managed Microsoft AD とは 制限事項 料金 ユースケース Managed Microsoft AD のユースケース 既存ドメインからの移行 前提 Active Directory Migration Toolkit (ADMT) を使った移行 既存ドメインとの信頼関係 前提 アーキテクチャの検討 リソースフォレスト Managed Microsoft AD の機能と非機能 ドメイン ドメインコントローラ 信頼関係 ネットワーク 冗長化 モニタリング バックアップ・リストア 概要 Managed Microsoft AD とは Managed Service for Microsoft Active Directory (略称 Managed Microsoft AD )は Google Cloud(旧称 GCP)が提供する、フルマネージドな Microsoft Active Directory サービスです。 参考 : マネージド Microsoft AD の概要 Managed Microsoft AD では、AD のサーバー構築、パッチ適用、バックアップ、冗長化などが自動化されており、インフラを意識すること無く Active Directory ドメインを作成することができます。またオンプレミスのフォレスト(ドメイン)と片方向/双方向の信頼関係を結ぶことも可能です。 また、簡単にマルチリージョン構成を構築することができ、追加の料金は発生しますがドメインコントローラを最大 4 つのリージョンに冗長化することもできます。 Managed Microsoft AD ではユーザー、デバイス、グループ、OU、GPO(グループポリシーオブジェクト)など一通りのオブジェクトを利用することができます。 ただし、後述する各種制限がありますので、要件に適しているかの検討が必要です。 制限事項 以下の制限事項があることに注意が必要です。 Managed Microsoft AD は既存ドメインのドメインコントローラとなることはできない (新規フォレスト・ドメインとなる) Managed Microsoft AD のドメインコントローラにはリモートデスクトップ等でログインすることができない ドメインに参加した別の管理用マシンから操作する Managed Microsoft AD のドメインへ参加できるマシンの OS バージョンには制限あり Windows Linux Managed Microsoft AD のドメインの機能レベルは Windows Server 2012 R2 である 料金 Managed Microsoft AD は以下の通りです (2023 年 1 月現在)。 単価 単位 $0.4 時間あたり・リージョンあたり 例として東京リージョンのみで運用する AD は以下のような月額料金となります。 $0.4 × 24h × 31 days = $297.6 / 月 最新の料金は以下のドキュメントを参照してください。 参考 : Managed Service for Microsoft Active Directory の料金 ユースケース Managed Microsoft AD のユースケース Managed Microsoft AD の主なユースケースは「Compute Engine 等の Google Cloud リソースが所属するためのドメイン」であると言えます。 そのためのアーキテクチャとして、後述の「リソースフォレスト」パターンなどがあります。 一方で、前述の制限事項もあることから「オンプレミスの既存ドメインの移行先として」あるいは「冗長化先として」というユースケースは現在のところあまり想定されていないと言えます。 ただし、Active Directory Migration Toolkit (ADMT) を使った既存ドメインからのオブジェクト移行方法が、Preview 中ではありますが用意されており、これも後述します。 既存ドメインからの移行 前提 一般的なクラウド移行のユースケースとして、オンプレミスのドメインコントローラをクラウドへ移行したい、という要求があります。 しかし Managed Microsoft AD では制限事項として 既存ドメインには参加できません し、既存ドメインのドメインコントローラにはなれません。 つまり Managed Microsoft AD はあくまで新規フォレストとして構築することしかできません。よって、例えば「既存ドメインに参加させてドメインコントローラとして昇格させることでドメインコントローラを Managed Microsoft AD へそのまま移行する」ということは実現できないことになります。 Active Directory Migration Toolkit (ADMT) を使った移行 しかしながら Microsoft の提供するツールである Active Directory Migration Toolkit (ADMT) を利用することで、既存ドメインから Managed Microsoft AD で構築した新規ドメインへオブジェクトを移行する、という方法があります。 参考 : Existing domain migration overview ただしこの方法は Google Cloud 側としては Preview 状態であり (2023 年 1 月現在) 本番環境での利用は推奨されません。 この方法では、既存ドメインと新規ドメイン (Managed Microsoft AD) の間に信頼関係を結び、ADMT を使ってユーザー、グループ等のオブジェクトを移行します。 移行後のオブジェクトでは SID が新規に割り振られてしまいパーミッション設定等がやり直しになってしまうことを回避するために、SID 履歴を保持して移行するなどの考慮事項があります。 ADMT を利用した移行手順などは Google Cloud からは提供されておらず、独自に調査して手順を確立する必要があります。 既存ドメインとの信頼関係 前提 Managed Microsoft AD では、オンプレミスの既存ドメイン (フォレスト) との片方向/双方向の信頼関係を確立することが可能です。 ただし、以下の条件を満たしている必要があります。 既存ドメインコントローラが 対応 OS で稼働していること Windows Server 2008 / 2012 R2 / 2016 / 2019 オンプレミスネットワークと Cloud VPN / Cloud Interconnect 等でプライベートネットワーク接続され、必要な TCP/UDP ポートで通信できること アーキテクチャの検討 ドメイン間で信頼関係を結ぶにあたって、そもそもどういったフォレスト・ドメインアーキテクチャとすべきかを検討する必要があります。 Google Cloud から以下の詳細なドキュメントが公開されており、アーキテクチャ検討の参考にすることができます。 参考: ハイブリッド環境での Active Directory の使用パターン 次に、そのうちひとつだけをピックアップして紹介します。 リソースフォレスト Managed Microsoft AD で特に想定されているのは「リソースフォレスト」パターンです。 画像は 公式 より引用 このパターンでは Managed Microsoft AD で構築した新規フォレストからオンプレミスの既存フォレストに対して片方向の信頼関係を結びます。構成は以下のようになります。 オンプレミスのリソースはオンプレミスのフォレストに所属 ユーザーアカウント、PC など Google Cloud リソースは Managed Microsoft AD のフォレストに所属 Compute Engine VM など 信頼関係があるため、オンプレミスのフォレストに所属するユーザーは、Managed Microsoft AD のフォレストに所属する Google Cloud 上のリソースにアクセスできる これによりメインのフォレスト・ドメインは引き続きオンプレミスで管理し、Google Cloud 上のリソース管理を Managed Microsoft AD でホストする新しいフォレストに任せる、といった構成になります。 詳細は以下のドキュメントもご参照ください。 参考 : リソースフォレスト 参考 : Active Directory リソース フォレストをデプロイする Managed Microsoft AD の機能と非機能 ドメイン Managed Microsoft AD のドメインの構築は、Google Cloud コンソールもしくは gcloud コマンドで行います。 参考 : ドメインを作成する Managed Microsoft AD ではユーザー、デバイス、グループ、OU、GPO (グループポリシーオブジェクト) など一通りのオブジェクトを利用することができます。 また LDAPS の有効化、パスワードポリシー (Fine-Grained Password Policies, FGPP)、グループ マネージド サービス アカウント (gMSA)、ディレクトリスキーマの拡張などのセキュリティ施策を利用することも可能です。 新規ドメインを作成すると、いくつかの OU、グループ、GPO、ユーザーアカウントなどデフォルトのオブジェクトが作成されます。 その中には setupadmin (変更可能) という名前のユーザーも含まれています。これは 委任された管理者アカウント とも呼ばれおり、最初のセットアップはこのアカウントを用いて行います。 参考 : マネージド Microsoft AD のデフォルトの Active Directory オブジェクト また前述の通り、Managed Microsoft AD のドメインに参加できるマシンはサポート対象 OS が限定されていますのでご注意ください。 Windows Windows Server 2008 Windows Server 2008 R2 Windows Server 2012 Windows Server 2012 R2 Windows Server 2016 Windows Server 2019 Windows 10(バージョン 1909 以前) Linux Ubuntu 16.04 LTS Red Hat Enterprise Linux (RHEL) 8.2 (Ootpa) 上記のバージョン以外は「ここに記載されているバージョン以外も機能しますが、テストされていません。」とされています。また上記リストは 2023/01 現在のものですので、正確な情報としては以下のドキュメントをご参照ください。 参考 : 対応 OS のバージョン ドメインコントローラ ドメインコントローラはフルマネージドの Windows Server 2019 です。ドメインの機能レベルは Windows Server 2012 R2 です。 OS パッチの適用などは完全に自動で行われ、ユーザーは意識する必要がありません。 その代わり、ドメインコントローラの VM にリモートデスクトップ等でログインすることはできません。ではどのようにドメインを管理すればいいのかというと、別の Windows マシン (Compute Engine VM 等) にリモート サーバー管理ツール (RSAT) をインストールし、そのマシンからドメインに参加して、管理者アカウントの権限で管理タスクを実行します。 参考 : Windows VM をドメインに参加させる 参考 : Active Directory オブジェクトを管理する 信頼関係 前述のようなフォレスト設計を実現するために、他のドメインと双方向・片方向の信頼関係を結ぶことができます。 Managed Microsoft AD 側の作業は Google Cloud コンソールや gcloud コマンドで実施できます。 参考 : オンプレミス ドメインとの信頼の作成 ネットワーク Managed Microsoft AD では、ドメインコントローラはマネージドな VM として Google Cloud マネージドな VPC 内にデプロイされます。この VM や VPC は Google Cloud によってマネージされているため、ユーザーからは見えません。 ドメイン作成時に、最低 /24 の範囲でドメインコントローラが利用する CIDR を指定します。この CIDR は接続予定のネットワークと重複してはいけません。 ドメイン作成時もしくは設定変更により接続対象の VPC ネットワークを選択すると、ドメインコントローラのマネージドな VPC とユーザーの VPC が VPC Peering で接続されます。これにより VM 等がドメインに参加できるようになります。 これらの VPC は「承認済みネットワーク」と呼ばれ、最大 5 つの VPC ネットワークを選択できます。 本来、承認済みネットワークとして接続できるのは Managed Microsoft AD と同じ Google Cloud プロジェクトの VPC だけですが、 ドメインピアリング という機能で他のプロジェクトの VPC と接続することもできます (最大 10 個)。 なおドメインコントローラは Public IP を持たないため、インターネットに晒されることはありません。 冗長化 Managed Microsoft AD では、設定値として指定するだけで簡単に複数リージョンへのデプロイを実現できます。 また単一リージョンを指定したときでも、2つのドメインコントローラが別々のゾーンに設置されます。 リージョンは新規作成時に指定するほか、あとからリージョンを追加したり削除することもできます。 参考 : マルチリージョンのサポート モニタリング Managed Microsoft AD は Cloud Monitoring と統合されており、ドメインのヘルス状態や信頼関係の状態が情報収集されています。 ただし、2023 年 1 月現在でいずれのメトリクスも BETA 扱いですのでご注意ください。 参考 : Google Cloud metrics また、ドメインに対する監査ログを設定することも可能です。ログオンイベントやポリシー変更などが記録され、ログは Cloud Logging に出力されます。 参考 : ドメインの監査ロギングを設定する バックアップ・リストア 以下の 3 つのバックアップ方法があります。 No 名称 説明 1 オンデマンド バックアップ 任意のタイミングでバックアップを取ることができる。最大 5 世代まで 2 スケジュール バックアップ 12 時間ごとに自動的に取得される。21 世代保存される 3 スキーマ拡張バックアップ スキーマ拡張が実施されると取得される。最大 10 世代まで リストアは gcloud コマンドで実施可能です。これまでに取得されたスナップショット一覧から、スナップショット名を指定して行います。リストアには最長で 90 分ほどかかる場合があります。 参考 : ドメインをバックアップして復元する 杉村 勇馬 (記事一覧) 執行役員 CTO / クラウドソリューション部 部長 元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の神谷です。本記事では、Batch を使って、大容量の CSV ファイルを BigQuery に ETL してみます。 Cloud Functions や Cloud Run といった類似サービスに比べて Batch の使いどころはどこかを検証します。 基本的な情報 Batch とは Batch の利点 ユースケース 料金 類似プロダクトとの比較 検証要件と設計 要件 設計ポイント 実装方式 実装 ディレクトリ構成 main 処理 コンテナ作成 Batch の設定 ジョブの実行 性能検証と結果 検証結果 わかったこと Batch の使いどころ 補足(BigQuery ロード時のメモリエラー) 事象 暫定対応と課題 基本的な情報 Batch とは Batch は、Compute Engine 仮想マシン(VM)インスタンスでバッチ処理ワークロードのスケジューリング、キューイング、実行を行えるフルマネージド サービスです。 Batch は、ユーザーに代わってリソースをプロビジョニングして容量を管理し、バッチ ワークロードを大規模に実行できるようにします。 Batch の利点 筆者が考える Batch の利点は以下です。 サーバレスのコンピューティング基盤であり、処理の負荷に応じて、CPU やメモリを自由に選択できる コンテナが使えるため再利用性が高く、既存の資産を活用しやすい ジョブ実行時のみ Spot VM(プリエンプティブル VM の最新バージョン) を起動するため、費用を抑えることができる ユースケース Google がユースケースとして紹介しているのは以下です。 ゲノム配列決定、創薬などに使用される再現可能なパイプラインのハイスループット処理 モンテカルロ シミュレーションを実行し、市場での取引に必要な結果を迅速に分析する さまざまな入力に基づいて検証テストとシミュレーションを自動化し、設計を最適化する 料金 Batch そのものは無料です。しかし、バッチジョブの実行に使用される Google Cloud リソース( GCE の VM 料金。CPU、メモリ、GPU の利用料)に対しては、料金が発生します。 類似プロダクトとの比較 類似プロダクトとの比較です。 Batch は Cloud Run Jobs に近いですが、インスタンスサイズにほぼ制限がないことがポイントです。 Batch Cloud Functions(第 1 世代) Cloud Functions(第 2 世代) Cloud Run Jobs 言語対応 任意(コンテナのため) Python、Go、Java、Node.js、.Net Core、Ruby、PHP 第 1 世代 と同じ 任意(コンテナのため) イメージレジストリ Artifact Registry(Container Registryは未確認) Container Registry または Artifact Registry Artifact Registry のみ Container Registry または Artifact Registry インスタンスサイズ 事前定義されたマシンタイプ または カスタム マシンタイプ 最大 8 GB の RAM(2 vCPU) 最大 16 GiB RAM(4 vCPU) 最大 32 GiB RAM(8 vCPU) イベントタイプ - gcloud コマンド - HTTP トリガー - Cloud Scheduler - Workflows 7 つのソースからのイベントの直接サポート - HTTP トリガー - イベント トリガー: - Pub/Sub トリガー - Cloud Storage トリガー - Firestore トリガー - Firebase 向け Google アナリティクス トリガー - Firebase Realtime Database トリガー - Firebase Authentication トリガー - Firebase Remote Config トリガー - HTTP トリガー - イベント トリガー: - Pub/Sub トリガー - Cloud Storage トリガー - 汎用の Eventarc トリガー Eventarc でサポートされているすべてのイベントタイプをサポート(Cloud Audit Logs を介した 90 以上のイベントソースを含む) ※ Firebase、Firestore 系は一部未対応のため、第1世代を使う - gcloud コマンド - HTTP トリガー - Cloud Scheduler - Workflows リクエストタイムアウト なし 最大 9 分 HTTP でトリガーされる関数の場合は最大 60 分 イベントによってトリガーされる関数の場合は最大 9 分 - ジョブ:明示的なタイムアウトなし - タスク:最大 24 時間 同時リクエスト リージョンごとの1分あたりのエージェントリクエスト 最大 30,000 件 関数インスタンスごとに 1 件の同時リクエスト 関数インスタンスあたり最大 1,000 件の同時リクエスト コンテナ インスタンスあたり最大 1,000 件の同時リクエスト 並列処理 サポート対象 非対応 非対応 サポート対象 トラフィック分割(異なる関数のリビジョン間でトラフィックを分割するか、関数を以前のバージョンにロールバックする機能) 非対応(デプロイのたびにジョブが新規作成される) 非対応 サポート対象 サポート対象 リトライ あり(タスク単位で 0〜10 回) イベントドリブン関数ではあり。失敗後に正常完了 or 7日経過するまでリトライし続ける 第 1 世代 と同じ あり(0〜10回) 検証要件と設計 要件 今回の検証におけるデータ基盤の要件は以下です。 データソース BigQuery のサンプルテーブル「 wikipedia(313,797,035件、35.69 GB) 」 Zip で圧縮された大容量の CSV ファイル(1 GB、10 GB、35.7 GB)が GCS に連携されてくる CSV は Shift-JIS エンコードになっている(日本語含む) DWH BigQuery にスキーマ(文字列型、数値型、日付型等)を持った状態で保持したい 設計ポイント 上記要件に対して、技術選定、アーキテクチャ設計を行う上でのポイントは以下です。 BigQuery の機能制約で、Zip をそのまま取り込むことができないので、解凍が必要になる BigQuery の機能制約で、Shift-JIS をそのまま取り込むと日本語が文字化けするので、UTF8 変換を行う必要がある 大容量のファイルを扱えるスケーラブルな処理基盤を選択する必要がある 型変換などの簡単な前処理を行える必要がある 実装方式 これらを踏まえて、今回は Batch を使います。実装方式は以下です。 言語は Python Pandas を使って、Zip の解凍、型変換、エンコードを実現する 再利用性を意識して、コンテナを使う Batch の並列化機能を使って、データ分割しながら処理を行う 実装 大まかな実装の流れは こちら を参考にしました。 ディレクトリ構成 ディレクトリ構成は以下の通りです。 . ├── config │ ├── batch-test-case1.json ・ ・ │ └── batch-test-case4_1.json │ └── batch-test-case4_2.json └── src ├── main.py └── requirements.txt main 処理 メインとなる Python の処理は以下です。 並列化する場合としない場合とで、pd.read_csv での読み込み方法を変えています。 並列化する場合( parallelism==True ):BATCH_TASK_INDEX と chunksize によって読み込み対象行を指定し、分割した単位ごとに並列処理 並列化しない場合( parallelism==False ):chunksize ごとの iterator を取得し、逐次処理 import os import random import sys import time from datetime import datetime, timedelta from zoneinfo import ZoneInfo import pandas as pd from google.cloud import bigquery import psutil from distutils.util import strtobool from string import Template # Batch の環境変数として定義されている。並列化を行う際に活用する BATCH_TASK_COUNT = int (os.environ.get( 'BATCH_TASK_COUNT' )) BATCH_TASK_INDEX = int (os.environ.get( 'BATCH_TASK_INDEX' )) def display_resource_usage (message): # メモリ情報を取得 mem = psutil.virtual_memory() # CPU 情報を取得 cpu = psutil.cpu_percent(interval= 1 , percpu= True ) print ( f "memory_total: {round(mem.total / 1024 / 1024 / 1024, 2)} GB, memory_used: {round(mem.used / 1024 / 1024 / 1024, 2)} GB, memory_available: {round(mem.available / 1024 / 1024 / 1024, 2)} GB, cpu: {cpu}, BATCH_TASK_INDEX: {BATCH_TASK_INDEX}, message: {message}" ) def is_first_task_done (dest_table_path): client = bigquery.Client() now = datetime.now(ZoneInfo( "Asia/Tokyo" )) # 直近 60 min 以内で最大 300 件のジョブ一覧を取得 for job in client.list_jobs(max_results= 300 , min_creation_time=(now + timedelta(minutes=- 60 ))): # 宛先テーブルに書き込む初回のジョブが完了していた場合 if int (job.labels.get( "task_index" )) == 0 and job.labels.get( "dest_table_path" ) == dest_table_path and job.state == "DONE" : print ( f "First batch job is done {dest_table_path}, end_time is {job.ended.astimezone(ZoneInfo('Asia/Tokyo'))}" ) return True return False def transfer (df, dest_table_path, index): # Dataframeによる前処理 print (f "TASK_INDEX: {index}, {df[:1]}" ) # Dataframのメモリ使用量を見る print (f "TASK_INDEX: {index}, {df.info()}" ) # UNIX時間をTimestamp型に変換 df[ 'timestamp' ] = pd.to_datetime( df[ 'timestamp' ], unit= 's' ).dt.tz_localize( 'UTC' ) # BQのクライアントライブラリ client = bigquery.Client() # スキーマ定義 schema_definition = [ bigquery.SchemaField( "title" , bigquery.enums.SqlTypeNames.STRING, 'NULLABLE' ), bigquery.SchemaField( "id" , bigquery.enums.SqlTypeNames.INTEGER, 'NULLABLE' ), bigquery.SchemaField( "language" , bigquery.enums.SqlTypeNames.STRING, 'NULLABLE' ), bigquery.SchemaField( "wp_namespace" , bigquery.enums.SqlTypeNames.INTEGER, 'REQUIRED' ), bigquery.SchemaField( "is_redirect" , bigquery.enums.SqlTypeNames.BOOLEAN, 'NULLABLE' ), bigquery.SchemaField( "revision_id" , bigquery.enums.SqlTypeNames.INTEGER, 'NULLABLE' ), bigquery.SchemaField( "contributor_ip" , bigquery.enums.SqlTypeNames.STRING, 'NULLABLE' ), bigquery.SchemaField( "contributor_id" , bigquery.enums.SqlTypeNames.INTEGER, 'NULLABLE' ), bigquery.SchemaField( "contributor_username" , bigquery.enums.SqlTypeNames.STRING, 'NULLABLE' ), bigquery.SchemaField( "timestamp" , bigquery.enums.SqlTypeNames.TIMESTAMP, 'REQUIRED' ), bigquery.SchemaField( "is_minor" , bigquery.enums.SqlTypeNames.BOOLEAN, 'NULLABLE' ), bigquery.SchemaField( "is_bot" , bigquery.enums.SqlTypeNames.BOOLEAN, 'NULLABLE' ), bigquery.SchemaField( "reversion_id" , bigquery.enums.SqlTypeNames.INTEGER, 'NULLABLE' ), bigquery.SchemaField( "comment" , bigquery.enums.SqlTypeNames.STRING, 'NULLABLE' ), bigquery.SchemaField( "num_characters" , bigquery.enums.SqlTypeNames.INTEGER, 'REQUIRED' ) ] # ジョブを識別するためのラベル用 dest_table_path_ = dest_table_path.replace( "." , "-" ) # DataframeをBQにロードするジョブ生成 # 最初の1回は洗い替えをし、残りは追加を行う. if index == 0 : job_config = bigquery.LoadJobConfig( write_disposition=bigquery.WriteDisposition.WRITE_TRUNCATE, # 上書き schema=schema_definition, labels={ "dest_table_path" : dest_table_path_, "task_index" : index} ) print ( f "TASK_INDEX : {index}, WRITE_TRUNCATE" ) else : total_sec = 0 # 「TASK_INDEX = 0」のジョブが完了したかチェック while is_first_task_done(dest_table_path_) is False : # 未完了の場合、スリープ sec = random.uniform( 10 , 20 ) time.sleep(sec) total_sec += sec job_config = bigquery.LoadJobConfig( write_disposition=bigquery.WriteDisposition.WRITE_APPEND, # 追加 schema=schema_definition, labels={ "dest_table_path" : dest_table_path_, "task_index" : index} ) print ( f "TASK_INDEX : {index}, WRITE_APPEND, SLEEP_TIME: {total_sec} sec" ) # 書き込み先のテーブルpathを指定 # dest_table_path = "jkamiya.batch_test.sample1" job = client.load_table_from_dataframe( df, dest_table_path, job_config=job_config, ) print (f "TASK_INDEX: {index}, Job is {job}" ) display_resource_usage( "after client.load_table_from_dataframe" ) # ジョブの完了を待つ job.result() # ジョブが完了すると、書き込み件数などが取得できる table = client.get_table(dest_table_path) # Make an API request. print ( f "TASK_INDEX: {index}, Loaded {table.num_rows} rows and {len(table.schema)} columns to {dest_table_path}" ) def get_df_nrows (source_file_path, encoding, chunksize): try : display_resource_usage( "before pd.read_csv" ) # GCSにあるzipのCSVを直接読み込む(日本語が文字化けしないように、encoding="shift_jis" or "cp932"を指定) # skiprowsとnrowsで読み込み対象範囲を指定する df = pd.read_csv( source_file_path, low_memory= False , encoding=encoding, names=[ 'title' , 'id' , 'language' , 'wp_namespace' , 'is_redirect' , 'revision_id' , 'contributor_ip' , 'contributor_id' , 'contributor_username' , 'timestamp' , 'is_minor' , 'is_bot' , 'reversion_id' , 'comment' , 'num_characters' ], header= 0 , # skiprows:先頭から数えて「BATCH_TASK_INDEX * chunksize」行をスキップする skiprows=BATCH_TASK_INDEX * chunksize, # nrows:chunksize行分読み込む nrows=chunksize ) display_resource_usage( "after pd.read_csv" ) return df except Exception as e: print (f "Exception: {e}, TASK_INDEX: {BATCH_TASK_INDEX}" ) return def get_df_iterator (source_file_path, encoding, chunksize): try : display_resource_usage( "before pd.read_csv" ) # chunksizeで指定した件数分を分割して読み込む df_iterator = pd.read_csv(source_file_path, low_memory= False , encoding=encoding, chunksize=chunksize) display_resource_usage( "after pd.read_csv" ) except Exception as e: print (f "Exception: {e}" ) return return df_iterator def main_proc (source_file_path, dest_table_path, encoding, parallelism, chunksize): # 時間計測開始 time_sta = time.perf_counter() # 並列化するかどうか if parallelism: # する場合は、BATCH_TASK_INDEX と chunksize によって読み込み対象行を指定し、分割した単位ごとに並列処理 df = get_df_nrows(source_file_path, encoding, chunksize) transfer(df, dest_table_path, BATCH_TASK_INDEX) t = Template( 'TASK_INDEX: ${BATCH_TASK_INDEX}, processing_time: ${processing_time} sec' ) else : # しない場合は、chunksize ごとの iterator を取得し、逐次処理 df_iterator = get_df_iterator(source_file_path, encoding, chunksize) index = 0 for df in df_iterator: transfer(df, dest_table_path, index) index += 1 t = Template( 'processing_time: ${processing_time} sec' ) # 時間計測終了 time_end = time.perf_counter() # 経過時間(秒) tim = time_end - time_sta print (t.substitute(processing_time= round ( tim, 3 ), BATCH_TASK_INDEX=BATCH_TASK_INDEX)) if __name__ == '__main__' : args = sys.argv source_file_path = args[ 1 ] dest_table_path = args[ 2 ] encoding = str (args[ 3 ]) parallelism = strtobool(args[ 4 ]) chunksize = int (args[ 5 ]) print ( f "source_file_path: {source_file_path}, encoding: {encoding}, parallelism: {args[4]}, chunksize: {chunksize}" ) main_proc(source_file_path, dest_table_path, encoding, parallelism, chunksize) main.py と同一階層に「requirements.txt」を置き、必要なライブラリを定義します。 pandas==1.4.1 google-cloud-storage==2.2.1 gcsfs==2022.11.0 google-cloud-bigquery==3.4.1 pyarrow==10.0.1 psutil==5.9.4 コンテナ作成 次に、 buildpacks を使って、Dockerfile を用意することなくコンテナを作ります。 ローカルからコンテナを作る場合には以下を実行します。 sudo pack build --builder=gcr.io/buildpacks/builder batch-sample --env GOOGLE_ENTRYPOINT = " python " Cloud Build 経由で作る場合には以下を実行します。あらかじめ、Artifact Registry にコンテナ格納場所を作っておきます。 (筆者の環境だと作成までに20-25分程度かかりました) # 「containers」というリポジトリを作成 gcloud artifacts repositories create containers --repository-format=docker --location=asia-northeast1 # 「asia-northeast1-docker.pkg.dev/jkamiya/containers」というパスでリポジトリが生成されるので、そこに「batch-sample」というコンテナを配置 gcloud builds submit ./src/ --pack image =asia-northeast1-docker.pkg.dev/jkamiya/containers/batch-sample, env =GOOGLE_ENTRYPOINT = python Batch の設定 次に、今回の検証の肝となる Batch の設定を書いていきます( 参考 )。 以下は並列化する場合の設定例です。 { " taskGroups ": [ { " taskSpec ": { " runnables ": [ { " container ": { " imageUri ": " asia-northeast1-docker.pkg.dev/jkamiya/containers/batch-sample ", " commands ": [ " main.py ", " gs://kamiya-batch-test/export/case4/test_000000000000_shiftjis.zip ", " jkamiya.batch_test.sample ", " cp932 ", " true ", " 1000000 " ] } } ] , " computeResource ": { " cpuMilli ": 64 , " memoryMib ": 128 } , " maxRetryCount ": 10 } , " taskCount ": 300 , " parallelism ": 100 } ] , " allocationPolicy ": { " instances ": [ { " policy ": { " machineType ": " n2d-highmem-64 " } } ] } , " logsPolicy ": { " destination ": " CLOUD_LOGGING " } } 設定のポイントは以下です。 imageUri:ビルドしたイメージのパス(Artifact Registry) commands:コンテナに渡す引数。ビルド時のエンドポイントで「GOOGLE_ENTRYPOINT=python」を指定したため、pythonコマンド実行のあとに続くファイル名や実行時引数をセット computeResource:1 タスクあたりに確保するコンピュータリソース。並列数を上げたい場合、多く取りすぎないほうが良い cpuMilli:CPU はそんなに使い切れないので、低めで良い(machineType に対して cpuMilli が大きすぎると、parallelism で指定した並列数を割り当てられない) memoryMib:タスク単位でデータがギリギリ乗るサイズをセット。仮に、1 タスクで 扱う データ(Dataframe の 1 chunk) が 110 MBであれば、 memoryMib は 128 MB でも事足りる maxRetryCount:タスクレベルでの最大リトライ数。未指定の場合は0となる。ジョブを並列化したときにタスクが1つでもエラーになっていればジョブ全体がエラーとなってしまうため、ここは指定していたほうが良い(筆者の場合だと、タスク100個のうち2,3個はエラーになっていた) taskCount:タスク数。computeResource と machineType に応じた設定を行う parallelism:並列数。computeResource と machineType に応じた設定を行う machineType:VM のマシンタイプ(バッチの裏側は Compute Engine の VM) destination:ログ出力先指定(Cloud Logging) ジョブの実行 以下のコマンドでジョブを実行します。 現時点だと、「asia-northeast1(東京)」は Batch のロケーションとして、許可されていないようです。 gcloud batch jobs submit batch-sample- `date + " %Y%m%d%H%M%S " ` --location us-central1 --config ./config/batch-test-case1.json 無事デプロイされジョブがトリガーされると以下のようになります。 ジョブ実行 ジョブの詳細画面です。ジョブのマシンタイプやタスク数、並列数、実行時にセットした引数等を確認できます。 並列化の場合、画面右上にランニングとなっているタスク数や、失敗したタスク数が表示されます。 ここでエラーが多ければ、並列化が上手く行われていなかったり、VM としてジョブに必要なリソースが不足している可能性があります。 machineType を上げたり、parallelism や computeResource を下げたりといった調整します。 1 タスクあたりに必要十分な computeResource を確定した後、ジョブ全体として処理すべきデータ量が多い場合には、 machineType を上げて十分なメモリを確保すると良いでしょう。 ジョブ詳細 Compute Engine の画面です。ジョブごとに VM が作成され、ジョブが完了したら削除されます。 並列化が効いている場合には、グループインスタンスによって複数の VM が起動します。 parallelism を大きくすると、そのぶん起動する VM が多くなります。 Compute Engine の VM CPU やメモリ等のリソース利用状況を細かく見たければ、Compute Engine のダッシュボードではなく、Cloud Monitoring を使います。 よく見るのは以下のような指標です。 compute.googleapis.com/instance/cpu/utilization compute.googleapis.com/instance/memory/balloon/ram_used Cloud Monitoring のメトリクス ジョブが完了したので、BigQuery を見てみましょう。 想定通りデータが書き込まれているようです。 BigQuery への書き込み結果 性能検証と結果 大容量データを使った性能検証を行います。今回試すのは 3 種類の CSV ファイル(1 GB、10.7 GB、35.7 GB)です。 検証結果 結果は以下の通りです。 1 GB の csv No 元ファイルサイズ zipファイルサイズ 件数 ジョブ実行時間 chunk件数(1chunkあたりの想定サイズ) 1chunkあたりの想定サイズ computeResource.cpuMilli computeResource.memoryMib taskCount parallelism マシンタイプ vCPUs Memory 料金単価 VM 数 料金 備考 1 1GB 451.8MB 10,000,000 0:03:19 1,000,000 0.1GB デフォルト(2000) デフォルト(2000) 1 1 e2-standard-4 4 vCPUs 16GB $0.04021 hourly 1 $0.00222 10.7 GB の csv No 元ファイルサイズ zipファイルサイズ 件数 ジョブ実行時間 chunk件数(1chunkあたりの想定サイズ) 1chunkあたりの想定サイズ computeResource.cpuMilli computeResource.memoryMib taskCount parallelism マシンタイプ vCPUs Memory 料金単価 VM 数 料金 備考 2 10.7GB 4.5GB 100,000,000 0:39:49 1,000,000 0.1GB デフォルト(2000) デフォルト(2000) 1 1 e2-standard-4 4 vCPUs 16GB $0.04021 hourly 1 $0.02668 3 10.7GB 4.5GB 100,000,000 0:26:19 10,000,000 1.1GB デフォルト(2000) デフォルト(2000) 1 1 e2-standard-4 4 vCPUs 16GB $0.04021 hourly 1 $0.01764 4 10.7GB 4.5GB 100,000,000 0:05:59 1,000,000 0.1GB 64 128 100 100 e2-standard-32 32 vCPUs 128GB $0.34368 hourly 5 $0.17136 35.7 GB の csv No 元ファイルサイズ zipファイルサイズ 件数 ジョブ実行時間 chunk件数(1chunkあたりの想定サイズ) 1chunkあたりの想定サイズ computeResource.cpuMilli computeResource.memoryMib taskCount parallelism マシンタイプ vCPUs Memory 料金単価 VM 数 料金 備考 5 35.7GB 14.2GB 313,797,035 1:25:00 10,000,000 1.1GB デフォルト(2000) デフォルト(2000) 1 1 e2-standard-4 4 vCPUs 16GB $0.04021 hourly 1 $0.05696 6 35.7GB 14.2GB 313,797,035 -(エラー) 30,000,000 3.3GB デフォルト(2000) デフォルト(2000) 1 1 e2-standard-4 4 vCPUs 16GB $0.04021 hourly 1 - CSVを読み込めない(メモリ不足) 7 35.7GB 14.2GB 313,797,035 1:19:00 30,000,000 3.3GB デフォルト(2000) デフォルト(2000) 1 1 e2-standard-8 8 vCPUs 32GB $0.08041 hourly 1 $0.10587 8 35.7GB 14.2GB 313,797,035 1:14:00 30,000,000 3.3GB デフォルト(2000) デフォルト(2000) 1 1 e2-standard-32 32 vCPUs 128GB $0.34368 hourly 1 $0.42387 9 35.7GB 14.2GB 313,797,035 -(エラー) 35,000,000 3.85GB デフォルト(2000) デフォルト(2000) 1 1 e2-standard-8 8 vCPUs 32GB $0.08041 hourly 1 - BQ書き込みエラー(3.9+GB) 10 35.7GB 14.2GB 313,797,035 -(エラー) 40,000,000 4.4GB デフォルト(2000) デフォルト(2000) 1 1 e2-standard-4 4 vCPUs 16GB $0.04021 hourly 1 - BQ書き込みエラー(4.6+GB) 11 35.7GB 14.2GB 313,797,035 0:32:10 1,000,000 0.1GB 64 128 314 100 n2d-highmem-64 64 vCPUs 512GB $2.91789 hourly 5 $7.82157 計 11 回実行して、8 回成功、3 回 はエラーになりました。マシンタイプは、「e2-standard-4」、「e2-standard-8」、「e2-standard-32」、「n2d-highmem-64」の 4 つを使っています。 No.6 と No.7 を比較 1 chunk あたりの想定サイズが 3.3 GB であり、これが「e2-standard-4」のマシンタイプではメモリエラーになっている マシンタイプを「e2-standard-8」にスケールアップすることで、無事ジョブが成功している No.9 と No.10 のエラー BigQuery へのロード時に BigQuery 側でメモリエラーになっている(原因については後述) No.7、No.8、No.11 を比較 35.7GB のデータをシングルタスクでやった場合(No.7、No.8)と、並列化した場合(No.11)の違い 並列化によって倍以上のスピードで終わっているが、料金は 10 倍以上かかっている No.3、No.4 を比較 10.7GB のデータをシングルタスクでやった場合(No.3)と、並列化した場合(No.4)の違い 並列化によって 5 倍以上のスピードで終わっているが、料金は 17 倍以上かかっている わかったこと 今回の検証で分かったことは以下です。 タスクの並列化 タスクの並列実行機能を使って、chunk ごとに処理を行うことで効率的にマシンリソースを活用できる CSV の読み込み時に chunksize で指定した件数ごとに分割して処理を実行しているため、全データをメモリに乗せてしまって(Pandas のデフォルトの挙動)、メモリエラーになることはない chunksize で処理を分割することで BigQuery ロード時のメモリエラー(後述)にも対処できる マシンリソース CPU 使用率を 100 % に近づけつつ、メモリ使用量が溢れないよう設定を調整する必要がある memoryMib は 1 タスクで扱うデータサイズよりちょっと大きい値をセットする cpuMilli はそんなに取らなくて良い(Cloud Monitoring で使用率を見ると、余らせているケースが多い) GCE の Cloud Logging を観察し、 task task/j-a1f61f46-a24e-49b3-b013-8b9d2cf3231b-group0-230/2/0 runnable 0 wait error: exit status 137 のようなタスクレベルのエラーが出ている場合には、VM のメモリ不足が原因のことが多い Python の psutil 等を使ってメモリ使用率を確認し、machineType のメモリ値に近い場合には、machineType 自体のスペックを上げて十分にメモリを確保する 速度と料金 並列化によってかなり速くなるが、その分料金がかかる 実装方式 Dask や Modin、Vaex といった Pandas 高速化ライブラリを使わずに余裕を持ってスケールできる点はメリットだと考えられる(コンテナなので、これらを利用することもできる) Batch の使いどころ 今回の検証を通じてわかった Batch の使いどころは以下です。 Cloud Run Jobs で手に負えない重い処理 マシンリソースのスケールアップ(machineType のスペックアップ)やスケールアウト(並列数に応じてグループインスタンス内のVM数を増やす)の制限がないため、現実的な時間で実行できる 既存のワークロードの変更を最小限にしつつ、大容量のデータを扱いたいケース データ分割のロジックを入れるだけなので、分散処理用のライブラリやフレームワークで書き換える必要がない データ基盤の初期移行のようなショットで発生し、定常的に行うわけではないケース 瞬間的にクラウド料金がかかるが、作り込みの工数よりは費用が抑えられる 上記以外にも、MPI(Message Passing Interface)ライブラリや GPU を使いたいケースも向きそうですが、これらは今後の検証課題にしたいと思います。 補足(BigQuery ロード時のメモリエラー) 事象 Pandas の Dataframe を BigQuery にアップロードする際に、一回のデータ量が多すぎると(約 4GB 以上)、VM側ではなく BQ 側でメモリーエラーが発生します。 以下のようなエラーログが出ます。 Resources exceeded during query execution: The query could not be executed in the allotted memory. Peak usage: 126 % of limit. Top memory consumer ( s ) : input table/file scan: 100 % Error while reading data, error message: Failed to read a column from Parquet file gs://bigquery-prod-upload-asia-northeast1/prod-scotty-191e6c74-86b6-4251-9a29-37b393e64ebb: row_group_index = 0 , column = 9 . Exception message: Unknown error: CANCELLED: . Detail: CANCELLED: 事象を整理すると、 エラーメッセージにあるように、一旦中間ファイルとして GCS に Parquet で保存した後に、BigQuery にロードしている リファレンス には 読み込みジョブあたりの最大サイズが Parquet に関しては 15 TB とあるため、この制限にはかかっていない Parquet のレコードのサイズは50MB以下、カラム数は100個以下に抑える必要がある が、この制限にもかかっていない となります。仕様なのか、実装方法によっては解決できるのかまだ不明で、根本原因は引き続き調査していきます。 暫定対応と課題 暫定対応としては、Pandas の Dataframe を分割しながら BQ にロードすると良いです( 参考 )。 Batch の設定によって並列数を増やせば、1 chunk あたり 4 GB 以下しか処理できなくても、問題なく大容量データに対応できます。 ただし、このロード方法はトランザクションが管理されません。 同じテーブルに書き込む他のジョブとタイミングが重なった場合には、データ不整合が起きる可能性があります。 一旦中間テーブルに書き込んで、その後にターゲットテーブルに Merge するといったパイプライン設計を行うと良いでしょう。 神谷 乗治 (記事一覧) データアナリティクス準備室 室長 クラウドエンジニア。2017 年頃から Google Cloud を用いたデータ基盤構築や ML エンジニアリング、データ分析に従事。クラウドエース株式会社システム開発部マネージャーを経て現職。Google Cloud Partner Top Engineer 2023、Google Cloud Champion Innovators(Database)、 著書:「GCPの教科書III【Cloud AIプロダクト編】」  
アバター
G-genの佐伯です。当記事では、Vertex AIのAutoML及びバッチ予測の基本的な操作方法を解説しながら、簡易的で且つ安価に予測データを収集できる手法を解説できればと考えます。前編では、Vertex AIのAutoML及びバッチ予測の基本的な操作方法を解説させていただきます。 Vertex AI AutoML とは 当記事で行う検証作業 検証作業内容 今回のトレーニングデータについて データの前処理 作業の主な流れ 対象となるデータをデータセットに登録する データセットを指定してAutoMLの学習処理を実行する 推論手法 バッチ予測 推論データの結果確認 まとめ Vertex AI AutoML とは AIのモデル作成は、高度なデータサイエンスの知識・経験が必要ですが、Vertex AI AutoMLを使用すれば、トレーニングデータをアップロードするだけで自動的に機械学習モデルを構築することができます。 Vertex AIのAutoMLやバッチ予測は、誰でも簡易的にモデル作成や予測が行え、 最近ですとAutoMLがモデル構築において、その手法(学習及びトレーニングを行っているのかの過程)を 知ることもできる機能がリリースされるなど、機械学習初学者にも利便性の高いものであります。 機械学習をこれから学習したいや概要を掴みたいなどの初学者には、特に有用性が高いと考えます。 (参考) Vertex AIの概要 また、以下の4つのデータを取り扱うことが出来ます。 画像データ 表形式データ テキストデータ 動画データ 当記事で行う検証作業 検証作業内容 パブリックドメインとなっている [Adult Census Income]をトレーニングデータとして、 『所得:income(ターゲット)』とある個人に関する様々な情報(年齢、職業、結婚歴など)との相関性を調べ、AutoMLでモデルを作成します。 そのモデルを用いて年収($50,000よりも高いかどうか)を予測して行きます。 今回のトレーニングデータについて モデルの作成に使用するトレーニングデータとして、パブリックドメインとなっている Adult Census Income を使用しています。形式は csv です。 このデータは米国の国勢調査局のデータベースから抽出されたものであり、ある個人に関する様々な情報(年齢、職業、結婚歴など)と「年収(income)が$50,000よりも高いか、$50,000以下か」が記録されています。 データの前処理 トレーニングデータのAdult Census Incomeのセル中に『'?'』が含まれているため、これを以下のコードで事前に削除しておきます。 また、トレーニングデータを(モデルに与えて)予測用(pred_data.csv)と答え合わせ用(pred_answer.csv)に便宜上分割します。 import pandas as pd from sklearn.model_selection import train_test_split # データ読み込み df = pd.read_csv( '/home/saikio/SRC/Vertex_AI/adult.csv' ) # ?を含む行を削除 drop_index = [] for column in [ 'workclass' , 'occupation' , 'native.country' ]: drop_index.extend(df.loc[df[column] == '?' ].index.values) drop_index = sorted ( set (drop_index)) df2 = df.drop(index=drop_index) # 学習に使用するデータ(train)とモデルに予測させるデータ(test)に分ける train, test = train_test_split(df2, test_size= 0.01 , random_state= 0 ) # testを使ってincomeを予測したときの正解率を見たいので、incomeは分離しておく pred_data = test.drop( 'income' , axis= 1 ) pred_answer = test[ 'income' ] # それぞれCSVファイルに出力 train.to_csv( '/home/saikio/SRC/Vertex_AI/train.csv' , index= False ) # トレーニング用のデータ pred_data.to_csv( '/home/saikio/SRC/Vertex_AI/pred_data.csv' , index= False ) # テストの際にモデルに与えるデータ pred_answer.to_csv( '/home/saikio/SRC/Vertex_AI/pred_answer.csv' , index= False ) # テストの正解データ(※後で不要になる) トレーニングデータの前処理コードのサンプル 上記のコードは、作成時のものから一部抜粋したものになります。 作業の主な流れ 今回私が実施した全体的な操作の流れは、以下の3点になります。 1. 対象となるデータをデータセットに登録する 2. データセットを指定してAutoMLの学習処理を実行する 3. 学習済みモデルを使ってバッチ予測を行う 対象となるデータをデータセットに登録する 次に対象となるデータの選択を行います。 今回はターゲット列の予測を行いたいので、 タブ『表形式』⇛『回帰/分類』を選択 データセットが作成されます。 次にトレーニングでどのデータと紐つけるかを選択します。 ※今回は事前にCloud Storageにトレーニング用データを用意していましたので、 こちらを選択 データセットが作成されたことを確認。 データセットを指定してAutoMLの学習処理を実行する ①Vertex AIのダッシュボードから『トレーニング』⇛『作成』をクリック ②トレーニング方法 以下の手順で選択 Dataset:先程作成したデータセット Objective:Classification(今回は分類が対象) Model training method:AutoML ③モデルの詳細(トレーニングの作成と目的変数の設定) Vertex AIでは新規に学習をするほかに、既存の学習済みモデルの新しいバージョンを作成できます。 これはデータを更新して新しいモデルを作成する際など、モデルを更新しつつ旧バージョンも残しておくのに最適です。 Vertex AIでデータセットを利用する際には、学習時に自動的にtrain, valid, testの3つのデータに分割されます。 保存先は以下になります。 Cloud Storage BigQuery (『Export test dataset to BigQuery』にチェックを入れて出力先を設定する必要はあります) ③トレーニングオプション ここでは説明変数に関する設定を行います。 各列の項目にチェックを入れることで、その列を利用します。 また、データの型を明示的に設定することも可能です。 ④コンピュートと料金 「コンピューティングと料金」で最大でどのくらい学習を行うかの設定をします。 ここで設定した値が最大で発生する料金となります。 AutoMLでは精度向上のための様々な学習が行われますが、 より精度が向上する余地があってもここで設定したノード時間で処理を中断させることで結果とコストのトレードオフをユーザが設定できます。 この設定は"最大"ノード時間となっています。 「 早期停止を有効にする 」オプションを有効にすることで、これ以上の向上が見込めないと判断された場合は途中で処理を終了することが可能なため、余分なコストは発生しません。 ⑤モデル作成完了 モデルが作成されると推論が可能になります。 自分が作成したモデルの場合、作成時間は2時間 17分で作成料金は3017円となりました。 また、モデル作成完了時にはメールで完了メッセージも送信されます。 時間単位での課金ではない点は、ご注意ください。 Model Registory Model Registryに登録されたものはバージョンごとに学習済みモデルのファイルの他、学習時の情報や推論の際に利用するコンテナに関する情報が含まれています。 事例:信頼度50%を超えると、再現率と適合率の乖離が大きくなる。 推論手法 推論方法については、以下の2点があります。 1. エンドポイント作成(リアルタイム処理の場合に最適) 2. バッチ予測 (大量のデータに対してまとめて推論する場合に最適) 今回は、リアルタイム処理は必要ない為、バッチ予測を用いた方法をご紹介します。 バッチ予測 「バッチ予測の定義」では利用するモデルと入出力先の情報を設定します。 入力・出力はそれぞれBigQueryかCloud Storageを設定できます。 今回は以下の手順で設定します。 ・モデル名(上記で作成したモデル名を指定) ・推論用データ元のリソース指定:Cloud Storage ・推論用データ(Cloud Storage内で作成したvertex_ai_test/pred_data.csvファイルを指定) ・出力先のリソース指定:Cloud Storage ・推論出力先のCloud Storage(Cloud Storage内で作成したvertex_ai_testのバケット) 「モデルのモニタリング」では、特徴量が学習時と異なる場合に検出する設定が可能です。 オプショナルとなるため、今回は割愛しています。 「バッチ予測の定義」及び「モデルのモニタリング」の内容が、よければ『作成』ボタンを押し処理開始。 バッチ推論が完了すると、メールで終了の連絡が送信されます。 今回はCloud Storageを選択した為、複数ファイルに分割されていることが確認できます。 以下はCSV形式でCloud Storageに出力した結果です。多くの推論結果がcsvファイル形式で出力されています。 推論データの結果確認 CSV形式でCloud Storageに出力した結果です。 入力に使ったデータの各行の最後に推論結果(黄色でのマーキング箇所)が付与されているのが確認できます。 まとめ 今回は、Vertex AIのAuto MLを使用してバッチ予測を行う基本的な手法を行いました。 初心者にも大変使いやすい機能ですので、機械学習初学者の方やVertex AIを初めて使用される方の手助けになれば、幸いです。 後編では、今回作成した予測済みモデルとdockerを使用して 予測データを取得する方法をご紹介できればと思います。 佐伯 修 (記事一覧) クラウドソリューション部 前職では不動産業でバックエンドを経験し、2022年12月G-genにジョイン。 入社後、Google Cloudを触り始め、日々スキル向上を図る。 SEの傍ら、農業にも従事。水耕を主にとする。
アバター
当記事は みずほリサーチ&テクノロジーズ × G-gen エンジニアコラボレーション企画 で執筆されたものです。 みずほリサーチ&テクノロジーズ株式会社の藤根です。この度、G-gen さんとのコラボを通じて、弊社エンジニアによる Google Cloud の記事を執筆する機会をいただきました。 本記事では、Google Cloud が誇る BigQuery について、初学者を対象にご紹介させていただきます。 先行して弊社小野寺より AWS アーキテクトがはじめて Google Cloud で静的 Web ページを配信した話 も公開しておりますので、こちらも是非ご覧ください。 当ブログは G-gen × みずほRT によるコラボ記事です BigQuery でできること OLAP に特化したアーキテクチャ サーバーレス 低コスト 直近のアップデート 非構造化データのサポート SQL 以外の言語をサポート トランザクションデータをニアリアルタイムで分析 BigQuery のアンチパターン ① SELECT * を使わず、必要なカラムを指定する ② クエリに上限を設定する ③ テーブルを分割する サービスの概観 まとめ BigQuery でできること BigQuery とは、 様々なデータを蓄積・統合・クエリできる Google Cloud の データウェアハウス(DWH)サービス です。 「データの蓄積やクエリ」と言うと、Oracle や PostgreSQL 等の RDBMS をイメージする方も多いと思います。しかし、BigQuery は RDBMS とは全く異なり、以下のように多くのメリットがあります。 OLAP に特化したアーキテクチャ BigQuery は列指向アーキテクチャ(列方向にデータを保持する構造、図の右)であり、 列単位でのクエリが得意 です。オンライン分析処理( OLAP : Online Analytical Processing ) などのデータ分析では特定の列のみを抽出・処理することが多く、RDBMS(図の左)では行全体をスキャンする必要がありますが、 BigQuery なら必要な列だけをスキャンできるため、パフォーマンスに優れています 。 (画像は BigQuery 特集:ストレージの概要 より引用) また、BigQuery の内部ではストレージとコンピューティングのリソースが分離されています。ストレージ(図の左)はデータのレプリケーションと分散管理が行われているため、 単一障害点なしで大規模なデータを蓄積 できます。コンピューティング(図の右)は数万台規模のクラスターサーバーで構成されているため、複雑なクエリも 超並列処理 (MPP) による高速化 を利用することができます。 (画像は [新しいブログシリーズ] BigQuery 特集:概要 より引用) サーバーレス BigQuery はサーバーレスサービスです。BigQuery の ストレージ容量は実質無制限 のため、将来のクエリ計画やデータ量を予測してストレージ/メモリを購入・増強したり、定期的なバキューム処理で使用可能スペースを確保する必要はありません。インフラ管理者を悩ませる セキュリティパッチ適用やライセンス更新といった作業も不要 です。 加え、BigQuery の SLA は非常に高く、 2020 年には 99.99% の保証を発表 しています。これは、競合の AWS Redshift や Azure Synapse Analytics を大きく引き離しています。特に安定稼働を重視するプロジェクトでは、BigQuery の高い SLA は重要な指標の 1 つとなり得るでしょう。 プロバイダー サービス名 SLA Google Cloud BigQuery 99.99% AWS Redshift 99.9% Azure Synapse Analytics 99.9% 低コスト これだけのメリットがあるとさぞ高いのでは...と思いたくなりますが、BigQuery の オンデマンド分析は従量課金制 となっており、 使った分のみの請求 となります。単価も安く、仮に 10TB のデータに対して同量のクエリスキャンを毎月行ったとしても、使用料はわずか $300 未満/月 です。 高額な DWH サービスでは導入前に入念な事前検証を求められますが、BigQuery ならば 少額の予算からスモールスタートが可能 です。更に、1TB までのクエリ、10GB までのストレージ使用なら毎月無料のため、小規模なデータセットなら料金を気にせず実行できます。 科目 単価(東京リージョン) オンデマンドクエリ料金 $6.00/TB ストレージ料金 $0.023/GB 直近のアップデート 2022 年 10 月に Google Cloud Next'22 が開催され、多数のサービスで大幅なアップデートが発表されました。BigQuery でも重要な機能がプレビュー公開されましたので、いくつかご紹介いたします。 非構造化データのサポート BigQuery の新しいテーブルタイプである オブジェクトテーブルのプレビュー版が公開 され、Google Cloud Storage に保存された 画像、音声、PDF ドキュメントなどの非構造化データに対して直接クエリ・機械学習を実行できる ようになりました。 これまで非構造化データはサポートしておらず、API や前処理加工を通じて構造化データを抽出する作業が別途必要でしたが、このアップデートにより 非構造化データの検索・加工・学習を BigQuery だけで実行できる ようになります。 (画像は データと AI の統合により BigQuery に非構造化データ分析を提供する より引用) SQL 以外の言語をサポート Apache Spark 用ストアドプロシージャのプレビュー版が公開 され、 BigQuery から Apache Spark プログラムを実行できる ようになりました。 これまで Apache Spark を活用したデータ処理は、 DataProc 単体で実行する方法と、 BigQuery コネクタ を通じて DataProc からデータを読み書きする方法がありましたが、どちらも DataProc のクラスタ構築が必要でした。今回のアップデートで BigQuery 上で Apache Spark の ETL を直接実行できる ようになるため、既存の Spark 資産をサーバーレスな BigQuery で実行できるのはとても便利です。 さらに、 リモート関数が一般公開 され、Cloud Functions と Cloud Run で作成したユーザー定義関数を実行できるようになりました。SQL と JavaScript 以外の選択肢が増えたことで、開発の柔軟性がさらに高まりました。 (画像は BigQuery で無制限のワークロードを構築: SQL 以外の言語を使用した新機能 より引用) トランザクションデータをニアリアルタイムで分析 Datastream for BigQuery のプレビュー版が公開 され、PostgreSQL、MySQL、AlloyDB、Oracle などの データベースから BigQuery に直接データをレプリケーションできる ようになりました。 BigQuery へのデータ反映作業が自動化されることで、反映後の分析やレポート生成の頻度・スピードが向上し、データドリブンな意思決定を加速させることができます。 (画像は Datastream for BigQuery のご紹介 より引用) BigQuery のアンチパターン アップデートの度に便利になる BigQuery ですが、適切な使い方をしないと思わぬコストが発生する場合があります。 BigQuery ではクエリ料金が大半を占めることが多いため、 いかにスキャンデータを抑えるか、がコストコントロールの要 です。ここでは、 BigQuery におけるコスト最適化のベストプラクティス を参考に、コスト高になり得るアンチパターンとその回避方法をご紹介します。 ① SELECT * を使わず、必要なカラムを指定する SELECT * を実行すると、全ての列でフルスキャンが実行されてしまいます。代わりに、 必要なカラムを指定することで、スキャンデータ量を最小限に抑える ことができます。また、 LIMIT 句を指定してもスキャンデータ量は変わらない(コスト削減にならない) 点にも注意が必要です。 (画像は BigQuery におけるコスト最適化のベストプラクティス より引用) ② クエリに上限を設定する デフォルトではクエリのスキャンデータ量に上限は無いため、誤ったクエリによりフルスキャンが実行されることがあり得ます。代わりに、 課金される最大バイト数を設定する と、 上限値を超えそうな場合はクエリがエラーとなり、料金は発生しません 。人為的なミスはどんなに注意しても起こり得るものですので、設定を推奨します。 (画像は BigQuery におけるコスト最適化のベストプラクティス より引用) ③ テーブルを分割する 時系列に増えるデータを単一のテーブルに追加し続けると、テーブルサイズが大きくなり、スキャンデータ量が増加してしまいます。BigQuery では、①データの取り込み時間、②日付やタイムスタンプ列、③整数列のいずれかで テーブルをパーティション分割 することが推奨されています。これにより、クエリ時にテーブル全体ではなく必要なパーティションのみがスキャンされるため、スキャンデータ量を削減できます。 (画像は BigQuery 特集:ストレージの概要 より引用) サービスの概観 本記事では分量の都合から取り上げませんでしたが、BigQuery には他にも、 BigQuery ML による機械学習 BigQuery Omni によるマルチクラウド連携 Tableau や Looker Studio 等の BI ツールとの連携 など、多様な機能を有しています。BigQuery の概観をざっと知るには、以下のクイックリファレンスが便利です。 日本語の解説記事 もありますので、ぜひご覧下さい。 (画像は BigQuery で「ビッグ」なクエリを実行:クイックリファレンス より引用) まとめ 本記事では、BigQuery という DWH サービスを紹介させていただきました。BigQuery は DWH として優れた機能が多々あり、今後もアップデートが期待されるサービスの1つですので、Google Cloud を使用される際は積極的に活用していきたいですね。 より詳細に BigQuery を知りたい方は、以下の記事をご参照ください。 blog.g-gen.co.jp 藤根 成暢 みずほリサーチ&テクノロジーズ 先端技術研究部に所属。Pythonによるデータ分析やAI開発、Google Cloudの技術検証などを担当。保有資格はACE、PDE。
アバター
G-gen の又吉です。当記事では、Cloud Functions の呼び出しを許可されたアカウントのみが実行できるよう制御する方法を紹介します。 概要 背景 構成 準備 必要な API の有効化 サービスアカウントの作成 functions-2 関数のサービスアカウント作成 functions-3 関数のサービスアカウント作成 フォルダ構成 functions_1/main.py functions_1/requirements.txt functions_2_3/main.py functions_2_3/requirements.txt Cloud Functions の作成 functions-1 関数の作成 functions-2 関数の作成 functions-3 関数の作成 権限の付与 動作確認 実行 1 実行 2 もう少し深堀ってみる curl コマンドで実行 トークンの確認 トークンを取得する仕組み トークンのデコード 概要 背景 Cloud Functions のトリガーには大きく 2 つのカテゴリに分かれています。 No トリガー 名 説明 1 HTTP (S) トリガー Cloud Functions の URL エンドポイントを使用し HTTP リクエストをトリガーに関数を実行する 2 イベントトリガー Pub / Sub トピックのメッセージや Cloud Storage バケットの変更等をトリガーに関数を実行する さらに HTTP トリガーでは、以下の 2 つの認証方法が存在します。 No 認証方法 説明 1 未認証の呼び出しを許可 「 allUsers 」という特別なプリンシパルに「 Cloud Run 起動元 」ロールが付与されるため、インターネット上のすべてのユーザーがアクセスできるようになる 2 認証が必要 IAM を使用して許可するユーザーを管理できる Cloud Functions 新規作成時の HTTPS トリガー設定項目 Web サイト等のインターネットに公開するシステム以外は、基本的に [認証が必要] としてトリガーを設定することが HTTP トリガーの推奨事項とされています。 構成 今回の構成はシンプルに、 functions-1 関数を「 認証が必要 」とした HTTP トリガーでデプロイします。 functions-2 関数には functions-1 関数を 実行できる権限 を付与し、 functions-3 関数には 何も権限を付与せず 、それぞれが functions-1 関数を HTTP リクエストで呼び出します。 構成図 尚、本記事では Cloud Functions の概要については触れていないため、詳しく知りたい方は以下の記事をご参考に下さい。 blog.g-gen.co.jp 準備 準備と動作確認はすべて gcloud コマンドで実行します。 gcloud コマンドがローカル環境で使えない場合は、 Cloud Shell からでも実行可能です。 gcloud コマンドのインストール方法はこちらの 公式リファレンス を参照下さい。 必要な API の有効化 対象のプロジェクト内で以下の API を有効化します。 artifactregistry.googleapis.com cloudbuild.googleapis.com cloudfunctions.googleapis.com logging.googleapis.com pubsub.googleapis.com run.googleapis.com 以下のコマンドを実行します。 gcloud services enable artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ cloudfunctions.googleapis.com \ logging.googleapis.com \ pubsub.googleapis.com \ run.googleapis.com サービスアカウントの作成 functions-2 関数と、functions-3 関数のサービスアカウントを作成する。 functions-2 関数のサービスアカウント作成 gcloud iam service-accounts create functions-2 \ --display-name =" functions-2 " \ --project =< project_id > functions-3 関数のサービスアカウント作成 gcloud iam service-accounts create functions-3 \ --display-name =" functions-3 " \ --project =< project_id > フォルダ構成 実行環境で、以下のフォルダを作成する。 尚、functions-2 関数と functions-3 関数は同じソースコードを利用し、相違点は サービスアカウントの権限のみ とする。 authenticationg_for_invocation ├── functions_1 │ ├── main.py │ └── requirements.txt │ └── functions_2_3 ├── main.py └── requirements.txt functions_1/main.py functions-1 関数は、リクエストが来たら Hello HTTP!! と返すだけのシンプルな関数とする。 import functions_framework @ functions_framework.http def hello_http (request): return "Hello HTTP!!" functions_1/requirements.txt functions-framework == 3 .* functions_2_3/main.py Python クライアントライブラリのサンプル を参考に、実行関数に付与されたサービスアカウントの認証情報を使用して、functions-1 関数のトークンを取得する処理を実装している。 尚、実行関数に付与されたサービスアカウントに functions-1 関数に対しての roles/run.invoker 権限が含まれていればトークンが取得できる。 import os import functions_framework import urllib import google.auth.transport.requests import google.oauth2.id_token # functions-1 関数のエンドポイント URL ENDPOINT = os.environ[ "ENDPOINT" ] @ functions_framework.http def make_authorized_get_request (request): # Request をインスタンス化 req = urllib.request.Request(ENDPOINT) # サービスアカウントの認証情報を使用し functions-1 関数のトークンを取得 auth_req = google.auth.transport.requests.Request() id_token = google.oauth2.id_token.fetch_id_token(auth_req, ENDPOINT) print (id_token) # トークンをヘッダーに付与し functions-1 関数に HTTP リクエストを送信 req.add_header( "Authorization" , f "Bearer {id_token}" ) response = urllib.request.urlopen(req) return response.read() functions_2_3/requirements.txt functions-framework == 3 .* google-auth == 2 . 16 . 0 requests = = 2 . 27 . 1 urllib3 = = 1 . 26 . 14 Cloud Functions の作成 はじめに、デフォルトリージョンを設定する。 gcloud config set functions/region asia-northeast1 && \ gcloud config set run/region asia-northeast1 functions-1 関数の作成 authenticationg_for_invocation/ がカレントディレクトリになっていることを確認し、以下を実行。 gcloud functions deploy functions-1 \ --gen2 \ --trigger-http \ --runtime=python310 \ --entry-point=hello_http \ --source=functions_1/ functions-2 関数の作成 functions-2 関数のデプロイに必要な情報は以下の通り。 functions-1 関数の URI エンドポイント functions-2 関数に付与する サービスアカウントのメールアドレス 以下のコマンドで functions-1 関数の URI エンドポイント を確認する。 gcloud functions describe functions-1 --gen2 | grep uri 以下のように出力されたら、 https://functions-1-xxxxxxxxxx-an.a.run.app をコピーしておく。 matayuuu@cloudshell:~ ( project_id ) $ gcloud functions describe functions-1 --gen2 | grep uri uri: https://functions-1-xxxxxxxxxx-an.a.run.app 次に、以下のコマンドで functions-2 関数の サービスアカウントのメールアドレス を取得する gcloud iam service-accounts list | grep EMAIL: | grep functions-2 以下のように出力された、 functions-2@project_id.iam.gserviceaccount.com をコピーしておく。 matayuuu@cloudshell:~ ( project_id ) $ gcloud iam service-accounts list | grep EMAIL: | grep functions-2 EMAIL: functions-2@project_id.iam.gserviceaccount.com 以下コマンドの、 --set-env-vars と -service-account を書き換えて functions-2 関数デプロイを実行。 gcloud functions deploy functions-2 \ --gen2 \ --trigger-http \ --runtime=python310 \ --entry-point=make_authorized_get_request \ --source=functions_2_3/ \ --set-env-vars=ENDPOINT=<先程出力した functions-1 関数のURI > \ --service-account=<先程出力した functions-2 関数のサービスアカウント > functions-3 関数の作成 先程と同様の手順で functions-3 関数をデプロイする情報を取得し、以下のデプロイコマンドを実行する。 gcloud functions deploy functions-3 \ --gen2 \ --trigger-http \ --runtime=python310 \ --entry-point=make_authorized_get_request \ --source=functions_2_3/ \ --set-env-vars=ENDPOINT=<先程出力した functions-1 関数のURI > \ --service-account=<先程作成した functions-3 関数のサービスアカウント > 権限の付与 functions-1 関数の呼び出し元権限 ( roles/run.invoker ) を、functions-2 関数のサービスアカウントのみに付与する。 gcloud run services add-iam-policy-binding functions-1 \ --member= ' serviceAccount:functions-2@project_id.iam.gserviceaccount.com ' \ --role= ' roles/run.invoker ' 動作確認 実行 1 以下のコマンドから、functions-2 関数を実行する。 gcloud functions call functions-2 --gen2 以下のように、 Hello HTTP!! とレスポンスがあれば成功です。 matayuuu@cloudshell:~/authenticationg_for_invocation ( project_id ) $ gcloud functions call functions-2 --gen2 Hello HTTP!! 実行 2 以下のコマンドから、functions-3 関数を実行する。 gcloud functions call functions-3 --gen2 以下のように、エラーとなれば予測していた挙動となります。 matayuuu@cloudshell:~/authenticationg_for_invocation ( project_id ) $ gcloud functions call functions-3 --gen2 ERROR: gcloud crashed ( HTTPError ) : 500 Server Error: Internal Server Error for url: https://functions-3-xxxxxxxxxx-an.a.run.app/ If you would like to report this issue, please run the following command: gcloud feedback To check gcloud for common problems, please run the following command: gcloud info --run-diagnostics Cloud Logging にて functions-3 のログを確認すると、以下のエラーが出力されてました。 Traceback ( most recent call last ) : 〜(省略)〜 File " /layers/google.python.runtime/python/lib/python3.10/urllib/request.py " , line 643 , in http_error_default raise HTTPError ( req.full_url, code, msg, hdrs, fp ) urllib.error.HTTPError: HTTP Error 403: Forbidden HTTP リクエスト時に 403 エラー が返ってきてることがわかります。 functions-3 関数のサービスアカウントには functions-1 関数の呼び出し元権限がないため、HTTP リクエストに失敗していることが想定されます。 また、Cloud Logging にて functions-1 のログも確認すると、以下のエラーが出力されてました。 The request was not authenticated. Either allow unauthenticated invocations or set the proper Authorization header. Read more at https://cloud.google.com/run/docs/securing/authenticating Additional troubleshooting documentation can be found at: https://cloud.google.com/run/docs/troubleshooting #unauthorized-client 上記より、functions-3 関数からの呼び出しは 認証されていない呼び出し だったことがわかりました。 もう少し深堀ってみる curl コマンドで実行 functions-1 関数の呼び出しを、Cloud Shell から curl コマンドで呼び出すこともできます。 Cloud Functions の コンソール画面 > functions-1 関数を選択 > テスト中 タブを選択 > テストコマンド を確認すると以下のコマンドが出力されてました。 curl -m 70 -X POST https://functions-1-xxxxxxxxxx-an.a.run.app \ -H " Authorization: bearer $( gcloud auth print-identity-token ) " \ -H " Content-Type: application/json " \ -d ' { "name": "Hello World" } ' このコマンドを Cloud Shell から実行すると functions-1 関数から Hello HTTP!! が返ってきました。 matayuuu@cloudshell:~ ( project_id ) $ curl -m 70 -X POST https://functions-1-xxxxxxxxxx-an.a.run.app \ > -H " Authorization: bearer $( gcloud auth print-identity-token ) " \ > -H " Content-Type: application/json " \ > -d ' { "name": "Hello World" } ' Hello HTTP!! functions-1 関数が呼び出せたことがわかります。 トークンの確認 先程のテストコマンドの 2 行目にあるリクエストヘッダーに注目いただくと、 Authorization: bearer $(gcloud auth print-identity-token) と記載があります。 確認のため、Cloud Shell にて gcloud auth print-identity-token 以下を実行すると以下の文字列が返ってきました。 matayuuu@cloudshell:~ ( project_id ) $ gcloud auth print-identity-token eyJhbGciOiJSUzI1NiIsImtpZCI6ImFmYzRmYmE2NTk5ZmY1ZjYzYjcyZGM1MjI0MjgyNzg2ODJmM2E3ZjEiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiYXpwIjoiNjE4MTA0NzA4MDU0LTlyOXMxYzRhbGczNmVybGl1Y2hvOXQ1Mm4zMm42ZGdxLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiYXVkIjoiNjE4MTA0NzA4MDU0LTlyOXMxYzRhbGczNmVybGl1Y2hvOXQ1Mm4zMm42ZGdxLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwic3ViIjoiMTA0ODc3Mjg2MDgxMjE4NDY0NzA4IiwiaGQiOiJnLWdlbi5jby5qcCIsImVtYWlsIjoibWF0YXl1dXVAZy1nZW4uY28uanAiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6IlVGLWJuSHJSTzZBLW5kOE1zTVpBX0EiLCJpYXQiOjE2NzQzOTA0OTAsImV4cCI6MTY3NDM5NDA5MCwianRpIjoiMjlmY2VhOTQzMzFlNzMxOGIwNTFjNDQ4ZDUzOTBjMDBlNTQ5NDU4MSJ9.l1BfkuBlmYThwRkCpWFd7V3ATWSn-zwUfuLdChw6EKg3N0qyi2NYZioiDVEMFKy-OTbap4IpGzNYi3scpux9vMnGda-UDrDwWkN8iMhBpdD1ZVjiGew8kUYwOytr-2YRbk2dM_AnOTSIfB9dgj9drWsNZHrUuG6mnYK4l4zvwIRzzh4kwdtZpd0jLkmHHIaAORMHVkIdfx88peEK3BYKzdkNrwoveuG9VjZwtef0DHMtT0-Obmd0d7Yaa8v7Onzk0s0SrAwfvFyXrsi_wY8nRJ8C5f6ljNklLlyqxcZr8UFE-3Z64hYixWMjbTqgqpjFKq4v1Pxldm_MQauJ0RAg4A また、functions_2_3 のコード内でトークンを取得する処理において、取得したトークンを確認するため print() するようにしています 。 # 〜(抜粋)〜 # サービスアカウントの認証情報を使用し functions-1 関数のトークンを取得 auth_req = google.auth.transport.requests.Request() id_token = google.oauth2.id_token.fetch_id_token(auth_req, ENDPOINT) print (id_token) 再度、functions-2 関数を実行し Cloud Logging からログを確認すると、以下のトークンが print() されてました。 eyJhbGciOiJSUzI1NiIsImtpZCI6ImFmYzRmYmE2NTk5ZmY1ZjYzYjcyZGM1MjI0MjgyNzg2ODJmM2E3ZjEiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovL2Z1bmN0aW9ucy0xLXZlNXBzaHhjZHEtYW4uYS5ydW4uYXBwIiwiYXpwIjoiMTAxNzgwOTIxMzYzNDgwNTMyNTQ4IiwiZW1haWwiOiJmdW5jdGlvbnMtMkBwb2MtaW52b2tlLWdjZi1odHRwLTIuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZXhwIjoxNjc0Mzc1Mjc2LCJpYXQiOjE2NzQzNzE2NzYsImlzcyI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbSIsInN1YiI6IjEwMTc4MDkyMTM2MzQ4MDUzMjU0OCJ9.l7IvSXFWQu2NfvmCQEzdZbWQ3mPtzO3myqW45Grw_bEedLLAe7DYO0x3iPMBtOrlVXdl4REn8wxGNaDqsL_UZBAePAI6PQJdVmNn-QA46JGPC6K74ZohR3KzWFI7_NEudnL_l9ZBVazyQUc34XfG9T9OXJgtCmZefwWYTMvJC8EYkqg4FnvEkw1xAeuwCr9pE1aqFSsCQTFU-VMwzxPpQ33AF49UMtMfU5qhmFoeBMFnwfpMt9tFwR-K9HE2fAqtysUUXfk_FJDAkxw25rN2uA0EKHIS-FQ738N-ZKKD7wjlhrDcoAalerSjBpU0UgUpArK9o7gFAu5Ztyd4qv0tvQ gcloud auth print-identity-token で取得したトークンと比べてみると異なる文字列が返ってきました。 このトークンの正体は、 OpenID Connect(OIDC)トークンまたは ID トークン といい、Google によって署名された ID トークンであります。尚、存続期間は最大 1 時間 (デフォルト) となります。 Cloud Functions や Cloud Run の呼び出しにおいて、この ID トークンが必要になります。 参考: Cloud Run または Cloud Functions でホストされているアプリケーションの認証 トークンを取得する仕組み トークンを取得するときの認証情報の仕組みについては、 アプリケーションのデフォルト認証情報 (ADC) が使われています。 今回 ADC について詳しい説明は省略しますが、functions-2 関数では 接続されたサービスアカウント 認証情報が ADC に提供されています。 また、Cloud Shell のような Google Cloud 上のクラウドベース開発環境を使用する場合は、ログイン時に指定した認証情報が ADC に提供されるため、プロジェクトレベルのオーナー権限を持った筆者の ユーザーアカウント 認証情報が提供されていたことがわかります。 参考: Google Cloud のクラウドベースの開発環境 トークンのデコード No 実行環境 誰のトークン 1 Cloud Shell 筆者のユーザーアカウント 認証情報で取得したトークン 2 functions-2 関数 functions-2 関数のサービスアカウント 認証情報で取得したトークン このトークンはエンコードされているため、 jwt.io Debugger を使えばデコードができます。 Cloud Shell で出力したトークンをデコード functions-2 関数で取得したトークンをデコード 又吉 佑樹 (記事一覧) クラウドソリューション部 はいさーい!沖縄出身のクラウドエンジニアです!! 前職は SIer テクニカルセールス。Google Cloud の魅力に惚れ、技術を磨きたくセールスからエンジニアへ転身。Google Cloud 認定資格は全 11 資格保有。最近は AI/ML 分野に興味あり。 Follow @matayuuuu
アバター
当記事は みずほリサーチ&テクノロジーズ × G-gen エンジニアコラボレーション企画 で執筆されたものです。 GKE は Google Cloud の強みとして紹介されることの多いサービスです。 Kubenetes のマネージドサービスである GKE を理解するには、先ずは Kubenetes の理解が必要です。 GKE の優れた点を理解するための調査の一環として Kubenetes について調査することにしました。 G-gen の佐々木です。当記事では、オープンソースのコンテナオーケストレーションツールである Kubernetes の基本を解説します。 Google Cloud における代表的なプロダクトの 1 つである Google Kubernetes Engine ( GKE ) は Kubernetes のフルマネージドサービスであり、それを適切に利用していくためには、基盤となる Kubernetes についてある程度の知識が必要となります。 Kubernetes とは なぜ Kubernetes が必要なのか コンテナ運用の課題 コンテナオーケストレーション デファクトスタンダード Docker との関係 Kubernetes の詳細 アーキテクチャ コントロールプレーンの主なプロセス ノードの主なプロセス 宣言型 API によるリソースの登録 Kubernetes リソース Kubenetes の操作 ( kubectl ) マニフェストファイルによるリソース定義の例 基本的な記述例 複数のリソースを同時に作成する例 Kubernetes の利用方法 ローカル Kubernetes Kubernetes 構築ツール パブリッククラウド Kubernetes Kubernetes とは Kubernetes (読み:クバネティス / クバネテス / クーベネティス など) は、コンテナ化されたアプリケーションのデプロイ、スケーリングなどの管理を自動化するための オープンソース の コンテナオーケストレーションツール です。 Google 内部で利用されているクラスタマネージャの Borg を元に 2014 年に開発され、現在は Cloud Native Computing Foundation (CNCF) によって管理されています。 「 Kubernetes 」という語はギリシャ語で「操舵手」を意味し、最初の文字「 K 」と最後の文字「 s 」の間の 8 文字を省略して、 K8s と呼ばれることもあります。 なぜ Kubernetes が必要なのか コンテナ運用の課題 近年、アプリケーション開発の効率化、およびコンピュートリソース利用の効率化の観点から Docker を始めとするコンテナ仮想化技術が注目され、機能単位でアプリケーションを組み合わせてシステムを構成する マイクロサービス アーキテクチャ との相性が良いことから、モダンアプリケーション開発においてコンテナの採用が増えています。 しかし、機能単位でコンテナを実行することでコンテナの数が増えてくると、その運用管理が煩雑になってしまうという課題が出てきます。 コンテナオーケストレーション コンテナオーケストレーションとは、 コンテナ化されたアプリケーションを効率良く開発・運用する技術 のことで、Kubernetes のようなコンテナオーケストレーションツールを利用することで、コンテナの運用管理にまつわる以下のようなタスクを自動化することが可能です。 ■コンテナオーケストレーションツールで自動化できることの一例 スケジューリング ローリングアップデート スケーリング 死活監視 障害発生時のセルフヒーリング 宣言的なコードによるインフラ管理 ( Infrastructure as Code ) このような利点により、コンテナを用いた一定規模以上のシステム構築では、コンテナオーケストレーションツールの導入が一般的になっています。 デファクトスタンダード コンテナオーケストレーショツールとしては、Kubernetes の他に Docker Swarm Mode や Apache Mesos などがあります。 しかし、Google だけではなく AWS、Microsoft、Oracle といった企業が Kubernetes を管理している CNCF に参加していることや、AWS や Azure がコンテナオーケストレーションのマネージドサービスとして Kubernetes を採用したことにより、現在では コンテナオーケストレーションツールのデファクトスタンダード としての地位を固めています。 Docker との関係 コンテナ仮想化技術のデファクトスタンダードである Docker と コンテナオーケストレーションツールである Kubernetes は競合するテクノロジーではなく、むしろ連携、補完し合う関係にあると言えます。 Kubernetes は、Docker を用いてコンテナ化されたアプリケーションの運用管理を自動化することで、アプリケーションの開発速度を向上し、大規模な展開を効率よく行うことができます。 Kubernetes の詳細 アーキテクチャ Kubernetes は、実際にコンテナが実行される 1 つ以上の ノード と、それを管理する コントロールプレーン の 2 種類のコンポーネントからなる Kubernetes クラスタ を構成します。 各コンポーネント内ではコンテナの実行、管理に必要な複数のプロセスが稼働しています。 Kubernetes のアーキテクチャ コントロールプレーンの主なプロセス プロセス 主な役割 kube-apiserver Kubernetes API のエンドポイントを提供する。 Kubernetes クラスタを管理するためのリクエストを受信し、Kubernetes の各種リソースの操作(作成、削除など)を自動で行う。 kube-scheduler 新しく作成された Pod を適切なノードに割り当てる。 kube-controller-manager Kubernetes クラスタを、期待される状態と一致するように管理する。 etcd Kubernetes クラスタの構成情報の保存先となる。 kube-dns Kubernetes クラスタ内部の名前解決を可能にする DNS サービスを提供する。 ノードの主なプロセス プロセス 主な役割 kubelet Pod 内のコンテナの実行状態を管理し、障害状態にあるコンテナを置き換えたり、コントロールプレーンからの指示を受けてコンテナを起動、停止したりする。 kube-proxy クラスタ内部または外部のネットワークからの通信を Pod に転送する。 宣言型 API によるリソースの登録 コントロールプレーンの kube-controller-manager には、 Kubernetes クラスタの「実際の状態 (Actual State) 」と「理想の状態 ( Desired State ) 」を常に比較し、 両者に差異が生じたときに理想の状態を維持する 仕組みがループ処理として実装されています ( Reconciliation Loop )。 Kubernetes では、管理対象となる リソース を、設定ファイルである マニフェスト として記述します。 マニフェストに対して、システムの「理想の状態」を YAML 形式 で記述し、Kubernetes に登録することで、kube-controller-manager は記述通りの状態にシステムを構成、維持します。 設定ファイルに対して、システムを構成するために実行する処理 ( How ) を記述するような方式である 手続き型 API に対して、Kubernetes のマニフェストのように、どのようなシステムを構成するか ( What ) を記述する方式を 宣言型 API といいます。 Kubernetes リソース Kubernetes に登録することのできるリソースは、大きく分けて以下の 5 つのカテゴリがあります。 カテゴリ 概要 Workloads API コンテナの実行に関するリソース Service API コンテナを公開するためのエンドポイントを提供するリソース Config API 設定 / 機密情報 / 永続化ボリュームなどに関するリソース Cluster API セキュリティやクォータなどに関するリソース Metadata API クラスタ内の他のリソースを操作するためのリソース ここでは、代表的なリソースの一部を記載します( リソース一覧 )。 リソース名 カテゴリ 説明 Pod Workloads API Workloads API リソースの最小単位。1 つ以上のコンテナから構成され、同じ Pod 内のコンテナは IP アドレスを共有する。 多くの場合 Pod 1 つにつき 1 つのコンテナで構成するが、プロキシやローカルキャッシュ用のサブコンテナを含める場合もある。 ReplicaSet Workloads API Pod のレプリカを作成し、指定した数の Pod を維持するように動作する リソース。 ノードや Pod に障害が発生すると、指定された数だけ正常な Pod が稼働するように別の Pod を起動する。 Deployment Workloads API 複数の ReplicaSet を管理するリソースで、ローリングアップデートやロールバックを実現する。 ReplicaSet が Pod を管理するため、3 層の構造を持つことになる。 Deployment 内の ReplicaSet を変更すると、新しい ReplicaSet が作成され、指定された Pod 数を維持しつつ 新旧 Pod の入れ替えを行うことができる。 Service Service API ■ClusterIP Kubernetes クラスタ内で Pod 間通信を行うための内部 IP アドレスを払い出す。 クラスタ内の各 Pod にトラフィックを転送する 内部 ロードバランサとして機能する。 ■NodePort Kubernetes クラスタ内の各ノードに 外部 IP アドレスを払い出し、払い出した IP アドレスとポートの組み合わせにより、クラスタ外からのトラフィックを特定の ClusterIP に転送する。 クラスタ外から Pod に接続する必要がある場合に使用する。 ■LoadBalancer Kubernetes クラスタ外部にロードバランサを配置し、外部 IP アドレスを払い出すことで、クラスタ内への接続を可能にする。 ロードバランサの仕様は Kubernetes クラスタを構築している環境に依存し、Google Cloud の場合は Cloud Load Balancing の L4 ( TCP / UDP ) ロードバランサが自動的に使用される。 パスベースのルーティングや SSL ターミネーションなどをサポートする L7 ( HTTP / HTTPS ) ロードバランサを使用したい場合は Ingress リソースを使用する。 Secret Config API データベース接続情報や TLS 証明書などの機密情報を Key-Value で保存するために使用する。 ConfigMap Config API 各種設定情報などを Key-Value で保存するために使用する。 nginx.conf や httpd.conf のような設定ファイルを保存することも可能。 PersistentVolume Cluster API Pod とは別のリソースとしてボリュームを作成し、Pod からマウントする形で永続化領域として使用できる。 ノードのファイルシステムを使用する hostPath のほか、プラグインを使用することで Amazon EBS や GCE 永続ディスクなど、外部にあるボリュームをアタッチすることもできる。 Node Cluster API Kubernetes のコンポーネントの 1 つであるノードも Kubernetes 上のリソースとして登録されている。 基本的に作成や削除をするリソースではないが、IP アドレスの情報や、 CPU、メモリなどのリソースの情報を取得する際に、ノードに関する情報を返すように Kubernetes にリクエストすることがある。 Namespace Cluster API Kubernetes クラスタ内のリソースをグループ化し、仮想的に分離するために使用する。 Namespace 単位で CPU やメモリのクォータを設定したり、ロールベースのアクセス制御を設定したりすることができる。 Kubenetes の操作 ( kubectl ) Kubernetes では、CLI ツールである Kubectl を使ってコントロールプレーンに対して API リクエストを送信することで、Kubernetes クラスターを操作します。 各種リソースの作成は kubectl create コマンドで行うことができますが、マニフェストファイルで指定したリソースが存在しないときは新規に作成、存在するときは差分を自動で反映してくれる kubectl apply コマンドを使用するのが一般的です。 マニフェストファイルによるリソース定義の例 基本的な記述例 以下の YAML 形式の記述は、nginx コンテナを内包する Pod を 3 台起動し、その状態を維持する ReplicaSet を含めた Deployment リソースを作成するマニフェストです。 リソースの種類は kind で指定し、それに対応する apiVersion を記述する必要があります。 kind と apiVersion の対応は kubectl api-resources コマンドで出力することができます。 apiVersion : apps/v1 kind : Deployment metadata : name : sample-deployment spec : replicas : 3 template : spec : containers : - name : nginx-container image : nginx:1.23 このマニフェストファイルを用いて kubectl apply コマンドを実行すると、Kubernetes クラスタ内にリソースが作成されます。 リソースを更新する場合、マニフェストファイルを修正し、再度 kubectl apply を実行して修正内容を適用します。 たとえば、実行する Pod の数を 5 に増やしたい場合、 replicas の値を 5 に変更して適用します。 そうすると、Kubernetes がマニフェストファイルの差分を検出し、Pod を 2 つ新規作成してノードに割り当てます。 複数のリソースを同時に作成する例 1 つのマニフェストに複数のリソースを記載することもできます。 以下に記述したマニフェストでは、先程と同様の Pod を 3 台起動する Deployment リソースと、Pod を外部公開するための LoadBalancer リソースを 記述されている順番に 作成します。 そして、Key-Value で記述される label と selector の情報を使用して、ロードバランサから特定の Pod に対してトラフィックをルーティングするように設定します。 --- apiVersion : apps/v1 kind : Deployment metadata : name : sample-deployment spec : replicas : 3 selector : matchlabels : app : sample-app template : metadata : labels : app : sample-app spec : containers : - name : nginx-container image : nginx:1.23 --- apiVersion : v1 kind : Service metadata : name : sample-service spec : type : LoadBalancer ports : - name : "http-port" protocol : "TCP" port : 8080 targetPort : 80 selector : app : sample-app Kubernetes の利用方法 オープンソースである Kubernetes は、様々なプラットフォーム上で動かすことができます。 ローカル Kubernetes ローカル PC や単一の仮想マシンなどで気軽に Kubernetes を試したい場合は、 Minikube などのツールを使用することができます。 単一のマシン上でコントロールプレーンとノードが実行され、冗長性は担保されないので、あくまでも動作確認や開発環境としての利用が推奨されます。 ■主なローカル Kubernetes ツール Minikube kind ( Kubernetes in Docker ) Docker Desktop for Mac / Windows Kubernetes 構築ツール 構築ツールを使用することで、クラウド / オンプレミスにある複数台のマシンを Kubernetes クラスタとして構成することができます。 ■主な Kubernetes 構築ツール kubeadm Rancher パブリッククラウド 2015 年に Google Kubernetes Engine がリリースされて以来、Kubernetes はパブリッククラウドのマネージドサービスとして提供されており、各クラウドプロバイダの永続ボリュームやロードバランサーを活用できるほか、様々なサービスとの連携が可能となっています。 Kubernetes クラスタ全体がマネージドサービスとして提供されるため、各ノードの自動アップデートや自動修復など、クラスタ自体の運用負荷を下げることができます。 ■主な Kubernetes のマネージドサービス Google Kubernetes Engine ( GKE ) Elastic Kubernetes Service ( EKS ) Azure Kubernetes Service ( AKS ) GKE については以下の記事でも解説しています。 blog.g-gen.co.jp 佐々木 駿太 (記事一覧) G-gen最北端、北海道在住のクラウドソリューション部エンジニア 2022年6月にG-genにジョイン。Google Cloud Partner Top Engineer 2025 Fellowに選出。好きなGoogle CloudプロダクトはCloud Run。 趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。 Follow @sasashun0805
アバター
こんにちは、G-gen の荒井です。今回は Google Cloud の中でも人気プロダクトでもある Cloud Storage をコマンドラインで操作する方法についてご紹介いたします。ユースケースを想定しコマンド例も記載しておりますので、是非ご自身の環境でもお試しください。 はじめに gcloud storage とは gcloud storage の特徴 gcloud (CLI) の操作方法 Cloud Shell から操作 自身の端末から操作 gcloud storage メリット・デメリット gcloud storage (CLI) メリット 作業時間の短縮・自動化 操作ミスの減少 アップデートに左右されない gcloud storage (CLI) デメリット 学習コストがかかる システム状況のイメージが湧きづらい よく使う gcloud storage コマンド バケットの作成 バケットにオブジェクトをアップロードする バケットからオブジェクトをダウンロードする バケットを削除する オブジェクトを削除する ストレージクラスを変更する バケットまたはフォルダの内容を一覧表示する バケットへのアクセス権を付与 バケットへのアクセス権を削除 バケットのラベルを変更する その他のコマンド(リファレンス) はじめに gcloud storage とは Cloud Storage をコマンドラインで操作する。と聞くと「 gsutil コマンドでの操作」と思い浮かべる方も多いかと思います。しかし今回扱うコマンドは gcloud storage というコマンドです。 gsutil コマンドと同様の操作が可能な gcloud storage ですが、本コマンドは比較的最近(2022/9/13)GA(一般公開)となっております。また gcloud コマンドは、他のほとんどの Google Cloud プロダクトを操作できるコマンドラインツールです。そのため今後 Cloud Storage をコマンドラインで操作する際は gcloud storage コマンドが主流になっていきます。 今のうちから gcloud storage をチェックしておきましょう! Cloud Storage がどういったサービスか再確認したい方は、以下の記事を確認いただければと思います。 blog.g-gen.co.jp またAWSで同様のサービスである S3 との比較についてはこちらの記事で解説しております。 blog.g-gen.co.jp gcloud storage の特徴 Cloud Storage を利用するユーザーについては、大容量のデータを Cloud Storage に転送することが多いと想定されます。 gcloud storage では、従来の gsutil に比べデータ転送性能が向上しています。Google Cloud 社のテストでは最大94%も高速であったことが確認されています。 参考 : gcloud コマンドラインを使用した Cloud Storage の転送速度の向上 参考 : Introducing gcloud storage: up to 94% faster data transfers for Cloud Storage gcloud (CLI) の操作方法 gcloud コマンドを利用するには、大きく分けて2つの方法があります。 Cloud Shell から操作 1つ目の方法は、Google Cloud の Cloud Console (管理コンソール) 上で Cloud Shell を起動し操作する方法です。事前準備が不要で、すぐ使い始められるのが特徴です。 ただし Cloud Shell の実行環境はクラウド上にあり、私たちのパソコンからインターネット経由でアクセスするため、ローカルデータをアップロードするには時間がかかることなどがデメリットといえます。 参考 : Cloud Shell を使用する 自身の端末から操作 2つ目の方法は、私たちの端末に gcloud CLI ツールをインストールし、自身の端末から操作する方法です。 こちらの操作方法では、自身の端末に gcloud CLI をインストールしたり、インターネット (Google Cloud) にアクセスできる環境が必要となります。詳細な手順は以下リンクを参照ください。 参考 : gcloud CLI をインストールする 参考 : gcloud CLI の初期化 gcloud storage メリット・デメリット さて gcloud storage コマンド(CLI)を利用するにあたり、メリット・デメリットを整理しておきましょう。 システムを専門で扱っていない方にとってはただハードルが高いだけの操作方法なら扱いたくないですよね。しかし gcloud storage(CLI)を味方にすると次のようなメリットがあります。反面デメリットもありますが、それぞれどういったものか確認しましょう。 gcloud storage (CLI) メリット CLI で操作する際のメリットを3つほどご紹介いたします。 作業時間の短縮・自動化 GUI での作業では画面に表示された項目や説明を確認しながら操作を行います。設定箇所が複数ページに渡っている場合や、対話型ウィザードで [次へ] [次へ] とクリックしていると、単純な設定でも意外と時間がかかってしまうことがあります。 その反面 CLI の gcloud storage では設定したい内容を構文にしたがって作成し、システムに指示するのみです。設定を行う際のページ遷移や対話型ウィザードに比べ、コマンドが設定に直結しているため大幅な作業時間の短縮が期待できます。 また、シェルスクリプト等に組み込むことで、繰り返しの作業や定期実行などを自動化することができます。このような場合に CLI のメリットが最大限に発揮されます。 操作ミスの減少 GUI操作では、マウスを使って操作することが多いと思います。マウスを使って指定のボタンをクリックしようと思ったら、ポップアップが出て間違ったボタンをクリックしてしまった!こういった経験をされたことのある方は多くいらっしゃるのではないでしょうか。(私も時々あります…) CLI では設定前にコマンドを作成しておきます。その場でポチポチと作業を行う GUI に比べパラメータの確認を事前にじっくりすることができることや、コマンドラインではポップアップのような画面も表示されないため操作ミスの減少につながります。頻繁に設定作業を行う方にとって、CLI は強い味方です。 アップデートに左右されない 昨今IT業界の主流になりつつあるクラウドサービスですが、その特徴の一つとしてメーカー側の都合でシステムがアップデートされることが度々あります。セキュリティ強化による脆弱性の排除などのメリットもありますが、反面 GUI の画面が変更になることも度々あります。 機能追加アップデートによりボタン配置が変わってしまうことをはじめ、画面全体のデザインが変わってしまうこともしばしばあります。 社内にシステム利用方法を浸透させるため、時間をかけてスクリーンショット付きの手順書を作成したのに、アップデートにより使えなくなってしまった経験のある方も多いと思います。CLI 作業ではコマンドを指定箇所に入力するだけなので、こういったデザイン変更やボタン配置に影響されることがありません。 ただし、コマンドラインツールであっても稀に変更が発生することがあります (オプションの増減等)。とはいえ原則的には後方互換性が維持されるので、GUI で手順を作成するよりも、ずっと安定していると言うことができます。 gcloud storage (CLI) デメリット CLI を使用することのメリットはご理解いただけたかと思いますが、CLI にはデメリットもありますので合わせてご紹介いたします。 学習コストがかかる 普段のPC作業では CLI を利用することはあまり多くありません。そのため CLI 構文の学習や必要なコマンドを探すスキルが必要となり、学習コスト(時間)がかかることが想定されます。 システム状況のイメージが湧きづらい CLI での操作は基本的にコマンド(テキスト)のみになります。システムが視覚化された GUI では一目瞭然で理解できるシステム状況も、慣れないと操作イメージが湧きづらく作業に時間がかかってしまうこともしばしばあるかもしれません。 例)ディレクトリツリーが常時表示ではないためどこの作業をしているかわからなくなる、ディスクの使用領域がグラフ化されない…など よく使う gcloud storage コマンド 前置きが長くなりましたが、早速 gcloud storage コマンドを使用していきましょう。今回は基本編のため、Cloud Storage の基本的な操作を gcloud storage コマンドで実施してみようと思います。 <your-bucket> といった < > で区切られた部分はご自身の環境に沿ってバケット名等のパラメータを入力してください。 ※ コマンド入力の際は < > は入力不要です。 バケットの作成 $ gcloud storage buckets create gs://<your-bucket> --default-storage-class=standard --location=asia-northeast1 --uniform-bucket-level-access <your-bucket> というバケットを 東京リージョン に作成します。 バケットレベルのアクセス設定は 均一 、パブリックに対して 非公開 のバケットとなります。 <your-bucket> に入力するバケット名は、全世界でユニークな名称でなければなりません。 ユニークな名称になっていない場合、以下のようなエラーメッセージが出力されます。 エラーが発生した場合は、名称を変更して再度コマンドを実行してみてください。 HTTPError 409: The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again. またバケット名の命名ガイドラインは下記の通りになります。 参考 : Bucket names バケットにオブジェクトをアップロードする $ gcloud storage cp <sample.png> gs://<your-bucket> 指定したバケットに、ファイルをアップロードします。 <sample.png> の部分を、お使いの端末上のファイルパスに置き換えてください。また gs://<your-bucket> の部分は自分のバケット名に置き換えます。 gs://<your-bucket>/<folder> のように、配置先のパスを指定することも可能です。 バケットからオブジェクトをダウンロードする $ gcloud storage cp gs://<your-bucket>/<sample.png> <sample_download.png> 指定パスに保存されたオブジェクトをダウンロードします。 <sample_download.png> の部分は、ローカル上のファイル名 (パス) を指定しています。 バケットを削除する $ gcloud storage rm --recursive gs://<your-bucket>/ 指定したバケットを削除します。バケット内のデータも削除されるため、ご注意ください。 オブジェクトを削除する $ gcloud storage rm gs://<your-bucket>/<sample.png> 指定パスに保存されたオブジェクトを削除します。 ストレージクラスを変更する $ gcloud storage buckets update gs://<your-bucket> --default-storage-class=NEARLINE 指定バケットのデフォルトストレージクラスを変更します。上記サンプルコマンドでは、デフォルトストレージクラスを NEARLINE に変更しています。 バケットまたはフォルダの内容を一覧表示する $ gcloud storage ls gs://<your-bucket> 指定バケットの内容を一覧表示します。 gs://<your-bucket>/<folder> のようにフォルダパスを指定することも可能です。 バケットへのアクセス権を付与 $ gcloud storage buckets add-iam-policy-binding gs://<your-bucket> --member=user:<Google アカウント> --role=roles/storage.objectViewer バケットへのアクセス権(IAM)を付与します。 上記サンプルコマンドでは指定バケットに任意の Google アカウント を指定し、 Storage オブジェクト閲覧者 の権限を付与しています。 バケットへのアクセス権を削除 $ gcloud storage buckets remove-iam-policy-binding gs://<your-bucket> --member=user:<Google アカウント> --role=roles/storage.objectViewer 上記サンプルコマンドでは指定バケットの任意 Google アカウント に付与された Storage オブジェクト閲覧者 の権限を削除しています。 バケットのラベルを変更する $ gcloud storage buckets update gs://<your-bucket> --update-labels=<key>=<value> バケットのラベルを変更します。 ラベルを付与することにより、バケット単位で請求金額を確認することができるようになります。 その他のコマンド(リファレンス) 今回ご紹介したコマンドは基本編となります。 他にも各種コマンドやオプションを使用することで、色々な操作を行うことが可能です。 コマンドリファレンスは以下になりますため、基本編では物足りない方はご確認いただければと思います。 参考 : gcloud storage 荒井 雄基 (記事一覧) クラウドソリューション部 クラウドサポート課 オンプレ環境のネットワーク・サーバーシステムを主戦場としていたが、クラウド領域にシフト。現在は Google Workspace を中心に企業の DX 推進をサポート。 ・ Google Cloud Partner Top Engineer 2025 ・Google Cloud 認定資格 7冠 最近ハマっていることは、息子とのポケモンカード Follow @arapote_tweet
アバター
G-gen の武井です。 当記事では Infrastructure as Code (IaC) を実現する Terraform を Google Cloud (旧称 GCP) で実行する際、 GitHub の CI/CD 機能である GitHub Actions を介して実行する方法 を紹介します。 GitHub Actions とは 概要 ワークフロー 図説 Google Cloud との連携 概要 従来の認証 Workload Identity 連携による認証 Workload Identity 連携 仕組み メリット 図説 設定方法 概要 Terraform のセットアップ GitHub Actions の設定 ディレクトリ構成 Workload Identity 連携の設定 ワークフローの定義 動作検証 概要 動作検証用リソースの定義 Pull Request 実行 Merge 実行 Workload Identity 作成スクリプト ( 2024/12 追記 ) GitHub Actions とは 概要 GitHub Actions とは、ソースコード管理ツールである GitHub に包含される機能の1つで、GitHub 上で管理されるソースをもとに CI/CD (継続的インティグレーション / 継続的デリバリー) を実現します。 例えば Terraform を GitHub Actions で実行する場合、Pull Request や Merge などのイベントをトリガーにして、plan や apply などの処理を自動化できます。 ワークフロー GitHub Actions で自動化したい処理とその内容・条件を定義したものを ワークフロー (Workflow) と言います。 ワークフローは以下の条件に従い定義します。 定義ファイルは YAML 形式 で記述する 定義ファイルは .github/workflows ディレクトリ に保存する 図説 GitHub Actions で Terraform を実行した際のイメージは以下のとおりです。 main ブランチ へ Pull Request が行われた場合、Google Cloud 環境に terraform plan を実行するワークフローが起動 (図①) main ブランチ へ Merge が行われた場合、Google Cloud 環境に terraform apply を実行するワークフローが起動 (図②) GitHub Actions による Terraform デプロイの自動化 Google Cloud との連携 概要 GitHub Actions で Google Cloud 上のリソースを管理する場合、Google Cloud への 認証 を通す必要があります。 従来の認証 従来は サービスアカウントキーによる認証 が必要でした。キーによる認証では以下のような制約や懸念が考えられます。 キーの エクスポート / 保存 といった管理工数の発生 キー漏洩時のセキュリティリスクの懸念 組織のポリシー ( constraints/iam.disableServiceAccountKeyCreation ) で統制された環境下での利用制限 Workload Identity 連携による認証 2021年10月、GitHub Actions で OIDC (OpenID Connect) トークンを使った認証 がサポートされたことで、 Workload Identity 連携を使用したキーレスな認証 が実現可能となりました。 Workload Identity 連携 仕組み Workload Identity 連携 は、GitHub 等の外部 ID プロバイダ (IdP) と連携し、Google Cloud のリソースを呼び出します。 GitHub のワークロードはセキュリティトークンサービス (STS) エンドポイントを呼び出し、IdP から取得した認証トークンを有効期限が短い Google Cloud アクセストークン と交換します。 メリット ワークロード (GitHub Actions) はトークンの交換でサービスアカウントの権限を借用できます。そのため、従来のようなキー発行は不要となり、それに伴う制約や懸念が解消されます。 図説 Workload Identity 連携を図に表すと以下のイメージとなります。 Workload Identity 連携による認証イメージ 設定方法 概要 以下の流れで GitHub Actions を設定します。 Terraform のセットアップ GitHub Actions の設定 Terraform のセットアップ GitHub Actions の実行に必要なリソースを Terraform でデプロイするため、以下のリソースを事前に準備します。 プロジェクト tfstate ファイル格納用バケット Terraform 用サービスアカウント gcloud コマンドで準備する場合、以下の記事の 「3章 事前準備」 にて説明しています。 blog.g-gen.co.jp GitHub Actions の設定 Terraform のセットアップが完了したら、GitHub Actions を設定します。 ディレクトリ構成 GitHub 上で管理するソースのディレクトリ構成は以下の通りです。この章では main.tf と terraform.yml について説明します。 ディレクトリ構成 Workload Identity 連携の設定 main.tf に Workload Identity 連携に関する設定を定義し、Cloud Shell や Local 環境などから Terraform を実行してリソースをデプロイします。 コードは以下の通りで、詳細については 弊社ブログ で解説しています。 # local 定義 locals { github_repository = "myuser/myrepository" project_id = "myproject" region = "asia-northeast1" terraform_service_account = "tf-exec@myproject.iam.gserviceaccount.com" # api 有効化用 services = toset ( [ # Workload Identity 連携用 "iam.googleapis.com" , # IAM "cloudresourcemanager.googleapis.com" , # Resource Manager "iamcredentials.googleapis.com" , # Service Account Credentials "sts.googleapis.com" # Security Token Service API ] ) } # provider 設定 terraform { required_providers { google = { source = "hashicorp/google" version = ">= 4.0.0" } } required_version = ">= 1.3.0" backend "gcs" { bucket = "myproject_terraform_tfstate" prefix = "terraform/state" } } ## API の有効化(Workload Identity 用) resource "google_project_service" "enable_api" { for_each = local.services project = local.project_id service = each.value disable_dependent_services = true } # Workload Identity Pool 設定 resource "google_iam_workload_identity_pool" "mypool" { provider = google-beta project = local.project_id workload_identity_pool_id = "mypool" display_name = "mypool" description = "GitHub Actions で使用" } # Workload Identity Provider 設定 resource "google_iam_workload_identity_pool_provider" "myprovider" { provider = google-beta project = local.project_id workload_identity_pool_id = google_iam_workload_identity_pool.mypool.workload_identity_pool_id workload_identity_pool_provider_id = "myprovider" display_name = "myprovider" description = "GitHub Actions で使用" attribute_mapping = { "google.subject" = "assertion.sub" "attribute.repository" = "assertion.repository" } oidc { issuer_uri = "https://token.actions.githubusercontent.com" } } # GitHub Actions が借用するサービスアカウント data "google_service_account" "terraform_sa" { account_id = local.terraform_service_account } # サービスアカウントの IAM Policy 設定と GitHub リポジトリの指定 resource "google_service_account_iam_member" "terraform_sa" { service_account_id = data.google_service_account.terraform_sa.id role = "roles/iam.workloadIdentityUser" member = "principalSet://iam.googleapis.com/$ { google_iam_workload_identity_pool.mypool.name } /attribute.repository/$ { local.github_repository } " } ワークフローの定義 次に、ワークフローの定義ファイル ( terraform.yml ) を準備します。 ※ .github/workflows/ ディレクトリに格納してください。 コードは HashiCorp 公式サイト と Google Cloud 公式ガイド を参考にしています。 ※ 32行目の ${PROJECT_NUMBER} は適宜置き換えてください。 name : terraform # main ブランチへのPull Request と Merge をトリガーに指定 on : push : branches : - main pull_request : # 作業ディレクトリの指定 defaults : run : working-directory : ./ # ジョブ / ステップ / アクションの定義 jobs : terraform-workflow : runs-on : ubuntu-latest permissions : id-token : write contents : read pull-requests : write # Workload Identity 連携 steps : # https://cloud.google.com/iam/docs/using-workload-identity-federation#generate-automatic - uses : actions/checkout@v3 - id : 'auth' name : 'Authenticate to Google Cloud' uses : 'google-github-actions/auth@v1' with : workload_identity_provider : 'projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/mypool/providers/myprovider' service_account : 'tf-exec@myproject.iam.gserviceaccount.com' # https://github.com/hashicorp/setup-terraform - uses : hashicorp/setup-terraform@v2 - name : Terraform fmt id : fmt run : terraform fmt -check -recursive continue-on-error : true - name : Terraform Init id : init run : terraform init - name : Terraform Validate id : validate run : terraform validate -no-color - name : Terraform Plan id : plan run : terraform plan -no-color continue-on-error : true - name : Comment Terraform Plan uses : actions/github-script@v6 if : github.event_name == 'pull_request' env : PLAN : "terraform \n ${{ steps.plan.outputs.stdout }}" with : github-token : ${{ secrets.GITHUB_TOKEN }} script : | const output = `#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\` #### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\` #### Terraform Validation 🤖\`${{ steps.validate.outcome }}\` <details><summary>Validation Output</summary> \`\`\`\n ${{ steps.validate.outputs.stdout }} \`\`\` </details> #### Terraform Plan 📖\`${{ steps.plan.outcome }}\` <details><summary>Show Plan</summary> \`\`\`\n ${process.env.PLAN} \`\`\` </details> *Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`, Working Directory: \`${{ env.tf_actions_working_dir }}\`, Workflow: \`${{ github.workflow }}\`*`; github.rest.issues.createComment({ issue_number : context.issue.number, owner : context.repo.owner, repo : context.repo.repo, body : output }) - name : Terraform Plan Status if : steps.plan.outcome == 'failure' run : exit 1 # main ブランチに push した場合にだけ terraform apply も実行される - name : Terraform Apply if : github.ref == 'refs/heads/main' && github.event_name == 'push' run : terraform apply -auto-approve -input= false 動作検証 概要 以下の流れで GitHub Actions の動作検証を行います。 動作検証用リソースの定義 Pull Request 実行 Merge 実行 動作検証用リソースの定義 test.tf に動作検証用に作成する Cloud Storage バケットを定義します。 resource "google_storage_bucket" "test001" { name = "$ { local.project_id } -bucket-test001" project = local.project_id location = local.region force_destroy = true uniform_bucket_level_access = true } Pull Request 実行 GitHub にログインし、main ブランチに Pull Request を実行します。 Pull Request の実行 Actions タブから画面を確認すると、ワークフローが実行されたことがわかります。 Pull Request をトリガーにしたワークフローの実行 ワークフロー名をクリックすると詳細が確認できます。 今回のトリガーは main ブランチへの Pull Request ですので、 terrafrom plan が実行されています。 Pull Request をトリガーにしたワークフローの実行 terraform plan の詳細 Merge 実行 Pull Request の結果が問題ない事を確認したら main ブランチに Merge を実行します。 Merge の実行 Merge の実行 再度 Actions タブから画面を確認すると、さらにワークフローが自動実行されたことがわかります。 Merge をトリガーにしたワークフローの実行 今回のトリガーは main ブランチへの Merge ですので、先程とは異なり terrafrom apply が実行されています。 Merge をトリガーにしたワークフローの実行 terraform apply の詳細 Terraform (GitHub Actions) でデプロイされたバケット Workload Identity 作成スクリプト ( 2024/12 追記 ) GitHub Actions で Terraform を実行するための Workload Identity リソースを作成する bash スクリプトを公開しています。 前者はサービスアカウントの権限を借用する形式で、後者は Workload Identity プールに権限を付与する形式です。 こちらもあわせてご活用ください。 blog.g-gen.co.jp blog.g-gen.co.jp 武井 祐介 (記事一覧) クラウドソリューション部所属。G-gen唯一の山梨県在住エンジニア Google Cloud Partner Top Engineer 2025 選出。IaC や CI/CD 周りのサービスやプロダクトが興味分野です。 趣味はロードバイク、ロードレースやサッカー観戦です。 Follow @ggenyutakei
アバター
G-gen の神谷です。本記事では Google Cloud (旧称 GCP) の BigQuery のコスト削減の方法をまとめます。 はじめに 当記事について BigQuery の料金体系 どこに料金がかかっているか調べる 調査ポイント 調査方法 Looker Studio レポートから BigQuery へのクエリ テクニック SELECT * を使わず必要なカラムのみクエリする パーティションやクラスタリングを使う 不要なバックアップテーブルを削除 ストリーミングインサートを使わない BI ダッシュボードからビューを呼び出さない BigQuery BI Engine を利用 BigQuery Editions を利用 シャーディングテーブルを使わない API 上限を設定する マテリアライズドビューを使う Search Index を使う 公式のベストプラクティス その他の参考記事 はじめに 当記事について BigQuery は、分析用データベース製品の中でも、比較的コストパフォーマンスの良いプロダクトと言えますが、使い方次第では高額になってしまいます。 複合的な要因が積み重なって料金が決定するため、コスト削減にあたり銀の弾丸はありませんが、料金がかかる箇所を一つ一つ潰していくことで着実にトータルコストは抑えられます。本記事では、ここだけは押さえておきたいというポイントを解説します。 BigQuery の料金体系 まずは、BigQuery の料金体系を正確に理解する必要があります。 以下の2つの記事を参考にして、BigQuery のコンピュート料金およびストレージ料金の基本を理解してから、当記事の続きをお読み下さい。 blog.g-gen.co.jp blog.g-gen.co.jp どこに料金がかかっているか調べる 調査ポイント まずは、BigQuery の料金に関する現状分析を行います。料金が特に発生しがちなのは、以下のポイントです。 クエリ料金/コンピュート料金 必要がないのに SELECT * (全カラムの選択)を使っている BI ダッシュボードからビューを呼び出している パーティションやクラスタリングを適切に使っていない ストレージ料金 バックアップ用のデータセットやテーブルが整理されず残っている パーティションやクラスタリングを適切に使っていない データ格納料金 ストリーミングインサートを使っている 調査方法 調査方法として、以下を使用します。 Google Cloud 課金レポート 参考 : Cloud Billing レポート 参考 : Google Cloudの請求の仕組みを分かりやすく解説してみた - G-gen Tech Blog - 課金レポート ジョブエクスプローラー 参考 : 管理ジョブ エクスプローラを使用する システムビュー INFORMATION SCHEMA 参考 : JOBS ビュー Cloud Monitoring 指標 参考 : BigQuery Monitoring の概要 まず大原則として、 課金レポートを十分に読み込みましょう 。Google Cloud の料金は、Google Cloud コンソールの課金レポート画面から詳細に閲覧可能です。課金レポートを見れば、 課金の原因の大半が把握できます 。 BigQuery Studio(BigQuery の Web コンソール)に標準で付帯している ジョブエクスプローラー では、どのクエリにどのくらいのスキャンが発生しているか、またどのくらいスロットを占有しているかが一覧で表示されるため、課金レポートの次の調査ポイントとして有用です。 Looker Studio レポートから BigQuery へのクエリ Looker Studio レポートから BigQuery へ発生しているクエリを特定する方法については、以下の記事を参照してください。 blog.g-gen.co.jp テクニック SELECT * を使わず必要なカラムのみクエリする カラム数が多ければ多いほど、スキャン量が多くなり課金が大きくなる BigQuery は列指向データベースなので、選択する列を少なくすればするほどスキャン量が減る パーティションやクラスタリングを使う ストレージ料金とクエリ料金の両方を削減できるため、効果的 初めて BigQuery を使うケースでは後回しにしがちなので、初めから設計と実装に組み込んでおくのが望ましい 日次データであれば、ほとんどの場合日付パーティションを使った方が料金が安くなる カテゴリカルデータはクラスタリングがおすすめ BI のフィルタやディメンションで使われる項目にパーティションやクラスタを当てる パーティションとクラスタの推奨事項を確認する 参考 : パーティションとクラスタの推奨事項を管理する パーティションとクラスタの仕様については、以下の記事を参照してください。 blog.g-gen.co.jp 不要なバックアップテーブルを削除 デフォルトで7日間のバックアップ( タイムトラベル )が自動で取得されるため、基本的にはそれを使う 参考 : タイムトラベルとフェイルセーフによるデータの保持 そうでなければ Cloud Storage に CSV としてエクスポートする自動化処理を実装する ストリーミングインサートを使わない 旧来の書き込み方なので、非推奨 バッチ読み込みか、BigQuery Storage Write API を使うようにする BI ダッシュボードからビューを呼び出さない ビューはデータの実体を持たないのでクエリする度に元テーブルにスキャンがかかる 結合などは実体テーブル化しておきスキャン量を節約する BigQuery BI Engine を利用 BigQuery BI Engine (BI ツール向けのキャッシュ機能)との組み合わせによって、自社に最適なコストとパフォーマンスのトレードオフを決める Looker Studio、Looker、Tableau、コネクテッドシート などに対応 参考 : BI Engine の概要 BigQuery Editions を利用 BigQuery Editions を導入すると Autoscaler の効果で料金が安価になる可能性がある 参考 : BigQuery Editionsを徹底解説 - G-gen Tech Blog ヒューマンエラーに備えあらかじめ料金のキャップ(上限)を設けておく (BigQuery Editions Autoscaler の Max 値) 1年/3年コミットメントを購入するとスロット単価が割引料金になる エディションのスロットに関する推奨事項を確認する 参考 : エディションのスロットに関する推奨事項を表示する シャーディングテーブルを使わない シャーディングテーブル(テーブル名に日付を持つテーブル)は、現在非推奨 参考 : クエリ計算を最適化する - 処理されるデータの量を削減する なるべくパーティションテーブルを使うようにする API 上限を設定する オンデマンド課金がある一定以上にかからないように確実な上限設定をしたい場合は、以下の記事を参照してください。 blog.g-gen.co.jp マテリアライズドビューを使う マテリアライズドビュー を使うことで、事前にクエリ結果を計算することができる 参考 : マテリアライズド ビューの概要 繰り返し発生するクエリでは、コスト削減とパフォーマンス向上の効果が大きい マテリアライズド ビューの推奨事項を確認する 参考 : マテリアライズド ビューの推奨事項を管理する Search Index を使う 文字列の検索では、 Search Index (検索インデックス)を利用することで、コスト削減とパフォーマンス向上が期待できる 参考 : BigQuery での検索の概要 参考 : BigQueryのSearch Indexを解説 - G-gen Tech Blog 公式のベストプラクティス Google Cloud 公式で推奨されているコスト削減についても方法についても紹介します。 参考 : BigQuery での費用の管理 参考 : クエリ計算を最適化する 参考 : BigQuery におけるコスト最適化の ベスト プラクティス ダイレクトに課金を減らす方法に加えて、クエリパフォーマンスの最適化(処理や実行時間、リソース消費量の節減)による間接的な費用削減方法についても説明されています。以下は、一部の抜粋です。 大容量のクエリは小分けして中間テーブルに永続化する 課金される最大バイト数を設定して想定外に大きいクエリを仕組みによって回避する 正規化されているテーブルを非正規化する ネストデータ(STRUCT 型)や繰り返しデータ(ARRAY 型)を上手く使う。RDB の正規化のセオリーとは逆を行くもの 参考 : ネストされ繰り返されているフィールドを使用する 参考 : BigQueryのARRAYとSTRUCTを理解して使いこなす- G-gen Tech Blog WHERE 句で BOOL、INT、FLOAT または DATE 列を使用する クラスタ列の型として STRING も利用可能ですが、上記の型に比べてパフォーマンスが下がる 参考 : クエリ計算を最適化する - WHERE 句を使用する JOIN する前にデータを減らす 集計関数と GROUP BY は計算コストの高い処理なので、できるだけ早期にデータ量を減らしてから集計する その他の参考記事 blog.g-gen.co.jp blog.g-gen.co.jp 神谷 乗治 (記事一覧) クラウドソリューション部 クラウドエンジニア。2017 年頃から Google Cloud を用いたデータ基盤構築や ML エンジニアリング、データ分析に従事。クラウドエース株式会社システム開発部マネージャーを経て現職。Google Cloud Partner Top Engineer 2023,2024、Google Cloud Champion Innovators(Database)、 著書:「GCPの教科書III【Cloud AIプロダクト編】」  
アバター
当記事は みずほリサーチ&テクノロジーズ × G-gen エンジニアコラボレーション企画 で執筆されたものです。 はじめまして、みずほリサーチ&テクノロジーズの小野寺と申します。 みずほでは 2022 年 3 月に発表した Google との戦略的提携 の一環として Google Cloud の活用に取り組んでいます。 この記事では AWS のアーキテクトを経験してきた著者がはじめて Google Cloud で社内向けの静的 Web ページを配信するまでの経緯を記述しています。 Single Page Application を Google Cloud で構築予定の方や、これから Google Cloud に取り組む方の参考となれば幸いです。 当ブログは G-gen × みずほRT によるコラボ記事です システム特性 初期構成の検討 Cloud Load Balancing と Cloud Armor Cloud Storage から Cloud Run への切り替え Cloud Storage の検証 構成の見直し Cloud Run への切り替え その他 まとめ システム特性 先ずは配信する静的 Web ページの特徴(システム特性)についてまとめます。 題材の静的 Web ページは社内向けに Google Cloud の情報を発信する Web サイトです。 ポイントとなるシステム特性は以下の 3 点です。 将来的に Google Cloud のサービスとの連携を予定している。Google Cloud のサービスを使用して配信する 既存のインフラになるべく手を入れず、運用負荷が低い構成を優先する。通信はインターネット経由とする 利用者は社員のみ。アクセス元 IP アドレスによりアクセスを制限する 初期構成の検討 構成を検討するにあたり、先ずは経験のある AWS のサービスによる構成を考えました。 AWS での静的 Web サイト配信では Cloud Front 、WAF、S3 (静的サイトホスティング)を組み合わせるパターンが一般的です。 静的 Web サイトは Nuxt.js で開発し、リポジトリでソースを管理します。 特定の git ブランチに更新が発生した際に自動でデプロイされるようにしたいです。 また、Google Cloud には VPC Service Controls というサービスがあり、Google Cloud の API に対するアクセスを制御することができます。 アクセス元 IP アドレスによるアクセス制限で利用できそうなので、VPC Service Controls も検証してみます。 これを基本に、Google Cloud で対応するサービスに置き換えることで構成の初期案を作成しました。 役割 AWS Google Cloud WAF との連携によるオリジン保護 Cloud Front Cloud Load Balancing WAF (アクセス可能なIPアドレスの制御) WAF Cloud Armor 静的コンテンツの配置・配信 S3 Cloud Storage リポジトリ Code Commit Source Repositories 継続的デプロイ Code XXX(Code Pipeline, Code Buildなど) Cloud Build アクセス可能なIPアドレスの制御 - VPC Service Controls 初期構成案 Cloud Load Balancing と Cloud Armor Cloud Load Balancing はクライアントから見た最前面にあります。 今回はクライアントとの通信でインターネットを利用しますので、 アクセス元 IP アドレスベースのアクセス制御 と 十分に安全なアルゴリズムを使用した通信の暗号化 が必要になります。 Cloud Armor のセキュリティポリシーではクライアントの情報に基づいて Cloud Load Balancing へのアクセスを許可 / 拒否することができます。 アクセス元 IP アドレスを参照するアクセス制限が実現できます。 それ以外にも、 地理的条件やレートベースのアクセス制御 も実現できます。 Cloud Load Balancing では SSL 証明書を配置することで、クライアントとの通信暗号化が可能です。 今回は最も手のかからない Google マネージドの SSL 証明書を利用しました。 Google マネージドの SSL 証明書では DNS レコードを追加するだけで Google が証明書を発行・Cloud Load Balancing への配置まで実施してくれます。 また、Cloud Armor の SSL ポリシーを使用すると脆弱な暗号化方式による通信を拒否することができます。 これらにより、クライアント ⇔ Cloud Load Balancing の通信を保護することができました。 同様の構成を検討する場合、以下の点に留意してください。 Cloud Armor が併用可能な HTTP(s)ロードバランサは グローバル外部 HTTP(S) ロードバランサ のみ Google マネージドの SSL 証明書には厳格な審査プロセスはない(EV 証明書などが求められる場合は利用不可) Google マネージドの SSL 証明書は持ち出し不可 Cloud Storage から Cloud Run への切り替え Cloud Storage の検証 初期構成案を実装・検証してみると、以下のことがわかりました。 Cloud Storage 単体のアクセス制御では、アクセス元 IP アドレスのみを条件にすることはできない Cloud Storage へのアクセスは IAM によって制御します。 IAM では Principal(操作する主体)として Google アカウント、もしくは allUsers、allAuthenticatedUsers を指定します。 また、IAM には IAM の条件という設定があり、IP アドレスや操作時刻の条件を追加することができます。 IAM 条件でアクセス元 IP アドレスを指定した allUser に対して Storage レガシーバケット読み取りの権限を付与すれば、アクセス元 IP アドレスのみを参照するアクセス制御ができそうです。 しかし、Principal に allUsers/allAuthenticatedUsers を指定する場合は IAM の条件を指定することはできません。 VPC Service ControlsでCloud Storage 静的ウェブサイトホスティングへのHTTPアクセスを保護できる VPC Service Controls の保護対象は Google Cloud の API ですが、Cloud Storage 静的ウェブサイトホスティングでのHTTPアクセスも VPC Service Controls で保護されるようです。 Cloud Load Balancing と組み合わせたとしても、Cloud Storage への直接アクセスを制限することはできない Cloud Storage では Cloud Load Balancing を介して配信するように設定可能ですが、その場合も Cloud Storage への直接のアクセスを禁止することができません。 すなわち、オリジンを保護することができません。 構成の見直し Cloud Run への切り替え Cloud Storage 静的ウェブサイトホスティングではオリジンの保護ができない( Load Balancing を迂回するアクセスを拒否できない)ことがわかりました。 Load Balancing + Cloud Armor により、SSLポリシーによる通信の暗号アルゴリズム制限などを実装しています。 Load Balancing を迂回するアクセスは Cloud Armor で保護されませんので、オリジンへの直接アクセスは許容できません。 そこで Cloud Storage をあきらめ、Cloud Run を利用することにしました。 Cloud Run はコンテナイメージを Google Cloud 管理のマシン上で実行できるマネージドサービスです。 Cloud Run では Cloud Run へのアクセス元を Cloud Load Balancing に限定することで、オリジンを保護できます。 コンテナイメージの作成と登録が必要になりますが、静的 Web ページで利用している Nuxt.js では 公式ガイドに Cloud Run へのデプロイ方法が掲載 されており、スムーズにデプロイすることができました。 また、Cloud Build を利用することで Cloud Run への継続的デプロイを構成することができます。 Source Repositories でのコード管理、 Cloud Build によるパイプラインの構築によって master ブランチに push するだけで Cloud Run に最新の Frontend アプリケーションがデプロイされるようになりました。 最終的に以下の構成となりました。 最終的な構成 その他 記事が冗長になってしまうので詳細は省略しますが、その他の気になった点です。 Cloud Run の利用体験はすばらしかった すぐに利用できた。AWS の類似サービスでは VPC の構築、クラスタ定義等が必要だが Cloud Run では必要ない。 Cloud Run 自体もエンドポイントを持つ。Cloud Load Balancing を使用せず、直接独自ドメインで公開することもできる。 Google Cloud の他サービスとの連携が充実している。時刻起動させたり、キューをトリガーにすることもできる。 Web Security Scanner は同じ Google Cloud プロジェクトにある固定 IP アドレスに対してのみ利用可能。 Source Repositories は最低限の機能しかない。例えばプルリクはなく、ブランチの保護もできない。 まとめ 書いてしまえば当たり前なのですが、類似サービスといえど細かな仕様の違いがあります。 一見、同じような構成だとしても前述のオリジン保護のように非機能面で思わぬ落とし穴が潜んでいるかもしれません。 構成の検討に当たっては十分に検証しましょう。 個人的な感想ですが Cloud Run は設定可能な範囲と Google マネージドな範囲のバランスがよく、特にオススメできます。 最後まで読んでいただきありがとうございました。 どなたかの助けになれば幸いです。 小野寺 律文 みずほリサーチ&テクノロジーズ 2019年よりクラウドアーキテクトとして、主にAWSへのマイグレーションプロジェクトで活動。 2023年現在はGoogle Cloudの社内向け環境や教育コンテンツの整備を実施中。
アバター
G-gen の佐々木です。 サーバーレス VPC アクセスコネクタ を使用した検証の際、 コネクタを削除した後でも、コネクタ用の VPC を削除できない という事象に遭遇しました。当記事では、その原因と解決策を紹介します。 状況 エラーの内容 原因と対処 状況 Cloud Run からサーバーレス VPC アクセスコネクタを使用して Cloud SQL に接続していた。 Cloud Run を更新し、コネクタを使用しない設定でデプロイし直した。 コネクタを削除した後、コネクタ用の VPC を削除しようとすると、エラーが出て削除できなかった。 エラーの内容 ネットワークを削除できませんでした。エラー: Operation type [delete] failed with message "The network resource 'projects/<プロジェクト名>/global/networks/<vpcの名前>' is already being used by 'projects/<プロジェクト名>/global/networkInstances/v-1087083075-5562e15b-3637-4477-98e3-e3bebbee7b6a'" エラーの内容は、削除しようとしている VPC を使用しているリソースが存在する、といった内容に見えます。 Cloud Logging にも以下のようなメッセージが記録されています。 message: "RESOURCE_IN_USE_BY_OTHER_RESOURCE" しかし、この VPC はコネクタ用に作成したものであり、コネクタの削除後、この VPC を使用しているリソースはないはずです。 サーバーレス VPC アクセスコネクタ用 VPC 削除時のエラー サーバーレス VPC アクセスコネクタは既に削除済み 原因と対処 コネクタを使用しない設定で Cloud Run をデプロイし直したあと、 「コネクタを使用するように設定された Cloud Run のリビジョン(バージョン)」が残っていた ことが原因でした。 コネクタを使用していたリビジョンを削除したところ、コネクタ用の VPC も削除することができました。 サーバーレス VPC アクセスコネクタを使用する設定のリビジョンが残っている このように、「コネクタそのもの」や「現在コネクタを使用するリソース」がない場合でも、「コネクタを使用するように設定されたリビジョン」が 1 つでも存在していると、コネクタ用の VPC を削除する際に、まだ VPC を使用しているリソースがあると判定されてしまうようです。 コネクタ自体は問題なく削除できてしまうため、「コネクタを削除したのに、まだ存在しているかのようなエラーが出る」という状況になってしまいます。 今回はサーバーレス VPC アクセスコネクタを使用する設定のリビジョンが 1 つだったため、リビジョンの特定や削除は手間にならなかったのですが、「今までずっとコネクタを使用していたけど、使用しない設定に切り替える」ような場合に、それまでデプロイしたリビジョンを全て削除しなければならない、といった状況にもなり得ます。 Cloud Run はサーバーレスのサービスであり、コンテナイメージさえあれば同一のものを作成するのは非常に容易であるため、可能であれば、新しい Cloud Run サービスを作成しなおし、コネクタを使用していたほうは削除してしまうのが良いでしょう。 佐々木 駿太 (記事一覧) G-gen 最北端、北海道在住のクラウドソリューション部エンジニア。 2022 年 6 月に G-gen にジョイン。Google Cloud All Certifications Engineer。 好きな Google Cloud プロダクトは Cloud Run。最近は Dataflow を勉強中。 Follow @sasashun0805
アバター
G-gen の藤岡です。当記事では、 Workload Identity 連携を使う ことで Amazon Web Services(以下 AWS)の EC2 から Google Cloud(旧称 GCP)の Cloud Storage(以下 GCS)への操作を サービスアカウントキーを発行せず に実現する方法を紹介します。 なお、Google Cloud 側の設定は Terraform を使用します。 概要 Workload Identity 連携とは サービスアカウントキーと Workload Identity の認証情報 実施内容 構成図 Terraform テンプレート全体像 事前準備 tfstate ファイル用 GCS バケットの作成 Google Cloud の設定(Terraform 解説) Terraform の初期設定 API の有効化 サービスアカウントの作成 / 権限付与 Workload Identity の設定 Terraform の実行 Workload Identity の認証情報のダウンロード AWS の設定 IAM ロールの作成 EC2 インスタンスの作成 EC2 に IAM ロールをアタッチ Google Cloud CLI のインストール Workload Identity 連携を使用して認証 GCS の操作 環境の削除 AWS Google Cloud 注意点 概要 マルチクラウドなど複数のプラットフォームから Google Cloud APIs を呼び出し、認証が必要な場合にサービスアカウントキーを発行することがあります。しかしサービスアカウントキーは有効期限が長く、漏洩した際に危険が伴います。また、キーのローテーションなど運用負荷がかかります。 そこで、当記事では Workload Identity 連携を使うことで、サービスアカウントキーを発行せず に AWS の EC2 から Google Cloud の GCS を操作する方法について紹介します。 Google Cloud APIs について詳しく知りたい方は以下の記事をご参照ください。 blog.g-gen.co.jp まず、当記事で利用するサービスについて紹介します。 Workload Identity 連携とは Workload Identity 連携 は、オンプレミスや AWS 等の外部 ID プロバイダ(IdP)と連携をし、Google Cloud のリソースを呼び出します。オンプレミスや AWS のワークロードはセキュリティトークンサービス(STS)エンドポイントを呼び出し、IdP から取得した認証トークンを有効期限が短い Google Cloud アクセストークン と交換します。 この Google Cloud アクセストークンを使ってワークロードは サービスアカウントになりすまして Google Cloud のリソースにアクセスできる ようになります。 参考: ID 連携により有効期間の短い認証情報を取得する 当記事で紹介する構成では、認証・認可の流れは以下のようになっています。 構成図 参考: Workload Identity 連携の構成 なお、AWS の一時的なセキュリティ認証情報を生成するために、IAM ロールの AssumeRole を使用しています。 参考: AssumeRole サービスアカウントキーと Workload Identity の認証情報 前述の通り、サービスアカウントキーの発行にはセキュリティリスクが伴います。そこで、実際にサービスアカウントキーと Workload Identity の認証情報を比べることでどのようなリスクがあるのか見ていきます。 まず、サービスアカウントキーの json ファイルの内容は以下のようになっています。 { " type ": " service_account ", " project_id ": " <プロジェクト ID> ", " private_key_id ": " f20bce38bbbe5c38cbbb5ceb0ee768c84ff15388 ", " private_key ": "----- BEGIN PRIVATE KEY ----- <秘密鍵>", " client_id ": " <OAuth 2 クライアント ID> ", " auth_uri ": " https://accounts.google.com/o/oauth2/auth ", " token_uri ": " https://oauth2.googleapis.com/token ", " auth_provider_x509_cert_url ": " https://www.googleapis.com/oauth2/v1/certs ", " client_x509_cert_url ": " https://www.googleapis.com/robot/v1/metadata/x509/aws-sa%40<プロジェクト ID>.iam.gserviceaccount.com " } 次に、Workload Identity の認証情報の内容は以下のようになっています。 { " type ": " external_account ", " audience ": " //iam.googleapis.com/projects/<プロジェクト番号>/locations/global/workloadIdentityPools/aws-id-pool-1/providers/aws-provider ", " subject_token_type ": " urn:ietf:params:aws:token-type:aws4_request ", " service_account_impersonation_url ": " https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/aws-sa@<プロジェクト ID>.iam.gserviceaccount.com:generateAccessToken ", " token_url ": " https://sts.googleapis.com/v1/token ", " credential_source ": { " environment_id ": " aws1 ", " region_url ": " http://169.254.169.254/latest/meta-data/placement/availability-zone ", " url ": " http://169.254.169.254/latest/meta-data/iam/security-credentials ", " regional_cred_verification_url ": " https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15 " } } サービスアカウントキーには、 private_key に 秘密鍵が含まれています 。サービスアカウントキーが漏洩した場合、 Google Cloud 環境にあるデータは攻撃者によって取得される可能性があります。例えば、サービスアカウントにインスタンス起動の権限がある場合に、攻撃者によって大量のインスタンスが作成され多額の利用料金が請求される等の恐れがあります。 Workload Identity の認証情報には 秘密鍵は含まれておらず、Workload Identity プールで指定したプロバイダおよびアカウントからのみ この認証情報を使用してリソースにアクセスが可能です。今回はプロバイダに AWS を指定しているため、 "environment_id": "aws1" となっています。 実施内容 前述の通り、Google Cloud 側の設定は Terraform を使用します。テンプレートは後述の「Terraform テンプレート全体像」を1つの main.tf として実行しますが、テンプレートのブロックごとに解説を行います。そのため、 Terraform の解説が不要な方は「Google Cloud の設定(Terraform 解説)」はスキップしてください。 構成図 改めて、今回実施する構成は以下のとおりです。 構成図 Terraform テンプレート全体像 実行するテンプレートは以下の通りです。プロジェクト ID 等は適宜書き換えてください。 ## Terraform の初期設定 # local 定義 locals { project_id = "<プロジェクト id>" project_number = "<プロジェクト番号>" # api 有効化用 services = toset ( [ # Workload Identity 連携用 "iam.googleapis.com" , # IAM "cloudresourcemanager.googleapis.com" , # Resource Manager "iamcredentials.googleapis.com" , # Service Account Credentials "sts.googleapis.com" # Security Token Service API ] ) # workload identity provider 用 aws_id = "<aws アカウント id>" } # provider / state ファイル設定 terraform { required_providers { google = { source = "hashicorp/google" version = ">= 4.0.0" } } required_version = ">= 1.3.0" backend "gcs" { bucket = "fujioka_bucket_tfstate" prefix = "terraform/state" } } ## API の有効化(workload identity 用) resource "google_project_service" "enable_api" { for_each = local.services project = local.project_id service = each.value disable_dependent_services = true # destroy 時に依存サービスも無効化 } ## サービスアカウント # 作成 resource "google_service_account" "aws_sa" { project = local.project_id account_id = "aws-sa" display_name = "aws 用サービスアカウント" } # 権限付与 resource "google_project_iam_member" "aws_sa_role" { project = local.project_id role = "roles/storage.admin" member = "serviceAccount:$ { google_service_account.aws_sa.email } " } ## workload identity 設定 # id プール作成 resource "google_iam_workload_identity_pool" "aws_id_pool" { project = local.project_id workload_identity_pool_id = "aws-id-pool-1" display_name = "aws_id_pool" description = "aws 用プール" } # プールにプロバイダ追加 resource "google_iam_workload_identity_pool_provider" "aws_provider" { workload_identity_pool_id = google_iam_workload_identity_pool.aws_id_pool.workload_identity_pool_id workload_identity_pool_provider_id = "aws-provider" display_name = "aws_provider" description = "aws 用プロバイダ設定" aws { account_id = local.aws_id } } # workload identity プロバイダ(aws)がサービスアカウントの権限借用ができるようにする resource "google_service_account_iam_binding" "aws_sa_role_binging" { service_account_id = google_service_account.aws_sa.name role = "roles/iam.workloadIdentityUser" members = [ "principalSet://iam.googleapis.com/projects/$ { local.project_number } /locations/global/workloadIdentityPools/$ { google_iam_workload_identity_pool.aws_id_pool.workload_identity_pool_id } /*" , # workload identity プール内のすべての外部 id ] } 事前準備 なお、当記事では Terraform の概要等について触れないため、コマンドや tfstate ファイル等については以下の記事をご参照ください。 blog.g-gen.co.jp tfstate ファイル用 GCS バケットの作成 tfstate ファイルを保存するためのバケットを手動で作成します。 tfstate 用バケット Google Cloud の設定(Terraform 解説) それでは、テンプレートのブロックごとに解説を行っていきます。 Terraform の初期設定 local で変数を定義、 provider の設定をします。 ## Terraform の初期設定 # local 定義 locals { project_id = "<プロジェクト id>" project_number = "<プロジェクト番号>" # api 有効化用 services = toset ( [ # Workload Identity 連携用 "iam.googleapis.com" , # IAM "cloudresourcemanager.googleapis.com" , # Resource Manager "iamcredentials.googleapis.com" , # Service Account Credentials "sts.googleapis.com" # Security Token Service API ] ) # workload identity provider 用 aws_id = "<aws アカウント id>" } # provider / state ファイル設定 terraform { required_providers { google = { source = "hashicorp/google" version = ">= 4.0.0" } } required_version = ">= 1.3.0" backend "gcs" { bucket = "fujioka_bucket_tfstate" prefix = "terraform/state" } } 参考: Local Values / Provider Configuration / Backend Configuration API の有効化 Workload Identity 連携で 必要な API を有効化します。 local で定義している services が入ります。 ## API の有効化(workload identity 用) resource "google_project_service" "enable_api" { for_each = local.services project = local.project_id service = each.value disable_dependent_services = true # destroy 時に依存サービスも無効化 } 参考: google_project_service サービスアカウントの作成 / 権限付与 今回は EC2 から GCS バケットの作成、削除、オブジェクトの作成を行うため、 Storage 管理者 ( roles/storage.admin )の権限を付与します。 ## サービスアカウント # 作成 resource "google_service_account" "aws_sa" { project = local.project_id account_id = "aws-sa" display_name = "aws 用サービスアカウント" } # 権限付与 resource "google_project_iam_member" "aws_sa_role" { project = local.project_id role = "roles/storage.admin" member = "serviceAccount:$ { google_service_account.aws_sa.email } " } 参考: google_service_account / google_project_iam_member Workload Identity の設定 コンソールや gcloud コマンドで Workload Identity 連携の設定する場合は ドキュメント の通りです。今回は principalSet://〜 でマッピングをプール内の全ての外部 ID としていますが、マッピングを AWS の特定の IAM ロールに絞ることも可能です。 外部 ID にサービスアカウントの権限借用を許可 するには Workload Identity ユーザーロール ( roles/iam.workloadIdentityUser )を付与します。 ## workload identity 設定 # id プール作成 resource "google_iam_workload_identity_pool" "aws_id_pool" { project = local.project_id workload_identity_pool_id = "aws-id-pool-1" display_name = "aws_id_pool" description = "aws 用プール" } # プールにプロバイダ追加 resource "google_iam_workload_identity_pool_provider" "aws_provider" { workload_identity_pool_id = google_iam_workload_identity_pool.aws_id_pool.workload_identity_pool_id workload_identity_pool_provider_id = "aws-provider" display_name = "aws_provider" description = "aws 用プロバイダ設定" aws { account_id = local.aws_id } } # workload identity プロバイダ(aws)がサービスアカウントの権限借用ができるようにする resource "google_service_account_iam_binding" "aws_sa_role_binging" { service_account_id = google_service_account.aws_sa.name role = "roles/iam.workloadIdentityUser" members = [ "principalSet://iam.googleapis.com/projects/$ { local.project_number } /locations/global/workloadIdentityPools/$ { google_iam_workload_identity_pool.aws_id_pool.workload_identity_pool_id } /*" , # workload identity プール内のすべての外部 id ] } 参考: google_iam_workload_identity_pool / google_iam_workload_identity_pool_provider / google_service_account_iam_binding Terraform テンプレートの解説は以上です。 Terraform の実行 それでは、「Terraform テンプレート全体像」に記載の main.tf を Google Cloud 環境に適用していきます。今回は Cloud Shell から実行します。 まず terraform init で初期化をします。 fujioka@cloudshell:~/terraform-demo ( xxxx ) $ terraform init Initializing the backend... Successfully configured the backend " gcs " ! Terraform will automatically use this backend unless the backend configuration changes. 〜略〜 Terraform has been successfully initialized! 〜略〜 fujioka@cloudshell:~/terraform-demo ( xxxx ) $ 初期化することで backend で指定した fujioka_bucket_tfstate/terraform/state に default.tfstate が作成されます。 tfstate ファイル 次に terraform plan でドライランをします。 Plan: 9 to add, 0 to change, 0 to destroy. とあるように、今回は9つのリソースが作成されます。 fujioka@cloudshell:~/terraform-demo ( xxxx ) $ terraform plan Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: ~省略~ Plan: 9 to add, 0 to change, 0 to destroy. ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Note: You didn ' t use the -out option to save this plan, so Terraform can ' t guarantee to take exactly these actions if you run " terraform apply " now. fujioka@cloudshell:~/terraform-demo ( xxxx ) $ terraform apply を実行し、 実環境に適用します。 Apply complete! Resources: 9 added, 0 changed, 0 destroyed. と表示されれば成功です。 fujioka@cloudshell:~/terraform-demo ( xxxx ) $ terraform apply Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: ~省略~ Plan: 9 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only ' yes ' will be accepted to approve. Enter a value: yes ~省略~ Apply complete ! Resources: 9 added, 0 changed, 0 destroyed. fujioka@cloudshell:~/terraform-demo ( xxxx ) $ コンソール画面から各リソースが作成されていることがわかります。 サービスアカウント Workload Identity プール Workload Identity の認証情報のダウンロード Google Cloud コンソールで [IAM と管理] > [Workload Identity 連携] > [作成したプール] > [接続済みサービスアカウント] > [ダウンロード] をクリックします。 Workload Identity の認証情報のダウンロード① [プロバイダ] には Terraform の google_iam_workload_identity_pool_provider で設定をした aws_provider を設定し、[構成をダウンロード] をクリックします。 Workload Identity の認証情報のダウンロード② clientLibraryConfig-aws-provider.json がローカルにダウンロードされます。この Workload Identity の認証情報の内容については前述しているため、ここでは割愛します。 AWS の設定 次に AWS の環境を設定していきます。 IAM ロールの作成 信頼されたエンティティを選択 で以下のように設定します。 項目 設定値 信頼されたエンティティタイプ AWS のサービス ユースケース EC2 他の設定は ロール名 のみ入力をし、ポリシーはアタッチせずに作成します。ロール名は role-demo とします。 ロールの信頼関係は以下のようになります。 { " Version ": " 2012-10-17 ", " Statement ": [ { " Effect ": " Allow ", " Principal ": { " Service ": " ec2.amazonaws.com " } , " Action ": " sts:AssumeRole " } ] } EC2 インスタンスの作成 インスタンスの詳細な設定についての説明はしませんが、今回はコンソールから名前のみを入力し、他はデフォルト設定でインスタンスを作成しました。インスタンス名は ec2-demo とします。 OS 情報は以下の通りです。 [ ec2-user@ip-172-31-40-201 ~ ] $ cat /etc/os-release NAME = " Amazon Linux " VERSION = " 2 " ID = " amzn " ID_LIKE = " centos rhel fedora " VERSION_ID = " 2 " PRETTY_NAME = " Amazon Linux 2 " ANSI_COLOR = " 0;33 " CPE_NAME = " cpe:2.3:o:amazon:amazon_linux:2 " HOME_URL = " https://amazonlinux.com/ " [ ec2-user@ip-172-31-40-201 ~ ] $ EC2 に IAM ロールをアタッチ インスタンス( ec2-demo )に前述の IAM ロールの作成 で作成した role-demo をアタッチします。 ロールをアタッチ Google Cloud CLI のインストール インスタンスで gcloud コマンドを使えるようにするために ドキュメント を参考に Google Cloud CLI をインストールします。 # パッケージのダウンロード [ ec2-user@ip-172-31-40-201 ~ ] $ curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-410. 0 .0-linux-x86_64.tar.gz % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 156M 100 156M 0 0 89 .1M 0 0:00:01 0:00:01 --:--:-- 89 .1M [ ec2-user@ip-172-31-40-201 ~ ] $ # 展開 [ ec2-user@ip-172-31-40-201 ~ ] $ tar -xf google-cloud-cli-410. 0 .0-linux-x86_64.tar.gz [ ec2-user@ip-172-31-40-201 ~ ] $ # gcloud CLI をパスに追加 [ ec2-user@ip-172-31-40-201 ~ ] $ ./google-cloud-sdk/install.sh Welcome to the Google Cloud CLI! ~省略~ Do you want to help improve the Google Cloud CLI ( y/N ) ? N ~省略~ Modify profile to update your $PATH and enable shell command completion? Do you want to continue ( Y/n ) ? Y The Google Cloud SDK installer will now prompt you to update an rc file to bring the Google Cloud CLIs into your environment. Enter a path to an rc file to update, or leave blank to use [ /home/ec2-user/.bashrc ] : Backing up [ /home/ec2-user/.bashrc ] to [ /home/ec2-user/.bashrc.backup ] . [ /home/ec2-user/.bashrc ] has been updated. ~省略~ [ ec2-user@ip-172-31-40-201 ~ ] $ # インスタンスに再接続をし、gcloud CLI がインストールされていることを確認 [ ec2-user@ip-172-31-40-201 ~ ] $ gcloud version Google Cloud SDK 410 . 0 . 0 bq 2 . 0 . 81 bundled-python3-unix 3 . 9 . 12 core 2022 . 11 . 11 gcloud-crc32c 1 . 0 . 0 gsutil 5 . 16 [ ec2-user@ip-172-31-40-201 ~ ] $ # gcloud CLI の初期化 [ ec2-user@ip-172-31-40-201 ~ ] $ gcloud init # アカウントとプロジェクトが設定されていることを確認 [ ec2-user@ip-172-31-40-201 ~ ] $ gcloud config configurations list NAME IS_ACTIVE ACCOUNT PROJECT COMPUTE_DEFAULT_ZONE COMPUTE_DEFAULT_REGION default True fujioka@g-gen.co.jp < プロジェクト ID > [ ec2-user@ip-172-31-40-201 ~ ] $ Workload Identity 連携を使用して認証 ローカルにダウンロードした Workload Identity の認証情報をインスタンスに設置します。 [ ec2-user@ip-172-31-40-201 ~ ] $ cat clientLibraryConfig-aws-provider.json { " type " : " external_account " , " audience " : " //iam.googleapis.com/projects/<プロジェクト番号>/locations/global/workloadIdentityPools/aws-id-pool-1/providers/aws-provider " , " subject_token_type " : " urn:ietf:params:aws:token-type:aws4_request " , " service_account_impersonation_url " : " https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/aws-sa@<プロジェクト ID>.iam.gserviceaccount.com:generateAccessToken " , " token_url " : " https://sts.googleapis.com/v1/token " , " credential_source " : { " environment_id " : " aws1 " , " region_url " : " http://169.254.169.254/latest/meta-data/placement/availability-zone " , " url " : " http://169.254.169.254/latest/meta-data/iam/security-credentials " , " regional_cred_verification_url " : " https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15 " } } [ ec2-user@ip-172-31-40-201 ~ ] $ Workload Identity 連携を使用して認証します。 gcloud auth login で上記で設置したファイルを指定します。 # Workload Identity 連携を使用して認証 [ ec2-user@ip-172-31-40-201 ~ ] $ gcloud auth login --cred-file=clientLibraryConfig-aws-provider.json Authenticated with external account credentials for: [ aws-sa@ < プロジェクト ID > .iam.gserviceaccount.com ] . Your current project is [< プロジェクト ID >] . You can change this setting by running: $ gcloud config set project PROJECT_ID [ ec2-user@ip-172-31-40-201 ~ ] $ # サービスアカウントとプロジェクトが設定されていることを確認 [ ec2-user@ip-172-31-40-201 ~ ] $ gcloud config configurations list NAME IS_ACTIVE ACCOUNT PROJECT COMPUTE_DEFAULT_ZONE COMPUTE_DEFAULT_REGION default True aws-sa@ < プロジェクト ID > .iam.gserviceaccount.com < プロジェクト ID > [ ec2-user@ip-172-31-40-201 ~ ] $ 参考: クライアント ライブラリ、gcloud CLI、または Terraform を使用した認証 GCS の操作 ここでは GCS で以下の操作を順に実行および確認します。 バケットの作成 オブジェクトのアップロード バケットの削除 まず、バケットの作成をします。 # 1. バケットの作成 [ ec2-user@ip-172-31-40-201 ~ ] $ gcloud storage buckets create gs://bucket-demo-2023 Creating gs://bucket-demo-2023/... [ ec2-user@ip-172-31-40-201 ~ ] $ gcloud storage ls でバケットを一覧表示できます。Terraform の tfstate ファイル用のバケットも表示されています。 [ ec2-user@ip-172-31-40-201 ~ ] $ gcloud storage ls gs://bucket-demo-2023/ gs://fujioka_bucket_tfstate/ [ ec2-user@ip-172-31-40-201 ~ ] $ 次に、任意のオブジェクトをアップロードします。 # 2. オブジェクトのアップロード [ ec2-user@ip-172-31-40-201 ~ ] $ gcloud storage cp file-demo gs://bucket-demo-2023/ Copying file://file-demo to gs://bucket-demo-2023/file-demo Completed files 1 / 1 | 5 .0B/ 5 .0B [ ec2-user@ip-172-31-40-201 ~ ] $ --recursive オプションを付けることで、バケット内のオブジェクトを確認できます。 [ ec2-user@ip-172-31-40-201 ~ ] $ gcloud storage ls --recursive gs://bucket-demo-2023/** gs://bucket-demo-2023/file-demo [ ec2-user@ip-172-31-40-201 ~ ] $ 最後に、作成したバケットを削除します。 # 3. バケットの削除(オブジェクトとバケットを削除) [ ec2-user@ip-172-31-40-201 ~ ] $ gcloud storage rm --recursive gs://bucket-demo-2023/ Removing objects: Removing gs://bucket-demo-2023/file-demo# 1673232446429799 ... Completed 1 / 1 Removing Buckets: Removing gs://bucket-demo-2023/... Completed 1 / 1 [ ec2-user@ip-172-31-40-201 ~ ] $ 再度バケットを一覧表示すると、 bucket-demo-2023 バケットが削除されていることがわかります。 [ ec2-user@ip-172-31-40-201 ~ ] $ gcloud storage ls gs://fujioka_bucket_tfstate/ [ ec2-user@ip-172-31-40-201 ~ ] $ 参考: gcloud storage 環境の削除 AWS 今回は作成した以下のリソースを削除します。 EC2 IAM ロール Google Cloud terraform destroy コマンドで環境を削除します。 Destroy complete! Resources: 9 destroyed. と表示され、今回作成したリソース9つが削除されました。 fujioka@cloudshell:~/terraform-demo ( xxxx ) $ terraform destroy ~省略~ Plan: 0 to add, 0 to change, 9 to destroy. Do you really want to destroy all resources? Terraform will destroy all your managed infrastructure, as shown above. There is no undo. Only ' yes ' will be accepted to confirm. Enter a value: yes ~省略~ Destroy complete ! Resources: 9 destroyed. fujioka@cloudshell:~/terraform-demo ( xxxx ) $ 注意点 Workload Identity プールは削除後、 30日間は復元が可能 です。コンソールからは [IAM と管理] > [Workload Identity 連携] から 削除したプールとプロバイダを表示する を切り替えることで復元可能なプールが表示されます。 復元可能なプール そのため、環境を削除後に、Terraform テンプレートを再実行すると terraform plan は通りますが、 terraform apply で以下のように Requested entity already exists のエラーが表示されます。 │ Error: Error creating WorkloadIdentityPool: googleapi: Error 409: Requested entity already exists │ │ with google_iam_workload_identity_pool.aws_id_pool, │ on main.tf line 68 , in resource " google_iam_workload_identity_pool " " aws_id_pool " : │ 68: resource " google_iam_workload_identity_pool " " aws_id_pool " { │ ╵ プールが完全削除される30日以内に Terraform を再実行する場合は、 google_iam_workload_identity_pool の workload_identity_pool_id を変更する必要があります。 参考: プールの削除 藤岡 里美 (記事一覧) クラウドソリューション部 接客業からエンジニアへ。2022年9月 G-gen にジョイン。Google Cloud 認定資格は全冠。2023 夏アニメのオススメは、ダークギャザリング。箏を習っています :) Follow @fujioka57621469
アバター
G-gen の武井です。 Infrastructure as Code (IaC) を実現する Terraform を Google Cloud (旧称 GCP) で実行する際、ユーザーアカウントの権限ではなく、 サービスアカウントの権限を借用して実行 する方法を紹介します 。 Terraform Terraform が依存する IAM 権限 概要 IAM 権限の付与 サービスアカウントを利用した Terraform の実行 図説 権限借用のイメージ 権限借用のメリット 設定方法 概要 環境 事前準備 プロジェクトの作成 プロジェクトの請求先アカウントの紐づけ tfstate ファイル格納バケットの作成 Terraform 用サービスアカウントの作成 Terraform 用サービスアカウントに IAM ロールを付与 手順 roles/iam.serviceAccountTokenCreatorを付与 サービスアカウント権限借用の定義ファイルを作成 組織のポリシーを設定 動作確認 Google Cloud での認証 初期化 ドライラン 適用 Tips Terraform が依存する IAM 権限 概要 terraform コマンドを実行すると、その裏側では Google Cloud の API がコールされ、リソースが作成 / 更新 / 削除されます。 そのため、 Cloud ストレージバケットを作成する場合は storage.buckets.create 権限を持った IAM ロール、VM マシンを作成する場合は compute.instances.create 権限を持った IAM ロールが必要になります。 このように、 Terraform でやりたいことに応じて必要な IAM ロールを付与しなければいけません。 IAM 権限の付与 Terraform の実行に必要な IAM 権限は Google アカウント (グループ) 、またはサービスアカウントに付与します。 本記事ではサービスアカウントに IAM 権限を付与することを前提に解説します。 # アカウント種別 説明 1 Google アカウント (グループ) ユーザーが利用するアカウント 2 サービスアカウント アプリケーションが利用するアカウント サービスアカウントを利用した Terraform の実行 図説 サービスアカウント を利用した Terraform の実行方法を図でご説明します。 権限借用のイメージ 本記事で解説するこちらの方法は、 サービスアカウントの IAM 権限を借用することで Terraform を実行します。 Google アカウントがもつ IAM 権限でリソースを管理するわけではなく、サービスアカウントがもつ IAM 権限を Terraform 実行時に借用してリソースを管理します。 サービスアカウントの権限を借用してリソースを管理 権限借用のメリット ユーザー側にリソース管理に関わる IAM 権限は必要はありません。サービスアカウントの権限を借用するための IAM 権限をアタッチするだけです。 リソース管理に必要な IAM 権限はサービスアカウント側に集約できるため、権限管理の集約による 運用性の向上 が見込めます。 リソース管理に必要な IAM 権限はサービスアカウントに集約 設定方法 概要 サービスアカウント権限を借用して Terraform を実行する場合、以下の設定を行います。 ユーザーアカウントに roles/iam.serviceAccountTokenCreator を付与 サービスアカウントの権限を借用するための定義ファイルを作成 環境 今回の検証ではローカル PC 内の Linux 環境から Google Cloud 環境に対し、サービスアカウントの権限を借用して Terraform を実行し、組織のポリシーを 1つ 設定します。 サービスアカウントの権限を借用してリソースを管理 事前準備 Terraform の実行に必要なバックエンドリソースは以下のコマンドで事前に作成します。 プロジェクトの作成 gcloud projects create ${PROJECT} --name=${PROJECT} --organization=${ORGID} プロジェクトの請求先アカウントの紐づけ gcloud alpha billing accounts projects link ${PROJECT} --billing-account=${BILLINGID} tfstate ファイル格納バケットの作成 gsutil mb -b on -c standard -p ${PROJECT} -l ${REGION} gs://${PROJECT}-tfstate Terraform 用サービスアカウントの作成 gcloud iam service-accounts create terraform \ --display-name="terraform" \ --project=${PROJECT} Terraform 用サービスアカウントに IAM ロールを付与 gcloud organizations add-iam-policy-binding ${ORGID} \ --member="serviceAccount:terraform@${PROJECT}.iam.gserviceaccount.com" \ --role="roles/storage.admin" && \ gcloud organizations add-iam-policy-binding ${ORGID} \ --member="serviceAccount:terraform@${PROJECT}.iam.gserviceaccount.com" \ --role="roles/orgpolicy.policyAdmin" 手順 roles/iam.serviceAccountTokenCreator を付与 以下のコマンドで Terraform コマンドを実行するユーザーアカウントに対し、「サービスアクセストークン作成者ロール」を付与します。 gcloud projects add-iam-policy-binding ${PROJECT} \ --member user:"${USERACCOUNT}" \ --role "roles/iam.serviceAccountTokenCreator" サービスアカウント権限借用の定義ファイルを作成 こちら の公式サイトを参考にサービスアカウント権限借用の定義ファイルを作成します。 # Terraform コードにおける Google Cloud サービス アカウントの権限借用 locals { terraformadmin_project_id = "<プロジェクト>" terraform_service_account = "terraform@<プロジェクト>.iam.gserviceaccount.com" } provider "google" { project = local.terraformadmin_project_id region = "asia-northeast1" access_token = data.google_service_account_access_token.default.access_token request_timeout = "60s" } terraform { required_providers { google = { source = "hashicorp/google" version = ">= 4.0.0" } } required_version = ">= 1.3.0" backend "gcs" { bucket = "<バケット>" impersonate_service_account = "terraform@<プロジェクト>.iam.gserviceaccount.com" } } provider "google" { alias = "impersonation" scopes = [ "https://www.googleapis.com/auth/cloud-platform" , "https://www.googleapis.com/auth/userinfo.email" , ] } data "google_service_account_access_token" "default" { provider = google.impersonation target_service_account = local.terraform_service_account scopes = [ "userinfo-email" , "cloud-platform" ] lifetime = "1200s" } 組織のポリシーを設定 動作確認用のため、組織のポリシー constraints/compute.skipDefaultNetworkCreation (デフォルトネットワークの作成をスキップ) を定義します。 # デフォルト ネットワークの作成をスキップ resource "google_org_policy_policy" "compute_skip_default_network_creation" { name = "organizations/$ { var.organization_id } /compute.skipDefaultNetworkCreation" parent = "organizations/$ { var.organization_id } " spec { rules { enforce = "TRUE" } } } 動作確認 ここまでの準備、手順が実施し終えたら Terraform を実行して動作を確認します。 Google Cloud での認証 まず始めに、Google Cloud 環境に対して Terraform が実行できるよう 認証 を行います。 gcloud auth application-default login 初期化 次に Terraform を初期化します。 Terraform has been successfully initialized! と表示されれば成功です。 terraform init ドライラン 初期化が完了したら、定義ファイルが環境にどのような影響を及ぼすかを事前に確認します。 terraform plan 戻り値の 1行目〜2行目 を確認すると、サービス アカウントとしての認証で使用するアクセス トークンを取得しようとしていることがわかります。 また、 Plan: 1 to add, 0 to change, 0 to destroy. と表示されていることから、組織のポリシーが 1つ 作成されることもわかります。 data.google_service_account_access_token.default: Reading... data.google_service_account_access_token.default: Read complete after 1s [ id=projects/-/serviceAccounts/terraform@<プロジェクト>.iam.gserviceaccount.com ] Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # module.modules.google_org_policy_policy.compute_skip_default_network_creation will be created + resource "google_org_policy_policy" "compute_skip_default_network_creation" { + id = (known after apply) + name = "organizations/<組織ID>/compute.skipDefaultNetworkCreation" + parent = "organizations/<組織ID>" + spec { + etag = (known after apply) + update_time = (known after apply) + rules { + enforce = "TRUE" } } } Plan: 1 to add, 0 to change, 0 to destroy. 適用 ドライランの結果が想定通りであれば、最後に環境への適用を行います。 terraform apply -auto-approve 戻り値を確認すると、ドライラン実行時と同様、サービスアカウントの権限を借用して Terraform を実行しようとしていることがわかります。 また、 Apply complete! Resources: 1 added, 0 changed, 0 destroyed. と表示されていることから、権限を借用して組織のポリシーが設定できたことが確認できます。 module.modules.time_sleep.wait_resource: Refreshing state... [ id=2022-11-14T05: 06 :02Z ] data.google_service_account_access_token.default: Reading... data.google_service_account_access_token.default: Read complete after 1s [ id=projects/-/serviceAccounts/terraform@<プロジェクト>.iam.gserviceaccount.com ] module.modules.module.project-services.google_project_service.project_services [ "orgpolicy.googleapis.com" ] : Refreshing state... [ id=<プロジェクト>/orgpolicy.googleapis.com ] Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # module.modules.google_org_policy_policy.compute_skip_default_network_creation will be created + resource "google_org_policy_policy" "compute_skip_default_network_creation" { + id = (known after apply) + name = "organizations/<組織ID>/compute.skipDefaultNetworkCreation" + parent = "organizations/<組織ID>" + spec { + etag = (known after apply) + update_time = (known after apply) + rules { + enforce = "TRUE" } } } Plan: 1 to add, 0 to change, 0 to destroy. module.modules.google_org_policy_policy.compute_skip_default_network_creation: Creating... module.modules.google_org_policy_policy.compute_skip_default_network_creation: Creation complete after 3s [ id=organizations/<組織ID>/policies/compute.skipDefaultNetworkCreation ] Apply complete! Resources: 1 added, 0 changed, 0 destroyed. Tips 組織のポリシーをユーザーアカウントの権限を利用して作成しようとした場合、以下のエラーが発生します。 このようなエラーが発生した場合、本記事でご紹介したとおり、 サービスアカウントの権限を借用した上で組織のポリシーを作成してください。 # エンド ユーザー資格情報が `orgpolicy.googleapis.com` ではサポート外である旨のメッセージ Error 403 : Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the orgpolicy.googleapis.com. # サービスアカウントの権限借用を推奨する旨のメッセージ We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. # 詳細 google_org_policy_policy.compute_skip_default_network_creation: Creating... ╷ │ Error: Error creating Policy: failed to create a diff: failed to retrieve Policy resource: googleapi: Error 403 : Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the orgpolicy.googleapis.com. We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. For more information about service accounts and how to use them in your application, see https: //cloud.google.com/docs/authentication/. If you are getting this error with curl or similar tools, you may need to specify 'X-Goog-User-Project' HTTP header for quota and billing purposes. For more information regarding 'X-Goog-User-Project' header, please check https://cloud.google.com/apis/docs/system-parameters. │ Details: │ [ │ { │ "@type" : "type.googleapis.com/google.rpc.ErrorInfo" , │ "domain" : "googleapis.com" , │ "metadata" : { │ "consumer" : "projects/<組織ID>" , │ "service" : "orgpolicy.googleapis.com" │ } , │ "reason" : "SERVICE_DISABLED" │ } │ ] 武井 祐介 (記事一覧) 2022年4月入社 / クラウドソリューション部 / 技術2課所属 趣味はゴルフにロードバイク。IaC や CI/CD 周りのサービスやプロダクトが興味分野です。 Google Cloud 認定全冠達成!(2023年6月)
アバター
G-gen の杉村です。Google Cloud は Google Cloud APIs と呼ばれる Web API 群によって成り立っています。この仕組みを理解すると、Google Cloud というパブリッククラウドサービス全体への理解が深まります。 Google Cloud APIs とは API 設計 設計ガイド リソース指向 API エンドポイント インターフェイス 概要 Cloud SDK Web コンソール 認証・認可 アカウントと IAM リクエストへの署名 プロジェクトと API の有効化 割り当てとシステム上限 割り当て 割り当ての上限緩和 システム上限 各サービスの割り当てと上限 監査ログ 重要性 Google Cloud における監査ログ Google Cloud APIs とは Google Cloud APIs とは、Google Cloud がユーザーのために開放している Web API の 総称 です。 参考 : Google Cloud API 大事なポイントとして、Google Cloud APIs という名称の独立したプロダクトがあるわけではありません。Compute Engine や Cloud Storage、BigQuery といった各サービスには Web API が用意されていますが、そういった API 群を総称して Google Cloud APIs と呼んでいます。 Google Cloud APIs はインターネットに公開されており、誰でもアクセスすることができます。ただし、利用には Google アカウントと IAM による認証・認可が必要です。API エンドポイントはインターネットに公開されていますが、IAM という高度な仕組みによる認証・認可が必須なこと、また通信は SSL/TLS により暗号化されていることから、セキュアに利用することができます。 API 設計 設計ガイド Google Cloud APIs は一定の設計ガイドに沿って設計されており、異なるサービスでも一貫した構成となっているので、効率良く理解することができます。 そのガイドは公開されており、以下のリンクから確認できます。このガイドは Google の API 設計に対する考え方が詳細に書かれており、我々が REST API などを設計する際にも参考にすることができます。 参考 : API 設計ガイド リソース指向 Google Cloud APIs の多くは、 REST API として設計されています。 REST API では、原則的に URL(URI)をリソース名として、これに対する HTTP メソッド(CREATE、GET、POST、DELETE...)でリソースを操作します。REST API についてはインターネット上に多数の情報がありますので、そちらを参照してください。 Google Cloud の API はリソース指向で設計されており、リソースには親子関係があります。親となって複数の末端リソースを収容できるリソースを コレクション 、またはコレクションリソースと呼び、末端のリソースを単に リソース またはシンプルリソースと呼びます。 例として、Compute Engine のリソース URI を見てみます。以下は、インスタンス(VM)の URI です。 https://compute.googleapis.com/compute/v1/projects/{project}/zones/{zone}/instances/{resourceId} instances というコレクションの中に、リソース ID で一意に特定されるリソースがあることが分かります。この URI に対して GET リクエストをすることで、インスタンスの情報を得ることができます。 例として gcloud compute instances describe ${INSTANCE_ID} というコマンドを考えます。このコマンドを実行すると、gcloud コマンドが内部的に上記のインスタンスリソースの URI に対して HTTP プロトコルで GET リクエストを投げています。 また、上記のようなコマンドでインスタンス ID を指定しても、デフォルト値で、もしくは明示的にゾーンを指定しなければ「ゾーンを指定してください」というプロンプトが返されます。これも、リソース URI にゾーンが含まれているからだと理解することができます。 リソース構成を始めとするこういった API 設計の原則を知っていれば、Google Cloud や gcloud、Cloud SDK の利用方法に統一性が見いだせるため、学習効率が良くなります。 API エンドポイント 各 Google Cloud サービスには API のエンドポイント URL があります。以下は、一例です。 サービス名 代表的なリソース エンドポイント リファレンスへのリンク Compute Engine インスタンス、VPC、サブネット compute.googleapis.com リファレンス BigQuery データセット、テーブル、ジョブ bigquery.googleapis.com リファレンス Identity and Access Management (IAM) サービスアカウント、ロール iam.googleapis.com リファレンス Cloud Monitoring タイムシリーズ、稼働時間チェック monitoring.googleapis.com リファレンス Cloud Logging エントリ、ログバケット、シンク logging.googleapis.com リファレンス Cloud Run サービス、サービスリビジョン run.googleapis.com リファレンス Cloud Functions 関数 cloudfunctions.googleapis.com リファレンス Cloud Pub/Sub トピック、サブスクリプション pubsub.googleapis.com リファレンス Cloud Resource Manager プロジェクト、フォルダ、タグ cloudresourcemanager.googleapis.com リファレンス Organization Policy 制約、ポリシー orgpolicy.googleapis.com リファレンス Access Context Manager アクセスレベル、境界 (VPC SC) accesscontextmanager.googleapis.com リファレンス Cloud Identity-Aware Proxy (Cloud IAP) IAP (top level)、宛先グループ iap.googleapis.com リファレンス Cloud DNS マネージドゾーン、レコードセット dns.googleapis.com リファレンス インターフェイス 概要 Google Cloud APIs は Web API であり、インターネットからアクセスできるようになっています。 しかし利用にはそれなりの手順が必要です。署名した認証情報をリクエストヘッダに含める必要がありますし、正しい形でパラメータを持たせてリクエストを作成しなくてはいけません。 これを自前のプログラムで全て実装するのには、大きい労力がかかります。その代わりに、Google Cloud がオフィシャルに配布するツールを使うことで、簡単に API を利用することができます。 Cloud SDK Google からは、公式のクライアントライブラリ群である Cloud SDK が公開されています。 参考 : Cloud SDK Cloud SDK は、以下を総称したものです。 Google Cloud CLI(別名 gcloud CLI) クライアントライブラリ(Java、Python、Node.js、Ruby、Go、.NET、PHP、C#、C++ 用) Google Cloud CLI は、Windows、macOS、Linux で動作するコマンドラインツールです。簡単な操作で Google Cloud API を利用することができます。gcloud コマンドは Python で書かれており、実行環境には Python のインストールが必要です。Google Cloud を利用する場合、日常的に使うことになるツールです。 参考 : Google Cloud コマンドライン インターフェース(gcloud CLI) クライアントライブラリ は、各種プログラミング言語から Google Cloud API を呼び出すためのライブラリです。2025年4月現在では、Java、Python、Node.js、Ruby、Go、.NET、PHP、C#、C++ 用の公式ライブラリが公開されています。 これらの SDK を使えば、パラメータの整形や認証情報の取得、署名が自動的に行われ、簡単にリクエストを生成することができます。 参考 : Cloud クライアント ライブラリ Web コンソール 多くの人に馴染み深いであろう Google Cloud の Web コンソールも、 API を呼ぶための操作インターフェイスの一種 と言えます。 Web コンソール画面で操作を行うと、内部的にはログイン中の Google アカウントの認証情報を使って、各種 API へリクエストが行われます。 これを理解していれば、コンソール画面での操作中にエラーが発生した場合でも、API リファレンス等のドキュメントを活用してトラブルシューティングを適切に行うことができます。 認証・認可 アカウントと IAM Google Cloud APIs への認証・認可は Google アカウントと Identity and Access Management(IAM)の仕組みによって行われます。 Google アカウントは Google Workspace もしくは Cloud Identity により管理されるアカウントです。またこれらによって組織的に管理されない無料の Google アカウントも利用可能です。 IAM は、Google Cloud リソース(VM や BigQuery データセット等)と Google アカウントの間での権限のひも付きを管理する機能です。詳細については、以下のドキュメントと、当社記事を参照してください。 参考 : IAM の概要 参考 : Google CloudのIAMを徹底解説! リクエストへの署名 Google Cloud API へリクエストする際は、エンドポイント URI に対して HTTP リクエストを送りますが、このとき Authorization ヘッダに認証情報のトークンを含ませることで、認証・認可が行われます。 Cloud SDK や Web コンソールを用いていれば、ヘッダの追加は自動的に行われます。 参考 : REST を使用して認証する なお、Google Maps Platform など一部の API は、IAM ではなく API キーによる認証もサポートしています。 プロジェクトと API の有効化 Google Cloud APIs は原則的に Google Cloud リソースである プロジェクト にひも付きます。 Google Cloud のリソースは 組織 をトップとする階層構造になっており、プロジェクトはいわば「テナント」のイメージです。プロジェクトは、Amazon Web Services(AWS)で言うところの「AWS アカウント」に該当します。 参考 : リソース階層 プロジェクトで Google Cloud サービスごとの API を有効化 することで、そのプロジェクトで該当 API を利用することができます。API リクエスト時には、プロジェクト ID を指定する必要があります。 以下は、Google Cloud CLI(gcloud コマンド)を使い my-project というプロジェクトで Compute Engine API を有効化するコマンドです。 gcloud services enable compute.googleapis.com --project = my-project 有効化するとそれ以降、Compute Engine のサービスが利用可能になります。以下がその例です。 gcloud compute instances create my-first-vm \ --project = my-project \ --zone = us-central1-a \ --machine-type = e2-medium \ --create-disk = auto-delete = yes, boot =yes,device-name = instance-1, image =projects/debian-cloud/global/images/debian-11-bullseye-v20221206, mode =rw, size = 10 , type= projects/my-project/zones/us-central1-a/diskTypes/pd-balanced 上記のコマンドラインでは、 --project オプションで、プロジェクトを指定しています。なお、gcloud ではデフォルトプロジェクトを設定すれば、都度指定しなくても構いません。このコマンドを実行すると、プロジェクト my-project に対して HTTP リクエストが生成され、実行されます。IAM 認証情報も自動的にリクエストヘッダに付与されます。 なお、クラウドリソースの料金は、通常はそのリソースが所属するプロジェクトに対して課金されます。 割り当てとシステム上限 割り当て 割り当て (Quota)とは、Google Cloud の各 API に設定された、API の呼び出しに関する制限のことです。Google Cloud プロダクトには、組織単位・プロジェクト単位・ユーザ単位など様々な粒度で割り当てが設定されています。 例えば、Compute Engine API には、1つのプロジェクトで利用可能な永続ディスクの合計サイズに、リージョンごとの割り当てが存在しています。割り当てを超えて永続ディスクを作成しようとすると、作成が失敗します。 参考 : 割り当てとシステム上限について 割り当ての上限緩和 Google に対して、割り当ての 引き上げリクエスト を実行することができます。引き上げリクエストは Google Cloud コンソールの申請フォームから行うことができます。リクエストは Google によって審査され、これまでの使用実績や Google 側のリソース状況などを勘案して承認されます。 なお、他のパブリッククラウドでは、割り当ての上限緩和のためにサポート窓口でサポートケースを起票する必要がある場合があります。Google Cloud ではサポートケースを起票しなくても、Google Cloud コンソールの「割り当てとシステム上限」画面から割り当ての引き上げリクエストを申請できます。Google Cloudの技術サポート窓口である「カスタマーケア」は有償です。割り当ての引き上げリクエストのためだけに、有償のカスタマーケアを契約する必要はありません。 参考 : 割り当ての表示と管理 引き上げリクエストの手順については、以下の記事も参照してください。 blog.g-gen.co.jp システム上限 Google Cloud には割り当ての他に、 システム上限 (System limit)があります。割り当ては引き上げリクエストができるのに対して、システム上限は固定値であり、変更できません。 参考 : 割り当てとシステム上限について 各サービスの割り当てと上限 各 Google Cloud サービスには、割り当てや上限について説明した公式ドキュメントがあります。そのようなドキュメントを参考にしてください。 Compute Engine - Compute Engine の割り当てと上限の概要 Cloud Storage - 割り当てと上限 BigQuery - 割り当てと上限 Cloud Run - Cloud Run の割り当てと上限 監査ログ 重要性 すべての Google Cloud のサービスは、API で操作されます。BigQuery にデータをロードするのも、クエリを投入するのも、API 経由です。Cloud Storage にオブジェクトをアップロードしたり、ダウンロードするときにも、API を使います。 セキュリティインシデントが発生したときに、API の操作ログが残っていないと「いつ・どこから・誰が・何を・どうした」の追跡ができません。逆に、監査ログが適切に記録されていれば、上記の追跡ができることに加え、監査ログが正しく取られているということ自体が、セキュリティ侵害に対する抑止力になります。 また、セキュリティ関連の各種第三者認証で、監査ログが適切に取得されていることが要件となっており、監査機関への提出が求められることもあります。 上記の理由から監査ログは重要です。 Google Cloud ではデフォルトで一定のレベルで監査ログが記録されるほか、追加の設定をすることで記録の粒度や、保存期間を変更することができます。 Google Cloud における監査ログ Google Cloud では Cloud Audit Logs という仕組みで監査ログが記録されます。詳細は以下の記事をご参照ください。 blog.g-gen.co.jp 以下に、概要を記載します。 デフォルトではリソースに対する更新系の API リクエスト履歴のみが記録される デフォルトでは保存期間は 30 日間 ログは Cloud Logging に保存される。追加の設定により BigQuery や他のストレージにも保存できる 追加の設定により読み取り系の API リクエスト履歴や、リソース内のデータへのアクセス履歴の記録も可能 杉村 勇馬 (記事一覧) 執行役員 CTO 元警察官という経歴を持つ IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 認定資格および Google Cloud 認定資格はすべて取得。X(旧 Twitter)では Google Cloud や Google Workspace のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の杉村です。 Private Service Connect は Google Cloud API やユーザー独自で公開するサービスにプライベート接続を提供するサービスです。当記事では、Private Service Connect を使って独自サービスを公開する方法をご紹介します。 概要 Private Service Connect とは Private Service Connect によるサービス公開 Private Service Connect のアーキテクチャ 構成図 通信の流れ 詳細な構成 サービス提供側 サービス利用側 接続元 IP アドレス DNS 名 構築手順 サービス提供側の手順 サービス利用側の手順 Private Service Connect backends Private Service Connect interfaces 料金 サービス提供側 サービス利用側 概要 Private Service Connect とは Private Service Connect とは Google Cloud (旧称 GCP) の Virtual Private Cloud (VPC) に備わった一機能です。 以下の用途で用いられます。 Google Cloud の API にプライベート IP でアクセスする ユーザー独自のサービスを他の Google Cloud プロジェクト向けに公開する 前者は、本来パブリック IP を用いてインターネット経由でのアクセスが必要な Google Cloud の各種 API に対し、プライベート IP による接続を実現する用途です。以下の記事で詳細を紹介しています。 blog.g-gen.co.jp 後者は、当記事でご紹介する内容です。Google Cloud 上でホストするサービス (Web API やその他のサービス) を 他の Google Cloud ユーザー向け 、あるいは 社内の別 Google Cloud プロジェクト向け に公開する用途です。 AWS には類似の機能として AWS PrivateLink があり、これの Google Cloud 版と思えば良いでしょう。 Private Service Connect によるサービス公開 Compute Engine VM 等でホストするサービスを他の Google Cloud プロジェクトや他の VPC に向けに公開するには、以下のような方法が考えられます。 サービスエンドポイントをインターネットに公開する (外部 HTTP(S) ロードバランサ等を利用) VPC Peering で接続する Cloud VPN で VPC 同士を接続する Private Service Connect で公開する 選択肢 1. は、通常の Web サービスのようにインターネット公開する方法です。ただし、サービスが特定少数のクライアントにだけ向けたものであれば、セキュリティ上の理由でこの方法は避けたくなります。 選択肢 2. や 3. は、VPC 同士を直接接続し、プライベート IP で通信する方法です。これなら不特定多数のクライアントからアクセスされることはありませんが、全ての VPC 同士の IP アドレス帯が重複していない ことが必須条件です。複数の会社・官公庁をまたぐネットワークだと、IP アドレス帯が重複してしまっているケースも多いでしょう。 そこで選択肢 4. の Private Service Connect が検討に入ります。 Private Service Connect によるサービス公開では、IP アドレスの重複有無に関係なく、他の VPC 向けにサービスを公開し、プライベートネットワークでの接続を実現することができます。この方法を Private Service Connect によるマネージドサービス公開 と言います。 参考 : Private Service Connect でマネージド サービスを公開して使用する Private Service Connect のアーキテクチャ 構成図 Private Service Connect でのマネージドサービス公開は、以下のようなアーキテクチャで実現されます。 アーキテクチャ 左側の Google Cloud 環境がサービスを利用する側 (サービスコンシューマーとも呼称) で、右側がサービスを提供する側 (サービスプロデューサーとも呼称) です。 通信の流れ 通信は、以下の流れで実現されます。 前提 : 図右端のサーバは HTTP (tcp/80) でサービスを提供。図左端のクライアントからアクセスされる クライアントは 10.100.0.101:80 (Private Service Connect エンドポイント) へアクセス 通信は Google Cloud 内部ネットワークを通りサービス提供側環境の Service Attachment へ到達。SNAT されて内部ロードバランサへ到達 内部ロードバランサが負荷分散してバックエンドのサーバへ通信が届く (レスポンスは逆の経路を通ってクライアントに返る) 詳細な構成 サービス提供側 サービス提供側は 「サービスアタッチメント」「内部ロードバランサ」「バックエンドサーバ」 の組み合わせでサービスを提供します。 サービスアタッチメント はサービス公開のために作成されるリソースであり、1サービスにつき1個のサービスアタッチメントを作成します。サービスアタッチメントはパケット転送先として 転送ルール にひも付きます。この「転送ルール」とは、ロードバランサの「フロントエンド」と思えば良いです。 なおサービスアタッチメントを作成するための 専用サブネット が必要です。サブネット作成時に「Private Service Connect 用」と明示的に選択して作成する必要があります。サイズは任意であり最小サイズ ( /29 ) とすることもできますが同時接続するクライアント数が多すぎると IP 不足になるおそれがあります ( 参考 )。 内部ロードバランサ は、以下の種類に対応しています。 内部パススルーネットワークロードバランサ 内部アプリケーションロードバランサ 内部プロトコル転送 リージョン内部プロキシネットワークロードバランサ バックエンドサーバ としては、内部ロードバランサが対応している各種バックエンドが利用できます。すなわち、Compute Engine VM (インスタンスグループ) や VPN / 専用線で接続されたオンプレミスのサーバなどが利用できます。 サービス利用側 サービス提供側でサービスアタッチメントを作成すると、サービス名が払い出されます ( projects/${PROJECT_ID}/regions/${REGION}/serviceAttachments/${SERVICE_NAME} )。 サービス利用側ではこの名称を指定して、サービスに接続するためのエンドポイント (Private Service Connect Endpoint) を作成します。 エンドポイントを作成するとプライベート IP が割り当てられます。クライアントからはこのプライベート IP を宛先としてサービスを利用します。 なお、サービス提供側ではサービスアタッチメント作成時に、明示的に承認したプロジェクトのエンドポイントだけを受け付けるように設定できます。未承認のエンドポイントではパケットが転送されません。 ※ より詳細な仕様として、Private Service Connect エンドポイントの実体は「サービスアタッチメントをターゲットとする転送ルール」であり gcloud compute forwarding-rules list で一覧表示することができます。転送ルールはロードバランサのフロントエンドとしても利用されるリソースです。 接続元 IP アドレス トラフィックの接続元 IP アドレスはバックエンドサーバからどう見えるのかが問題になることがあります。Private Service Connect でルートされたトラフィックの接続元 IP は、利用しているロードバランサによって異なります。 内部ロードバランサが プロキシ型 の場合、バックエンドサーバから見た接続元 IP は プロキシ専用サブネットの CIDR 範囲 となる 内部ロードバランサが パススルー型 の場合、バックエンドサーバから見た接続元 IP は サービス専用サブネットの CIDR 範囲 となる いずれの場合でも、クライアントの元々の IP アドレスは得ることができません。元々の IP アドレスを知りたい場合にはサービスアタッチメントにて プロキシプロトコル を有効化します。有効化する場合は以下に注意が必要です。 対応しているのは「内部 TCP / UDP ロードバランサ (TCP 通信のみ)」と「内部プロトコル転送」のみ サーバ側でプロキシプロトコルヘッダを処理するように適切に設定しなければ、リクエストが正常に処理されない またプロキシプロトコルを使った場合でも VPC Firewall などではその情報を参照できないため、Firewall rule で接続元 IP に基づいたアクセス制御を行うことはできません。詳細は以下のドキュメントも参考にしてください。 参考 : コンシューマの接続情報を表示する DNS 名 エンドポイントに DNS 名を設定することもできます。 Service Directory の機能を利用することでサービス提供側で DNS 名を定義 することも可能ですし、サービス利用側で Cloud DNS を使って 定義する ことも可能です。 構築手順 サービス提供側の手順 大まかに、以下の作業を行います。 バックエンドサーバを構築 内部ロードバランサを構築 (適切な VPC Firewall rule を作成) Private Service Connect サービス専用サブネットを作成 (パススルー型ロードバランサの場合) サービス専用サブネットからの通信を許可する VPC Firewall rule を作成 サービスアタッチメントを作成 承認するプロジェクトを追加 詳細は以下のドキュメントを参照してください。 参考 : Private Service Connect を使用してマネージド サービスを公開する サービス利用側の手順 サービス利用側では原則的に「エンドポイントを作成する」だけです。 その他にも DNS の設定などを使用する場合は、追加の手順があります。詳細は以下のドキュメントを参照してください。 参考 : Private Service Connect を使用してマネージド サービスにアクセスする Private Service Connect backends 応用として Private Service Connect backends という手法を用いることもできます (かつては「コンシューマ HTTP(S) コントロールを使用する Private Service Connect エンドポイント」と呼称されていました)。 こちらですと、サービス利用側は外部 HTTP(S) ロードバランサをエンドポイントとして利用します。ロードバランサのバックエンドサービスとして「Private Service Connect NEG」を利用することで実現します。 メリットとしては「サービスを柔軟に任意の URL にマップできる」「Cloud Logging に全リクエストをロギングできる」「任意の SSL/TLS 証明書を利用できる」「段階的に Private Service Connect にホストされたサービスへ移行できる」などがあります。 詳細は以下のドキュメントを参照してください。 参考 : About backends 参考 : 初めてのPrivate Service Connect #4 L7 PSC 編 Private Service Connect interfaces Private Service Connect interfaces は、Private Service Connect Endpoint とは逆で、サービス提供側 から開始 してサービス利用側へ通信する経路を確立する機能です。 サービス利用側のサブネットに ネットワークアタッチメント (network attachment) というコンポーネントを作成します。このコンポーネントには Internal IP アドレスが割り振られ、サービス提供側からの通信を中継します。 サービス提供側の Compute Engine VM は最低2つの NIC を持つ必要があり、うち一つが Private Service Connect interface であり、サービス利用側 (顧客側) との通信に使われます。一つの VM には7つまで Private Service Connect interface を作成できます。 当機能の詳細は、以下の公式ガイドを参照してください。 なお当機能は2023年6月現在、Preview であることにご留意ください。 参考 : About Private Service Connect interfaces 料金 サービス提供側 サービスアタッチメントで処理したデータ 1 GB につき $0.01 が発生します (上り・下りの両面)。 料金 | Virtual Private Cloud | Google Cloud Private Service Connect 自体にかかる料金は上記のみですが、これに加えてバックエンドのサーバ (Compute Engine 等) の利用料金や、内部ロードバランサの利用料金も発生しますのでご留意ください。 サービス利用側 エンドポイントに 1 時間あたり $0.01 の料金が発生します。 また処理したデータ 1 GB あたり $0.01 が発生します (上り・下りの両面)。 料金 | Virtual Private Cloud | Google Cloud 杉村 勇馬 (記事一覧) 執行役員 CTO / クラウドソリューション部 部長 元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の杉村です。ある Google Cloud 組織でサービスアカウントキーを発行しようとしたところ 不明なエラーです。 というメッセージと共に作成が失敗した事象が起きました。原因と対策を紹介します。 事象 調査 サービスアカウントキー作成の失敗ログ 同時刻のログに解決の糸口 原因と対処 事象 サービスアカウントからサービスアカウントキー (秘密鍵) を生成しようとしたところ、以下のメッセージが出て作成できなかった。 `不明なエラーです。` `操作に失敗しました。もう一度お試しください。` メッセージは 不明なエラーです。 操作に失敗しました。もう一度お試しください。 追跡番号 xxxxxxxxxxxxxxxx のみだ。 またコンソールだけでなく、gcloud コマンドでのキー生成を試みてもエラーとなる。 $ gcloud iam service-accounts keys create ./sa-key.json \ > --iam-account=my-service-account@my-project.iam.gserviceaccount.com \ > --project=my-project ERROR: ( gcloud.iam.service-accounts.keys.create ) FAILED_PRECONDITION: Precondition check failed. 調査 サービスアカウントキー作成の失敗ログ 同プロジェクトの Cloud Logging をクエリすると、以下のログが出ている (一部を伏せ字・仮の値に置き換えている)。 サービスアカウントキーの作成が Precondition check failed. というメッセージ (“前提条件のチェックに失敗” の意味) と共にコード 9 で失敗していることが分かるが、それ以上は分からない。 { " protoPayload ": { " @type ": " type.googleapis.com/google.cloud.audit.AuditLog ", " status ": { " code ": 9 , " message ": " Precondition check failed. " } , " authenticationInfo ": { " principalEmail ": " my-account@my-domain.com ", " principalSubject ": " user:my-account@my-domain.com " } , " requestMetadata ": { " callerIp ": " x.x.x.x ", " callerSuppliedUserAgent ": " Mozilla/5.0 (X11; CrOS x86_64 15183.59.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36,gzip(gfe) ", " requestAttributes ": { " time ": " 2022-12-14T08:42:34.568951085Z ", " auth ": {} } , " destinationAttributes ": {} } , " serviceName ": " iam.googleapis.com ", " methodName ": " google.iam.admin.v1.CreateServiceAccountKey ", " authorizationInfo ": [ { " resource ": " projects/-/serviceAccounts/123456789012345678901 ", " permission ": " iam.serviceAccountKeys.create ", " granted ": true , " resourceAttributes ": { " name ": " projects/-/serviceAccounts/123456789012345678901 " } } ] , " resourceName ": " projects/-/serviceAccounts/123456789012345678901 ", " request ": { " private_key_type ": 2 , " @type ": " type.googleapis.com/google.iam.admin.v1.CreateServiceAccountKeyRequest ", " name ": " projects/my-project/serviceAccounts/123456789012345678901 " } , " response ": { " @type ": " type.googleapis.com/google.iam.admin.v1.ServiceAccountKey " } } , " insertId ": " abcd123456789 ", " resource ": { " type ": " service_account ", " labels ": { " email_id ": " my-service-account@my-project.iam.gserviceaccount.com ", " project_id ": " my-project ", " unique_id ": " 123456789012345678901 " } } , " timestamp ": " 2022-12-14T08:42:34.548887889Z ", " severity ": " ERROR ", " logName ": " projects/my-project/logs/cloudaudit.googleapis.com%2Factivity ", " receiveTimestamp ": " 2022-12-14T08:42:36.473110470Z " } 同時刻のログに解決の糸口 しかし、上記ログとほぼ同タイミングで、以下のようなログが出力されていた。ほぼ同時刻であるためコンソールの Cloud Logging のログエクスプローラーで隣り合った位置に出力されており、特にクエリでログを絞っていなかったため気がつくことができた。 { " protoPayload ": { " @type ": " type.googleapis.com/google.cloud.audit.AuditLog ", " status ": { " code ": 7 , " message ": " PERMISSION_DENIED " } , " authenticationInfo ": {} , " requestMetadata ": { " callerIp ": " private ", " requestAttributes ": {} , " destinationAttributes ": {} } , " serviceName ": " resourcesettings.googleapis.com ", " methodName ": " google.cloud.resourcesettings.v1alpha1.ResourceSettingsService.LookupEffectiveSettingValue ", " resourceName ": " projects/123456789012 ", " metadata ": { " @type ": " type.googleapis.com/google.cloud.audit.OrgPolicyRestrictionAuditMetadata ", " violationReason ": " SERVICE_USAGE_RESTRICTION_VIOLATED ", " resourceNames ": [ " projects/123456789012/settings/iam-serviceAccountKeyExpiry " ] } , " policyViolationInfo ": { " orgPolicyViolationInfo ": { " violationInfo ": [ { " constraint ": " constraints/gcp.restrictServiceUsage ", " errorMessage ": " Resource Usage Restriction Org Policy is violated ", " policyType ": " LIST_CONSTRAINT " } ] } } } , " insertId ": " 123456789abc ", " resource ": { " type ": " audited_resource ", " labels ": { " project_id ": " my-project ", " service ": " resourcesettings.googleapis.com ", " method ": " google.cloud.resourcesettings.v1alpha1.ResourceSettingsService.LookupEffectiveSettingValue " } } , " timestamp ": " 2022-12-14T08:42:34.705300886Z ", " severity ": " ERROR ", " logName ": " projects/my-project/logs/cloudaudit.googleapis.com%2Fpolicy ", " receiveTimestamp ": " 2022-12-14T08:42:35.286107268Z " } これは、組織のポリシー constraints/gcp.restrictServiceUsage の制限によって API resourcesettings.googleapis.com が拒否されたことを示すログだ。 確かに、今回事象が起きた Google Cloud 組織では 組織のポリシー constraints/gcp.restrictServiceUsage (利用可能な Google Cloud サービスを制限するポリシー) を使って、環境利用者が特定の Google Cloud サービスしか使えないように制限をかけていた。このポリシーが、原因に関係しそうだ。 参考 : Restricting resource usage 二種類のログがセットで出力されていたことに気がついた 原因と対処 対処法を先に書くと、組織ポリシー constraints/gcp.restrictServiceUsage の許可リストに resourcesettings.googleapis.com を追加すると、事象は解決した。 Resource Settings API は Google Cloud リソースの振る舞いを管理する API であり、VM、VPC Firewall、プロジェクトなど様々なリソースの管理のため、バックエンドで用いられている。 また、我々ユーザーも同 API を利用することにより、リソース作成時のデフォルトのロケーションを設定するなど、組織で一貫した設定値を管理することができる。 参考 : リソースの設定の概要 今回の事象の原因は、組織ポリシー constraints/gcp.restrictServiceUsage によってバックエンドで用いられている Resource Settings API が禁止されてしまっていたためだった。そのため同 API を示す resourcesettings.googleapis.com を許可リストに追加することで、事象が解決した。 ほとんどの場合で Google Cloud API は適切なエラーログを出力するため、トラブルに遭遇したらまずを Cloud Logging を精査するのが得策だ。 杉村 勇馬 (記事一覧) 執行役員 CTO / クラウドソリューション部 部長 元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。Twitter では Google Cloud や AWS のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の杉村です。Compute Engine VM を自動で管理・運用するための機能である VM Manager について徹底解説します。 概要 VM Manger とは OS Config エージェント 料金 パッチ(Patch) パッチ(Patch)とは パッチ コンプライアンス レポート パッチ デプロイ 概要 適用タイミング 対象 VM の指定 アップデート 前処理・後処理 OS Inventory Management OS Inventory Management とは 閲覧方法 OS ポリシー(OS policies) OS ポリシーとは 構成要素 OS ポリシー OS ポリシーの割り当て ロールアウト エージェントと情報収集 有効化 概要 サービス API の有効化 OS Config エージェント プロジェクト全体でメタデータを設定 VM 単位でメタデータを設定 組織レベルでメタデータを設定 ネットワーク要件 VM にサービスアカウントをアタッチ 組織で VM Manager を利用する 組織レベルまたはプロジェクトレベルで VM Manager を有効化する 組織レベルでのパッチ情報閲覧 OS ポリシーの利用 Policy orchestrator 概要 VM Manger とは VM Manager は、Google Cloud(旧称 GCP)の Compute Engine VM 群の管理・運用を自動化するためのサービスです。 参考 : VM Manager VM Manager は、CentOS、RHEL、Debian、Ubuntu などの各種 Linux ディストリビューションに加えて、Windows Server にも対応しています。対応 OS の一覧は以下のドキュメントから確認できます。 参考 : オペレーティング システムの詳細 VM Manager には、大きく分けて以下の機能が存在します。 No 機能名 用途 利用方法 1 パッチ(Patch) OS やパッケージへのパッチ適用自動化やレポーティング Google Cloud コンソールの「パッチ」、gcloud、REST API 2 OS Inventory Management OS やパッケージの情報収集 Google Cloud コンソールの VM 詳細画面、gcloud、REST API 3 OS ポリシー(OS policies) パッケージのインストール・削除・更新 Google Cloud コンソールの「OS ポリシー」、gcloud、REST API Patch はかつて OS patch management と、OS policies は OS configuration management と呼ばれていましたが2023年9月に機能名が改名されました。 なお Amazon Web Services(AWS)にも類似のサービスとして AWS Systems Manager があります。VM Manger は、AWS Systems Manager の Google Cloud 版とも言えます。 OS Config エージェント VM Manager の機能を実現するため、OS 上には OS Config エージェント と呼ばれるエージェントソフトウェアをインストールします。このエージェントが Google Cloud と通信し、様々な管理タスクを実行します。 OS Config エージェントは、特定日以降(ビルド日付が v20200114 以降)の Ubuntu、Debian、RHEL、Windows Server などの Google Cloud 公式イメージにはプリインストール済みです。 詳細なインストール手順や、ネットワーク要件等は後述します。 参考 : OS Config エージェントがインストールされているかどうかを確認する 料金 VM Manager では、VM Manager が有効化されている VM の台数 に対して発生します。 月に100台の無料枠 があり、100台を超える VM からは1台につき $0.003/時間の料金が発生します。31日ある月の場合、$0.003 × 744時間 = $2.232/台/月の料金が発生することになります。 課金が発生するのは無料枠を超えた 101台目のインスタンスから ですので、安価に大量の VM を管理できます。 参考 : VM Manager pricing パッチ(Patch) パッチ(Patch)とは パッチ (Patch)は Compute Engine VM の OS や、パッケージの管理をするための機能です。2023年9月までは OS Patch Management と呼ばれていました。 パッチには、以下の2つの主要機能があります。 パッチ コンプライアンス レポート パッチ デプロイ パッチ コンプライアンス レポート は VM OS やパッケージのパッチ状況を分析・レポーティングしてくれる機能です。 パッチ デプロイ は OS やパッケージのパッチ適用を自動化する仕組みです。いずれも VM 内で OS Config エージェントが動作し、yum や apt などのコマンドを実行して実現します。 参考 : Patch について パッチ コンプライアンス レポート パッチ コンプライアンス レポート は、VM の OS やインストール済みパッケージの情報をダッシュボード化する機能です。 VM Manager が有効化されると OS Config エージェントは 約10分ごと に各種情報を取得し、VM のメタデータの「ゲスト属性」に書き込みます。この情報は、後述の OS Inventory Management でも利用されます。 参考 : ゲスト属性 さらに VM Manager は、各 OS ごとに一般公開されている脆弱性情報と照合してレポートを作成します。脆弱性情報は RHEL、CentOS、Debian、Ubuntu で対応しており SLES、Rocky Linux、Windows Server では対応していません。 参考 : パッチ コンプライアンス データの生成方法 入手可能なアップデートがある場合、レポート上ではアップデートが「重大(赤)」「重要/セキュリティ(オレンジ)「その他(黄色)」「最新(緑)」に分類されます。 画像は 公式ドキュメント より引用 パッチ デプロイ 概要 パッチ デプロイ 機能は、 OS やミドルウェアに対して自動的なパッチ適用を行う機能です。 パッチ デプロイ機能は、Google Cloud コンソール、gcloud コマンド、REST API エンドポイント経由で、Patch API(OS Config API)を呼び出して実行します。 参考 : パッチジョブを作成する Patch API によりパッチデプロイが開始されると、Patch API は VM 内の OS Config エージェントに指示を出し、エージェントは apt、yum、Windows Update 等、OS 固有のパッケージ管理サービスを呼び出してアップデートを実行します。 そのため yum、apt といったパッケージ管理サービスがレポジトリにアクセスするために、当該 VM がインターネットにリーチできる(パブリック IP を持っているか、Cloud NAT 経由)、またはローカルレポジトリを用意する必要があります。 適用タイミング パッチ デプロイ機能によるパッチ適用は、 オンデマンド実行 (即時実行)するか、事前に スケジュール指定 することができます。また、繰り返し予定としてスケジューリングすることも可能です。 オンデマンド実行は「 同時パッチ適用 (Simultaneous patching)」、スケジュール実行は「 定期パッチ適用 (Scheduled patching)」とも呼ばれます。 参考 : 同期パッチ適用 参考 : 定期パッチ適用 対象 VM の指定 パッチ適用の対象インスタンスは次のいずれかの方法で指定します。 プロジェクトに所属する全 VM を指定 単一のインスタンスを指定 インスタンス名のプレフィクス(接頭辞)で指定 ゾーン単位で指定 ラベルで指定 また、対象となった VM 群のうち一度に停止する VM 数の割合を % で指定することができます。これにより一斉に VM が停止してしまうことを防ぐことができます。 ラベルについては、以下の記事を参照してください。 参考 : タグとラベルの違いについて (Tags / Labels) アップデート アップデートのパッケージは、特定の名称を指定したり、Windows の場合では KB 番号を指定することもできます。 例として、Debian/Ubuntu ではディストリビューションやパッケージマネージャーから配布されるアップデートが対象であり、Windows では定義更新プログラム、ドライバー更新プログラム、機能パックの更新、などが対象です。 対象となるパッケージ種別は以下のドキュメントを参照してください。 参考 : OS パッチジョブの内容 パッチ構成指定画面 前処理・後処理 アップデートを適用した VM の挙動として「再起動なし」「常に再起動」「必要なら再起動」のいずれかから指定することができます。 また、パッチ適用前、あるいは適用後(再起動があれば再起動後)に実行するスクリプトを指定することもできます。スクリプトは Cloud Storage バケットに配置します。 OS Inventory Management OS Inventory Management とは OS Inventory Management は、OS レベルの各種情報や、パッケージ情報を詳細に収集・表示するための機能です。また、パッケージに関する脆弱性情報を表示することもできます。 プロジェクトレベルまたは VM レベルで VM Manager が有効化されると、情報収集が開始されます。 参考 : OS Inventory Management OS Inventory Management では、OS Config エージェントがおよそ10分間隔で収集した以下の情報を表示可能です。 OS 情報 ホスト名 LongName (OS の詳細名称。例 : Microsoft Windows Server 2016 Datacenter) ShortName (OS の短縮名。例 : Windows) カーネルバージョン OS のアーキテクチャ OS バージョン OS Config エージェントのバージョン Last updated (OS Config エージェントが最後に情報を更新した時間) パッケージ情報 パッケージマネージャー(RPM、yum、DEB、apt、GooGet for Windows Server)取得する情報 Windows Server で取得可能な以下の情報 Windows Update Agent Windows Quick Fix Engineering アップデート Windows Installer 閲覧方法 OS Inventory Management の情報を閲覧するには、Google Cloud コンソールの VM 詳細画面で「OS 情報」タブへ遷移します。 また gcloud または REST API を利用することで、特定ゾーンにある VM の情報を一覧取得することもできます。 参考 : オペレーティング システムの詳細を表示する OS Inventory Management の情報閲覧 OS ポリシー(OS policies) OS ポリシーとは OS ポリシー (OS policies)機能は、VM のパッケージ構成のデプロイ、メンテナンス、レポート作成を行うことができる機能です。2023年9月までは OS Configuration Management という名称でした。 参考 : OS ポリシーについて OS ポリシーという定義ファイル(JSON または YAML)により VM のパッケージ構成のあるべき姿を定義して VM に適用すると、その状態とのずれが発生したときに、自動的に是正アクションが実行されます。 前述のパッチ デプロイ機能がオンデマンドあるいは定期的にアップデート指示を配信するものであるのに対して、OS ポリシー機能は あるべき姿を定義してずれをなくしていく というコンセプトです。 以下のようなユースケースが想定されています。 モニタリングエージェントやセキュリティエージェント等のインストール・保守 スタートアップスクリプトの管理 コンプライアンスチェック パッケージレポジトリの管理 ファイルの配信 スクリプト実行によるサーバ内の状態維持 構成要素 OS ポリシー OS ポリシー ファイルは、VM のパッケージ構成のあるべき姿を宣言的に定義するファイルです。OS ポリシーは JSON または YAML 形式で記述します。 参考 : OS ポリシー OS ポリシーファイルは、以下の2つのモードのいずれかとして定義します。 モード名 意味 Validation リソースが望ましい状態かチェックする。是正アクションは行わない Enforcement リソースが望ましい状態かチェックする。望ましい状態でなければ是正アクションを実行する また OS ポリシー内には以下の リソース を定義でき、実施するチェックまたはアクションを定義できます。 リソース名 意味 pkg パッケージのインストールまたは削除を行う(Linux、Windows の両方で利用可能) repository パッケージを取得するレポジトリを指定する exec /bin/sh (Linux)または Powershell(Windows)を実行する file サーバー上のファイルを管理する 以下は、YAML 形式で定義した OS ポリシーファイルのサンプルです。以下のドキュメントから引用しています。以下のサンプルでは、Cloud Storage から MSI ファイルをダウンロードして、サーバーにインストールします。 参考 : Example OS policies # An OS policy to install a Windows MSI downloaded from a Google Cloud Storage bucket. id : install-msi-policy mode : ENFORCEMENT resourceGroups : - resources : - id : install-msi pkg : desiredState : INSTALLED msi : source : gcs : bucket : my-bucket object : my-app.msi generation : 1619136883923956 OS ポリシーの割り当て OS ポリシーの割り当て (OS policy assignment)は OS ポリシーを実際に VM に適用する際に作成する設定です。 1 個の OS ポリシー割り当てで複数の OS ポリシーを指定できます。また適用対象の VM は以下の軸で選択することができます。 ゾーン OS ファミリー ラベル(含める) ラベル(除外) 例えば以下のような指定をすると「 asia-northeast-1-b ゾーンにある」「 ubuntu の VM で」「 env:test というラベルを持ち」「かつ goog-gke-node というラベルを持たない」に当てはまるすべての VM に、OS ポリシーを適用できます。 ゾーン : asia-northeast-1-b OS ファミリー : ubuntu ラベル(含める): env:test ラベル(除外): goog-gke-node 参考 : OS policy assignment ロールアウト OS ポリシーの割り当てを作成する際に以下の ロールアウトオプション を設定することができます。 ウェーブサイズ 待機時間 ウェーブサイズは一度にポリシーを適用する VM の割合です。対象となる VM のうち、何割が同時にアップデート等の対象になるかを指定できます。デフォルトは10%です。 待機時間は、ポリシー適用開始から実際にロールアウトが始まるまでの猶予時間です。ウェーブサイズごとにポリシー適用が始まり、最初のウェーブで問題が発生した際などに、次のウェーブが始まるまでにロールアウトを中止することが可能になります。 エージェントと情報収集 OS ポリシーの取得と実行は、VM 上の OS Config エージェントが行っています。OS ポリシーの割り当てが作成されると、VM では 60分のチェック間隔 でポリシー確認と適用が実行されます。 ポリシーが VM に配信されると、OS Config エージェントは VM の内部状況を確認し、ポリシー通りの状態になっていれば何もせず、ポリシーとの差異があれば是正アクションを実行します。 有効化 概要 以下のすべての条件を満たしていると、VM Manager のすべての機能が利用できるようになります。 Google Cloud プロジェクトで OS Config Service API が有効化されている 対象 VM に OS Config エージェントがインストールされている プロジェクト単位または VM 単位で、必要な Compute Engine メタデータが設定されている VM がネットワーク要件を満たしている VM にサービスアカウントがアタッチされている 詳細な手順は、以下の公式ドキュメントに記載されています。当記事では概要を解説します。 参考 : VM Manager を設定する サービス API の有効化 Compute Engine API に加えて、以下サービスの API を有効化する必要があります。有効化は、Google Cloud コンソールの API とサービス の画面から行ったり、gcloud コマンドラインで行うことができます。 OS Config Service API ( osconfig.googleapis.com ) OS Config エージェント VM を VM Manager 機能の対象とするには、VM に OS Config エージェントをインストールします。 Google Cloud 公式のイメージで VM を作成した場合、ビルド日付が v20200114 以降の CentOS、Container-Optimized OS、Debian、Red Hat Enterprise Linux (RHEL)、Rocky Linux、SLES、Ubuntu、Windows Server には既にエージェントがインストール済みです。 もしこれ以外のイメージの場合、以下のドキュメントを参考にしてエージェントをインストールします。 参考 : OS Config エージェントをインストールする VM Manager の各機能がサポートする OS 一覧は、以下の公式ドキュメントに記載されています。 参考 : オペレーティング システムの詳細 プロジェクト全体でメタデータを設定 プロジェクトに所属する全ての VM を管理対象にする場合は、以下の手順を実施します。実施すると、既存の VM に加え今後作成される全ての VM が自動的に対象になります。 該当プロジェクトの Compute Engine コンソールにて「メタデータ」ページに移動します。ここで以下のメタデータを追加します。 enable-osconfig : TRUE メタデータ とは、Compute Engine に設定できる Key-Value のテキスト情報です。プロジェクト単位または VM 単位で、各種メタデータを登録できます。 なお、以前のバージョンの OS Inventory Management 機能では enable-guest-attributes : TRUE というメタデータも追加する必要がありましたが、現在のバージョンでは不要です。 参考 : メタデータ値を設定する VM 単位でメタデータを設定 プロジェクト全体ではなく、個別の VM 単位で有効化したい場合は対象 VM のレベルでメタデータを設定します。メタデータは、VM の新規作成時に追加することもできますし、既存 VM に追加することもできます。 プロジェクト全体レベルでメタデータを追加済みの場合は、当手順を行う必要はありません。 コンソールでは、VM 編集画面からカスタムメタデータを設定できます。追加するメタデータはプロジェクト全体のときと同様で、 enable-osconfig : TRUE です。 組織レベルでメタデータを設定 後述する 組織のポリシー 機能を使うと、組織やフォルダ配下で今後作成されるすべてのプロジェクトにメタデータを自動で追加することができます。 当記事の 組織で VM Manager を利用する の章をご参照ください。 ネットワーク要件 OS Config エージェントが Google Cloud の API と通信できるよう、VM が通信要件を満たしている必要があります。 VM が外部 IP を持っていたり、Cloud NAT 経由でインターネットに出られるようになっていれば問題有りません。そうではない場合、以下のいずれかの方法で VM 内の OS Config エージェントが OS Config API と通信できるようにします。 HTTP プロキシを利用 サブネットで 限定公開の Google アクセス を有効化 VM で HTTP プロキシを利用する方法については、以下のドキュメントを参照してください。 参考 : HTTP プロキシを構成する 限定公開の Google アクセス機能については、以下の記事を参照してください。 参考 : 限定公開の Google アクセスの仕組みと手順をきっちり解説 VM にサービスアカウントをアタッチ 対象 VM に サービスアカウント がアタッチされている必要があります。 ただしこのサービスアカウントには IAM ロールの紐づけは不要です。サービスアカウントは OS Config API との通信に署名をするためだけに用いられるため、IAM ロールが全く付与されていない空のサービスアカウントでも問題ありません。 組織で VM Manager を利用する 組織レベルまたはプロジェクトレベルで VM Manager を有効化する 組織のポリシー 機能を使うことで、組織やフォルダ全体で VM Manager を有効化できます。組織のポリシー機能については、以下の記事も参照してください。 blog.g-gen.co.jp 組織レベルまたはフォルダレベルで Require OS Config ( constraints/compute.requireOsConfig )制約を TRUE に設定すると、新規に作成されるプロジェクトに、自動的に enable-osconfig : TRUE メタデータが追加されます。 また、 enable-osconfig を FALSE に変えるような設定は拒否されます。 ただし、この組織のポリシーの制約を有効化する前から存在した 既存の Google Cloud プロジェクトのメタデータは変更されません 。既存プロジェクトで VM Manager を有効化したい場合は、 個別にメタデータを追加する必要 があります。プロジェクトの数が多い場合、gcloud コマンドラインや各プログラミング言語用のクライアントライブラリを用いて、プログラマブルにプロジェクトにメタデータを追加することを検討してください。 加えて、この組織のポリシーの制約で有効化できるのはメタデータのみです。前述した OS Config エージェントの要件やネットワーク要件は 個別の VM ごとに満たしている必要 があります。 参考 : 組織のポリシーを使用して VM Manager を有効にする 組織レベルでのパッチ情報閲覧 パッチのサマリ情報を、 組織レベル または フォルダレベル で閲覧することができます。 組織、フォルダ、プロジェクトに対して適切な権限を持っていれば、特別な設定をすることなく、プロジェクトをまたいだ情報確認ができます。Google Cloud コンソール画面の「パッチ」から「プロジェクト」タブを選択したうえで、画面上部のプロジェクトセレクタで、組織またはフォルダを選択します。 この画面では、各プロジェクトの VM の合計、VM Manager のモニタリング対象となっている VM の数、「重大」「重要」など各レベルで検知されているパッケージアップデートの数などのサマリが確認できます。 組織レベルでのパッチサマリ なお「VM の合計」はプロジェクトで VM Manager が有効でなくても確認できますが、App Engine のカスタムランタイムで起動された VM 等もカウントされる場合があります。 組織またはフォルダ配下のすべてのプロジェクトで VM Manager が有効になっていない場合は、有効になっているプロジェクトの情報のみが表示されます。 また、同画面の Query Builder を使うと、OS や OS のバージョン、CVE で脆弱性が報告されている VM などをフィルタして表示することができます。 Query Builder さらに、Google Cloud コンソール画面の「パッチ」>「ダッシュボード」タブでは、組織やフォルダの配下にある全 VM の OS の総数や、パッチ適用状況を確認できます。ただし、VM Manager が有効になっていないプロジェクトや VM の情報は表示されません。 「パッチ」>「ダッシュボード」タブ 参考 : View patch summary for VMs in an organization or folder OS ポリシーの利用 OS ポリシーの遵守状況を、 組織レベル または フォルダレベル で閲覧することができます。 パッチ機能と同様に、組織、フォルダ、閲覧対象のプロジェクトに対して適切な権限を持っていれば、プロジェクトをまたいだ情報確認ができます。Google Cloud コンソール画面の「OS ポリシー」から「プロジェクト」タブを選択したうえで、画面上部のプロジェクトセレクタで、組織またはフォルダを選択します。 参考 : View OS policy compliance summary for all VMs in an organization or folder Policy orchestrator Policy orchestrator を使うと、複数のゾーンやプロジェクトをまたいで OS ポリシーを適用することができます。通常、OS ポリシーの割り当てはゾーンレベルですが、フォルダレベルで Policy orchestrator を作成することで、複数のゾーンやプロジェクトに対して OS ポリシーを適用できます。 適用範囲を調整することで、一部のプロジェクトでテスト適用を行い、うまくいったら範囲を広げるといった、順次ロールアウトも可能です。詳細は以下の公式ドキュメントを参照してください。 なお当機能は2024年11月現在、Preview 状態です。 参考 : About policy orchestrator 杉村 勇馬 (記事一覧) 執行役員 CTO / クラウドソリューション部 部長 元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の藤岡です。当記事では、Google Cloud(旧称 GCP)の BigQuery に特定の IP アドレスからのアクセスのみを許可する VPC Service Controls を設定しつつ、Looker Studio には IP アドレスの制限をかけずレポートを閲覧できるようにする方法を紹介します。 サービス・機能の概要 VPC Service Controls Looker Studio サービスアカウントの権限借用 VPC Service Controls と Looker Studio 実施内容 構成図 事前準備 Cloud Storage の設定 BigQuery の設定 Looker Studio でレポートの作成 パターン1 VPC Service Controls の設定 確認 パターン2 サービスアカウントの作成 VPC Service Controls の設定 Looker Studio サービス エージェントにサービス アカウントへのアクセスを許可 ユーザーロールの付与 BigQuery へのアクセスを許可 Looker Studio のデータの認証情報を更新 確認 パターン3 Looker Studio でレポートの共有 確認 監査ログ Looker Studio のログイベント 注意点 サービス・機能の概要 当記事で使用するサービスや機能の概要は以下の通りです。 VPC Service Controls VPC Service Controls は Google Cloud のセキュリティ機能です。 境界 (Perimeter) と呼ばれる論理的な囲いを作り、その囲いの中のリソースへのアクセスを IP アドレスやサービスアカウント等に制限することができます。 詳細ついては以下の記事をご参照ください。 blog.g-gen.co.jp Looker Studio Looker Studio (旧称 データポータル)は Google Cloud が提供する BI ツールです。 Google スプレッドシートや BigQuery 等のデータソースからレポートを作成し、データの可視化をすることができます。 以下の記事で Looker Studio について触れていますので、ご参照ください。 blog.g-gen.co.jp blog.g-gen.co.jp Looker Studio のデータの認証情報には以下の3種類があります。 オーナーの認証情報 閲覧者の認証情報 サービス アカウントの認証情報 後述しますが、当記事では「サービス アカウントの認証情報」を使用します。 なお、現在 サービス アカウントの認証情報はデータソースが BigQuery の場合にのみ使用できます 。 また、サービスアカウントの認証情報を利用するにあたり必要な Looker Studio サービス エージェントを取得するには、Workspace または Cloud Identity のユーザーである必要があります 。 参考: データの認証情報 Looker Studio サービス エージェントをサービスアカウントのプリンシパルに追加することで、サービスアカウントを使用して Looker Studio のレポートを閲覧および編集等ができるようになります。 参考: Looker Studio 用に Google Cloud サービス アカウントを設定する Looker Studio サービス エージェントについては以下の記事でも触れていますので、ご参照ください。 blog.g-gen.co.jp サービスアカウントの権限借用 Identity and Access Management (以下 IAM)には サービスアカウントの権限借用 という機能があります。本機能を使用することで、特定のサービスアカウントへの権限借用を許可されているプリンシパル(ユーザー等)は、そのサービスアカウントの権限を使用してリソースへアクセスすることができます。 参考: サービス アカウントの権限借用の管理 IAM の基本的な概念については以下の記事をご参照ください。 blog.g-gen.co.jp VPC Service Controls と Looker Studio それぞれのサービスや機能を確認したところで、当記事で紹介する内容について触れていきます。 Looker Studio のデータソースに BigQuery を使用した場合、 BigQuery が VPC Service Controls の境界内にあると Looker Studio にも同様の制限がかかります 。 具体的には、BigQuery に特定の IP アドレスからのアクセスのみを許可する VPC Service Controls を設定した場合、Looker Studio にも同様の IP アドレスの制限がかかります。 理由は、Looker Studio のレポートの編集や保存、閲覧時に BigQuery に対するクエリが実行されるからです。 許可されていない IP アドレスから Looker Studio のレポートを閲覧すると以下のように Service Control のエラー と表示されます。 Looker Studio の VPC Service Controls のエラー画面 参考: Google BigQuery に接続する 実施内容 当記事では、以下の内容を実現するための方法を紹介します。 VPC Service Controls を設定することで、 BigQuery へのアクセスは特定の IP アドレスからのみに制限 Looker Studio のサービスアカウントの認証情報を設定することで、ユーザーは IP アドレスの制限なく Looker Studio のレポートの操作および閲覧が可能 構成図 以下の3パターンを順に設定および確認していきます。 なお今回は VPC Service Controls と Looker Studio に焦点を当てて紹介するため、他の部分の設定についての詳細は割愛します。 構成図(パターン1) 構成図(パターン2) 構成図(パターン3) 事前準備 Cloud Storage の設定 Cloud Storage(以下 GCS)でバケットの作成およびオブジェクトをアップロードします。 今回はオブジェクトに「sample-data.csv」としてランダムに生成された販売実績データの csv ファイルを使用しています。 GCS の画面 BigQuery の設定 BigQuery でデータセット「fujioka_dataset_01」を作成し、GCS の「sample-data.csv」をソースとするテーブル「table-01」を作成します。 BigQuery の画面 テーブルの中身は以下のようになっています。 テーブルの画面 Looker Studio でレポートの作成 Looker Studio にログインし、レポートを作成します。 Looker Studio レポート作成画面 データのレポートへの追加 で [BigQuery] を選択します。 データに接続 対象のプロジェクト、データセット、テーブルを選択します。 レポートへ BigQuery のテーブルを追加 円グラフを作成しました。 レポート画面 ここまでで、以下の構成が出来上がりました。 ここまでの構成 パターン1 VPC Service Controls の設定 Access Context Manager でアクセスレベルの作成をします。 今回はアクセスポリシーに default policy を使用するため、VPC Service Controls および Access Context Manager は組織レベルで設定をします。 コンソールで [セキュリティ] > [Access Context Manager] > [+ アクセスレベルを作成] を選択します。 Access Context Manager の画面 新しいアクセスレベル を以下のように設定します。 なお、この IP サブネットワークに プライベート IP 範囲を含めることはできません。 参考: アクセスレベルの属性 項目 設定値 備考 アクセスレベルのタイトル fujioka-home 任意の名前 IP サブネットワーク xxx.xxx.xxx.6/32 アクセスを許可する IPv4 または IPv6 を設定 アクセスレベル 次に [セキュリティ] > [VPC Service Controls] > [+ 新しい境界] を選択します。 VPC Service Controls の画面 新しい VPC サービス境界 を以下のように設定します。 ① Details 項目 設定値 備考 境界のタイトル fujioka-vpcsc 任意の名前 境界のタイプ 標準境界(デフォルト) ① Details ② Projects 項目 設定値 備考 保護するプロジェクト fujioka 対象のプロジェクト ② Projects ③ Restricted Services 項目 設定値 備考 保護するサービス BigQuery API Google Cloud Storage API BigQuery と GCS を境界内に入れる ③ Restricted Services ④ VPC accessible services [すべてのサービス] を選択します。 ④ VPC accessible services ⑤ Access Levels 設定しないで進みます。 ⑤ Access Levels ⑥ 内向きポリシー 今回は、GCP サービス / リソースの TO 属性 のメソッドを All methods にしていますが、 Selected method にすることでより細かに操作を絞ることができます。 ⑥ 内向きポリシー ⑦ 下り(外向き)ポリシー 設定しないで進みます。 ⑦ 下り(外向き)ポリシー 確認 ここまでで、以下の構成が出来上がりました。 構成図(パターン1) アクセスレベルで 許可されていない IP アドレスからレポートを見ると Service Control のエラー と表示されます。 エラー画面が表示されない場合は、ブラウザの更新やディメンションの変更等をお試しください。 Looker Studio の VPC Service Controls のエラー画面 パターン2 次に、BigQuery と GCS への IP アドレス制限はかけながら、 Looker Studio への IP アドレス制限をかけない ようにします。 サービスアカウントの作成 コンソールで [IAM と管理] > [サービスアカウント] > [+ サービスアカウントを作成] を選択します。 サービスアカウントを作成 任意の サービスアカウント名 および サービスアカウント ID を設定します。 今回は、 looker-studio-sa@<プロジェクト ID>.iam.gserviceaccount.com というサービスアカウントを作成します。 サービスアカウントの作成① ロールは BigQuery ジョブユーザー を設定します。 サービスアカウントの作成② VPC Service Controls の設定 次に、パターン1で作成した fujioka-vpcsc の VPC Service Controls に新しく作成したサービスアカウントからのアクセスを許可する設定を入れます。 VPC Service Controls の画面 [境界を編集] を選択します。 境界を編集 ⑥ 内向きポリシー で [ADD RULE] をし、以下の設定を追加します。 API クライアントの FROM 属性 の ユーザーアカウント / サービスアカウント に作成したサービスアカウント looker-studio-sa@<プロジェクト ID>.iam.gserviceaccount.com を選択します。 ⑥ 内向きポリシー の画面 Looker Studio サービス エージェントにサービス アカウントへのアクセスを許可 Looker Studio サービス エージェントのヘルプページ で表示される Service Agent service-org-<組織 ID>@gcp-sa-datastudio.iam.gserviceaccount.com をコピーします。 Google アカウントでログインしていない場合はログインをしてから、再度ページを開いてください。 Looker Studio Service Agent の画面 コンソールから、作成したサービスアカウント looker-studio-sa@<プロジェクト ID>.iam.gserviceaccount.com に Looker Studio サービス エージェントのアクセスを許可する設定をします。 サービスアカウントの権限画面 Looker Studio サービス エージェントに iam.serviceAccount.getAccessToken 権限を付与するロールを選択します。今回は サービス アカウント トークン作成者 ロールを選択していますが、この権限を付与する任意のカスタムロールも使用できます。 項目 設定値 備考 新しいプリンシパル service-org-<組織 ID>@gcp-sa-datastudio.iam.gserviceaccount.com Looker Studio サービス エージェント ロール サービス アカウント トークン作成者 アクセスの許可画面 ユーザーロールの付与 次に、作成したサービスアカウント looker-studio-sa@<プロジェクト ID>.iam.gserviceaccount.com の権限借用をするユーザーを設定します。 サービスアカウントの権限画面 データソース(BigQuery)を作成または編集する Looker Studio ユーザーに、 iam.serviceAccounts.actAs 権限を含むロールを付与 します。今回は サービス アカウント ユーザー のロールを付与します。 なお、後述のパターン3のような Looker Studio のレポートの表示のみ行うユーザーには、サービス アカウントの権限は不要 です。 項目 設定値 備考 新しいプリンシパル fujioka@xxxx Google アカウント ロール サービス アカウント ユーザー アクセスの許可画面 BigQuery へのアクセスを許可 Looker Studio からサービスアカウントで BigQuery データへのアクセスを許可するには、テーブルまたはデータセットレベルでサービス アカウントに BigQuery データ閲覧者 のロールを付与します。 今回はテーブルレベルでロールを付与するため、今回の Looker Studio のレポートのソースであるテーブル table-01 に対して行います。 [BigQuery] > [fujioka_dataset_01] > [table-01] > [共有] を選択します。 テーブルへアクセス権付与 [プリンシパルを追加] を選択します。 プリンシパルを追加 項目 設定値 備考 新しいプリンシパル looker-studio-sa@<プロジェクト ID>.iam.gserviceaccount.com 作成したサービスアカウント ロール BigQuery データ閲覧者 アクセスの許可画面 Looker Studio のデータの認証情報を更新 Looker Studio のレポート画面から [リソース] > [追加済みのデータソースの管理] を選択します。 Looker Studio のレポート画面 [編集] を選択します。 データソース データの認証情報が現在は作成者になっているため、サービスアカウントに変更します。ユーザーアイコンを選択します。 データの認証情報 [サービスアカウント認証情報] にチェックを入れ、作成したサービスアカウント looker-studio-sa@<プロジェクト ID>.iam.gserviceaccount.com を入力します。 ここで [サービスアカウント認証情報] が選択肢にない場合は、Looker Studio のレポートを開き直してください。 データの認証情報を更新 データの認証情報が以下のようにサービスアカウントに変更されました。 データの認証情報 確認 ここまでで、以下の構成が出来上がりました。 構成図(パターン2) パターン1では、アクセスレベルで 許可されていない IP アドレスからレポートを見ると Service Control のエラー と表示されていましたが、問題なく閲覧ができるようになりました。 Looker Studio のレポート画面 但し、構成図の通りアクセスレベルで 許可されていない IP アドレスから境界内の BigQuery や GCS は閲覧ができません。 BigQuery の閲覧不可(データセット表示されない) GCS の閲覧不可 パターン3 最後のパターンは、Looker Studio のレポートを他のユーザーに共有した場合についてです。 Looker Studio でレポートの共有 レポートの画面から [共有] > [他のユーザーを招待] を選択します。 レポートの共有 今回は fujioka-dev ユーザーを 閲覧者 として共有しました。 ユーザーを追加 確認 共有されたユーザーで、アクセスレベルで 許可されていない IP アドレスからもレポートが閲覧できます。 Looker Studio のレポート画面 ここまでで、以下の構成が出来上がりました。 構成図(パターン3) 監査ログ 以下は、共有されたユーザーが xxx.xxx.xxx.57 の IP アドレスからレポートのコントロールプルダウン変更をした時の 監査ログ (Cloud Audit Logs)です。 protoPayload.requestMetadata.callerIp= は共有されたユーザーの IP アドレス xxx.xxx.xxx.57 です。 但し、 protoPayload.authenticationInfo.principalEmail="looker-studio-sa@<プロジェクトID>.iam.gserviceaccount.com" となっており、実行はサービスアカウントがしていることが確認できます。 { "protoPayload": { "@type": "type.googleapis.com/google.cloud.audit.AuditLog", "status": {}, "authenticationInfo": { "principalEmail": "looker-studio-sa@<プロジェクトID>.iam.gserviceaccount.com" }, "requestMetadata": { "callerIp": "xxx.xxx.xxx.57" }, "serviceName": "bigquerybiengine.googleapis.com", "methodName": "ExecutionService.Query", "authorizationInfo": [ { "resource": "projects/<プロジェクトID>/datasets/fujioka_dataset_01/tables/table-01", "permission": "bigquery.tables.getData", "granted": true } ], "resourceName": "projects/<プロジェクトID>/datasets/fujioka_dataset_01/tables/table-01", "request": { "@type": "type.googleapis.com/google.cloud.bi.v1.QueryRequest" } }, "insertId": "fjx8nse21hx8", "resource": { "type": "audited_resource", "labels": { "project_id": "<プロジェクトID>", "method": "ExecutionService.Query", "service": "bigquerybiengine.googleapis.com" } }, 〜省略〜 } 参考: AuditLog Looker Studio のログイベント 監査ログでは閲覧元 IP アドレスはわかりますが、 閲覧ユーザーは表示されません 。 閲覧ユーザーを確認したい場合は、Google Workspace 管理コンソール admin.google.com の Looker Studio のログイベント から確認できます。 管理コンソールの Looker Studio のログイベント画面 参考: Looker Studio のログイベント 以下の記事で Workspace レポートと監査ログについて触れていますので、ご参照ください。 blog.g-gen.co.jp 注意点 VPC Service Controls は Cloud Shell をサポートしていません 。Cloud Shell は境界外として扱われます。そのため、今回の構成で IP アドレスが許可されているアクセス元の Cloud Shell から以下のようなコマンドを実行したとしてもエラーになります。 fujioka@cloudshell:~ (fujiokaxxxx)$ bq ls BigQuery error in ls operation: VPC Service Controls: Request is prohibited by organization's policy. vpcServiceControlsUniqueIdentifier: xxxxxx fujioka@cloudshell:~ (fujiokaxxxx)$ fujioka@cloudshell:~ (fujiokaxxxx)$ gcloud storage ls ERROR: (gcloud.storage.ls) HTTPError 403: Request is prohibited by organization's policy. vpcServiceControlsUniqueIdentifier: xxxxxx fujioka@cloudshell:~ (fujiokaxxxx)$ エラー文 参考: Cloud Shell 藤岡 里美 (記事一覧) クラウドソリューション部 数年前までチキン売ったりドレスショップで働いてました!2022年9月 G-gen にジョイン。今期は「おっさんずラブ」がイチオシです :) Google Cloud All Certifications Engineer / Google Cloud Partner Top Engineer 2024 Follow @fujioka57621469
アバター