株式会社G-genのブログ - TECH PLAY

TECH PLAY

株式会社G-gen

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

全888件

当記事では、 Google Cloud(旧称 GCP)の Filestore を Compute Engine(以下 GCE)の Windows Server にマウントする方法を紹介します。 サービスの概要 Filestore とは ネットワーク サービスティア クライアントへの接続 実施内容 構成図 前提条件 構築 事前作業 プロジェクトの作成と請求先アカウントの紐づけ デフォルトプロジェクトのセット API の有効化 ネットワーク構築 VPC とサブネットの作成 ファイアウォールルールの作成 HA Cloud VPN ゲートウェイの作成 Cloud Router の作成 VPN トンネルの作成 BGPセッションの構成 GCE 構築 GCE(Windows Server)の作成 GCE に RDP 疎通テスト Filestore 構築 Filestore の作成 マウント(nfs-client-a) NFS クライアントの設定 マウント ルートのアドバタイズ マウント(nfs-client-b) テスト 事後作業 プロジェクトの削除 注意点 サービスの概要 Filestore とは Filestore は、 GCE や GKE クラスタ、オンプレミスマシンに接続できるフルマネージドのファイルサーバーです。 プロトコルは NFSv3 で NFSv3 互換のクライアントがサポートされています。 Cloud VPN または Cloud Interconnect を使用して、異なる VPC のGCE やオンプレミスマシン等のリモートネットワーク上のクライアントに接続することもできます。 Linux や Windows にマウントしてファイルサーバーとして利用出来るため、オンプレミスマシンの急な容量不足にも対応可能です。 ネットワーク Filestore では、ネットワークに 標準 VPC または 共有 VPC を選択できます。クライアントが Filestore にアクセスするには Filestore と同じネットワーク上にある必要があり、作成後にネットワークを変更することはできません。 Filestore のインスタンスはサービスプロデューサーのネットワークと呼ばれる Google が管理する専用ネットワークに配置されます。 Cloud SQL や Cloud Build 等と同様の扱い になります。 Filestore インスタンスに使われる IP アドレスは内部 IP アドレス( 10.0.0.0/8 , 172.16.0.0/12 , 192.168.0.0/16 )の範囲である必要があり、後述するサービスティアによって /29 や /26 のように必要となるレンジが異なります。 なお、推移的ピアリングをサポートしていません。そのため、当記事で紹介する構成で、 vpc-a と vpc-b を Cloud VPN ではなく、 VPC ネットワークピアリング で接続していた場合、 vpc-b 内のインスタンスは Filestore へアクセスできません。 参考: ネットワーキング / 予約済み IP アドレスの範囲を構成する サービスティア サービスティアとは、 Filestore インスタンスのインスタンスタイプとストレージタイプを組み合わせたものです。以下の4種類があり、インスタンスの作成後にサービスティアを変更することはできません。 基本 HDD 基本 SSD 高スケール SSD エンタープライズ パフォーマンスはもちろん、プロビジョニング可能な容量もサービスティアによって異なりますので、ユースケースに合わせて選択してください。 参考: サービスティア クライアントへの接続 前述の通り、 GCE や GKE クラスタ、オンプレミスマシンにマウントすることが出来ますが、最適なパフォーマンスを得るには、マシンタイプファミリーが n1-standard-8 以上のスペックのクライアントにマウントすることが推奨されています。 参考: Compute Engine クライアントでのファイル共有のマウント 実施内容 構成図 今回の作成する構成は以下の通りです。 構成図 前提条件 当記事では、 gcloud CLI を使用してリソースを作成するため、 CUI 操作に慣れていない方は以下の記事で Cloud VPN をコンソールから作成する方法について紹介していますのでご参照ください。 blog.g-gen.co.jp 各コマンドは Cloud Shell から実行 します。参考までに、実行時の環境は以下の通りです。 fujioka@cloudshell:~ (fujioka-xxxx)$ gcloud -v Google Cloud SDK 416.0.0 alpha 2023.01.30 app-engine-go 1.9.72 app-engine-java 2.0.10 app-engine-python 1.9.101 app-engine-python-extras 1.9.97 beta 2023.01.30 bigtable bq 2.0.84 bundled-python3-unix 3.9.16 cbt 0.13.0 cloud-datastore-emulator 2.3.0 cloud-run-proxy 0.3.0 core 2023.01.30 gcloud-crc32c 1.0.0 gke-gcloud-auth-plugin 0.4.0 gsutil 5.19 kpt 1.0.0-beta.24 local-extract 1.5.7 minikube 1.29.0 pubsub-emulator 0.7.4 skaffold 2.1.0 fujioka@cloudshell:~ (fujioka-xxxx)$ 構築 事前作業 プロジェクトの作成と請求先アカウントの紐づけ プロジェクトを作成し、作成したプロジェクトに請求先アカウントを紐づけます。 $ gcloud projects create ${PROJECT_ID} --name=${PROJECT_NAME} --organization=${ORGANIZATION_ID} && \ gcloud beta billing projects link ${PROJECT_ID} --billing-account=${BILLING_ACCOUNT_ID} 参考: gcloud projects create / gcloud beta billing projects link デフォルトプロジェクトのセット 作成したプロジェクトをデフォルトプロジェクトとしてセットし、結果を確認します。 $ gcloud config set project ${PROJECT_ID} && \ gcloud config list project 参考: gcloud config set / gcloud config list API の有効化 これ以降は、実行したコマンドを出力結果とともに記載します。コマンドのリファレンスを参考に載せているので、試す際にはリソース名やオプション等は環境に合わせて適宜置き換えてください。 今回有効化する API は以下の2つです。 Compute Engine API Cloud Filestore API 環境によりますが、 API の有効化には数分程度かかる場合があります。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud services enable compute.googleapis.com && \ gcloud services enable file.googleapis.com Operation "operations/acf.p2-381487557941-71a52ef2-f5c9-49de-9a68-fbd6f88beafa" finished successfully. Operation "operations/acf.p2-381487557941-81c07e57-3e55-4386-ac3a-33767bbef368" finished successfully. fujioka@cloudshell:~ (fujioka-230212)$ 参考: gcloud services enable ネットワーク構築 VPC とサブネットの作成 2つの VPC とサブネットを作成します。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud compute networks create vpc-a --subnet-mode custom && \ gcloud compute networks subnets create subnet-a --network vpc-a --region asia-northeast1 --range 10.0.0.0/24 && \ gcloud compute networks create vpc-b --subnet-mode custom && \ gcloud compute networks subnets create subnet-b --network vpc-b --region asia-northeast1 --range 172.16.0.0/24 ~省略~ Created [https://www.googleapis.com/compute/v1/projects/fujioka-230212/regions/asia-northeast1/subnetworks/subnet-b]. NAME: subnet-b REGION: asia-northeast1 NETWORK: vpc-b RANGE: 172.16.0.0/24 STACK_TYPE: IPV4_ONLY IPV6_ACCESS_TYPE: INTERNAL_IPV6_PREFIX: EXTERNAL_IPV6_PREFIX: fujioka@cloudshell:~ (fujioka-230212)$ 作成済みの VPC とサブネットを確認します。今回はデフォルトで作成される default 以外を出力させます。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud compute networks list --filter="name!='default'" && \ gcloud compute networks subnets list --filter="name!='default'" NAME: vpc-a SUBNET_MODE: CUSTOM BGP_ROUTING_MODE: REGIONAL IPV4_RANGE: GATEWAY_IPV4: NAME: vpc-b SUBNET_MODE: CUSTOM BGP_ROUTING_MODE: REGIONAL IPV4_RANGE: GATEWAY_IPV4: NAME: subnet-a REGION: asia-northeast1 NETWORK: vpc-a RANGE: 10.0.0.0/24 STACK_TYPE: IPV4_ONLY IPV6_ACCESS_TYPE: INTERNAL_IPV6_PREFIX: EXTERNAL_IPV6_PREFIX: NAME: subnet-b REGION: asia-northeast1 NETWORK: vpc-b RANGE: 172.16.0.0/24 STACK_TYPE: IPV4_ONLY IPV6_ACCESS_TYPE: INTERNAL_IPV6_PREFIX: EXTERNAL_IPV6_PREFIX: fujioka@cloudshell:~ (fujioka-230212)$ 参考: gcloud compute networks create / gcloud compute networks list ファイアウォールルールの作成 各 VPC に2つのファイアウォールルールを作成します。 icmp は GCE 同士の疎通確認用です。 tcp:3389 は RDP 用のため、 --source-ranges ${YOUR_GROBAL_IP_ADDRESS} は自身のグローバル IP アドレスに置き換えてください。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud compute firewall-rules create allow-rdp-from-home-a \ --network vpc-a \ --direction ingress \ --action allow \ --source-ranges ${YOUR_GROBAL_IP_ADDRESS} \ --rules=tcp:3389 && \ gcloud compute firewall-rules create allow-icmp-from-subnet-b-a \ --network vpc-a \ --direction ingress \ --action allow \ --source-ranges 172.16.0.0/24 \ --rules=icmp && \ gcloud compute firewall-rules create allow-rdp-from-home-b \ --network vpc-b \ --direction ingress \ --action allow \ --source-ranges ${YOUR_GROBAL_IP_ADDRESS} \ --rules=tcp:3389 && \ gcloud compute firewall-rules create allow-icmp-from-subnet-a-b \ --network vpc-b \ --direction ingress \ --action allow \ --source-ranges 10.0.0.0/24 \ --rules=icmp ~省略~ Creating firewall...working..Created [https://www.googleapis.com/compute/v1/projects/fujioka-230212/global/firewalls/allow-icmp-from-subnet-a-b]. Creating firewall...done. NAME: allow-icmp-from-subnet-a-b NETWORK: vpc-b DIRECTION: INGRESS PRIORITY: 1000 ALLOW: icmp DENY: DISABLED: False fujioka@cloudshell:~ (fujioka-230212)$ 作成済みのファイアウォールルールを確認します。デフォルトで作成されるルール以外を出力させます。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud compute firewall-rules list --filter="name!='default'" NAME: allow-icmp-from-subnet-a-b NETWORK: vpc-b DIRECTION: INGRESS PRIORITY: 1000 ALLOW: icmp DENY: DISABLED: False NAME: allow-icmp-from-subnet-b-a NETWORK: vpc-a DIRECTION: INGRESS PRIORITY: 1000 ALLOW: icmp DENY: DISABLED: False NAME: allow-rdp-from-home-a NETWORK: vpc-a DIRECTION: INGRESS PRIORITY: 1000 ALLOW: tcp:3389 DENY: DISABLED: False NAME: allow-rdp-from-home-b NETWORK: vpc-b DIRECTION: INGRESS PRIORITY: 1000 ALLOW: tcp:3389 DENY: DISABLED: False To show all fields of the firewall, please show in JSON format: --format=json To show all fields in table format, please see the examples in --help. fujioka@cloudshell:~ (fujioka-230212)$ 参考: gcloud compute firewall-rules create / gcloud compute firewall-rules list HA Cloud VPN ゲートウェイの作成 今回は 高可用性(HA)Cloud VPN を使用します。はじめに、vpc-a と vpc-b に HA Cloud VPN ゲートウェイを作成します。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud compute vpn-gateways create vpn-gateway-a \ --region=asia-northeast1 --network=vpc-a && \ gcloud compute vpn-gateways create vpn-gateway-b \ --region=asia-northeast1 --network=vpc-b ~省略~ Creating VPN Gateway...done. NAME: vpn-gateway-b INTERFACE0: 34.157.79.62 INTERFACE1: 34.157.206.255 NETWORK: vpc-b REGION: asia-northeast1 fujioka@cloudshell:~ (fujioka-230212)$ 作成されていることを確認します。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud compute vpn-gateways list NAME: vpn-gateway-a INTERFACE0: 34.157.66.147 INTERFACE1: 34.157.195.105 NETWORK: vpc-a REGION: asia-northeast1 NAME: vpn-gateway-b INTERFACE0: 34.157.79.62 INTERFACE1: 34.157.206.255 NETWORK: vpc-b REGION: asia-northeast1 fujioka@cloudshell:~ (fujioka-230212)$ 参考: gcloud compute vpn-gateways create / gcloud compute vpn-gateways list Cloud Router の作成 次に、vpc-a と vpc-b に Cloud Router を作成します。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud compute routers create cloud-router-a \ --region=asia-northeast1 --network=vpc-a \ --asn=65001 && \ gcloud compute routers create cloud-router-b \ --region=asia-northeast1 --network=vpc-b \ --asn=65002 ~省略~ Creating router [cloud-router-b]...done. NAME: cloud-router-b REGION: asia-northeast1 NETWORK: vpc-b fujioka@cloudshell:~ (fujioka-230212)$ 作成されていることを確認します。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud compute routers list NAME: cloud-router-a REGION: asia-northeast1 NETWORK: vpc-a NAME: cloud-router-b REGION: asia-northeast1 NETWORK: vpc-b fujioka@cloudshell:~ (fujioka-230212)$ 参考: gcloud compute routers create / gcloud compute routers list VPN トンネルの作成 HA Cloud VPN のため、トンネルは計4本作ります。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud compute vpn-tunnels create vpn-tunnel-a-1 \ --peer-gcp-gateway=vpn-gateway-b \ --region=asia-northeast1 \ --ike-version=2 \ --shared-secret=sdijennji29duj \ --router=cloud-router-a \ --vpn-gateway=vpn-gateway-a \ --interface=0 && \ gcloud compute vpn-tunnels create vpn-tunnel-b-1 \ --peer-gcp-gateway=vpn-gateway-a \ --region=asia-northeast1 \ --ike-version=2 \ --shared-secret=sdijennji29duj \ --router=cloud-router-b \ --vpn-gateway=vpn-gateway-b \ --interface=0 && \ gcloud compute vpn-tunnels create vpn-tunnel-a-2 \ --peer-gcp-gateway=vpn-gateway-b \ --region=asia-northeast1 \ --ike-version=2 \ --shared-secret=sdijennji29duj65 \ --router=cloud-router-a \ --vpn-gateway=vpn-gateway-a \ --interface=1 && \ gcloud compute vpn-tunnels create vpn-tunnel-b-2 \ --peer-gcp-gateway=vpn-gateway-a \ --region=asia-northeast1 \ --ike-version=2 \ --shared-secret=sdijennji29duj65 \ --router=cloud-router-b \ --vpn-gateway=vpn-gateway-b \ --interface=1 ~省略~ Creating VPN tunnel...done. NAME: vpn-tunnel-b-2 REGION: asia-northeast1 GATEWAY: vpn-gateway-b VPN_INTERFACE: 1 PEER_ADDRESS: 34.157.195.105 fujioka@cloudshell:~ (fujioka-230212)$ 作成されていることを確認します。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud compute vpn-tunnels list NAME: vpn-tunnel-a-1 REGION: asia-northeast1 GATEWAY: vpn-gateway-a PEER_ADDRESS: 34.157.79.62 NAME: vpn-tunnel-a-2 REGION: asia-northeast1 GATEWAY: vpn-gateway-a PEER_ADDRESS: 34.157.206.255 NAME: vpn-tunnel-b-1 REGION: asia-northeast1 GATEWAY: vpn-gateway-b PEER_ADDRESS: 34.157.66.147 NAME: vpn-tunnel-b-2 REGION: asia-northeast1 GATEWAY: vpn-gateway-b PEER_ADDRESS: 34.157.195.105 fujioka@cloudshell:~ (fujioka-230212)$ 参考: gcloud compute vpn-tunnels create / gcloud compute vpn-tunnels list 現時点をコンソールから確認をすると、トンネルは確立されていますが BGP セッションが構成されていません。 BGP セッション構成前 BGPセッションの構成 BGP セッションを構成します。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud compute routers add-interface cloud-router-a \ --interface-name=bgp-a-1 \ --ip-address=169.254.0.1 \ --mask-length=30 \ --vpn-tunnel=vpn-tunnel-a-1 \ --region=asia-northeast1 && \ gcloud compute routers add-bgp-peer cloud-router-a \ --peer-name=bgp-b-1 \ --interface=bgp-a-1 \ --peer-ip-address=169.254.0.2 \ --peer-asn=65002 \ --region=asia-northeast1 && \ gcloud compute routers add-interface cloud-router-b \ --interface-name=bgp-b-1 \ --ip-address=169.254.0.2 \ --mask-length=30 \ --vpn-tunnel=vpn-tunnel-b-1 \ --region=asia-northeast1 && \ gcloud compute routers add-bgp-peer cloud-router-b \ --peer-name=bgp-a-1 \ --interface=bgp-b-1 \ --peer-ip-address=169.254.0.1 \ --peer-asn=65001 \ --region=asia-northeast1 && \ gcloud compute routers add-interface cloud-router-a \ --interface-name=bgp-a-2 \ --ip-address=169.254.0.5 \ --mask-length=30 \ --vpn-tunnel=vpn-tunnel-a-2 \ --region=asia-northeast1 && \ gcloud compute routers add-bgp-peer cloud-router-a \ --peer-name=bgp-b-2 \ --interface=bgp-a-2 \ --peer-ip-address=169.254.0.6 \ --peer-asn=65002 \ --region=asia-northeast1 && \ gcloud compute routers add-interface cloud-router-b \ --interface-name=bgp-b-2 \ --ip-address=169.254.0.6 \ --mask-length=30 \ --vpn-tunnel=vpn-tunnel-b-2 \ --region=asia-northeast1 && \ gcloud compute routers add-bgp-peer cloud-router-b \ --peer-name=bgp-a-2 \ --interface=bgp-b-2 \ --peer-ip-address=169.254.0.5 \ --peer-asn=65001 \ --region=asia-northeast1 ~省略~ Creating peer [bgp-a-2] in router [cloud-router-b]...done. fujioka@cloudshell:~ (fujioka-230212)$ 参考: gcloud compute routers add-interface / gcloud compute routers add-bgp-peer 以上でネットワークの構築は完了です。先程構成されていなかった BGP セッションも構成されています。 BGP セッション構成後 GCE 構築 GCE(Windows Server)の作成 次に Filestore をマウントする用の GCE を2つ作成します。OS は Windows Server 2022 を使用します。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud compute instances create nfs-client-a \ --zone asia-northeast1-a \ --boot-disk-auto-delete \ --image-project windows-cloud \ --image-family windows-2022 \ --machine-type n1-standard-8 \ --network=vpc-a \ --subnet=subnet-a \ --private-network-ip=10.0.0.2 && \ gcloud compute instances create nfs-client-b \ --zone asia-northeast1-a \ --boot-disk-auto-delete \ --image-project windows-cloud \ --image-family windows-2022 \ --machine-type n1-standard-8 \ --network=vpc-b \ --subnet=subnet-b \ --private-network-ip=172.16.0.2 ~省略~ Created [https://www.googleapis.com/compute/v1/projects/fujioka-230212/zones/asia-northeast1-a/instances/nfs-client-b]. NAME: nfs-client-b ZONE: asia-northeast1-a MACHINE_TYPE: n1-standard-8 PREEMPTIBLE: INTERNAL_IP: 172.16.0.2 EXTERNAL_IP: 34.84.161.249 STATUS: RUNNING fujioka@cloudshell:~ (fujioka-230212)$ 作成されていることを確認します。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud compute instances list NAME: nfs-client-a ZONE: asia-northeast1-a MACHINE_TYPE: n1-standard-8 PREEMPTIBLE: INTERNAL_IP: 10.0.0.2 EXTERNAL_IP: 35.187.213.228 STATUS: RUNNING NAME: nfs-client-b ZONE: asia-northeast1-a MACHINE_TYPE: n1-standard-8 PREEMPTIBLE: INTERNAL_IP: 172.16.0.2 EXTERNAL_IP: 34.84.161.249 STATUS: RUNNING fujioka@cloudshell:~ (fujioka-230212)$ 参考: gcloud compute instances create / gcloud compute instances list GCE に RDP Windows Server に初回ログイン時は Windows パスワードを再設定する必要があります。2台分の GCE のパスワードを再設定します。出力される password を使用して各 GCE へ RDP します。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud beta compute reset-windows-password "nfs-client-a" --zone "asia-northeast1-a" && \ gcloud beta compute reset-windows-password "nfs-client-b" --zone "asia-northeast1-a" ~省略~ Would you like to set or reset the password for [fujioka] (Y/n)? Y Resetting and retrieving password for [fujioka] on [nfs-client-a] Updated [https://www.googleapis.com/compute/beta/projects/fujioka-230212/zones/asia-northeast1-a/instances/nfs-client-a]. ip_address: 35.187.213.228 password: [ao9+Tf4TitXWyh username: fujioka ~省略~ Would you like to set or reset the password for [fujioka] (Y/n)? Y Resetting and retrieving password for [fujioka] on [nfs-client-b] Updated [https://www.googleapis.com/compute/beta/projects/fujioka-230212/zones/asia-northeast1-a/instances/nfs-client-b]. ip_address: 34.84.161.249 password: .fD_brM2U~k$yeR username: fujioka fujioka@cloudshell:~ (fujioka-230212)$ コンソールから [RDP] をクリックし、再設定したパスワードを入力し、ログインします。 コンソールから RDP 参考: RDP を使用して Windows VM に接続する / gcloud beta compute reset-windows-password 疎通テスト 異なる VPC に属する GCE 同士が内部 IP アドレスで疎通出来ることを確認します。左が nfs-client-a、右が nfs-client-b です。 問題なく疎通出来ています。 疎通テスト Filestore 構築 Filestore の作成 Filestore を作成します。サービスティアや環境によって異なりますが、数分〜数十分程かかる場合があります。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud filestore instances create nfs-server \ --zone=asia-northeast1-a \ --tier=basic-hdd \ --file-share=name="vol",capacity=1TB \ --network=name="vpc-a",reserved-ip-range="10.0.1.0/29" Waiting for [operation-1676217502204-5f482ccc90135-fd023b8f-aac4ad51] to finish...done. fujioka@cloudshell:~ (fujioka-230212)$ 参考: gcloud filestore instances create マウント(nfs-client-a) NFS クライアントの設定 nfs-client-a のインスタンスで ドキュメント に従い、 管理者として PowerShell を開き 以下を順に実行します。 NFS クライアントをインストールする Install-WindowsFeature -Name NFS-Client インスタンスを再起動する NFS クライアントが使用するユーザー ID を構成する New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ClientForNFS\CurrentVersion\Default" ` -Name "AnonymousUid" -Value "0" -PropertyType DWORD New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ClientForNFS\CurrentVersion\Default" ` -Name "AnonymousGid" -Value "0" -PropertyType DWORD NFS クライアントサービスを再起動する nfsadmin client stop nfsadmin client start PowerShell を終了する exit マウント マウント前は C ドライブのみです。 マウント前(nfs-client-a) Command Prompt で Filestore 上のファイル共有名とドライブ文字をマッピングし、マウントします。 mount -o mtype=hard 10.0.1.2:/vol Z: マウント後(nfs-client-a) 参考 Compute Engine VM インスタンスにファイル共有をマウントする ルートのアドバタイズ nfs-client-b に Filestore をマウントする前に、Filestore のサービス用サブネット( 10.0.1.0/29 )をアドバタイズする必要があります。アドバタイズしない場合に発生するエラーについては後述の 注意点 の通りです。 vpc-a のルートでは 10.0.1.0/29 へのルートがあります。 vpc-a のルート それに対し、vpc-b には 10.0.1.0/29 へのルートがありません。 vpc-b のルート cloud-router-a で 10.0.1.0/29 のルートをアドバタイズします。 fujioka@cloudshell:~ (fujioka-230212)$ gcloud compute routers update cloud-router-a \ --advertisement-mode=CUSTOM \ --region=asia-northeast1 \ --set-advertisement-groups=ALL_SUBNETS \ --set-advertisement-ranges 10.0.1.0/29=filestore-range Updating router [cloud-router-a]...done. fujioka@cloudshell:~ (fujioka-230212)$ vpc-b に Filestore のサービス用サブネット( 10.0.1.0/29 )がアドバタイズされました。 アドバタイズ後の vpc-b のルート 参考: カスタム IP 範囲のアドバタイズ マウント(nfs-client-b) 上記の マウント(nfs-client-a) と同様の手順を nfs-client-b にも行い、Filestore をマウントをさせます。 マウント後(nfs-client-b) テスト nfs-client-a の Z ドライブ(Filestore)で任意のファイルを作成し、nfs-client-b の Z ドライブにも反映されていることが確認できます。左が nfs-client-a、右が nfs-client-b です。 テスト 事後作業 プロジェクトの削除 fujioka@cloudshell:~ (fujioka-230212)$ gcloud projects delete fujioka-230212 Your project will be deleted. Do you want to continue (Y/n)? Y Deleted [https://cloudresourcemanager.googleapis.com/v1/projects/fujioka-230212]. You can undo this operation for a limited period by running the command below. $ gcloud projects undelete fujioka-230212 See https://cloud.google.com/resource-manager/docs/creating-managing-projects for information on shutting down projects. fujioka@cloudshell:~ (fujioka-xxxx)$ 参考: gcloud projects delete 注意点 nfs-client-b に Filestore をマウントする前に、Filestore のサービス用サブネット( 10.0.1.0/29 )をアドバタイズせずにマウントをしようとすると、以下のようなエラーが発生します。エラー発生時には、ルートが原因の場合がありますので、確認してください。 C:\Users\fujioka>hostname nfs-client-b C:\Users\fujioka> C:\Users\fujioka>mount -o mtype=hard 10.0.1.2:/vol Z: Network Error - 53 Type 'NET HELPMSG 53' for more information. C:\Users\fujioka> G-gen 編集部 (記事一覧) 株式会社G-genは、サーバーワークスグループとして「クラウドで、世界を、もっと、はたらきやすく」をビジョンに掲げ、クラウドの導入から最適化までを支援している Google Cloud 専業のクラウドインテグレーターです。
当記事は みずほリサーチ&テクノロジーズ × G-gen エンジニアコラボレーション企画 で執筆されたものです。 みずほリサーチ&テクノロジーズ株式会社の舘山と申します。 本日は、Google Cloudの監査ログの長期保管とアクセス監査について、調査した内容を共有します。 参考資料として、Google Cloudのログ取得サービス、監査ログの全体像は下記のブログ、Google Cloudドキュメントにまとめられています。 G-genブログ Cloud Loggingの概念と仕組みをしっかり解説 Cloud Audit Logsを解説。Google Cloud(GCP)の証跡管理 Google Cloudドキュメント Cloud Audit Logs の概要 Cloud 監査ログのベスト プラクティス Google Cloud でのセキュリティ ログ分析 当ブログは G-gen × みずほRT によるコラボ記事です 1.当記事が前提とする要件 2.デフォルトの監査ログ設定と要件のギャップ 3.要件を満たす対応の実施 (1)データアクセス監査ログの有効化 (2)Cloud Loggingバケットの保存先を東京リージョンに変更 (3)Cloud Loggingバケットの暗号化に顧客管理の暗号鍵(CMEK)を利用 (4)組織の監査ログを集約して、長期保管 A.集約シンクの設定 B.配信先ストレージの選択 C.Cloud Storageの保持ポリシーによるログの保護 D.組織、フォルダーに紐づくリソースの設定変更監視について 4.アクセス監査資料の作成 (1)ログフォーマットの把握 (2)BigQuery外部テーブルの作成 (3)BigQueryから読み込むデータ量(=分析料金)の最適化 集約シンクから直接エクスポートしたBigQueryテーブルの場合 (4)アクセス監査のためのクエリを考える (5)処理の自動化を考える A. Looker Studioによるレポート自動配信 B. CloudSchedularからPub/Sub経由でCloudFunctions起動 (a)Cloud Functions サーバレスVPCアクセスコネクタインスタンスはCMEKでの暗号化に非対応 (b)Cloud Functions(第二世代)が自動生成するCloud Storage バケット、Artifact Registry リポジトリはCMEKでの暗号化に非対応 5.まとめ 1.当記事が前提とする要件 当記事が前提とする要件を記載します。 組織全体の監査ログを本番/開発別の監査用プロジェクトに集約し2年間保管する。 組織全体で日次で開発者がアクセスした本番プロジェクト(組織、フォルダ)の監査を行う。 リソースの更新(ADMIN_WRITE)だけでなく、リソースの参照(ADMIN_READ)、データの参照、更新(DATA_READ、DATA_WRITE)の監査ログも保管する。 サービス制約がない限り、データは国内リージョンに保有する。 (組織的な統制には、 組織ポリシーconstraints/gcp.resourceLocations が利用可能です。) サービス制約がない限り、暗号化には 顧客管理の暗号鍵(CMEK) を利用する。 (組織的な統制には、 組織ポリシーconstraints/gcp.restrictNonCmekServices が利用可能です。) 実際のシステム構築では、以下のトピックについても考慮が必要ですが、当記事では基本的に扱いません。 VPCフローログ 、 ファイアウォールルールログ 等のネットワークのログ 業務アプリケーションやミドルウェアのログ GKEのKubernetes API(k8s.io)の監査ログ Cloud Identity(ユーザーアカウント管理) 、請求先アカウントの監査ログ アクセスの透明性 のログ(Googleのエンジニアによるアクセスの監査ログ) リアルタイムの監査ログ監視 ログに対する細かいアクセス制御 Cloud Asset Inventoryによるリソースの スナップショット 、 変更履歴 の集約 Security Command Center の検出結果の集約 2.デフォルトの監査ログ設定と要件のギャップ デフォルトの監査ログ設定での、今回の要件の順守状況を整理すると下の表のようになります。 要件 順守状況 全ての監査ログ取得 ×:BigQuery以外のデータアクセス監査ログは取得対象外 国内リージョンの利用 ×:Cloud Loggingバケットの保存先はグローバル(海外含む) 暗号化に顧客管理の暗号鍵(CMEK)の利用 ×:Cloud LoggingバケットはGoogle管理の鍵で暗号化 組織全体の監査ログ集約、長期保管 ×:各プロジェクトの監査ログは、各プロジェクトのCloud Loggingバケットにのみ保存    Requiredバケットの保存期間は400日固定    Defaultバケットの保存期間の初期設定は30日 3.要件を満たす対応の実施 (1)データアクセス監査ログの有効化 各プロジェクト単位ではなく、組織レベルでデータアクセス監査ログの有効化設定が可能です。 設定手順についてはCloud Loggingのガイドを参照してください。 データアクセス監査ログを構成する 各サービスのデータアクセス監査ログを有効にした場合、Cloud Loggingのデフォルト設定では、API実行対象の組織、フォルダ、プロジェクトの_Defaultバケットに全てのログが取り込まれ、追加の料金が発生します。 GoogleCloud のオペレーション スイートの料金 大量のログを取り込む場合のCloud Loggingの費用感としては、 Cloud Bigtableの例 が参考になります。(加えて、ログ集約先のストレージコスト、監査のためのクエリのコストにも影響があります。) 要件に対して不要なログを削減するため、 特定のプリンシパルのロギングを制限する ことが可能です。 (2)Cloud Loggingバケットの保存先を東京リージョンに変更 こちらも組織レベルで保存先リージョンを設定することが可能です。​​ ​​​​​ 設定手順についてはCloud Loggingのガイドを参照してください。 Cloud Logging のデータ リージョン なお、Loggingバケットのリージョン指定は、既存のバケットには遡及しないため、フォルダ、プロジェクトを作成するより前に設定を行う必要があります。 組織作成時に作成された、組織自体に対する操作の監査ログが格納される _Requiredバケットについては、保存先をリージョンに変更することができません。 また、現状ではLoggingバケットの保存先をグローバルからリージョンに変更した場合、 Error Reporting 機能が利用できない制約 があります。 (3)Cloud Loggingバケットの暗号化に顧客管理の暗号鍵(CMEK)を利用 こちらも組織レベルでCMEKの利用を設定することが可能です。 設定手順についてはCloud Loggingのガイドを参照してください。 Logging のストレージ データを保護する鍵を管理する ガイドの手順に従い、組織に関連付けられたサービスアカウント( cmek-o<組織ID>@gcp-sa-logging.iam.gserviceaccount.com )に暗号鍵の暗号化 / 復号の役割を割り当てる際に、追加で以下の対応が必要でした。 暗号鍵がVPC Service Controlsの境界内にある場合、組織のサービスアカウントを アクセスレベル に追加して、境界への アクセス許可を設定 する。 組織ポリシーconstraints/iam.allowedPolicyMemberDomains で組織外部への権限付与を制限している場合、組織のサービスアカウントは外部IDと判定されポリシー違反となった。暗号鍵の利用権付与する際、鍵を保有するプロジェクトで一時的に組織ポリシーを上書きしてエラーを回避する。 保存先がグローバルのバケットの暗号化にはCMEKを利用できない制約があります。そのため、(保存先をグローバルから変更できない)組織自体の _RequiredバケットをCMEKで暗号化することはできません。 (4)組織の監査ログを集約して、長期保管 A.集約シンクの設定 Cloud Loggingの集約シンクを利用することで、組織の全プロジェクトの監査ログを監査プロジェクトへ配信することができます。 設定手順についてはCloud Loggingのガイドを参照してください。 集約シンクを構成する 全ての監査ログを転送する場合、包含フィルタ条件には  logName:cloudaudit.googleapis.com を指定します。 本番/開発別の監査プロジェクトへ集約は、(本番と開発でプロジェクトを配置するフォルダを分けていることを前提に)フォルダに対して集約シンクを適用することで実現できます。 また組織自体に対する操作は、組織のCloud Loggingに記録されるため、下位のフォルダの集約シンクでは拾われません。組織自体にも(非集約)シンクを作成して、本番用の監査プロジェクトへログを転送します。 ​​​​​​​​​Cloud Identityの監査ログも集約対象とする場合、事前に 監査ログの共有設定 が必要です。 シンク設定前のログは転送されませんが、 ログのコピー機能 がプレビュー版で提供されています。 組織の監査ログの集約構成例 今回検証していませんが、別案として組織直下に集約シンクを2つ作成し、フィルタ条件で本番/開発プロジェクトのログを選別するという構成も可能だと思います。 また、後述のBigQueryによる監査クエリのコストを最適化する観点で、監査が人(Googleアカウント)による操作だけを対象とする場合には、人以外(サービスアカウント)のAPI実行の監査ログ保管先を分けるという構成も考えられます。 B.配信先ストレージの選択 シンクからログを配信する先のストレージと対応するユースケースは以下の表のようになります。 配信先 ユースケース BigQuery 高度な分析 Cloud Storage コンプライアンス、長期保管 Pub/Sub Splunk等外部サービスとの統合 ログバケット ログベースの指標 、 アラート 参考サイト: BigQuery の監査ログ パイプラインを活用した使用状況分析 今回はコンプライアンスと長期保管を主目的として、Cloud Storageを選択します。 Cloud Storageバケットのロケーション、CMEKの利用についてはCloud Storageのガイドを参照してください。 バケットの保存場所 顧客管理の暗号鍵の使用 C.Cloud Storageの保持ポリシーによるログの保護 Cloud Storageの保持ポリシー機能を利用することで、保存期間内の監査ログの更新、削除が不可になります。​​​​​​​ 設定手順についてはCloud Storageのガイドを参照してください。 保持ポリシーと保持ポリシーのロック なお、保持ポリシーでバケット内のログは保護されますが、集約シンクが削除されると新規ログの配信がストップするため、集約シンク自体は別途保護(IAMポリシーを適切に設定する、変更を監視する等)する必要があります。 また、Cloud Storageのライフライクル管理機能により保存期間を超過したログを自動削除することも可能です。監査等によるアクセス頻度によっては、一定期間経過後の ストレージクラス の変更もコスト削減に寄与します。 設定手順についてはCloud Storageのガイドを参照してください。 オブジェクトのライフサイクル管理 D.組織、フォルダーに紐づくリソースの設定変更監視について リソースの設定変更監視は、 Cloud Security Centerのモニタリング脆弱性チェック のように、監査ログに対してログベースの指標に基づくアラートを作成する方法があります。(現在はログベースのアラートもGAになっています。) 一方で、組織、フォルダ階層の監査ログをソースとする場合 ログベースの指標、アラートは 組織、フォルダの階層では定義不可能。 組織、フォルダからプロジェクトのログバケットへ転送されたログに対する、ログベースの指標は 、2023年1月時点でGA前。 組織、フォルダー階層の監視用ログシンクからPub/Subトピックへの配信を利用する場合、組み込みのメール送信が未サポート。 という制限事項があります。 また、監視に Cloud Asset Inventoryの変更フィード を利用する場合、組織レベル、フォルダーレベルの変更フィードからVPC Service Controls境界内のPub/Subトピックへの配信不可など、 VPC Service Controls関連の制限事項 があります。 4.アクセス監査資料の作成 前掲の監査ログ保管ストレージの選択肢の表から、高度な分析にはBigQueryが適しています。 監査資料作成のためのクエリをBigQueryで実行するため、監査ログをBigQueryにも重複配信(BigQuery側での保存期間は監査要件に応じて短く設定)するという構成も可能ですが、今回は監査ログを保管しているCloud StorageバケットをBigQueryから外部テーブルとして参照する方法を紹介します。 (1)ログフォーマットの把握 Cloud Loggingのログレコードは LogEntryという構造 になっています。 監査ログの場合、LogEntryのprotoPayload要素が、監査ログを表す AuditLogという構造 になっています。 このレコード定義と実ログのサンプルから監査資料で必要そうな項目がどこにあるかを把握していきます。 下の画像はBigQueryテーブルのメタデータ更新が権限不足エラーとなった場合の監査ログを一部加工したものです。 監査ログレコードのサンプル 日次のアクセス監査ではプロジェクト(組織、フォルダー)の粒度でアクセス先を識別できればよいものとして、必要な項目の格納場所を整理します。 項目 LogEntry内の格納場所 操作日時 timestamp が使えそうです。 注意点としてBigQueryのデータ読み取り量を最適化するため、WHERE句で日付を限定する条件はこの項目ではなく、_FILE_NAME疑似列に適用します。(詳細は後述) 操作ユーザー protoPayload.authenticationInfo.principalEmail が該当します。 システム自動処理や、Google Cloudの内部処理によるAPI実行も監査ログに記録されます。 また、権限不足エラーとなった操作など 操作ユーザーが匿名化されるケース があります。 アクセスしたプロジェクト(組織、フォルダー) logName が監査ログの出元です。 ​​​​​logNameの例: ​​​​​"projects/[PROJECT_ID]/logs/[LOG_ID]" ​​​​​"organizations/[ORGANIZATION_ID]/logs/[LOG_ID]" ​​​​​"billingAccounts/[BILLING_ACCOUNT_ID]/logs/[LOG_ID]" ​​​​​"folders/[FOLDER_ID]/logs/[LOG_ID]" ​​​​​logNameの二階層目の文字列までを抽出することで、アクセスしたプロジェクト(組織、フォルダー)が特定できそうです。 監査ログの種類(リソースの更新操作か) logName 末尾の[LOG_ID]部分を見ればわかりそうです。 cloudaudit.googleapis.com%2Factivity がリソース更新の監査ログです。 注意点として操作日時同様、BiqQueryクエリのWHERE句では、_FILE_NAME疑似列に条件を適用します。 データアクセス監査ログのサブタイプ(ADMIN_READ、DATA_READ、DATA_WRITE)については直接識別する属性がなく、protoPayload.serviceNameとprotoPayload.methodNameの組から個別に判断するしかなさそうです。 同様にポリシー拒否監査ログの対象操作がADMIN_WRITE、ADMIN_READ、DATA_READ、DATA_WRITE、のどれに該当するかも直接識別できません。 権限不足エラーだったか 権限エラーとなった操作の監査ログを確認すると protoPayload.status.code の値が 7 になっています。 Java Cloud Client Libraries のEnumの定義を見ると、PERMISSION_DENIEDのエラーコードが7のようです。 なお、VPC Service Controlsのポリシー違反も同じエラーコードになるようです。 区別が必要な場合は、外部テーブルの_FILE_NAME疑似列の値にcloudaudit.googleapis.com/policyが含まれるものが、ポリシー違反のログになります。 接続元IPアドレス protoPayload.requestMetadata.callerIp に格納されています。 Google Cloudサービス経由の呼び出しなど、 IPアドレスが秘匿化されるケース も存在します。 (2)BigQuery外部テーブルの作成 監査ログを保管したCloud Storageバケットを参照する外部テーブルを作成します。 作業手順についてはBigQueryのガイドを参照してください。 Cloud Storage データのクエリ シンクの転送先に直接BigQueryを指定した場合には 特別な命名規則を使用するスキーマ が自動生成されます。 一方で外部テーブルとして監査ログを保管したCloud Storageバケットを参照する場合、スキーマの自動認識に特別な配慮はないようです。@typeなどのフィールド名がBigQueryの命名規則に合致しないため、スキーマの自動認識はエラーとなりました。 インターネットで検索しましたが流用できるスキーマ定義が見つからなかったため、以下のスキーマ定義を手動で作成しました。 LogEntry の第一階層までを定義し、ネストされた構造化データのフィールドはRECORD型ではなく、JSON型としています。 監査ログ格納バケットを参照する外部テーブルのスキーマ定義 (3)BigQueryから読み込むデータ量(=分析料金)の最適化 BigQueryではクエリで読み込んだデータ量に応じても従量課金されます。( オンデマンド料金モデル の場合) そのためBigQueryのテーブルはクエリの条件となる項目(日付等)でパーテーション分割して、アクセスするデータ範囲を削減することが定石となっています。 Cloud Storageの場合、Hiveパーティション分割レイアウトに沿ったフォルダ構成 例: gs://[バケット名]/myTable/dt=2019-10-31/lang=en/foo になっていれば、BigQueryからパーテーション分割された外部テーブルとして扱われます。 Cloud Storage の外部パーティション分割データに対してクエリを実行する 監査ログを 集約シンクでCloud Storageへ配信した場合のファイルパス は下記の様になります。 gs://[バケット名]/cloudaudit.googleapis.com/[activity|data_access|policy]/2022/12/28/03:00:00_03:59:59_S0.json これは2022/12/28 3時台のログファイルの例です。なお、タイムゾーンは日本時間ではなく、UTCです。 パスに日付と時間が含まれているものの、Hiveパーティション分割レイアウトに沿っていないため、BigQueryからはパーテーション分割されたデータとは認識されません。 一方で、ファイルのパスは  クエリから _FILE_NAMEという疑似列で参照することができ、 BigQueryガイド Cloud Storage でパーティション分割されていないデータをクエリする には クエリに _FILE_NAME 疑似列に対するフィルタ述語がある場合、BigQuery は、フィルタに一致しないファイルの読み取りをスキップしようとします。 と記載されています。 この特性から1日分のアクセス監査資料を作成したい場合、監査ログ内のタイムスタンプではなく、 日時を含む_FILE_NAME疑似列のパスに対して条件を適用することで、アクセスするデータ範囲を削減することが可能になります。 _FILE_NAME LIKE ' %2022/12/30% ' という条件では日本時間ではなく、UTCでの1日分の監査ログが対象になります。 日本時間での1日分の監査ログの抽出が必要な場合、日付を求める手順としては、 ・正規表現でファイルパスから年/月/日/時間を抽出し ・タイムスタンプ型にパースした上で日本時間での日付に変換する という方法が考えられます。 DATE (PARSE_TIMESTAMP( ' %Y/%m/%d/%H ' , REGEXP_EXTRACT(_FILE_NAME,  ' [0-9]+/[0-9]+/[0-9]+/[0-9]+ ' )) , ' Asia/Tokyo ' ) =  ' 2022-12-30 ' _FILE_NAME 疑似列への条件の記載方法によっては、実データへのアクセスがスキップされないケース があります。 実際に実データへのアクセスがスキップされるかは、先日付を指定してクエリ結果の「課金されるバイト数」が0 Bとなることで裏取りします。 _FILE_NAME疑似列条件による実データへのアクセススキップ なお、 組織ポリシーconstraints/gcp.restrictNonCmekServices でBigQueryのCMEK暗号化利用を必須としている場合、コンソールからクエリを実行する前に、 クエリ結果を格納する一時テーブルの暗号化に利用する鍵を設定する 必要があります。 (クエリ画面の「その他」→「クエリの設定」→「詳細オプション」→「顧客管理の暗号化」に鍵のリソースIDを入力します。) 集約シンクから直接エクスポートしたBigQueryテーブルの場合 ログシンクからBigQueryへ直接エクスポートする場合、 自動生成されるテーブルはtimestampのUTC日付でパーテーション分割 (クラスタリング列は未指定)されます。私が調べた限り、シンクからのエクスポート時にパーテーションのタイムゾーンを調整する設定は見つかりませんでした。 外部テーブルとの違いとして、日本時間での1日分のログの参照条件の記載は DATE ( timestamp , " Asia/Tokyo " ) = " 2022-12-30 " という記載では、全パーテーションが走査対象となってしまうため、パーテーション列側を加工するのを避け timestamp >= TIMESTAMP ( ' 2022-12-29 15:00:00 ' ) AND timestamp < TIMESTAMP ( ' 2022-12-30 15:00:00 ' ) という記載にする必要がありました。 自然体だと日本時間での1日分のログを監査するには、UTC2日分のパーテーションの走査が必要となります。 クエリ最適化対策として、オンデマンド配車および配達ソリューションのログ解析のガイドでは、 自動生成されたテーブルに後からtimestampをクラスタリング列に追加する方法 が紹介されていました。 for TABLE in `bq ls --format=csv -project_id =< プロジェクトID > < ログエクスポート先のデータセットID > | cut -d, -f2 | tail + 2 ` \ ; do \ bq update --clustering_fields=timestamp ${TABLE} \ ; done (4)アクセス監査のためのクエリを考える 一例として、本番プロジェクトへのアクセスには事前申請が必要であり、無申請のアクセスがないかを監査するシナリオを想定します。 ユーザーはコンソールからユーザーアカウント(Cloud Identityで管理するユーザー)でアクセスすることを前提として、各ユーザーが1日にアクセスしたプロジェクトの情報を出力します。 Cloud Identityへのログインは、特定のプロジェクトへのアクセスを示すものではないため、ログインの監査ログだけではアクセス先は不明です。 AWSでIAMユーザーでログイン後に各アカウントのIAMロールにスイッチロールする運用の場合には、スイッチロールを各アカウントへのログイン操作とみなす作戦が取れますが、 Google Cloudには当てはまりません。 代替手段として力技になりますが、なんらかの監査ログが記録されていれば当該プロジェクトへログインしたとみなし、各ユーザーアカウント/アクセス先プロジェクト毎に ユーザーアカウント アクセスしたプロジェクト(組織、フォルダ) (権限エラーのぞく)最初の操作時間 (権限エラーのぞく)最後の操作時間 (権限エラーの)最初の操作時間 (権限エラーの)最後の操作時間 接続元IPアドレス(複数ある場合カンマで連結) アクセス先横断で当該ユーザーの当日の全操作が権限エラーの場合〇を表示 を権限エラーの明細行を分けて出力します。​​​​​​​改善の余地ありますが、以下のようなSQLが考えられます。 WITH audit_logs AS ( SELECT JSON_VALUE(protoPayload.authenticationInfo.principalEmail) AS principalEmail, REGEXP_EXTRACT(logName, ' [^/]+/[^/]+ ' ) AS accessedProject, /* 正規表現で[organizations/xxxx][folders/xxxxx][projects/xxxx]部分を抽出 */ DATETIME ( timestamp , ' Asia/Tokyo ' ) AS operationTimestamp, /*パフォーマンス最重視する場合、tz補正は最後のSELECT句で行う*/ JSON_VALUE(protoPayload.requestMetadata.callerIp) AS callerIp, CASE WHEN JSON_VALUE(protoPayload.status.code) = ' 7 ' THEN true ELSE false END AS permissionDenied FROM `poc01-hn- audit -■■■■■■■■■■. audit .external_audit_log` WHERE DATE (PARSE_TIMESTAMP( ' %Y/%m/%d/%H ' , REGEXP_EXTRACT(_FILE_NAME, ' [0-9]+/[0-9]+/[0-9]+/[0-9]+ ' )) , ' Asia/Tokyo ' ) = ' 2022-12-29 ' /* 日付はパラメタ化*/ /* 読み取りデータ量削減のため、実データではなく_FILE_NAME疑似列で日付、ログ種別を絞る。_FILE_NAMEはUTCの日時 */ AND ( _FILE_NAME LIKE ' %cloudaudit.googleapis.com/activity% ' OR _FILE_NAME LIKE ' %cloudaudit.googleapis.com/data_access% ' OR _FILE_NAME LIKE ' %cloudaudit.googleapis.com/policy% ' ) /* 監査対象はユーザーアカウントに絞る*/ AND JSON_VALUE(protoPayload.authenticationInfo.principalEmail) LIKE ' %@% ' AND JSON_VALUE(protoPayload.authenticationInfo.principalEmail) NOT LIKE ' %gserviceaccount.com ' ) SELECT principalEmail, accessedProject , MIN ( CASE WHEN permissionDenied THEN null ELSE operationTimestamp END ) AS firstOperationTimestamp, MAX ( CASE WHEN permissionDenied THEN null ELSE operationTimestamp END ) AS lastOperationTimestamp, MIN ( CASE WHEN permissionDenied THEN operationTimestamp ELSE null END ) AS firstAuthorizationErrorTimestamp, MAX ( CASE WHEN permissionDenied THEN operationTimestamp ELSE null END ) AS lastAuthorizationErrorTimestamp, STRING_AGG( DISTINCT callerIp ORDER BY callerIp) AS callerIp , CASE WHEN    COUNTIF( NOT permissionDenied ) OVER( PARTITION BY principalEmail ) > 0 THEN '' ELSE ' 〇 ' END AS permissionDeniedOnlyUser FROM audit_logs GROUP BY principalEmail,accessedProject,permissionDenied order by 1 , 2 , 3 , 5 アクセス監査クエリ結果 監査用クエリで利用している下記の要素 WITH句、 共通テーブル式 SELECT句内での 条件分岐 Window関数 (クエリ中のCOUNTIF関数は、集計関数ではなくWindow関数として利用) は、SQLの入門書では扱われる事が少なく、馴染みがない人もいたと思います。 共通テーブル式と、SELECT句内でのCASEの活用については以下の記事が参考になります。 SQL緊急救命室 第5回 時代錯誤症候群~進化し続けるSQLに取り残されるな! SQL緊急救命室 第2回 冗長性症候群~条件分岐をUNIONで表現するなかれ Window関数(OLAP関数)については、以下の記事が参考になります。 SQLアタマアカデミー 最終回 OLAP関数で強力な統計処理を実現!―手続き型から理解するSQL (2)OLAP関数の基本構文 両方の記事の著者であるDBエンジニアのミック氏のサイトには、有益な記事が多数掲載されています。 リレーショナル・データベースの世界 一般的なDBエンジンと異なり、BigQueryでは非再帰の共通テーブル式がSQL文中で複数回参照される場合でも実体化されず、毎回SELECT処理が実行される点に注意が必要です。 そのため、監査クエリの後半部分をSELECT句内のCASEにより分岐ではなく、共通テーブル式を参照する2つのSELECT文をUNION ALLするようなSQLで記載すると、データ処理料金が2倍になってしまいます。 BigQueryでインラインビューではなく非再帰の共通テーブル式を使う主なメリットは、性能面にはなく、SQLの可読性になります。 SQL文がBigQueryのパフォーマンスに与える影響については、以下のブログ記事が具体例が豊富で参考になります。 14 Best Practices to Tune BigQuery SQL Performance (5)処理の自動化を考える A. Looker Studioによるレポート自動配信 Googleが提供するBIツールの Looker Studio には、 レポートのメール配信スケジュールを設定する機能 があります。 この機能を利用して、日次でBigQueryをデータソースに監査資料を作成し、PDFを監査担当者にメール配信できないかと期待しましたが、私が確認した限り 明細行数の多い表を、レポートを改ページして全行表示することができない。(明細行数が多い場合、レポート"ページ内部で"スクロールかページングする構成) PDFにはレポートページで見える範囲の明細行しか出力できない という仕様のため、全ての明細行をPDFに出力することが不可能でした。 B. CloudSchedularからPub/Sub経由でCloudFunctions起動 代替策として Cloud Scheduler から日次で  Pub/Subトピック経由で Cloud Functions を起動 し、BigQueryのクエリ結果から作成した監査資料をCloud Storageへアップロードする構成が考えられます。(最大実行時間等の クォータ には注意が必要です) その際CMEKの利用について、以下の制約、ワークアラウンドがあります。 (a) Cloud Functions サーバレスVPCアクセスコネクタインスタンスはCMEKでの暗号化に非対応 ネットワーク統制要件として、Cloud Functions関数の全通信をサーバレスVPCアクセスコネクタ経由にする要件がある場合に問題となります。 CMEKの利用を組織レベルで強制するために、 組織ポリシーconstraints/gcp.restrictNonCmekServices でConpute EngineのCMEK利用を必須としていると、コネクタインスタンスの起動に失敗します。 コネクタインスタンスはオートスケールの対象のため、設定時のみポリシーを無効化するワークアラウンドは採用できません。 サーバレスVPCアクセスコネクタを利用する際は、Compute Engineについては、組織ポリシーconstraints/gcp.restrictNonCmekServicesの適用対象外とし、別途発見的統制でCMEK利用の統制を行う必要があります。 (b)Cloud Functions(第二世代)が自動生成するCloud Storage バケット、Artifact Registry リポジトリはCMEKでの暗号化に非対応 ワークアラウンドとして、最初のCloudFunctions関数を作成するより前に同名のリソース Cloud Storageバケット gcf-v2-uploads-<プロジェクト番号>-<リージョン> Cloud Storageバケット gcf-v2-sources-<プロジェクト番号>-<リージョン> Artifact Registryリポジトリ gcf-artifacts をCMEKを利用する設定で作成しておくことで、CMEKの利用が可能になります。 なお、コンソールからは確認、設定できませんが、自動生成されるCloud StorageバケットにはCORS設定がされています。先回りして作成するバケットにも同じCORS設定をしないと、コンソールから関数のソースコードの参照、更新が不可になります。 CloudFunctionsが自動生成するGCSバケットのCORS設定 5.まとめ 本日の内容をまとめると以下になります。 デフォルトでは(BigQuery以外の)データアクセス監査ログは記録されない。全ての監査ログを記録するには追加の設定が必要。 リージョン指定、CMEK利用の要件がある場合は、追加の設定が必要。 集約シンクを利用することで組織全体の監査ログを集約して保管できる。 Cloud Storageの保持ポリシーにより、監査ログを変更、削除から保護できる。 BigQueryからCloud Storage上の監査ログの分析ができる。 舘山 浩之 みずほリサーチ&テクノロジーズ 先端技術研究部に所属。個人のキャリアではAWSの利用経験が長く、Google Cloudは2022年より利用開始。
G-gen の武井です。 当記事では Google Cloud (旧称 GCP) のリソース情報を gcloud コマンドと jq コマンドで 取得する方法を紹介します。 概要 gcloud コマンド jq コマンド 実行方法 コマンドツールの準備 使い方 失敗例 成功例 実例 組織 組織名 (ドメイン名) を抽出 組織 ID を抽出 条件に合致する値を抽出 フォルダ フォルダ名を抽出 フォルダ ID を抽出 条件に合致する値を抽出 プロジェクト プロジェクト名を抽出 プロジェクト ID を抽出 プロジェクト番号 を抽出 条件に合致する値を抽出 概要 gcloud コマンド gcloud コマンド ( gcloud CLI ) は、Google Cloud リソースの管理を行うコマンドツールです。 Cloud コンソール ( GUI ) と同様、Google Cloud のリソース作成からその後の管理を含め、一連の操作をコマンドラインを介して行えます。 jq コマンド jq コマンドは JSON データの加工や整形 ( 抽出 / 変換 / 集計 ) をするツールです。Linux でいう grep / sed / awk コマンドに相当します。 実行方法 それぞれのコマンドを組み合わせて実行するには、 gcloud コマンドの取得したデータを | (パイプ) コマンドで jq コマンドに渡します。 gcloud コマンドで取得したデータは JSON 形式して渡す必要があるため、 --format を使ってデータを変換します。 コマンドツールの準備 Cloud Shell では gcloud / jq コマンドのどちらもインストール済みですが、それ以外の環境ではインストールが必要です。 ※ 当記事では実行例を中心に紹介するため、インストール方法等の説明は割愛します。 使い方 gcloud organizations list コマンド ( 組織を一覧表示するコマンド ) を例に使い方を紹介します。 失敗例 前述の通り、 jq コマンドに渡すデータは JSON 形式にする必要があります。 gcloud コマンドの出力 (デフォルト) はテキスト形式なので、データ形式を明示的に指定しない場合はエラーになります。 $ gcloud organizations list | jq parse error : Invalid numeric literal at line 1 , column 13 成功例 --format=json でデータ形式を JSON に変換して jq コマンドに渡すことでコマンドラインが成功します。 まずは jq コマンドには渡さず、JSON 形式で出力した場合の例です。 $ gcloud organizations list -- format = json [ { " creationTime ": " 2023-01-19T23:02:33.677Z ", " displayName ": " example001.co.jp ", " lifecycleState ": " ACTIVE ", " name ": " organizations/11111111 ", " owner ": { " directoryCustomerId ": " AAAAAAAA " } } , { " creationTime ": " 2022-11-02T00:35:22.696Z ", " displayName ": " example002.co.jp ", " lifecycleState ": " ACTIVE ", " name ": " organizations/22222222 ", " owner ": { " directoryCustomerId ": " BBBBBBBB " } } , { " creationTime ": " 2021-11-11T03:22:50.021Z ", " displayName ": " example003.co.jp ", " lifecycleState ": " ACTIVE ", " name ": " organizations/33333333 ", " owner ": { " directoryCustomerId ": " CCCCCCCC " } } , { " creationTime ": " 2021-10-27T03:09:00.929Z ", " displayName ": " example004.co.jp ", " lifecycleState ": " ACTIVE ", " name ": " organizations/44444444 ", " owner ": { " directoryCustomerId ": " DDDDDDDD " } } , { " creationTime ": " 2021-08-12T08:08:27.729Z ", " displayName ": " example005.co.jp ", " lifecycleState ": " ACTIVE ", " name ": " organizations/55555555 ", " owner ": { " directoryCustomerId ": " EEEEEEEE " } } ] 次に jq コマンドに渡した場合です。オプション等を使用せず、単に jq に渡しただけでは前述の出力と変わりありません。 jq コマンドによる加工や整形については次の章でご紹介します。 $ gcloud organizations list -- format = json | jq [ { " creationTime ": " 2023-01-19T23:02:33.677Z ", " displayName ": " example001.co.jp ", " lifecycleState ": " ACTIVE ", " name ": " organizations/11111111 ", " owner ": { " directoryCustomerId ": " AAAAAAAA " } } , { " creationTime ": " 2022-11-02T00:35:22.696Z ", " displayName ": " example002.co.jp ", " lifecycleState ": " ACTIVE ", " name ": " organizations/22222222 ", " owner ": { " directoryCustomerId ": " BBBBBBBB " } } , { " creationTime ": " 2021-11-11T03:22:50.021Z ", " displayName ": " example003.co.jp ", " lifecycleState ": " ACTIVE ", " name ": " organizations/33333333 ", " owner ": { " directoryCustomerId ": " CCCCCCCC " } } , { " creationTime ": " 2021-10-27T03:09:00.929Z ", " displayName ": " example004.co.jp ", " lifecycleState ": " ACTIVE ", " name ": " organizations/44444444 ", " owner ": { " directoryCustomerId ": " DDDDDDDD " } } , { " creationTime ": " 2021-08-12T08:08:27.729Z ", " displayName ": " example005.co.jp ", " lifecycleState ": " ACTIVE ", " name ": " organizations/55555555 ", " owner ": { " directoryCustomerId ": " EEEEEEEE " } } ] 実例 組織 組織に関する情報の取得には、 gcloud organizations list コマンドを使用しますが、その中から特定の値を抽出する方法をいくつかご紹介します。 組織名 (ドメイン名) を抽出 組織名の key は displayName ですので、以下のようにコマンドを実行すると組織名を抽出できます。 $ gcloud organizations list -- format json | jq - r '.[].displayName' example001 . co . jp example002 . co . jp example003 . co . jp example004 . co . jp example005 . co . jp 組織 ID を抽出 組織 ID の key は name ですので、以下のようにコマンドを実行すると組織 ID を抽出できます。 $ gcloud organizations list -- format json | jq - r '.[].name' organizations /11111111 organizations /22222222 organizations /33333333 organizations /44444444 organizations /55555555 ID 部分だけを抽出したい場合、"organizations/" は不要となるので除外します。 ( どちらも結果は同じ ) # gsub に渡して置換するパターン $ gcloud organizations list -- format json | jq - r '.[].name | gsub("organizations/";"")' 11111111 22222222 33333333 44444444 55555555 # sed に渡して置換するパターン $ gcloud organizations list -- format json | jq - r '.[].name' | sed - e " s | organizations /||" 11111111 22222222 33333333 44444444 55555555 条件に合致する値を抽出 select を使用して条件 (組織名) に合致する値 (組織 ID) を抽出します。 # gsub に渡して置換するパターン $ gcloud organizations list -- format json | jq - r '.[] | select(.displayName == "example001.co.jp") | .name | gsub("organizations/";"")' 11111111 # sed に渡して置換するパターン $ gcloud organizations list -- format json | jq - r '.[] | select(.displayName == "example001.co.jp") | .name' | sed - e " s | organizations /||" 11111111 key を , (カンマ) で区切れば複数の値 (組織 ID と 顧客 ID) も抽出可能です。 # gsub に渡して置換するパターン $ gcloud organizations list -- format json | jq - r '.[] | select(.displayName == "example001.co.jp") | .displayName,.name,.owner.directoryCustomerId | gsub("organizations/";"")' example001 . co . jp 11111111 AAAAAAAA # sed に渡して置換するパターン gcloud organizations list -- format json | jq - r '.[] | select(.displayName == "example001.co.jp") | .displayName,.name,.owner.directoryCustomerId' | sed - e " s | organizations /||" example001 . co . jp 11111111 AAAAAAAA フォルダ フォルダに関する情報の取得には、 gcloud resource-manager folders list コマンドを使用しますが、その中から特定の値を抽出する方法をいくつかご紹介します。 出力例は以下のとおりです。 $ gcloud resource - manager folders list -- organization =$ { ORG_ID } -- format json [ { " createTime ": " 2021-12-26T15:07:59.662Z ", " displayName ": " dev ", " lifecycleState ": " ACTIVE ", " name ": " folders/11111111 ", " parent ": " organizations/11111111 " } , { " createTime ": " 2021-10-27T03:32:42.669Z ", " displayName ": " stg ", " lifecycleState ": " ACTIVE ", " name ": " folders/22222222 ", " parent ": " organizations/11111111 " } , { " createTime ": " 2022-11-11T11:26:24.972Z ", " displayName ": " prod ", " lifecycleState ": " ACTIVE ", " name ": " folders/33333333 ", " parent ": " organizations/11111111 " } ] フォルダ名を抽出 フォルダ名の key は displayName ですので、以下のようにコマンドを実行するとフォルダ名だけを抽出できます。 $ gcloud resource - manager folders list -- organization =$ { ORG_ID } -- format json | jq - r '.[].displayName' dev stg prod フォルダ ID を抽出 フォルダ ID の key は name ですので、以下のようにコマンドを実行するとフォルダ ID だけを抽出できます。 $ gcloud resource - manager folders list -- organization =$ { ORG_ID } -- format json | jq - r '.[].name' folders /11111111 folders /22222222 folders /33333333 ID 部分だけを抽出したい場合、"folders/" は不要となるので除外します。 ( どちらも結果は同じ ) # gsub に渡して置換するパターン $ gcloud resource - manager folders list -- organization =$ { ORG_ID } -- format json | jq - r '.[].name | gsub("folders/";"")' 11111111 22222222 33333333 # sed に渡して置換するパターン $ gcloud resource - manager folders list -- organization =$ { ORG_ID } -- format json | jq - r '.[].name' | sed - e " s | folders /||" 11111111 22222222 33333333 条件に合致する値を抽出 select を使用して条件 (フォルダ名) に合致する値 (フォルダ ID) だけを抽出します。 # gsub に渡して置換するパターン $ gcloud resource - manager folders list -- organization =$ { ORG_ID } -- format json | jq - r '.[] | select(.displayName == "dev") | .name | gsub("folders/";"")' 11111111 # sed に渡して置換するパターン $ gcloud resource - manager folders list -- organization =$ { ORG_ID } -- format json | jq - r '.[] | select(.displayName == "dev") | .name' | sed - e " s | folders /||" 11111111 プロジェクト プロジェクトに関する情報の取得には、 gcloud projects list コマンドを使用しますが、その中から特定の値を抽出する方法をいくつかご紹介します。 今回の例ではフォルダ配下のプロジェクトをリストするため、 ${FLDR_ID} で特定のフォルダ ID を指定します。 また、組織直下に作成されたプロジェクトリソースをリストする場合は組織 ID を指定します。 $ gcloud projects list -- filter =" parent . id : $ { FLDR_ID } " -- format json [ { " createTime ": " 2023-02-07T04:52:43.403Z ", " lifecycleState ": " ACTIVE ", " name ": " alpha ", " parent ": { " id ": " 11111111 ", " type ": " folder " } , " projectId ": " alpha ", " projectNumber ": " 11111111 " } , { " createTime ": " 2023-01-06T03:57:43.872Z ", " lifecycleState ": " ACTIVE ", " name ": " bravo ", " parent ": { " id ": " 11111111 ", " type ": " folder " } , " projectId ": " bravo ", " projectNumber ": " 22222222 " } , { " createTime ": " 2022-12-20T05:53:14.193Z ", " lifecycleState ": " ACTIVE ", " name ": " charlie ", " parent ": { " id ": " 11111111 ", " type ": " folder " } , " projectId ": " charlie ", " projectNumber ": " 33333333 " } ] プロジェクト名を抽出 プロジェクト名の key は name ですので、以下のようにコマンドを実行するとプロジェクト名だけを抽出できます。 $ gcloud projects list -- filter =" parent . id : $ { FLDR_ID } " -- format json | jq - r '.[].name' alpha bravo charlie プロジェクト ID を抽出 プロジェクト ID の key は projectId' ですので、以下のようにコマンドを実行するとフォルダ ID だけを抽出できます。 $ gcloud projects list -- filter =" parent . id : $ { FLDR_ID } " -- format json | jq - r '.[].projectId' alpha bravo charlie プロジェクト番号 を抽出 プロジェクト ID の key は projectNumber' ですので、以下のようにコマンドを実行するとフォルダ ID だけを抽出できます。 $ gcloud projects list -- filter =" parent . id : $ { FLDR_ID } " -- format json | jq - r '.[].projectNumber' 11111111 22222222 33333333 条件に合致する値を抽出 select を使用して条件 (プロジェクト名) に合致する値 (プロジェクト ID と番号) だけを抽出します。 $ gcloud projects list -- filter =" parent . id : $ { FLDR_ID } " -- format json | jq - r '.[] | select(.name == "alpha") | .projectId, .projectNumber' alpha 11111111 武井 祐介 (記事一覧) 2022年4月入社 / クラウドソリューション部 / 技術2課所属 趣味はゴルフにロードバイク。IaC や CI/CD 周りのサービスやプロダクトが興味分野です。 Google Cloud 認定全冠達成!(2023年6月)
G-gen の杉村です。Google Cloud(旧称 GCP)の VPC では、備え付きのファイアウォール機能である Cloud Next Generation Firewall (Cloud NGFW)が利用できます。そのうち ファイアウォールポリシー (Firewall policies)で利用可能な Cloud NGFW Standard の通信制御機能について解説します。 概要 Cloud NGFW Standard とは 利用可能な制御機能 ルールの適用 料金 FQDN オブジェクト 概要 ユースケース 仕組み その他の仕様 名前解決順序 利用できないドメイン 位置情報オブジェクト 概要 ユースケース 仕組み 脅威インテリジェンス(Google Cloud Threat Intelligence) 概要 ユースケース 仕組み 概要 Cloud NGFW Standard とは Cloud NGFW Standard とは、Google Cloud の VPC ネットワークで利用可能なファイアウォールである、Cloud Next Generation Firewall(以下、Cloud NGFW)の有償機能です。 Cloud NGFW には無償の Essentials と、有償の Standard 、および Enterprise の3ティアが存在します。Essentials は IP アドレスやプロトコル、ポート番号などの L3/L4 レベルの制御のみを提供し、Standard では FQDN ベースの制御や地理情報に基づいた制御など、高度なルールが利用可能です。Enterprise は、IPS(侵入防止サービス)を提供します。 参考 : Cloud NGFW の概要 Cloud NGFW Standard や Essentials、Enterprise を含めた全体の体系については、以下の記事をご参照ください。 blog.g-gen.co.jp 利用可能な制御機能 Cloud NGFW Standard では、以下の制御オブジェクトが利用可能です。 参考 : ファイアウォール ポリシールール No 名称 概要 1 FQDN オブジェクト FQDN (fully qualified domain name) を基にフィルタリング 2 位置情報オブジェクト 接続元/先の地理的情報をもとにフィルタリング 3 脅威インテリジェンス(Google Cloud Threat Intelligence) Google が持つ脅威インテリジェンスをもとにフィルタリング ルールの適用 Cloud NGFW Standard のルールは、 ファイアウォールポリシー でのみ利用可能です。 ファイアウォールポリシーとは、通信制御ルールをまとめるためのグルーピング機能であり、複数のプロジェクトや複数の VPC ネットワークに適用可能です。ファイアウォールポリシーには、階層型ファイアウォールポリシー、グローバルネットワークファイアウォールポリシー、リージョンネットワークファイアウォールポリシー」の3種類があります。 Google Cloud の VPC ネットワークにおいては、ファイアウォールポリシーの他に、単一 VPC ネットワークでのみ利用可能な VPC ファイアウォールルール も存在していますが、こちらでは Cloud NGFW Standard の機能は利用できず、無償で L3/L4 レイヤの制御を提供する Cloud NGFW Essentials のみが利用できます。 ファイアウォールポリシーや VPC ファイアウォールルールの解説は、以下の記事も参照してください。 blog.g-gen.co.jp 料金 Cloud NGFW Standard ルールを使用したファイアウォールポリシーがインターネットと VM 間で発生したトラフィックを評価すると、$0.018/GB の料金が発生します(2025年4月現在)。課金対象は以下のトラフィックです。 インターネットから VM への通信 VM からインターネットへの通信 反対に、以下のトラフィックは課金対象になりません。 インターネットと VM 間の通信のうち、プロキシ型の Cloud Load Balancing で中継される通信 Google Cloud 内に閉じる通信 詳細は、以下の公式料金表を参照してください。 参考 : Cloud Next Generation Firewall の料金 FQDN オブジェクト 概要 FQDN オブジェクト を使うと、アクセス先やアクセス先として FQDN(ドメイン名)を指定できます。 FQDN とは Fully Qualified Domain Name の略であり、 www.google.com や g-gen.co.jp などのいわゆる「ドメイン名」と呼ばれるものを指します。厳密な定義では、 www というホスト名と google.com というドメイン名をつなげて、末尾に . をつけるのが、FQDN の正式なフォーマットです。 FQDN オブジェクトを使うことで、VM から指定の FQDN へのアクセス、または指定の FQDN から VM へのアクセスを禁止したり、許可したりできます。 参考 : ファイアウォール ポリシールール - FQDN オブジェクト ユースケース 当機能を使うことで、例えば「 g-gen.co.jp へのアクセスを禁止する」や、「 update.microsoft.com などいくつかのドメインへのアクセスを許可し、それ以外への外向きアクセスは全て禁止する」などのルールが作成可能です。 仕組み FQDN オブジェクト機能は、パケットのどの部分を見て FQDN を判断しているかという点で注意が必要です。 一般的なファイアウォール製品で URL フィルタリングを行う場合、HTTP ヘッダの HOST ヘッダや、CONNECT メソッドの URI などを読み取って、これをもとにフィルタリングを行います。つまり、L7(アプリケーション層)の情報をもとにしてフィルタリングをするのが一般的です。 一方で VPC ファイアウォールポリシーの FQDN オブジェクトでは、以下のような方法で FQDN を IP アドレスに変換したうえで、 IP アドレスベースで フィルタリングを行います。 FQDN を Cloud DNS により IP アドレスへ名前解決 その IP アドレスをファイアウォールが保持(定期的に更新) 保持した IP アドレスをもとにフィルタリング つまり、HTTP リクエスト等に含まれる URI の情報を見ているわけではなく、あくまで IP ヘッダに含まれる IP アドレスをもとにフィルタリングをしていることになります。 このことから、以下のようなことも起こります。 例えば 1.1.1.1 という IP アドレスに名前解決される hoge.example.com があるとします。しかしこの IP アドレスには別名があり、 fuga.example.com も 1.1.1.1 に名前解決されるとします。 この場合、 hoge.example.com だけをフィルタリング対象としてファイアウォールポリシーに登録した場合でも、 fuga.example.com にはアクセスできなくなります。IP アドレスが同じだからです。また 1.1.1.1 という IP アドレスを直接指定してアクセスしようとしても、同様にアクセスは拒否されます。 その他の仕様 名前解決順序 Cloud DNS による名前解決は、そのファイアウォールポリシーが適用されている VPC の名前解決順序に依存します。 参考 : 名前解決順序 たとえば VPC A に Cloud DNS の限定公開ゾーン(Private Zone) example.com が紐付けられており、この Zone では www.example.com が 10.0.0.10 という A レコードとして登録されているとします。この場合、ファイアウォールポリシーでフィルタリングされる IP アドレスは 10.0.0.10 になります。 このとき仮に、 www.example.com がパブリックで名前解決できる FQDN だとしても、VPC の名前解決順序の仕様として限定公開ゾーンが優先されるため、こちらがフィルタリング対象の IP アドレスとなります。 利用できないドメイン *.example.com などアスタリスクを含むドメイン、すなわちワイルドカードドメインは利用できません。 また .org などトップレベルドメインも指定できません。 位置情報オブジェクト 概要 位置情報オブジェクト では、アクセス元やアクセス先の、地理的情報に基づいてフィルタリングを行うルールを作成できます。 位置情報オブジェクトは、Google が管理するデータベースに基づいて、地域情報と IP アドレスのマッピングから地理的情報を取得します。 参考 : ファイアウォール ポリシールール - 位置情報オブジェクト ルール内で地域を指定するには、US、FR、JP のような、ISO 3166-1 alpha-2 コードを使います。 参考 : Wikipedia - ISO 3166-1 alpha-2 ユースケース 位置情報オブジェクトは、ファイアウォールポリシーのルール内で、アクセス元としてもアクセス先としても利用できるため、特定地域から VM に入ってくるアクセスを拒否(許可)したり、VM から特定地域へ向けて出ていくアクセスを拒否(許可)したりできます。 ただし、あくまで IP アドレスの登録情報により国を判別しているので、必ずしも100%の精度で地域を特定できるわけでは無いことに留意してください。 仕組み 地理情報の判断は、IP アドレスと国コードのマッピングデータベースに基づきます。データベースは Google によって管理されています。 IP アドレスの所有権が移動した場合などに、Google のデータベースへの反映が遅れる場合もあるため、IP アドレスが常に正しい地理情報と紐付いていることは保証されないことに注意が必要です。 脅威インテリジェンス(Google Cloud Threat Intelligence) 概要 脅威インテリジェンス (Google Cloud Threat Intelligence)では、Google が持つ脅威インテリジェンス情報に基づいて、パケットをフィルタリングすることができます。 Google の持つ情報をもとに、以下のような IP アドレスをフィルタリングして拒否したり、許可することができます。以下から、利用したい項目のみを選択的に使用できます。 No 名称 説明 1 iplist-tor-exit-nodes Tor の出口ノード(exit node)として知られている IP アドレス 2 iplist-known-malicious-ips 既知の悪意ある IP アドレス 3 iplist-search-engines-crawlers サーチエンジンのクローラー(bot)の IP アドレス 4 iplist-public-clouds-aws / iplist-public-clouds-azure / iplist-public-clouds-gcp / iplist-public-clouds-google-services Amazon Web Services (AWS) / Microsoft Azure / Google Cloud の IP アドレス / Google サービスの IP アドレス 5 iplist-public-clouds No. 5 のすべてを包含 6 iplist-vpn-providers 評価の低い VPN プロバイダに属する IP アドレス 7 iplist-anon-proxies 公開の匿名プロキシに属する IP アドレス 8 iplist-crypto-miners 暗号通貨マイニングサイトに属する IP アドレス 参考 : ファイアウォール ポリシールール - ファイアウォール ポリシールールの Google 脅威インテリジェンス ユースケース 例として、以下のような設定が可能です。 悪用されている既知の IP アドレスから、VM への上り(Ingress)通信を拒否 VM から、悪用されている既知の IP アドレスへの下り(Egress)通信を拒否 Tor から VM への上り(Ingress)通信を拒否 仕組み 脅威インテリジェンスの IP アドレスリストは、Google によって管理されているため、ブラックボックスです。対象となっている IP アドレス範囲は、IPv4、IPv6、またはその両方の場合もあります。 また当機能は、パケットの振る舞いを見てブロックするわけではなく、あくまで IP アドレス情報に基づいて パケットをフィルタリングする機能です。当機能を使ったとしても、未知の IP アドレスからの攻撃を防げるわけではない点に留意が必要です。あくまで、既知の攻撃元からの侵害の可能性を下げるものであることを、理解して利用してください。 杉村 勇馬 (記事一覧) 執行役員 CTO / クラウドソリューション部 部長 元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。 Follow @y_sugi_it
当記事は みずほリサーチ&テクノロジーズ × G-gen エンジニアコラボレーション企画 で執筆されたものです。 G-gen の佐々木です。当記事では、Google Cloud(旧称 GCP)でマネージドな Kubernetes クラスタを使用することができる Google Kubernetes Engine (GKE)を解説します。Amazon Elastic Kubernetes Service(EKS)や Azure Kubernetes Service(AKS)など、Kubernetes をマネージドに提供するサービスは存在しますが GKE はそれらの中でもよい評判を耳にします。例えばマスターノードの料金が不要、起動が早いといった具合です。GKE は Google Cloud 採択の理由たりえるサービスのため、優先的に仕様を調査することにしました。 Google Kubernetes Engine とは GKE クラスタのアーキテクチャ コントロールプレーン ノード クラスタの運用モード(クラスタタイプ) Autopilot モード Standard モード クラスタの可用性 クラスタのネットワークモード VPC ネイティブクラスタ ルートベースクラスタ GKE Dataplane V2 ロードバランシング クラスタのスケーリング ノードプールとは ノードのスケーリング Pod のスケーリング ストレージ マネージドオプション Kubernetes のストレージ抽象化 バックアップ Kubernetes ボリュームスナップショット Backup for GKE セキュリティ GKE クラスタの認証と認可 ネットワーク分離(コントロールプレーンアクセスとプライベートノード) Workload Identity Federation for GKE クラスタのアップグレード リリースチャンネル アップグレードによるクラスタへの影響 モニタリング AI ワークロードへの対応 クラスタ設計時の考慮事項 GKE のエディションについて 料金 クラスタ管理手数料 運用モードごとの利用料 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 実行のコスト、実行中のワークロードに関係しないリソースの使用などの料金は発生しません。 ただし2026年8月現在、特定のマシンシリーズやアクセラレータ(GPU / TPU)を指定した Pod については、ノード単位の課金(ハードウェア料金 + 管理プレミアム)が適用されます。詳細は後述の「料金」の章を参照してください。 2026年8月現在、GKE バージョン1.32.3以降の Autopilot モードでは、一般用途のワークロードは container-optimized compute platform と呼ばれるコンピューティングプラットフォームで実行されます。実行中のノードのリソースを動的にリサイズできるほか、事前プロビジョニングされたキャパシティにより、新規ノードの起動を待たずに高速なスケーリングができます。 参考 : GKE Autopilot の概要 また2026年8月現在、 Standard モードのクラスタ内でも ComputeClass を使用して Autopilot モードのワークロードを実行できます (GA)。既存の Standard クラスタを使いながら、ワークロード単位で Autopilot の運用モデルを段階的に導入することができます。対応する GKE バージョンなどの詳細は、以下の公式ドキュメントを参照してください。 参考 : GKE Standard での Autopilot モードのワークロードについて Standard モード Standard モードでは、コントロールプレーンのみ Google Cloud によって管理され、クラスタとノードの構成および管理についてはユーザが行います。 ユーザが管理する必要がある主な設定は次の通りです。 管理対象 内容 ノードプール 同様の構成設定をもつノードをグループ化して管理する。 セキュリティ Workload Identity Federation for GKE (旧称 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 に紐づくリソースとなることで得られるメリットが多いことから、現在はルートベースクラスタの利用は推奨されていません。 GKE Dataplane V2 ネットワークモードとは別の軸として、GKE にはクラスタ内のネットワーク処理を担うデータプレーンの実装として GKE Dataplane V2 があります。 GKE Dataplane V2 は eBPF をベースとした高性能なデータプレーンであり、従来の kube-proxy と iptables による実装を置き換えるものです。2026年8月現在、Autopilot / Standard のどちらの運用モードでも、新規クラスタのデフォルトのデータプレーンとなっています。 GKE Dataplane V2 では、アドオンを追加することなく Kubernetes のネットワークポリシーを適用できるほか、ネットワークポリシーロギングによってクラスタ内のネットワークアクティビティを可視化することができます。 参考 : GKE Dataplane V2 ロードバランシング GKE クラスタ上のワークロードを外部に公開する場合、Kubernetes の Service や Ingress リソースを使用して、Google Cloud のロードバランサを構成することができます。 レイヤ7の負荷分散には従来 Ingress リソースが使用されてきましたが、2026年8月現在、Ingress の後継である Gateway API の使用が推奨されています。 Gateway API は、Ingress よりも表現力と拡張性の高いロードバランシングの標準仕様です。クラスタ運用者とアプリケーション開発者が管理するリソースを分離できるロール指向の設計となっており、GKE では GKE Gateway コントローラ を通じて Cloud Load Balancing と統合されています。シングルクラスタ用・マルチクラスタ用のいずれのコントローラも GA となっており、既存の Ingress リソースも引き続き使用することができます。 参考 : Gateway API について GKE における Gateway API の詳細については、以下の記事を参照してください。 blog.g-gen.co.jp クラスタのスケーリング 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 のリソースリクエスト 2026年8月現在 Preview 公開 水平 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 ファイルサーバー Cloud Filestore なお、コンテナイメージレジストリとして提供されていた Container Registry は2025年3月18日にシャットダウンされており、2026年8月現在は後継の Artifact Registry を使用します。 参考 : Container Registry からの移行 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 では、コントロールプレーンとノードをインターネットから分離する構成を「 限定公開クラスタ 」と呼び、クラスタ作成時のみ設定することができました。 2026年8月現在、この構成は コントロールプレーンへのアクセス設定 と ノードのネットワーク設定 という2つの独立した設定に再編されており、いずれも クラスタ作成後に、クラスタを再作成することなく変更できます。 コントロールプレーンへのアクセス方法として、以下の2種類のエンドポイントを構成できます。 エンドポイント 説明 DNS ベースエンドポイント(推奨) コントロールプレーンに一意の DNS 名でアクセスする。アクセス可否は IAM で制御されるため、Google Cloud API に到達できるネットワークであればどこからでもアクセスでき、踏み台サーバーやプロキシが不要になる。VPC Service Controls と組み合わせた多層防御も可能。 IP ベースエンドポイント 従来のパブリックエンドポイントおよびプライベートエンドポイント。 承認済みネットワーク を設定し、アクセス元 IP アドレスを制限することができる。 ノード側は プライベートノード として構成することで、ノードにプライベート IP アドレスのみを付与し、インターネットからの直接アクセスを遮断することができます。 外部ネットワークからノード上のワークロードにアクセスする場合は、LoadBalancer や Ingress などの Service を作成し、ロードバランサを使用してワークロードを公開できるように設定します。 プライベートノードで構成したクラスタに対するアクセスの例 参考 : GKE でのネットワーク分離について DNS ベースエンドポイントの詳細については、以下の記事を参照してください。 blog.g-gen.co.jp Workload Identity Federation for GKE GKE クラスタ内の Pod から Google Cloud 内の他のリソースにアクセスする場合、クラスタに設定した IAM サービスアカウントの認証情報を使用することができますが、その場合、クラスタ内のすべての Pod が IAM サービスアカウントの認証情報を使用することができてしまいます。 GKE では、より安全な方法として Workload Identity Federation for GKE の使用が推奨されます。 Workload Identity Federation for GKE では、 Kubernetes のリソースである ServiceAccount と IAM サービスアカウントを紐付ける ことで、その Kubernetes の ServiceAccount を使用する Pod だけが Google Cloud のリソースにアクセスすることができます。 blog.g-gen.co.jp また、より簡略化された方法として、Kubernetes の ServiceAccount に IAM ロールを直接紐づけることもできます。 blog.g-gen.co.jp クラスタのアップグレード リリースチャンネル Kubernetes では、セキュリティの更新や既知の問題の修正、新機能導入のため、頻繁にアップデートがリリースされています。 GKE では、クラスタを リリースチャンネル に登録することで、クラスタのアップグレードを自動で管理することができます。 2026年8月現在、リリースチャンネルは4種類あり、Kubernetes のアップデートが GKE クラスタにリリースされるまでの早さや、1つのマイナーバージョンに留まれる期間を制御することができます。 リリースチャンネル Kubernetes のアップデートから GKE にリリースされるまでの期間 備考 Rapid アップストリーム Kubernetes の GA から1~2週間後 GKE の SLA 対象外のため、検証環境での使用が推奨される。 Regular Rapid チャンネルのリリースから約2ヶ月後 デフォルトの設定 Stable Regular チャンネルのリリースから3~4ヶ月後 Extended - 長期サポート向けのチャンネル。1つのマイナーバージョンに最大24ヶ月間留まることができる。 GKE の各マイナーバージョンは約14ヶ月間の標準サポートの対象となり、その後、Extended チャンネルのクラスタは約10ヶ月間の延長サポート期間に入ります。 延長サポート期間中のクラスタには、通常のクラスタ管理手数料に加えて $0.50 / クラスタ / 時間 の延長サポート料金が発生します。 特定のバージョンの 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 クラスタで実行されるワークロードをモニタリングすることができます。 AI ワークロードへの対応 GKE は、AI / ML ワークロードの実行基盤としても使用することができます。 ノードに GPU や TPU を接続してワークロードから使用でき、Autopilot / Standard のどちらの運用モードにも対応しています。Autopilot モードでは、ドライバのインストールやノードのプロビジョニングも GKE によって管理されます。 なお、先述の通り、Autopilot モードで GPU / TPU を使用する Pod にはノード単位の課金が適用されます。 また、2026年8月現在、推論ワークロード向けの機能として、LLM の推論に最適化されたルーティングを行う GKE Inference Gateway や、モデルやアクセラレータの選定・デプロイ構成についてベンチマークに基づく推奨を確認できる GKE Inference Quickstart が GA となっています。 参考 : GKE での AI / ML ワークロードの概要 GKE の AI 推論関連の機能については、以下の記事もあわせて参照してください。 blog.g-gen.co.jp blog.g-gen.co.jp クラスタ設計時の考慮事項 ここまで解説してきたように、GKE を使用する際には様々な要素を考慮する必要があります。 クラスタ設計時に特に気をつけなければならない点としては、以下のような クラスタ作成後に変更できない 設定項目があります。 項目 検討内容 運用モード まずは構築・運用負荷の低い Autopilot モードを検討し、Autopilot モードでは達成できない要件がある場合に Standard モードを選択します。 可用性タイプ Autopilot モードの場合は自動的にリージョンクラスタとして構成されます。 Standard モードのクラスタを使用する場合は、当記事で解説したコントロールプレーンおよびノードの冗長化に伴うトレードオフを考慮します。 ネットワークモード Pod が VPC に紐づく多数の機能を利用することができる VPC ネイティブクラスタの利用が推奨されます。 VPC ネイティブクラスタでは Service や Pod が VPC で使用できる IP アドレスを消費するため、それが許容できない場合はルートベースクラスタを検討します。 GKE のエディションについて かつての GKE には、基本の Standard エディション と、従来の Anthos の後継としてマルチクラスタ管理機能を強化した上位エディションの GKE Enterprise (Enterprise エディション)が存在しました。 2025年9月に GKE Enterprise の機能は標準の GKE に統合され、 2026年8月現在、GKE はエディションや tier の区別のない単一のサービスとして提供されています。 これに伴い、複数の GKE クラスタや Google Cloud 以外の Kubernetes クラスタを フリート と呼ばれる論理グループにまとめて管理する機能や、大規模なマルチクラスタの管理に役立つ以下のような機能を、GKE の標準機能として使用することができます。 フリート全体で同じクラスタ構成、機能、セキュリティポリシーを自動的に構成するポリシー管理ツール マルチクラスタ Ingress 、マネージドなサービスメッシュなどのマルチクラスタに対応したネットワーク管理機能 フリート全体で一貫した ID 管理機能 フリート内のクラスタやアプリケーションのモニタリング、トラブルシューティングを可能にするオブザーバビリティ機能 Teams 機能(クラスタを管理する単位「Team」を提供) 参考 : GKE は 10 周年!新機能とよりお得な料金でお祝いしましょう 料金 GKE の利用料金は、 クラスタ管理手数料 + 運用モードごとの利用料 で決まります。 クラスタ管理手数料 2026年8月現在、GKE では、運用モードや可用性タイプ、クラスタの規模に関係なく、1クラスタあたり $0.10 / 時間 のクラスタ管理手数料が発生します(1秒単位の課金)。 シングルゾーンクラスタもしくは Autopilot モードのクラスタの場合、 月額$74.40の無料枠 があり、請求先アカウントごとに提供されます。 クラスタが1つであれば、クラスタの管理手数料は無料枠ですべてカバーされます。 なお、先述の通り、延長サポート期間中のクラスタには $0.50 / クラスタ / 時間 の延長サポート料金が追加で発生します。 運用モードごとの利用料 Autopilot モード Autopilot モードのクラスタでは、一般用途のワークロードの場合、ノード上で実行中の Pod でリクエストされている CPU 、メモリ、エフェメラルストレージリソースに対して料金が発生します。 ノードの未使用のコンピューティングリソースや OS 実行のコスト、実行中のワークロードに関係しないリソースの使用などの料金は発生しません。 一方、2026年8月現在、特定のマシンシリーズやアクセラレータ(GPU / TPU)を指定した Pod については、Pod 単位ではなく、 Pod が実行されるノードのハードウェアに対する料金と管理プレミアムが発生する ノード単位の課金が適用されます。 また、 Spot Pod や 確約利用割引 を使用することで、料金を節約することができます。 リージョンごとの最新の単価については、 GKE の料金ページ を参照してください。 Standard モード Standard モードのクラスタでは、ノードを構成する Compute Engine インスタンスに対して料金が発生します。 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 では、従来はコントロールプレーンとノードのアップグレードをそれぞれユーザが実施する必要がありましたが、2026年8月現在は EKS Auto Mode を使用することで、ノードのプロビジョニングやパッチ適用を自動化することができます。ただし、コントロールプレーンのバージョンアップグレードは Auto Mode でもユーザが開始する必要があり、自動化されるのはアップグレードに追随したノードの更新です。 なお、EKS Auto Mode では、コンピューティング料金に対して Auto Mode の追加料金が発生します。 また、延長サポート期間が終了したクラスタのコントロールプレーンは、Amazon EKS によってサポート対象のバージョンへ自動的にアップグレードされます。この場合も、アドオンとノードのアップデートはユーザが実施する必要があります。 アップグレードのスケジュール GKE と Amazon EKS とでは、Kubernetes の新しいバージョンがリリースされてから利用できるようになるまでの期間と、バージョンごとのサポート終了のタイミングが異なります。 最新のスケジュールについては以下のドキュメントを参照してください。 GKE リリーススケジュール EKS リリーススケジュール リリースまでのスケジュール GKE のほうが、比較的短い期間で Kubernetes の新しいバージョンに対応する傾向があります。 Rapid のリリースチャンネルでは SLA が適用されないことには注意が必要ですが、早い段階から新バージョンの検証を行うことができます。 サポート期間 GKE では、各マイナーバージョンが約14ヶ月間の標準サポートの対象となり、Extended チャンネルを使用することで、さらに約10ヶ月間の延長サポートを受けることができます。 Amazon EKS でも同様に、標準サポート(約14ヶ月間)の終了後、12ヶ月間の延長サポートが提供されています。 どちらも延長サポート期間中は追加料金が発生します(後述の「クラスタの料金について」を参照)。 Ingress で使用されるロードバランサについて ワークロードに対する レイヤ7 のトラフィックを負荷分散したい場合、Kubernetes の Ingress リソースを利用します。 Ingress リソースで使用されるロードバランサは、GKE では Google Cloud の アプリケーションロードバランサ (旧称 HTTP(S) ロードバランサ)、Amazon EKS では AWS の Application Load Balancer(ALB) となっています。 AWS の ALB は自動でスケーリングされるため、大半のワークロードには事前準備なしで対応できますが、急激なトラフィックのスパイクが予測される場合は、 キャパシティ予約 (LCU 予約)による事前の容量確保や、AWS サポートへの Pre-warming (暖機運転)の依頼が推奨されています。 それに対して、Google Cloud のアプリケーションロードバランサは常にトラフィックのスパイクに対応できるようになっており、 キャパシティ予約や Pre-warming などの事前準備の必要がありません。 2026年8月現在、両者の差は、スパイクに備えた事前準備の要否にあります。 参考 : Application Load Balancer のキャパシティ予約 クラスタのモニタリングについて リソースのモニタリングについて、GKE では、Cloud Monitoring との統合がデフォルトで有効となっていますが、Amazon EKS では Amazon CloudWatch の Container Insights を手動で設定するか、サードパーティツールを使用する必要があります。 クラスタの料金について EKS では、GKE 同様に1クラスタあたり $0.10 / 時間 の料金が発生します。 GKE の場合、クラスタの可用性モードにもよりますが、無料枠によって1クラスタぶんの料金が相殺されるため、EKS よりも料金が安くなる傾向があります。 延長サポート期間中のクラスタの料金は、2026年8月現在、GKE が $0.50 / クラスタ / 時間 の追加料金であるのに対し、Amazon EKS はクラスタ料金自体が $0.60 / クラスタ / 時間 に引き上げられます。 なお、Amazon EKS ではクラスタのアップグレードポリシーがデフォルトで延長サポート有効となっているため、意図せず延長サポート料金が発生しないように注意が必要です。 佐々木 駿太 (記事一覧) クラウドソリューション部 クラウドエンジニアリング1課 北海道在住 大学院まで社会心理学を専攻し、AI に興味を持ち IT 業界へ。2022年6月に G-gen にジョイン。Google Cloud Partner Top Engineer に選出(2024 / 2025 Fellow / 2026)。好きな Google Cloud プロダクトは Cloud Run。 趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。最近は法律の勉強にも目覚め、2級知的財産管理技能士を取得。 Follow @sasashun0805
当記事では、Google Cloud(旧称 GCP)の 予算アラート の設定方法を紹介します。請求先アカウントに予算アラートを設定することで、請求額が一定を超えたり、超えそうになったときに、メール通知することができます。 概要 予算アラートとは 請求先アカウントについて 通知先 設定の概要 通知チャンネルの準備 通知チャンネルの設定 予算とアラートの設定 動作確認 概要 予算アラートとは Google Cloud の請求先アカウントに 予算アラート を設定することで、指定期間内の請求額がしきい値を超えたときに、E メールで通知することができます。通知を設定しておけば、予期しない請求に早めに気が付くことができます。 予算 (Budget)という設定オブジェクトを請求先アカウントに作成し、その中に予算アラートを設定します。 予算は、請求先アカウント全体を対象とすることができるほか、特定のプロジェクトやフォルダ、特定の Google Cloud サービスのみを対象とすることもできます。 参考 : 予算と予算アラートの作成、編集、削除 請求先アカウントについて 前提となる Google Cloud の請求の仕組みや請求先アカウントについては、以下の記事を参照して下さい。 blog.g-gen.co.jp 通知先 予算アラートは2026年2月現在、 メール通知のみ が可能です。以下のいずれか、または複数を選択して通知先として設定できます。 請求先アカウントに対して、「請求先アカウント管理者」または「請求先アカウント ユーザー」ロールを持っている人 Google Cloud プロジェクトに対して、「オーナー」ロールを持っている人 Cloud Monitoring の通知チャンネル(メールのみ) 上記のとおり、予算アラートの通知先として Cloud Monitoring の通知チャンネルを指定できますが、指定できるのはメールの通知チャンネルのみであり、Slack や SMS 等の通知チャンネルは予算アラートからは使用できません。 参考 : 予算アラートメールの受信者をカスタマイズする - 始める前に: メール通知チャンネルを作成する なお当記事では、後述する Slack の メールインテグレーション 機能を利用することで、Slack の DM やチャンネルへの通知を実現しています。 設定の概要 当記事では以下の図のように、あるプロジェクトの予算を¥10,000/月とし、3種類のしきい値を超えた場合にアラート通知をする設定をします。 今回は、「E メール」「Slack(メールインテグレーション)」の2つの通知先を設定します。実際には、環境に合わせて適切な通知先を選択してください。 構成 設定は、以下の流れで行います。当記事では Google Cloud コンソールを使った設定方法を紹介しますが、 コンソールの表記や見た目は変わる 可能性があるため、参考リンクも確認しながら作業を行って下さい。 通知チャンネルの準備 通知チャンネルの設定 予算とアラートの設定 通知チャンネルの準備 まずは、通知先メールアドレスを用意します。個人アドレスではなくメーリングリストを用意することが望ましいでしょう。 さらに、Slack 通知用のメールアドレスを事前に作成します。Slack では、 メールインテグレーション 機能を使うことで、チャンネルへの通知用メールアドレスを簡単に作成可能です。 作成方法は以下の Slack 公式ドキュメントを参照してください。 参考 : Slack にメールを送信する - チャンネルまたは DM 用メールアドレスを作成する 通知チャンネルの設定 参考 : 通知チャンネルを作成して管理する 通知チャンネルは、いずれかの Google Cloud プロジェクトに作成します。作業者は、Google Cloud プロジェクトのレベルで モニタリング編集者 ( roles/monitoring.editor )ロールが必要です。 まず、Google Cloud コンソールで [モニタリング] > [アラート] へ進みます。 コンソール画面 [EDIT NOTIFICATION CHANNELS] をクリックします。 EDIT NOTIFICATION CHANNELS [メール] セクションで [ADD NEW] をクリックします。 通知チャンネルの作成① Email Address にメールアドレス、 Display Name は任意の表示名を入力し [SAVE] をクリックします。 通知チャンネルの作成② 保存すると、以下のように通知先が追加されます。 通知チャンネルの作成③ 予算とアラートの設定 参考 : 予算と予算アラートの作成、編集、削除 予算とアラートの設定作業を行うには、請求先アカウントに対して、 請求先アカウント管理者 ( roles/billing.admin )ロールまたは 請求先アカウントの費用管理者 ( roles/billing.costsManager )ロールが必要です。 Google Cloud コンソールの上部検索ボックスに「予算とアラート」と入力し、サジェストされた [予算とアラート] ページへ進みます。 検索ボックス 次の画面で、予算を設定する対象の請求先アカウントを選択し、 [予算とアラートのページに移動] をクリックします。 予算とアラート 以下の項目を入力し、[次へ] をクリックします。用途に合わせて設定項目は変更してください。 項目 設定値 備考 名前 Monthly-Billing-Alert 任意の表示名 期間 月別 ここでは月別(単月)とするが、四半期、年間、あるいは任意の期間指定も可能 プロジェクト 対象プロジェクト 予算の対象とするプロジェクトを選択。組織全体やフォルダ、対象サービスも指定可能 予算の作成(範囲) 目標金額 に ¥10,000 を入力し、[次へ] をクリックします。 予算の作成(金額) Set alert threshold rules にアラート通知をするしきい値を入力します。 通知の管理 で モニタリング メール通知チャネルをこの予算にリンクする にチェックを入れ、 プロジェクト に対象のプロジェクト、 Nortification Channels に 2. 通知チャンネルの設定 で設定をした通知先を選択し、 [終了] をクリックします。 予算の作成(操作) 動作確認 予算のしきい値に達すると以下のような通知メールが届きます。送信者は Google Cloud Billing Alerts <CloudPlatform-noreply@google.com> です。 予算アラートのメール通知例 G-gen 編集部 (記事一覧) 株式会社G-genは、サーバーワークスグループとして「クラウドで、世界を、もっと、はたらきやすく」をビジョンに掲げ、クラウドの導入から最適化までを支援している Google Cloud 専業のクラウドインテグレーターです。
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
本記事では、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 するといったパイプライン設計を行うと良いでしょう。 G-gen 編集部 (記事一覧) 株式会社G-genは、サーバーワークスグループとして「クラウドで、世界を、もっと、はたらきやすく」をビジョンに掲げ、クラウドの導入から最適化までを支援している Google Cloud 専業のクラウドインテグレーターです。
当記事では、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を使用して 予測データを取得する方法をご紹介できればと思います。 G-gen 編集部 (記事一覧) 株式会社G-genは、サーバーワークスグループとして「クラウドで、世界を、もっと、はたらきやすく」をビジョンに掲げ、クラウドの導入から最適化までを支援している Google Cloud 専業のクラウドインテグレーターです。
当記事は みずほリサーチ&テクノロジーズ × 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。
当記事では、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 関数で取得したトークンをデコード G-gen 編集部 (記事一覧) 株式会社G-genは、サーバーワークスグループとして「クラウドで、世界を、もっと、はたらきやすく」をビジョンに掲げ、クラウドの導入から最適化までを支援している Google Cloud 専業のクラウドインテグレーターです。
当記事は みずほリサーチ&テクノロジーズ × 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
本記事では 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 G-gen 編集部 (記事一覧) 株式会社G-genは、サーバーワークスグループとして「クラウドで、世界を、もっと、はたらきやすく」をビジョンに掲げ、クラウドの導入から最適化までを支援している Google Cloud 専業のクラウドインテグレーターです。
当記事は みずほリサーチ&テクノロジーズ × 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
当記事では、 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 を変更する必要があります。 参考: プールの削除 G-gen 編集部 (記事一覧) 株式会社G-genは、サーバーワークスグループとして「クラウドで、世界を、もっと、はたらきやすく」をビジョンに掲げ、クラウドの導入から最適化までを支援している Google Cloud 専業のクラウドインテグレーターです。
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