はじめに Link to heading
「Infrastructure as Code (IaC)」は理念としては理解していても、実際のプロジェクトでどう使い分けるかは悩ましいものです。
- TerraformとAnsibleの役割分担は?
- 変数はどこで管理する?
- 環境ごとの差異はどう扱う?
- 本当に再現可能な構成になっているか?
この記事では、GCP上でWordPress マルチテナント環境(10サイト)を構築する過程で確立した Terraform + Ansibleの実践的な運用パターン を共有します。
この記事で扱う内容:
- TerraformとAnsibleの責任分離
- モジュール設計とディレクトリ構造
- 変数管理とシークレット管理
- 冪等性の担保と検証
- 運用フェーズでの変更管理
1. TerraformとAnsibleの責任分離 Link to heading
「何をTerraformで、何をAnsibleで管理するか」 Link to heading
これはIaC運用の最重要設計判断です。
基本原則: インフラ vs 構成 Link to heading
┌─────────────────────────────────────────┐
│ Terraform │
│ 「リソースの存在」を管理 │
│ - VPCネットワーク │
│ - Computeインスタンス │
│ - Cloud SQL │
│ - ロードバランサ │
│ - IAMロール │
└─────────────────────────────────────────┘
↓ 作成
┌─────────────────────────────────────────┐
│ Ansible │
│ 「リソースの状態」を管理 │
│ - パッケージインストール │
│ - 設定ファイル配置 │
│ - サービス起動 │
│ - アプリケーションデプロイ │
└─────────────────────────────────────────┘
具体的な責任分離表 Link to heading
| 項目 | Terraform | Ansible | 理由 |
|---|---|---|---|
| VPCネットワーク作成 | ✅ | ❌ | GCPリソース |
| Computeインスタンス作成 | ✅ | ❌ | GCPリソース |
| Cloud SQL作成 | ✅ | ❌ | GCPリソース |
| Nginx インストール | ❌ | ✅ | OS設定 |
| PHP設定 | ❌ | ✅ | ミドルウェア設定 |
| WordPressデプロイ | ❌ | ✅ | アプリケーション |
| SSL証明書取得 | ❌ | ✅ | アプリケーション層 |
| IAMロール作成 | ✅ | ❌ | GCPリソース |
| Service Account作成 | ✅ | ❌ | GCPリソース |
| ファイアウォールルール | ✅ | ❌ | GCPリソース |
| NFSマウント | ❌ | ✅ | OS設定 |
判断基準 Link to heading
Terraformで管理すべきもの:
1✅ GCP APIで作成・管理されるリソース
2✅ 削除するとデータロスのリスクがあるもの
3✅ 複数環境で共通の定義
4✅ 依存関係が複雑なもの
Ansibleで管理すべきもの:
1✅ OSレベルの設定
2✅ パッケージのインストール
3✅ 設定ファイルの配置・テンプレート化
4✅ サービスの起動・停止
5✅ アプリケーションコードのデプロイ
6✅ 頻繁に変更されるもの
グレーゾーンの判断例 Link to heading
ケース1: Computeインスタンスのメタデータ Link to heading
選択肢:
- Terraformでメタデータとして設定
- Ansibleで動的に取得
今回の判断: Terraformで設定、Ansibleで読み取り
1# Terraform
2resource "google_compute_region_instance_template" "web" {
3 metadata = {
4 env = var.env
5 db_host = module.database.private_ip_address
6 nfs_ip = var.nfs_ip
7 nfs_path = var.nfs_path
8 }
9}
1# Ansible
2- name: メタデータから環境情報取得
3 uri:
4 url: "http://metadata.google.internal/computeMetadata/v1/instance/attributes/db_host"
5 headers:
6 Metadata-Flavor: "Google"
7 return_content: yes
8 register: db_host_metadata
理由: インフラ情報はTerraformが単一真実の情報源(SSOT)
ケース2: データベースパスワード Link to heading
選択肢:
- Terraformで生成してSecret Managerに保存
- Ansibleで生成
今回の判断: Terraformで生成
1# Terraform
2resource "random_password" "db_passwords" {
3 count = 10
4 length = 20
5 special = true
6}
7
8resource "google_secret_manager_secret_version" "db_passwords" {
9 count = 10
10 secret = google_secret_manager_secret.db_passwords[count.index].id
11 secret_data = random_password.db_passwords[count.index].result
12}
理由: インフラ層のリソース(Cloud SQL User)と密接に関連
2. モジュール設計とディレクトリ構造 Link to heading
プロジェクト全体のディレクトリ構造 Link to heading
infra-ai-agent/
├── terraform/
│ ├── modules/ # 再利用可能なモジュール
│ │ ├── network/
│ │ ├── compute/
│ │ ├── database/
│ │ ├── filestore/
│ │ ├── loadbalancer/
│ │ ├── iam/
│ │ └── monitoring/
│ └── environments/ # 環境ごとの設定
│ ├── dev/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── terraform.tfvars
│ │ └── outputs.tf
│ └── prod/
│ ├── main.tf
│ ├── variables.tf
│ ├── terraform.tfvars
│ └── outputs.tf
├── ansible/
│ ├── inventory/ # 動的インベントリ
│ │ └── gcp.yml
│ ├── playbooks/ # Playbook
│ │ └── deploy-wordpress.yml
│ └── roles/ # ロール
│ └── wordpress/
│ ├── tasks/
│ ├── templates/
│ ├── files/
│ └── defaults/
└── scripts/ # 運用スクリプト
└── sync-db-passwords.sh
Terraformモジュール設計原則 Link to heading
原則1: 単一責任の原則 Link to heading
各モジュールは1つのGCPサービスに対応:
1# ❌ 悪い例: すべてを1つのモジュールに
2module "wordpress_infra" {
3 source = "../../modules/all"
4 # すべてのリソースをここで作成
5}
6
7# ✅ 良い例: 責任を分離
8module "network" {
9 source = "../../modules/network"
10}
11
12module "database" {
13 source = "../../modules/database"
14 depends_on = [module.network]
15}
16
17module "compute" {
18 source = "../../modules/compute"
19 depends_on = [module.database]
20}
原則2: 依存関係の明示 Link to heading
1# terraform/environments/prod/main.tf
2module "compute" {
3 source = "../../modules/compute"
4
5 db_host = module.database.private_ip_address # 明示的な依存
6 nfs_ip = module.filestore.nfs_ip
7
8 depends_on = [module.database, module.filestore]
9}
原則3: 出力値の活用 Link to heading
1# terraform/modules/database/outputs.tf
2output "private_ip_address" {
3 description = "Cloud SQL Private IP Address"
4 value = google_sql_database_instance.wordpress.private_ip_address
5}
6
7output "instance_connection_name" {
8 description = "Cloud SQL Instance Connection Name"
9 value = google_sql_database_instance.wordpress.connection_name
10}
11
12output "database_names" {
13 description = "List of database names"
14 value = google_sql_database.wordpress_dbs[*].name
15}
モジュール構造の例: Database Link to heading
terraform/modules/database/
├── main.tf # メインリソース定義
├── variables.tf # 入力変数
├── outputs.tf # 出力値
└── README.md # モジュールのドキュメント
main.tf:
1resource "google_sql_database_instance" "wordpress" {
2 name = "${var.env}-wordpress-db"
3 database_version = "MYSQL_8_0"
4 region = var.region
5
6 settings {
7 tier = var.tier
8 availability_type = var.availability_type
9
10 ip_configuration {
11 ipv4_enabled = false
12 private_network = var.network_id
13 require_ssl = false
14 }
15
16 backup_configuration {
17 enabled = true
18 start_time = "03:00"
19 binary_log_enabled = true
20 }
21 }
22}
23
24resource "google_sql_database" "wordpress_dbs" {
25 count = 10
26 name = "wordpress_db_${count.index + 1}"
27 instance = google_sql_database_instance.wordpress.name
28}
29
30resource "google_sql_user" "wordpress_users" {
31 count = 10
32 name = "wp_user_${count.index + 1}"
33 instance = google_sql_database_instance.wordpress.name
34 password = random_password.db_passwords[count.index].result
35}
variables.tf:
1variable "env" {
2 description = "Environment name"
3 type = string
4}
5
6variable "region" {
7 description = "GCP region"
8 type = string
9}
10
11variable "tier" {
12 description = "Cloud SQL machine tier"
13 type = string
14 default = "db-f1-micro"
15}
16
17variable "network_id" {
18 description = "VPC network ID for private IP"
19 type = string
20}
Ansibleロール設計 Link to heading
ディレクトリ構造 Link to heading
ansible/roles/wordpress/
├── tasks/
│ ├── main.yml # エントリーポイント
│ ├── packages.yml # パッケージインストール
│ ├── nginx.yml # Nginx設定
│ ├── php.yml # PHP設定
│ ├── wpcli.yml # WP-CLIインストール
│ ├── nfs.yml # NFSマウント
│ └── scripts.yml # スクリプト配置
├── templates/
│ ├── nginx-site.conf.j2
│ ├── php-fpm-pool.conf.j2
│ └── setup-wordpress-site.sh.j2
├── files/
│ └── cloudflare-origin-ca.pem
├── defaults/
│ └── main.yml # デフォルト変数
└── handlers/
└── main.yml # サービス再起動ハンドラ
tasks/main.yml (エントリーポイント) Link to heading
1---
2- name: パッケージインストール
3 import_tasks: packages.yml
4 tags: packages
5
6- name: Nginx設定
7 import_tasks: nginx.yml
8 tags: nginx
9
10- name: PHP設定
11 import_tasks: php.yml
12 tags: php
13
14- name: NFS設定
15 import_tasks: nfs.yml
16 tags: nfs
17
18- name: WP-CLI インストール
19 import_tasks: wpcli.yml
20 tags: wpcli
21
22- name: スクリプト配置
23 import_tasks: scripts.yml
24 tags: scripts
これにより、特定のタスクのみ実行可能:
1# Nginxだけ再設定
2ansible-playbook -i inventory/gcp.yml playbooks/deploy-wordpress.yml --tags nginx
3
4# WP-CLIだけ更新
5ansible-playbook -i inventory/gcp.yml playbooks/deploy-wordpress.yml --tags wpcli
3. 変数管理とシークレット管理 Link to heading
変数管理の階層 Link to heading
┌─────────────────────────────────────────┐
│ 1. デフォルト値 (defaults/main.yml) │ 優先度: 低
└────────────┬────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ 2. 環境固有値 (terraform.tfvars) │ 優先度: 中
└────────────┬────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ 3. コマンドライン (-e "var=value") │ 優先度: 高
└─────────────────────────────────────────┘
Terraform変数の管理 Link to heading
terraform.tfvars (本番環境) Link to heading
1# terraform/environments/prod/terraform.tfvars
2env = "prod"
3project_id = "infra-ai-agent"
4region = "asia-northeast1"
5zone = "asia-northeast1-a"
6
7# Compute
8machine_type = "e2-micro"
9min_replicas = 3
10max_replicas = 10
11
12# Database
13db_tier = "db-f1-micro"
14db_availability_type = "ZONAL"
15
16# Filestore
17filestore_tier = "BASIC_HDD"
18filestore_capacity_gb = 1024
19
20# Domains
21domains = [
22 "ai-jisso.tech",
23 "dev-ops.tech",
24 "cloud-native.tech",
25 "kube-master.tech",
26 "infra-code.tech",
27 "serverless-app.tech",
28 "micro-service.tech",
29 "data-pipeline.tech",
30 "ml-platform.tech",
31 "edge-computing.tech"
32]
terraform.tfvars (開発環境) Link to heading
1# terraform/environments/dev/terraform.tfvars
2env = "dev"
3project_id = "infra-ai-agent-dev"
4region = "asia-northeast1"
5zone = "asia-northeast1-a"
6
7# Compute (開発環境は小さめ)
8machine_type = "e2-micro"
9min_replicas = 1
10max_replicas = 3
11
12# Database (開発環境は最小構成)
13db_tier = "db-f1-micro"
14db_availability_type = "ZONAL" # 高可用性は不要
15
16# Filestore (開発環境は最小容量)
17filestore_tier = "BASIC_HDD"
18filestore_capacity_gb = 256
19
20# Domains (開発用ドメイン)
21domains = [
22 "dev.ai-jisso.tech",
23 "staging.ai-jisso.tech"
24]
Ansibleの変数管理 Link to heading
defaults/main.yml Link to heading
1---
2# PHP設定
3php_version: "8.2"
4php_memory_limit: "256M"
5php_max_execution_time: "300"
6php_upload_max_filesize: "64M"
7
8# Nginx設定
9nginx_worker_connections: 1024
10nginx_client_max_body_size: "64M"
11
12# WordPress設定
13wordpress_version: "latest"
14wpcli_url: "https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar"
15wpcli_bin_path: "/usr/local/bin/wp"
16
17# NFS設定
18nfs_mount_point: "/var/www/wordpress"
19nfs_mount_options: "defaults,hard,intr"
Playbook内での変数上書き Link to heading
1# ansible/playbooks/deploy-wordpress.yml
2- name: WordPress デプロイ
3 hosts: label_service_wordpress
4 become: yes
5
6 vars:
7 env: "{{ lookup('env', 'ENV') | default('prod', true) }}"
8 gcp_project_id: "{{ lookup('env', 'GCP_PROJECT_ID') | default('', true) }}"
コマンドラインからの上書き Link to heading
1# 特定の変数を上書きして実行
2ansible-playbook -i inventory/gcp.yml playbooks/deploy-wordpress.yml \
3 -e "db_host=10.168.0.2" \
4 -e "nfs_ip=10.0.3.2" \
5 -e "nfs_path=/wordpress"
シークレット管理 Link to heading
NGパターン Link to heading
1# ❌ 絶対にやってはいけない
2vars:
3 db_password: "my_secret_password" # 平文でコミット
正しいパターン Link to heading
Option 1: Secret Managerから動的取得
1# ✅ 推奨
2- name: Secret Managerからパスワード取得
3 command: >
4 gcloud secrets versions access latest
5 --secret={{ env }}-wordpress-db-password-{{ item }}
6 --project={{ gcp_project_id }}
7 register: db_password
8 no_log: true # ログに出力しない
9 loop: "{{ range(1, 11) | list }}"
Option 2: Ansible Vault
1# パスワードを暗号化
2ansible-vault encrypt_string 'my_secret_password' --name 'db_password'
3
4# 実行時に復号化
5ansible-playbook -i inventory/gcp.yml playbooks/deploy-wordpress.yml \
6 --ask-vault-pass
Option 3: 環境変数
1vars:
2 db_password: "{{ lookup('env', 'DB_PASSWORD') }}"
1# 実行時に環境変数を設定
2export DB_PASSWORD="my_secret_password"
3ansible-playbook -i inventory/gcp.yml playbooks/deploy-wordpress.yml
4. 冪等性の担保と検証 Link to heading
冪等性とは Link to heading
同じ操作を複数回実行しても、結果が変わらない性質
terraform apply # 1回目: リソース作成
terraform apply # 2回目: 何も変更なし ← 冪等性
ansible-playbook deploy.yml # 1回目: 設定適用
ansible-playbook deploy.yml # 2回目: 何も変更なし ← 冪等性
Terraformの冪等性 Link to heading
Terraformは宣言的なため、基本的に冪等性が保証されます:
1# 常に同じ状態を宣言
2resource "google_compute_instance" "web" {
3 name = "prod-web-server"
4 machine_type = "e2-micro"
5}
冪等性を壊す例 Link to heading
1# ❌ 悪い例: タイムスタンプを含む
2resource "google_compute_instance" "web" {
3 name = "web-${timestamp()}" # 実行のたびに異なる名前
4}
5
6# ✅ 良い例: 固定値または環境変数
7resource "google_compute_instance" "web" {
8 name = "${var.env}-web-server"
9}
冪等性の検証 Link to heading
1# 1回目の実行
2terraform apply
3
4# 2回目の実行(変更がないことを確認)
5terraform plan
6# 出力: No changes. Your infrastructure matches the configuration.
Ansibleの冪等性 Link to heading
Ansibleも基本的に冪等性を持つが、コマンド実行時は注意が必要:
冪等的なタスク Link to heading
1# ✅ パッケージインストール(冪等的)
2- name: Nginxインストール
3 apt:
4 name: nginx
5 state: present # すでにインストール済みなら何もしない
非冪等的なタスク Link to heading
1# ❌ コマンド実行(常に実行される)
2- name: ファイルに追記
3 command: echo "log entry" >> /var/log/myapp.log
4 # 実行のたびに追記される!
冪等性を担保する方法 Link to heading
方法1: changed_when を使う
1- name: 設定ファイルの存在確認
2 command: test -f /etc/myapp/config.yml
3 register: config_check
4 changed_when: false # 常に "changed" にならない
5 failed_when: config_check.rc not in [0, 1]
方法2: creates パラメータを使う
1- name: WP-CLI ダウンロード
2 get_url:
3 url: "{{ wpcli_url }}"
4 dest: /tmp/wp-cli.phar
5 creates: /tmp/wp-cli.phar # ファイルが存在すればスキップ
方法3: stat モジュールで事前チェック
1- name: 設定ファイルの存在確認
2 stat:
3 path: /etc/nginx/sites-available/wordpress.conf
4 register: nginx_conf
5
6- name: Nginx設定ファイル配置
7 template:
8 src: nginx-site.conf.j2
9 dest: /etc/nginx/sites-available/wordpress.conf
10 when: not nginx_conf.stat.exists
冪等性のテスト Link to heading
Ansible Dry Run:
1# チェックモード(実際には変更しない)
2ansible-playbook -i inventory/gcp.yml playbooks/deploy-wordpress.yml --check
3
4# 差分表示
5ansible-playbook -i inventory/gcp.yml playbooks/deploy-wordpress.yml --check --diff
2回実行して検証:
1# 1回目
2ansible-playbook -i inventory/gcp.yml playbooks/deploy-wordpress.yml
3
4# 2回目(変更がないことを確認)
5ansible-playbook -i inventory/gcp.yml playbooks/deploy-wordpress.yml
6
7# 出力例
8# PLAY RECAP *******************************************
9# prod-web-l0br : ok=25 changed=0 unreachable=0 failed=0
10# ^^^^^^^^^ 変更なし!
5. 運用フェーズでの変更管理 Link to heading
変更の種類と対応方法 Link to heading
| 変更の種類 | 使用ツール | 例 |
|---|---|---|
| インフラリソース追加 | Terraform | Computeインスタンス追加 |
| インフラ設定変更 | Terraform | Cloud SQL SSL無効化 |
| ミドルウェア設定変更 | Ansible | Nginx worker数変更 |
| アプリケーションデプロイ | Ansible | WordPress更新 |
| 緊急対応 | 手動 + 後でIaC化 | サービス再起動 |
変更フロー Link to heading
graph TD
A[変更要求] --> B{変更の種類}
B -->|インフラ| C[Terraform修正]
B -->|構成| D[Ansible修正]
C --> E[terraform plan]
E --> F{影響範囲確認}
F -->|OK| G[terraform apply]
F -->|NG| H[設計見直し]
D --> I[ansible-playbook --check]
I --> J{影響範囲確認}
J -->|OK| K[ansible-playbook]
J -->|NG| H
G --> L[検証]
K --> L
L --> M[完了]
ケーススタディ1: Cloud SQL SSL無効化 Link to heading
変更内容: require_ssl = true → false
手順:
1# 1. Terraform設定変更
2cd terraform/environments/prod
3vim ../../modules/database/main.tf
4# require_ssl = false に変更
5
6# 2. 差分確認
7terraform plan
8# Cloud SQL設定が変更されることを確認
9
10# 3. 適用
11terraform apply
12
13# 4. 影響確認
14gcloud sql instances describe prod-wordpress-db \
15 --format="value(settings.ipConfiguration.requireSsl)"
16# 出力: False
17
18# 5. WordPressから接続テスト
19ansible-playbook -i ../../ansible/inventory/gcp.yml \
20 ../../ansible/playbooks/deploy-wordpress.yml
結果: インスタンステンプレートが変更され、インスタンスが再作成された
学び: Instance Template変更はインスタンス再作成を引き起こす
ケーススタディ2: Nginx設定変更 Link to heading
変更内容: worker_connections を 1024 → 2048 に変更
手順:
1# 1. Ansible変数変更
2cd ansible/roles/wordpress
3vim defaults/main.yml
4# nginx_worker_connections: 2048 に変更
5
6# 2. ドライラン
7cd ../../
8ansible-playbook -i inventory/gcp.yml playbooks/deploy-wordpress.yml \
9 --tags nginx --check --diff
10
11# 3. 適用
12ansible-playbook -i inventory/gcp.yml playbooks/deploy-wordpress.yml \
13 --tags nginx
14
15# 4. 確認
16ansible -i inventory/gcp.yml label_service_wordpress \
17 -m shell -a "nginx -T | grep worker_connections" --become
結果: Nginxがリロードされ、新しい設定が反映された
学び: タグを使って部分的な変更が可能
ケーススタディ3: 緊急対応(サービス再起動) Link to heading
状況: WordPressサイトが応答しなくなった
緊急対応:
1# 手動でサービス再起動
2gcloud compute ssh prod-web-l0br \
3 --zone=asia-northeast1-a \
4 --tunnel-through-iap \
5 --command="sudo systemctl restart php8.2-fpm nginx"
後処理:
1# 原因調査
2ansible-playbook -i inventory/gcp.yml playbooks/deploy-wordpress.yml \
3 --tags nginx,php
4
5# 設定が正しいことを確認
6# 必要に応じてAnsible Playbookを修正
学び: 緊急時は手動対応OK、ただし後で必ずIaC化
Gitワークフロー Link to heading
1# 1. ブランチ作成
2git checkout -b feature/disable-cloud-sql-ssl
3
4# 2. 変更実施
5vim terraform/modules/database/main.tf
6
7# 3. コミット
8git add terraform/modules/database/main.tf
9git commit -m "feat: disable Cloud SQL SSL requirement for private IP connection"
10
11# 4. テスト環境で検証
12cd terraform/environments/dev
13terraform plan
14terraform apply
15
16# 5. プッシュ
17git push origin feature/disable-cloud-sql-ssl
18
19# 6. プルリクエスト作成
20# GitHub上でレビュー
21
22# 7. マージ後、本番適用
23git checkout main
24git pull
25cd terraform/environments/prod
26terraform apply
6. ベストプラクティス Link to heading
Terraform Link to heading
1□ モジュール化で再利用性を高める
2□ terraform.tfvarsで環境ごとの差異を管理
3□ terraform planで必ず変更内容を確認
4□ ステートファイルをリモートバックエンドで管理(GCS等)
5□ ステートファイルのロック機能を有効化
6□ 破壊的変更は lifecycle.prevent_destroy で保護
7□ 出力値を活用してモジュール間連携
Ansible Link to heading
1□ ロールで機能を分割
2□ タグで部分実行を可能に
3□ テンプレートで設定ファイルを動的生成
4□ ハンドラでサービス再起動を自動化
5□ no_log でシークレット情報の漏洩を防止
6□ changed_when で冪等性を担保
7□ --check --diff でドライラン
変数管理 Link to heading
1□ シークレットは平文で保存しない
2□ Secret Manager / Ansible Vaultを活用
3□ 環境ごとの差異はtfvarsで管理
4□ デフォルト値はdefaults/main.ymlに
5□ コマンドラインからの上書きを許可
運用 Link to heading
1□ 変更前に必ずplanまたは--check
2□ Gitでバージョン管理
3□ プルリクエストでレビュー
4□ テスト環境で先に検証
5□ ドキュメントを更新
6□ 変更履歴をコミットメッセージに記録
まとめ Link to heading
TerraformとAnsibleの使い分け Link to heading
| ツール | 役割 | 再実行の影響 |
|---|---|---|
| Terraform | インフラリソースの作成・管理 | べき等(差分のみ適用) |
| Ansible | OS・ミドルウェア・アプリの設定 | べき等(変更検知) |
成功のポイント Link to heading
明確な責任分離
- Terraformはインフラ層
- Ansibleは構成管理層
変数管理の一元化
- 環境ごとの差異をtfvarsで管理
- シークレットはSecret Managerで管理
冪等性の担保
- 何度実行しても安全
- ドライランで事前確認
Gitによるバージョン管理
- すべての変更を記録
- レビュープロセスの導入
ドキュメント化
- モジュールの使い方を記録
- 運用手順を文書化
次のステップ Link to heading
- CI/CDパイプラインの構築
- Terraformステートのリモート管理
- Ansibleの実行をCI/CDに統合
- 自動テストの追加
参考リンク Link to heading
- Terraform Best Practices
- Ansible Best Practices
- Google Cloud Terraform Provider
- Ansible gcp_compute collection
この記事のコード Link to heading
GitHub: infra-ai-agent
Terraformモジュール:
Ansible Playbook:
この記事が役に立ったら: GitHub Starをいただけると嬉しいです! infra-ai-agent