「HCLの構文は調べたが、実際にterraform applyするまでの全体像がつかめない」
こういった悩みを持つエンジニアは多いです。Terraformのドキュメントは英語が中心で、しかもProviderのバージョンによって書き方が変わるため、情報が散らばりがちです。
この記事では、terraform aws vpc の構築を軸に、VPC・サブネット・インターネットゲートウェイ・EC2インスタンスをHCL(HashiCorp Configuration Language)で定義し、terraform init / plan / apply の実行フローまで一気通貫で解説します。動作確認環境は Terraform v1.8.x / AWS Provider v5.x(Rocky Linux 9 / Amazon Linux 2023で動作確認済み)です。
この記事のポイント
・terraform aws vpcはHCLのresourceブロックで宣言的に定義する
・VPC→サブネット→IGW→ルートテーブルの順に依存関係を組む
・terraform plan で差分確認、apply で実際にAWSリソースが作成される
・tfstateはS3+DynamoDBでチーム共有するのが本番運用の鉄則
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
Terraform で AWS インフラを構築するとは(概要・terraform aws vpcの位置づけ)
Terraformは HashiCorp 社が開発したオープンソースの IaC(Infrastructure as Code)ツールです。HCL(HashiCorp Configuration Language)という独自のDSLを使ってインフラをコードで定義し、そのコードを元に実際のクラウドリソースを作成・変更・削除します。AWSでVPCやEC2を構築する場合、マネジメントコンソールから手動でポチポチ作業するのが最初は手軽です。しかし、本番・ステージング・開発の3環境を用意するとなると、手作業では設定のズレやミスが生まれます。Terraformを使えば、同じHCLのコードから同一構成の環境を何度でも再現できます。
terraform aws vpc というキーワードで検索する人のほとんどは、「VPCをTerraformで定義するときのHCL構文が知りたい」「どのresourceブロックをどの順番で書けばいいか知りたい」という実務ニーズを持っています。この記事ではまさにその点を、実際に動くコード付きで解説していきます。
Terraformは「宣言的」なアプローチをとります。「このリソースをこの状態にしてほしい」と書けば、現状との差分を計算して必要な操作だけを実行してくれます。スクリプトで手続きを書く方法(AnsibleやShellScript)とは根本的に発想が異なります。
Linux ポート確認の全コマンドと組み合わせると、構築後のEC2インスタンスの疎通確認がスムーズになります。
事前準備(AWS CLI・Terraform インストール・IAM 権限設定)
1. Terraform のインストール
TerraformはHashiCorpの公式リポジトリからインストールします。Rocky Linux / RHEL 系の手順を示します。# HashiCorp の GPG キーとリポジトリを追加 sudo dnf install -y dnf-plugins-core sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo # Terraform をインストール sudo dnf install -y terraform # バージョン確認 terraform version # Terraform v1.8.5 # on linux_amd64
# GPG キーとリポジトリを追加 wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list sudo apt update && sudo apt install terraform # バージョン確認 terraform version
2. AWS CLI のインストールと認証情報設定
TerraformがAWSのAPIを呼び出すために、AWS CLIの設定が必要です。# AWS CLI v2 のインストール(Linux x86_64) curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" unzip awscliv2.zip sudo ./aws/install # バージョン確認 aws --version # aws-cli/2.17.x Python/3.11.x Linux/6.1.x # 認証情報を設定(アクセスキー・シークレットキーを入力) aws configure # AWS Access Key ID [None]: AKIA... # AWS Secret Access Key [None]: xxxxxxxx # Default region name [None]: ap-northeast-1 # Default output format [None]: json
3. IAM 権限の設定
Terraformを実行するIAMユーザーまたはIAMロールには、VPCとEC2を操作するための権限が必要です。最小権限の原則に従い、以下のポリシーを付与してください。・AmazonVPCFullAccess:VPC・サブネット・IGW・ルートテーブル操作
・AmazonEC2FullAccess:EC2インスタンスのCRUD操作
・IAMReadOnlyAccess(キーペア管理など、必要に応じて)
注意:本番環境では「FullAccess」ではなく最小権限のカスタムポリシーを作成することを強く推奨します。Terraformは実行者の権限内でしか動きません。権限が足りないとapply時に「UnauthorizedOperation」エラーが出ます。
HCL 基本構文とプロバイダー設定(provider "aws"ブロック)
Terraformのコードはすべて `.tf` 拡張子のファイルに記述します。まず作業ディレクトリを作成してください。# 作業ディレクトリを作成 mkdir ~/terraform-aws-vpc && cd ~/terraform-aws-vpc
1. main.tf と versions.tf の構成
Terraformプロジェクトの基本的なファイル構成はシンプルです。・versions.tf:Terraform本体とProviderのバージョン制約
・main.tf:プロバイダー設定とリソース定義
・variables.tf:変数定義(規模が大きくなったら分離)
・outputs.tf:出力値の定義
# versions.tf terraform { required_version = ">= 1.5.0" required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } }
# main.tf — プロバイダー設定 provider "aws" { region = "ap-northeast-1" # 東京リージョン }
HCLの基本構文は以下の形です。
# リソースブロックの基本形 resource "リソースタイプ" "ローカル名" { 引数名 = 値 引数名 = 値 } # 例: VPCを作るリソースブロック resource "aws_vpc" "main" { cidr_block = "10.0.0.0/16" tags = { Name = "main-vpc" } }
Linux無料マニュアルを受け取る >>
VPC と関連リソースの HCL 定義(vpc / subnet / igw / route_table)
terraform aws vpc を実際にコード化していきます。VPCを作るだけでは外部と通信できません。パブリックサブネット・インターネットゲートウェイ・ルートテーブルまでセットで定義する必要があります。1. VPC の定義
# main.tf — VPC の定義 resource "aws_vpc" "main" { cidr_block = "10.0.0.0/16" enable_dns_support = true enable_dns_hostnames = true tags = { Name = "main-vpc" Environment = "dev" } }
2. パブリックサブネットの定義
# main.tf — パブリックサブネット resource "aws_subnet" "public" { vpc_id = aws_vpc.main.id cidr_block = "10.0.1.0/24" availability_zone = "ap-northeast-1a" map_public_ip_on_launch = true tags = { Name = "public-subnet" } }
`map_public_ip_on_launch = true` を設定すると、このサブネットにEC2を起動した際に自動的にパブリックIPが割り当てられます。
3. インターネットゲートウェイ(IGW)の定義
# main.tf — インターネットゲートウェイ resource "aws_internet_gateway" "main" { vpc_id = aws_vpc.main.id tags = { Name = "main-igw" } }
4. ルートテーブルとアソシエーションの定義
IGWを作っただけでは通信できません。ルートテーブルにIGWへの経路を追加し、サブネットに紐付ける必要があります。# main.tf — ルートテーブル resource "aws_route_table" "public" { vpc_id = aws_vpc.main.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.main.id } tags = { Name = "public-rt" } } # ルートテーブルとサブネットのアソシエーション resource "aws_route_table_association" "public" { subnet_id = aws_subnet.public.id route_table_id = aws_route_table.public.id }
5. セキュリティグループの定義
# main.tf — セキュリティグループ resource "aws_security_group" "web" { name = "web-sg" description = "Allow SSH and HTTP" vpc_id = aws_vpc.main.id # インバウンド: SSH を許可(実務では自分のIPのみに制限すること) ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] # 本番では要注意: 自分のIPに制限すること } # インバウンド: HTTP を許可 ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } # アウトバウンド: すべて許可 egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "web-sg" } }
EC2 インスタンスの HCL 定義(ami / instance_type / key_name)
1. キーペアの準備
EC2にSSHログインするためのキーペアを事前に作成します。# 自分のPC上でSSHキーペアを作成 ssh-keygen -t ed25519 -C "terraform-key" -f ~/.ssh/terraform-key # ~/.ssh/terraform-key(秘密鍵) # ~/.ssh/terraform-key.pub(公開鍵)
# main.tf — キーペアをAWSに登録 resource "aws_key_pair" "main" { key_name = "terraform-key" public_key = file("~/.ssh/terraform-key.pub") }
2. AMI の確認
EC2インスタンスに使うAMIのIDはリージョンによって異なります。以下のコマンドでAmazon Linux 2023の最新AMI IDを確認できます。# Amazon Linux 2023 の最新 AMI ID を確認 aws ec2 describe-images \ --owners amazon \ --filters "Name=name,Values=al2023-ami-*-x86_64" \ "Name=state,Values=available" \ --query 'sort_by(Images, &CreationDate)[-1].ImageId' \ --output text # ami-0d4f40b5677cdf27c (実際のIDは定期的に変わります)
3. EC2 インスタンスの定義
# main.tf — data ブロックで最新 Amazon Linux 2023 AMI を動的取得 data "aws_ami" "amazon_linux_2023" { most_recent = true owners = ["amazon"] filter { name = "name" values = ["al2023-ami-*-x86_64"] } filter { name = "virtualization-type" values = ["hvm"] } } resource "aws_instance" "web" { ami = data.aws_ami.amazon_linux_2023.id instance_type = "t3.micro" key_name = aws_key_pair.main.key_name subnet_id = aws_subnet.public.id vpc_security_group_ids = [aws_security_group.web.id] # EBS ルートボリューム設定 root_block_device { volume_size = 20 volume_type = "gp3" encrypted = true } tags = { Name = "web-server" Environment = "dev" } }
4. 出力値の定義(outputs.tf)
EC2のパブリックIPを `terraform apply` 後に確認できるよう、outputs.tf に出力値を定義しておきます。# outputs.tf output "vpc_id" { description = "作成したVPCのID" value = aws_vpc.main.id } output "public_subnet_id" { description = "パブリックサブネットのID" value = aws_subnet.public.id } output "ec2_public_ip" { description = "EC2インスタンスのパブリックIP" value = aws_instance.web.public_ip }
terraform init / plan / apply の実行フロー
HCLファイルが揃ったら、実際にTerraformコマンドを実行します。1. terraform init — 初期化
# 作業ディレクトリで初期化 cd ~/terraform-aws-vpc terraform init # 実際の出力例: # Initializing the backend... # Initializing provider plugins... # - Finding hashicorp/aws versions matching "~> 5.0"... # - Installing hashicorp/aws v5.55.0... # - Installed hashicorp/aws v5.55.0 (signed by HashiCorp) # # Terraform has been successfully initialized!
2. terraform plan — 差分確認
terraform plan # 実際の出力例(一部): # Terraform will perform the following actions: # # # aws_instance.web will be created # + resource "aws_instance" "web" { # + ami = "ami-0d4f40b5677cdf27c" # + instance_type = "t3.micro" # ... # } # # # aws_vpc.main will be created # + resource "aws_vpc" "main" { # + cidr_block = "10.0.0.0/16" # ... # } # # Plan: 8 to add, 0 to change, 0 to destroy.
実行計画をファイルに保存しておくと、applyで同じ内容を適用できます。
# 実行計画をファイルに保存(推奨) terraform plan -out=tfplan # 保存した計画を適用 terraform apply tfplan
3. terraform apply — リソース作成
terraform apply # 確認プロンプトが出る # Do you want to perform these actions? # Enter a value: yes # 適用後の実際の出力例: # Apply complete! Resources: 8 added, 0 changed, 0 destroyed. # # Outputs: # # ec2_public_ip = "54.249.xxx.xxx" # public_subnet_id = "subnet-0abc12345def67890" # vpc_id = "vpc-0123456789abcdef0"
# SSH 接続確認(applyで表示されたIPを使用) ssh -i ~/.ssh/terraform-key ec2-user@54.249.xxx.xxx # 実際の接続成功例: # , #_ # ~\_ ####_ Amazon Linux 2023 # ~~ \_#####\ # ~~ \###| # ~~ \#/ ___ https://aws.amazon.com/linux/amazon-linux-2023 # [ec2-user@ip-10-0-1-xxx ~]$
4. terraform destroy — リソース削除
検証が終わったら忘れずにリソースを削除してください。放置すると料金が発生し続けます。terraform destroy # Do you really want to destroy all resources? # Enter a value: yes # # Destroy complete! Resources: 8 destroyed.
tfstate と backend 設計のポイント(state管理トラブル回避)
Terraformは実際に作成したリソースの状態を `terraform.tfstate` というJSONファイルに記録します。このファイルが「Terraformが管理するインフラの現状」そのものです。1. tfstate がローカルに存在するリスク
デフォルトではtfstateは作業ディレクトリのローカルに保存されます。本番運用でこのまま使うとトラブルが起きます。・チームで共有できない:別のメンバーがapplyするとtfstateが衝突する
・tfstateを誤って削除すると復元が困難:Terraformがリソースを「把握していない」状態になる
・tfstateにはシークレット情報が含まれる:Gitにcommitしてはいけない
2. S3 + DynamoDB による Remote Backend の設定
本番・チーム開発では必ずRemote Backendを使ってください。AWSのS3にtfstateを保存し、DynamoDBで排他ロック(同時実行の衝突防止)を管理するのが定番構成です。# versions.tf に backend の設定を追加 terraform { required_version = ">= 1.5.0" required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } backend "s3" { bucket = "my-terraform-state-bucket" # 事前に作成したS3バケット名 key = "vpc-ec2/terraform.tfstate" region = "ap-northeast-1" dynamodb_table = "terraform-state-lock" # DynamoDBテーブル名(LockID属性が必要) encrypt = true } }
# S3 バケット作成(バージョニング有効化を推奨) aws s3api create-bucket \ --bucket my-terraform-state-bucket \ --region ap-northeast-1 \ --create-bucket-configuration LocationConstraint=ap-northeast-1 # バージョニングを有効化(tfstateの誤削除・上書きを防ぐ) aws s3api put-bucket-versioning \ --bucket my-terraform-state-bucket \ --versioning-configuration Status=Enabled # DynamoDB テーブル作成(排他ロック用) aws dynamodb create-table \ --table-name terraform-state-lock \ --attribute-definitions AttributeName=LockID,AttributeType=S \ --key-schema AttributeName=LockID,KeyType=HASH \ --billing-mode PAY_PER_REQUEST \ --region ap-northeast-1
3. .gitignore の設定
ローカル開発時のtfstateやキャッシュをGitにコミットしないよう、`.gitignore` を設定してください。# .gitignore の設定内容 .terraform/ terraform.tfstate terraform.tfstate.backup *.tfvars # 機密情報を含む変数ファイル # 注意: .terraform.lock.hcl は commit すること(Providerバージョン固定のため)
よくあるエラーと対処法(トラブルシューティング)
「Error: UnauthorizedOperation」— IAM権限不足
# エラー例 Error: creating VPC: UnauthorizedOperation: You are not authorized to perform this operation. status code: 403
・IAMユーザーに必要なポリシー(AmazonVPCFullAccess等)が付与されているか確認
・`aws sts get-caller-identity` で現在認証しているIAMユーザー/ロールを確認
・複数のAWSプロファイルを使っている場合は `AWS_PROFILE` 環境変数を確認
「Error: Error acquiring the state lock」— tfstateロック衝突
# エラー例 Error: Error acquiring the state lock Error message: ConditionalCheckFailedException Lock Info: ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Operation: OperationTypeApply Who: user@hostname
・前回のapplyが正常終了したか確認する
・DynamoDBテーブルのロックレコードを確認する
・ロックを強制解除する(IDを確認した上で実行すること)
# ロックを強制解除 terraform force-unlock xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
「Error: InvalidAMIID.NotFound」— AMI IDが存在しない
# エラー例 Error: InvalidAMIID.NotFound: The image id 'ami-xxxxxxxxxxxxxxxxx' does not exist
「Error: VPC cidr_block conflicts」— CIDRブロックの重複
# エラー例 Error: creating VPC: InvalidVpc.Conflict: The CIDR '10.0.0.0/16' conflicts with another VPC in the same region.
「Error: waiting for EC2 Instance State」— インスタンス起動タイムアウト
# エラー例 Error: waiting for EC2 Instance (i-xxxxxxxxxxxxxxxxx) create: timeout while waiting for state to become 'running'
構築後のEC2でSSHポート(22番)が開いているかどうかは、AWSマネジメントコンソールのセキュリティグループ設定と、EC2インスタンスのステータスチェックで確認してください。
まとめ
この記事では terraform aws vpc の構築を軸に、HCLの書き方からterraformコマンドの実行フロー、tfstate管理のポイントまでを一気通貫で解説しました。| やりたいこと | TerraformのHCL / コマンド |
|---|---|
| VPCを作る | resource "aws_vpc" "main" { cidr_block = "10.0.0.0/16" } |
| パブリックサブネットを作る | resource "aws_subnet" "public" { vpc_id = aws_vpc.main.id } |
| インターネットゲートウェイを作る | resource "aws_internet_gateway" "main" { vpc_id = aws_vpc.main.id } |
| EC2インスタンスを作る | resource "aws_instance" "web" { ami = data.aws_ami.xxx.id } |
| 初期化する | terraform init |
| 差分確認する | terraform plan |
| リソースを作成する | terraform apply |
| リソースを削除する | terraform destroy |
| S3にtfstateを保存する | backend "s3" { bucket = "..." key = "..." } |
| tfstateロックを解除する | terraform force-unlock <LOCK_ID> |
mount コマンドの使い方と合わせて、EC2のEBSボリュームをマウントしてファイルシステムを構成する際にも活用してください。
Terraformで構築したEC2に実際にログインして設定を進める際は、Linux 基本コマンドの解説も参考にしてください。
Linux無料マニュアルを受け取る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら
- 次のページへ:Terraformのtfstate管理とS3バックエンド設定|チーム運用で壊さないための基礎
- 前のページへ:Terraform入門|Infrastructure as CodeでAWSインフラをコード化する基礎ハンズオン
- この記事の属するカテゴリ:Terraformへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。
登録無料・いつでも解除できます