0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS IaC入門】Phase2: TerraformでS3バケットをデプロイしてリモートステートまで設定した

0
Last updated at Posted at 2026-06-01

はじめに

前回のPhase1ではIAM・CLI・CloudFormationの基礎を学んだ。
Phase2ではいよいよTerraformに入門し、実際にS3バケットをデプロイしてリモートステートまで設定した記録。


目次

  1. TerraformとCloudFormationの違い
  2. Terraformインストール
  3. ファイル構成と各ファイルの役割
  4. init / plan / apply の流れ
  5. tfstateとは
  6. リモートステート設定
  7. ハマったポイント
  8. まとめ

1. TerraformとCloudFormationの違い

CloudFormation Terraform
作成元 AWS HashiCorp
対応クラウド AWSのみ AWS / GCP / Azure など
記法 YAML / JSON HCL(独自言語)
tfstate管理 AWSが自動管理 自分で管理が必要

一番大きな違いはマルチクラウド対応

AWSとGCPを両方使う場合、CloudFormationはAWSしか管理できないが、Terraformなら同じ書き方でどちらも管理できる。


2. Terraformインストール

Windowsの場合、公式サイトからzipをダウンロードして terraform.exeC:\Windows\System32\ に置く。

terraform -version
# Terraform v1.x.x

3. ファイル構成と各ファイルの役割

phase2/
  ├── provider.tf   # どのクラウドを使うか
  ├── main.tf       # 何を作るか
  └── outputs.tf    # 作った後に何を表示するか

provider.tf

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

version = "~> 5.0" は「5.x系を使う(6.0は使わない)」という意味。

main.tf

resource "aws_s3_bucket" "practice" {
  bucket = "my-terraform-practice-123456789012"
}

resource "aws_s3_bucket_versioning" "practice" {
  bucket = aws_s3_bucket.practice.id
  versioning_configuration {
    status = "Enabled"
  }
}

CloudFormationと違い、TerraformではS3バケット本体とバージョニング設定は別リソースとして書く。
aws_s3_bucket.practice.id のようにリソース同士を参照できるのがTerraformの強み。

outputs.tf

output "bucket_name" {
  value = aws_s3_bucket.practice.id
}

output "bucket_arn" {
  value = aws_s3_bucket.practice.arn
}

terraform apply 後に自動で表示される。デプロイ直後に情報を確認できて便利。


4. init / plan / apply の流れ

terraform init

terraform init

AWSプロバイダー(AWSを操作するためのプラグイン)をダウンロードする。初回だけ実行すればOK。

npm install に近いイメージ。

terraform plan

terraform plan

実際には何も変わらない。差分のプレビューを確認するためのコマンド。

Plan: 2 to add, 0 to change, 0 to destroy.
         ↑              ↑              ↑
      新規作成        変更なし        削除なし

+ が新規作成、~ が変更、- が削除を意味する。
(known after apply) はデプロイ後にAWSが決める値(ARNなど)。

デプロイ前に必ずplanで差分確認するのが鉄則。本番環境への誤デプロイ事故を防げる。

terraform apply

terraform apply

planの内容を実際に実行する。yes と入力して確定。

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:
bucket_arn  = "arn:aws:s3:::my-terraform-practice-123456789012"
bucket_name = "my-terraform-practice-123456789012"

outputs.tfで定義した値がここで表示される。


5. tfstateとは

terraform apply を実行すると terraform.tfstate というファイルが自動生成される。

{
  "resources": [
    {
      "type": "aws_s3_bucket",
      "name": "practice",
      "instances": [
        {
          "attributes": {
            "bucket": "my-terraform-practice-123456789012",
            "arn": "arn:aws:s3:::my-terraform-practice-123456789012"
          }
        }
      ]
    }
  ]
}

これは**「今AWSに何が存在するか」を記録したファイル**。

terraform plan を実行すると:

tfstate(現状) vs .tfファイル(あるべき姿)
  └── 差分だけ実行する

この差分計算のためにtfstateが必要。tfstateがないとTerraformは現状を把握できない。

tfstateは絶対にGitHubにpushしない。AWSの構成情報が全部入っているため、流出すると危険。.gitignore に必ず追加する。


6. リモートステート設定

なぜリモートステートが必要か

デフォルトではtfstateがローカルPCに保存される。

問題点:
  └── チームで共有できない
  └── PC壊れたら消える
  └── 間違えて削除したら管理不能になる

これを解決するのがリモートステート。tfstateをS3で管理する。

手順

1. tfstate用のS3バケットを作成

resource "aws_s3_bucket" "tfstate" {
  bucket        = "my-tfstate-123456789012"
  force_destroy = true
}

resource "aws_s3_bucket_versioning" "tfstate" {
  bucket = aws_s3_bucket.tfstate.id
  versioning_configuration {
    status = "Enabled"
  }
}

force_destroy = true をつけておくと terraform destroy 時にバケットの中身ごと削除できる。

2. provider.tf に backend を追加

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }

  backend "s3" {
    bucket = "my-tfstate-123456789012"
    key    = "phase2/terraform.tfstate"
    region = "ap-northeast-1"
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

backend "s3" ブロックは必ず terraform {}に書く。外に書くとエラーになる。

3. terraform init を再実行

バックエンドの設定が変わったので再度initが必要。

terraform init

これでtfstateがS3に保存されるようになる。

my-tfstate-123456789012/
  └── phase2/
        └── terraform.tfstate

7. ハマったポイント

backend ブロックの位置を間違えた

# NG: terraform {} の外に書いてしまった
terraform {
  required_providers { ... }
}

backend "s3" {  # ← ここはダメ
  ...
}
# OK: terraform {} の中に書く
terraform {
  required_providers { ... }

  backend "s3" {  # ← ここが正しい
    ...
  }
}

tfstateバケットをterraform destroyで消せない

バージョニングを有効にしたtfstateバケットをdestroyしようとするとエラーになる。

Error: BucketNotEmpty: The bucket you tried to delete is not empty.
You must delete all versions in the bucket.

対策として force_destroy = true を最初からつけておく。

yes ではなく y と入力してキャンセルになった

Only 'yes' will be accepted to approve.

y だけだと Apply cancelled. になる。必ず yes と全部入力する。誤操作防止のための仕様。


8. まとめ

Phase2で学んだこと:

  • Terraformはマルチクラウド対応のIaCツール。実務でのシェアが高い
  • init → plan → apply の流れを必ず守る。planで差分確認してからapply
  • tfstateはTerraformの記憶。現状とコードの差分計算に使う
  • リモートステートでtfstateをS3管理するとチーム開発・バックアップに対応できる
  • force_destroy = true でバケットの中身ごと削除できる
  • tfstateは.gitignoreに追加してGitHubにpushしない

コードはGitHubで公開しています:
https://github.com/Allure2140/aws-iac-learning

次のPhase3ではVPC・EC2をTerraformでコード化し、複数環境(dev/prod)管理に挑戦します。


参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?