
こんにちは。Looopでシステムアーキテクチャやインフラのエンジニアをしている中澤です🙇
Looopでは、会社でGithub Copilot Businessを契約していて、開発者にアカウントを発行しています。
いまや当たり前?となった「AI駆動開発」や「バイブコーディング」ですが、Terraformのようなインフラコードでももちろん力を発揮してくれます。
今回はインフラを担当している私のチームでのGithub Copilotを使った取り組みをご紹介します。
AIを使って出てきた課題や要望
AIを使ったコーディングは非常に強力ですが、使ってみて色々と課題や「⚪︎⚪︎にもAI使いたい」といった要望も出てきていました。
AIの使い方や使いこなす程度が人それぞれ
設定やプロンプトの書き方など積極的に試して使いこなしている人もいれば、適当にプロンプトを投げるだけの人もいます。中にはほぼ使ってない?といった人も。開発ルールやコーディングルールを取り決めていても・・・
これはAI以前からある課題ではありますが、ルールがあってもそれを100%自身のアウトプットに反映させられるか、というとなかなか難しいですよね。AIを使ったとしても、AIに与えるコンテキストが人それぞれなので結局品質にばらつきが出てしまいます。コミットメッセージやPR Descriptionの品質
上記の開発ルールの課題と関連しますが、コミットメッセージやPR(プルリクエスト)のDescriptionに何を書くか?のルールを決めていたとしても品質にばらつきが出ますよね。どうせならコミットからPRの作成まで全てAIがやってくれないか?と思うようになってきました。PRのレビューにもAI使いたい
これは開発エンジニアの方から聞いていた悩みで、私も同じように感じていました。特にプロジェクトの理解をしているAIにレビューしてもらいたいですよね。
AI駆動開発ガイドラインを作りました
これらの課題や要望に対応するため、まずはチームで共通のAI駆動開発ガイドラインの作成をしてみました。その内容を以下にご紹介します。
Important
VSCode + Github Copilot環境が前提の内容となります。
環境構築
まずは環境構築手順です。主にMCPサーバーを使うための設定が中心となります。
Docker
MCPサーバーはDockerを使うものがあります。未インストールの場合はインストールしましょう! www.docker.com
Python(uv)
Pythonを使うMCPサーバーもあります。特にuvが使われることが多いのでインストールします。uvを入れたらPythonのインストールを忘れずに。今回はPython 3.10をインストールしました。 docs.astral.sh
Node.js & npm
nodeを使うMCPサーバーもあるのでインストールします。 docs.npmjs.com
Terraform
今回はTerraformの開発に焦点を当てますのでインストールします。まずはバージョン管理ツールであるtenvをインストールし、そこから最新の安定版をインストールしましょう。
ぜんぶtenvのリポジトリのREADMEに書いてあります。
github.com
Checkov
チェコフ、と読むらしいです。Terraformコードの静的解析ツールです。AIによるコードレビューで活躍します。 www.checkov.io
Terraform MCPサーバー
さてようやくMCPサーバーのインストールです😓
Terraform MCPサーバーには以下のツールセットが含まれます。
- プロバイダードキュメントの検索と参照
- 公開モジュールの検索と参照
- Sentinelポリシーの検索と参照
- HCP Terraform(Terraform Cloud)にも対応
LooopではTerraform Cloudを利用しているため、主に4つ目のツールを使っています。 VSCodeのMCPレジストリからインストールできます。 code.visualstudio.com
インストールボタンをクリックすると、自動でmcp.jsonファイルに以下のようなエントリを追記してくれます。
{ "servers": { "hashicorp/terraform-mcp-server": { "type": "stdio", "command": "docker", "args": [ "run", "-i", "--rm", "-e", "TFE_TOKEN=${input:tfe_token}", "-e", "TFE_HOSTNAME=${input:tfe_hostname}", ], "gallery": "https://api.mcp.github.com/2025-09-15/v0/servers/34cd3839-461a-404a-a290-3d3bc9d8bee3", "version": "1.0.0" } }, "inputs": [ { "id": "tfe_token", "type": "promptString", "description": "Terraform API Token", "password": true }, { "id": "tfe_hostname", "type": "promptString", "description": "Terraform hostname", "password": false } ] }
inputsセクションにある通り、MCPサーバーを起動するとHCP TerraformのAPIトークンとホスト名を入力するよう促されるので入力しましょう。Terraform Cloudの場合、ホスト名はhttps://app.terraform.io/です。
AWS Terraform MCPサーバー
AWSが提供するTerraform MCPサーバー。他にもCDK用やCFn用もあります。以下のようなツールセットが含まれます。
- Terraform Development Workflow
Hashicorpが推奨する開発プロセスの理解。ワークスペース分割、Chekovによる静的解析など。 - AWS Best Practices
Well-Architected Frameworkやセキュリティベストプラクティスの理解。 - AWS Provider Resources
AWSプロバイダー情報へのアクセス - AWSCC Provider Resources
AWSCCプロバイダー情報へのアクセス
TerraformでAWS環境構築する際には主力になってくれそうなMCPです。インストールは公式ページを参照ください。 https://awslabs.github.io/mcp/servers/terraform-mcp-server/awslabs.github.io
Bitbucket MCPサーバー
LooopではコードリポジトリにBitbucketを利用していますので、BitbucketのMCPサーバーもインストールします。Githubを使っている場合は、Copilotがネイティブで連携可能なのでMCPサーバーは不要だと思います。
Githubを使っている場合の設定手順 docs.github.com
さて、Bitbucketですが公式のMCPサーバーが存在しません😭
ですので有志の方が公開されているものを利用します。
github.com
以下のツールセットが含まれます。
- リポジトリ情報の取得 最近のコミットや、レビューが必要なPRの情報など
- 横断的な検索
- コードのレビュー
- PRの作成やPRへのコメント
インストラクションファイルを作成する
ここからが課題を解決するためのキモになります!
インストラクションとは、プロジェクトの共通ルールやガイドラインをAIに認識させるためのものです。詳細はVSCodeのドキュメントを参照ください。
code.visualstudio.com
グローバルなインストラクション
リポジトリの.github/copilot-instructions.mdファイルにプロジェクトにおけるカスタムインストラクション(ガイドラインやルール等)をマークダウン形式で記載します。これはリポジトリ全体に適用され、リポジトリに1つだけ配置します。記載する内容はVSCode公式ページによれば
- コーディング方法、推奨テクノロジー、プロジェクト要件を指定して、生成されたコードが標準に準拠するようにします。
- コミット メッセージまたはプル リクエストのタイトルと説明の構成方法に関するガイドラインを提供します。
- セキュリティの脆弱性、パフォーマンスの問題、コーディング標準の遵守などのチェックなど、コードレビューのルールを設定します。
とあります。
個別インストラクション
.github/instructions/配下に複数のインストラクションファイルを配置することができます。メタデータヘッダに適用するファイルを指定するのが一般的です。例えばapplyTo: "**/*.ts,**/*.tsx"で Type Scriptファイルを指定します。
Terraform開発におけるチームのルール
とりあえず以下のルールで運用をしてみることにしました!
リポジトリ全体に適用するグローバルインストラクションファイルを作成する
リポジトリ全体に適用するインストラクションとして.github/copilot-instructions.mdを使用します。
グローバルインストラクションの内容
チームで使用しているグローバルインストラクションの内容を(少しブログ用に変えてますが)ご紹介します。
これで正解!というものではありません。私たちもこれからの運用を通して改善していくつもりです。
Note
コーディングルールについてはHashicorp社のTerraform Style Guideを参考にしています。またAWSのタグ付与ルールや、リソース命名規則についてはご利用の環境に合わせて変更してください。
copilot-instructions.mdサンプル
# Terraformコード開発インストラクション ## 基本方針 - Terraformワークスペースはリソース間の独立性やライフサイクルを考慮して適切に分割する。 - 主にAWSを対象とするが、他のクラウドプロバイダーも含む可能性がある。 - Terraformコードを実行する環境と`tfstate`を管理する環境はHCP Terraformとする。 - Chatでの応答には日本語を使用する。 ## ファイル構成 - locals.tf, outputs.tf等ファイル構成はTerraformのベストプラクティスに従う。 - モジュールのコードは`modules/`配下にある。 - 環境ごと(dev, staging, prod等)にワークスペースを分ける。 ## コード品質と保守性 - 各Terraformリソースのパラメータ記載順は、以下のルールに従う。 1. `count`/`for_each`メタ引数。 2. 非ブロックパラメータ 3. ブロックパラメータ 4. `lifecycle`ブロック 5. `depends_on`メタ引数 - リソースやパラメータの定義有無を分岐させる場合は、`enable_<resource_name>`や`create_<resource_name>`のようなboolean変数を使用する。 - リソース定義数が 0 or 1 になる場合は `count` を使用し、複数になる場合は `for_each` を使用する。 - ブロックパラメータ定義数が 0 or 1 になる場合はboolean変数で制御し、定義する場合は`for_each`メタ引数に`[true]`を渡す。 - ブロックパラメータ定義数が複数になる場合は`for_each`メタ引数にマップやセットを渡す。 - `variable`設定は、`type`と`description`を必須とし、`type`, `description`, `default`, `sensitive`, `validation`の順に定義する。 - `output`設定は、`description`と`value`を必須とし、`description`, `value`, `sensitive`の順に定義する。 - 可読性を高めるため、適切にコメントを追加する。 - 各ワークスペースにはREADME.mdを配置し、以下の内容を記載する。 - ワークスペースの目的と概要 - 主なリソースとその用途 - 重要な変数とその説明 - デプロイ手順や注意点 - 各環境(dev, staging, prod等)間でコードを再利用可能にするため、環境固有の設定は変数化し、可能な限り共通コードを使用する。 ## Terraformとproviderのバージョン管理 - Terraform, providerは原則として最新の安定バージョンを使用する。 - Terraform, providerのバージョンはワークスペース毎に`=`で固定する。 - ただし最新バージョンに上げて問題ない場合は最新バージョンを使用する。 - モジュールのバージョンも明示的に指定する。 - ローカル環境のTerraformバージョン管理は`tenv`を使用し、ワークスペースに合わせてバージョンを切り替える。 ## テストとデプロイ - plan実行前に必ず`terraform fmt`と`terraform validate`を実行する。 - Pull Request作成前に必ず`terraform plan`を実行し、差分とエラー有無を確認する。 - applyはHCP TerraformのUIから実行するのを基本とするが、必要に応じてCLIから実行することも可能とする。 ## バージョン管理とコラボレーション - リポジトリ管理にはBitbucketを使用する。 - ブランチ戦略はシンプルなGit Flowを採用し、`master`ブランチと`feature/{チケット番号}_{simple-comment}`ブランチを使用する。 - コミットメッセージは日本語で記載し、`[ワークスペースディレクトリパス] 変更の要約` の形式で記載する。 - コミットメッセージは修正差分を見れば分かるような内容にとどめず、変更理由や意図がわかるように記載する。 - 1つのコミットには1つの論理的な変更のみを含める。 - Pull Request作成前に必ず`terraform plan`を実行し、差分とエラー有無を確認する。 - PRには以下の情報を必ず含める: - 変更内容と変更理由 - 影響範囲(ワークスペース名、リソース名) - テスト結果(fmt/validate/plan実行済みチェックリスト) - 関連するチケットやSlackスレッドのリンク - チケットやSlackスレッドのURLが不明な場合は質問すること。 - プルリクエストの作成にはBitbucket MCPサーバー(`bitbucket`)を使用する。 - Bitbucketのワークスペースは、`hogefuga`を使用する。 ## プルリクエストのレビュー - レビューはリモートブランチをローカルにチェックアウトして行う。 - ベストプラクティスの参照、Checkovによる静的解析にMCPサーバー(`aws/terraform`)を使用する。 - コード内で使用されているTerraformモジュールの内容を`modules/`から確認する。 ## AWSリソースタグ付けポリシー タグ付けポリシー: - Name: 必須 / 値=リソース名 / 用途: 一意識別 - Description: 必須 / 値=リソース説明文 / 用途: 横断検索性・資産把握向上(サービス固有のDescription有無に依存せず統一運用) - Env: 原則必須 / 許容値=prod|staging|test|dev / 例外=課金非依存かつ環境中立(IAMユーザ等)は省略可 / 本番+テスト両方利用は prod を設定 - System: 必須 / 値=システム名 / 用途: コスト集計の主キー - Owner: 必須 / 値=責任者 or 作成者 / 用途: エスカレーション・棚卸し - Backup: 任意 / 対象=EC2、EBSのみ / 値=yes|no / 用途: バックアップ対象管理 - Terraform: 必須 / 値=true|false / 用途: IaC管理資産の識別フラグ 補足運用ルール: - 可能な限りタグキーは先頭大文字の Pascal 風 (Env, System, Owner) を維持し、ぶれを防止。 - 例外(Env省略等)が発生した場合は README または resources メモリファイルに理由を明記。 ## AWSリソース命名規則の基本 リソース名の構成要素: - {env}: 環境名 (prod, staging, test, dev) - {system}: システム名 (例: sample) - {role}: リソースの役割 (例: web, db, app, api, cache, tbl等) - {usage}: リソースの用途や追加情報。{role}と合わせて一意識別可能にする。 - {region}: マルチリージョン展開する場合にリージョン識別子を付与 (例: usw2, apne1等) - {az}: マルチAZ展開する場合にAZ識別子を付与 (例: a, b, c等) - {company}: 会社を特定したい場合に会社識別子を付与。主にIAM Identity Centerユーザー用 (例: looop, partner1等) - {aws_service}: AWSサービス名を略称で付与。主にIAM系リソース用 (例: s3, ec2, rds, alb等) - {access}: ネットワーク情報を特定したい場合に付与 (例: public, private, internal等) - {aws_account_id}: 主にIAM系リソースやS3バケット用。 共通ポリシー: - ケバブケースを基本とし、単語間はハイフン(-)で区切る。 - パスカルケースとの併用も許容する。 - リソース名の長さはAWSの制限内に収める。 - ただし運用のしやすさを優先し、柔軟に対応する。 ## AWSリソース命名規則の詳細 ### IAM - IAM Identity Centerユーザー: `{company}_{name}` / 既存リソースとの整合性を重視しアンダースコア区切り。他ユーザ名と重複する場合は末尾にファーストネームにちなんだアルファベットを1〜2文字追加。 - IAMユーザー: `[{env}_]{system}_{usage}_user` / 環境名は省略可。 - IAMロール: `{env}-{system}-{aws_service}-{usage}-role` / 例: `prod-sample-ec2-web-role` - IAMポリシー: `{env}-{system}-{aws_service}-{usage}-policy` / 例: `prod-sample-s3-backup-policy` ### VPC - VPC: `vpc-{system}-{env}` / 例: `vpc-sample-prod` - サブネット: `subnet-{access}-{az}-{system}-{env}` / 例: `subnet-public-a-sample-prod` - EIP: EIPをアタッチするリソースと同名。 - ルートテーブル: `rt-{access}[-{az}]-{system}-{env}` / AZ間で共有するケースが多いため{az}は省略可。AZ毎に定義する場合は{az}を付与する。例: `rt-public-sample-prod` - インターネットゲートウェイ: `igw-{system}-{env}` / 例: `igw-sample-prod` - NATゲートウェイ: `nat-{az}-{system}-{env}` / 例: `nat-a-sample-prod` - VPCエンドポイント: `vpce-{system}-{env}-{aws_service}` / 例: `vpce-sample-prod-s3` - セキュリティグループ: `secg-{system}-{env}-{aws_service}-{usage}` / 例: `secg-sample-prod-ec2-web` ### API Gateway - REST API: `apigw-{system}-{env}-{usage}-{access}` / 例: `apigw-sample-prod-FileUpload-public` ### EC2/ECS - EC2: `{system}-{env}-{role}{NN} ` / NNは同一役割の複数台識別用連番。例: `sample-prod-web01` - EBS: アタッチするEC2と同名。複数ボリュームをアタッチする場合は末尾に任意の文字列を追加して良い。 - EFS: `efs-{system}-{env}-{usage}` / 例: `efs-sample-prod-shared` - LB: `lb-{system}-{env}-{role}[-{usage}][-internal]` / 例: `lb-sample-prod-web-internal` - ターゲットグループ(複数ターゲット): `tg-{system}-{env}-{role}[-{usage}][-blue|green]` / 例: `tg-sample-prod-web-blue` - ターゲットグループ(単一ターゲット): `st-{system}-{env}-{role}[-{usage}]` / 例: `st-sample-prod-web01` - ECSクラスター: `ecs-cluster-{system}-{env}` / 例: `ecs-cluster-sample-prod` - ECSサービス: `ecs-sv-{system}-{env}-{role}[-{usage}]` / 例: `ecs-sv-sample-prod-front` - ECSタスク定義: `ecs-tsk-{system}-{env}-{role}[-{usage}]` / 例: `ecs-tsk-sample-prod-front` ### Lambda - Lambda関数: `function-{system}-{env}-{usage}` / 例: `function-sample-prod-AlertToSlack` - Lambdaレイヤー: `layer-{system}-{env}{runtime}-{usage}` / 例: `layer-sample-prod-python39-CommonLibs` ### RDS - Auroraクラスター: `{system}-{env}-{role}[-{usage}]-cluster` / 例: `sample-prod-db-cluster` - RDSインスタンス: `{system}-{env}-db-[-{usage}]{NN}` / NNは同一役割の複数台識別用連番。例: `sample-prod-db01` - パラメータグループ: `pg-{system}-{env}-db[-{usage}]-{engine}-{version}[-cluster]` / 例: `pg-sample-prod-db-aurora-mysql-80-cluster` - オプショングループ: `og-{system}-{env}-db[-{usage}]-{engine}-{version}` / 例: `og-sample-prod-db-mysql-80` - サブネットグループ: `snetg-{system}-{env}-db[-{usage}]` / 例: `snetg-sample-prod-db` - 手動スナップショット: `{yyyymmdd}-{system}-{env}-db[-{usage}]` / 例: `20231001-sample-prod-db` - RDS Proxy: `rds-proxy-{Auroraクラスター名}` / 例: `rds-proxy-sample-prod-db-cluster` ### S3 - S3バケット: `{system}-{env}-{usage}-{aws_account_id}` / 例: `sample-prod-backup-123456789012` ### SQS - 標準キュー: `queue-{system}-{env}-{usage}` / 例: `queue-sample-prod-OrderProcessing` - デッドレターキュー: `queue-{system}-{env}-{usage}-dlq` / 例: `queue-sample-prod-OrderProcessing-dlq` - FIFOキュー: `queue-{system}-{env}-{usage}.fifo` / 例: `queue-sample-prod-TaskQueue.fifo` ### Kinesis - Kinesis Data Stream(IoT等のイベントデータ): `stream-{system}-{env}-{role}-{usage}-{schema}` / {role}はデータの方向 (import/export)、{schema}はデータの種別等を表す。例: `stream-sample-prod-import-sensor-temp` - Kinesis Data Stream(ログデータ): `stream-{system}-{env}-logs-{usage}` / 例: `stream-sample-prod-logs-application` ### EventBridge - EventBridgeルール: `event-{system}-{env}-{usage}-{src}-{dest}` / {src}はイベントの発生元、{dest}はイベントの送信先を表す。スケジュールイベントは{src}に`schedule`と指定する。例: `event-sample-prod-DataSync-s3-lambda` ### その他 - CloudWatchロググループ: `/aws/{aws_service}/{system}/{env}/{usage}` / 例: `/aws/lambda/sample/prod/AlertToSlack` ## メモリ機能 - Github Copilotのメモリ機能を活用し、ワークスペースの構成や設計方針を記録する。 - 作成したリソースの依存関係や設定理由をメモリに保存し、必要に応じて参照できるようにする。 - 作業中のタスクや課題を記録し、進捗を追跡できるようにする。 - 定期的にメモリ内容を見直し、最新の設計方針やベストプラクティスに沿って更新する。 ## ファイル出力 - メモリ情報は`.github/memories/`配下に以下ファイル形式で保存する。 - `{ワークスペース名}-design.md`: ワークスペースの設計方針や構成に関する情報 - `{ワークスペース名}-resources.md`: 作成したリソースの詳細情報や依存関係 - `{ワークスペース名}-tasks.md`: 作業中のタスクや課題に関する情報 - 各ファイルは該当ワークスペースでの作業開始時に必ず確認し、最新情報を把握する。
Terraformワークスペース個別のインストラクションを作成する
.github/instructions/配下には各ワークスペース毎に専用のインストラクションファイルを配置します。ファイル名は{システム名}.mdや{ワークスペース名}.mdとします。
applyTo: "hoge_system/**/*.tf"のようにパスを指定することで適用範囲を個別のシステムやワークスペースに限定します。新規システムや既存システム改修時など、最初にこのファイルを編集するイメージです。
Tips
Looopでは複数のシステムのTerraformコードを1つのリポジトリで管理しているため、このような形にしています。1システム=1リポジトリで対応させる場合はグローバルインストラクションだけで十分かもしれません。
コミットやPR作成もAIにやってもらう
これにより、コミット粒度やコミットメッセージ、PR Descriptionの品質均一化を狙います。
PR作成前にAIにレビューをしてもらう
これによりPRの品質均一化を狙います。レビュアーの負担が軽減されるだけでなく、AIにレビューしてもらうことで勉強にもなり、一石二鳥です👍
実際にやってみた
Terraformコードの作成
効果が分かりやすくなるよう、雑に振ってみます。
TerraformでAWS上に構築するシステムのサンプルコードを作りたいと思います。ALB、ECS、Aurora MySQLで構成されるシンプルなWebシステムとします。設計のためまずは色々質問してください。設計にあたり、MCPサーバー #aws/terraform を活用してください。
Github Copilotの動作の様子です。

この画像から以下のことが分かります。
- グローバルインストラクションファイル
copilot-instructions.mdが参照されている。 - MCPサーバーを使ってベストプラクティスやAWSプロバイダードキュメントを参照している。
また詳細は割愛しますが、この後のAIからの質問に以下の内容が含まれていて、ベストプラクティスやインストラクションを理解していることが伺えました。
- セキュリティや可用性など、ベストプラクティスに沿った設計をベースにしている。
- 既存モジュールを参照し、それを使うかどうか質問してくる。
- インストラクションファイルに命名規則の記載がないサービスについて命名をどうするか質問してくる。
などなど。
PRの作成
PRの作成もお願いしてみました。
copilot-instructions.md を改修しました。初期作成後に実際に少し使ってみた上で手を加えたものです。これをコミットしてBitbucketにプッシュし、プルリクエストを作成してください。
動作の様子は似ているので割愛しますが、最終的に以下のようにプルリクエストを作成してくれました。コミットメッセージもバッチリです。

PRのレビュー
PRのレビューもやってもらいました。
リポジトリhoge/fuga_repoのプルリクエスト#351をレビューしてください。
かなりシステムの内部に迫る内容でしたので詳細は割愛しますが😓、以下のような結果でした。
- インストラクションに記載の通り、リモートブランチをチェックアウトし、Checkovによる静的解析まで実施してくれました。
- タグ付与ルールもインストラクションに従い、不足しているタグについて指摘してくれました。
- 可読性を向上させるための提案もしてくれました。
- タイポやケアレスミスをガンガン見つけてくれました。
総評
まだ運用を始めたばかりで、これからのところもありますが、現時点でもチームの開発品質や効率向上に大きく貢献してくれそうなレベルだと思いました。
特にインストラクションはリポジトリ単位で自動で認識してくれるものなので、新規メンバーがJoinした際や、新規プロジェクトにおいて初めてLooopのシステムに関わるメンバーが複数いる場合など、非常に効果的だと期待できます。
今回はTerraformにフォーカスした内容となりましたが、どんな開発プロジェクトでも応用できると思いますので参考になれば幸いです🙇
他にもAIの機能としてAgent SkillsやSubAgentなどもありますので、色々試してみてより良いチーム開発ができるような情報があれば記事にしたいと思います。
おまけ
Looopでは一緒に働く仲間を募集中です!ぜひ採用ページからご連絡ください!