72
71

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

# いまから始めるクラウド環境構築のためのTerraform

Posted at

はじめに

業務でクラウド環境を構築する必要があり、Infrastructure as Code (IaC) ツールのTerraformについて調査しました。N番煎じかもしれませんが、初めてTerraformを使う方でも理解できるよう、AWS・GCPでの基本的な環境構築方法をまとめています。

この記事の対象者

  • クラウドインフラ構築を自動化したい
  • 手作業でのリソース管理から脱却したい
  • AWS・GCP両方の構築方法を知りたい

上記に当てはまる方に向けて、実際に調査した内容を共有します。


Terraformとは?

TerraformはHashiCorp社が開発したオープンソースのIaCツールで、インフラストラクチャをコードで定義・管理できます。

IaCとは?
Infrastructure as Code(コードとしてのインフラ)の略で、サーバーやネットワークなどのインフラ設定をプログラムコードで記述・管理する手法です。手作業でのポチポチ作業から解放されます。

なぜTerraformを選んだのか

競合としてAWS CDK(AWS専用)やPulumi(複数言語対応)などが存在しますが、弊社ではAWSだけでなくGCPを使用するプロジェクトもあるため、マルチクラウド対応可能なTerraformを選択しました。

特徴 メリット
マルチクラウド対応 AWS、GCP、Azureなど複数のクラウドを統一管理
宣言的な記述 「何を作りたいか」を記述するだけで、「どう作るか」はTerraformが自動処理
状態管理 インフラの現在状態を自動追跡し、変更差分を検出
変更の可視化 適用前に変更内容をプレビュー確認でき、事故を防止
再現性 同じコードから何度でも同じ環境を作成可能

事前準備

1. Terraformのインストール

macOS

brew tap hashicorp/tap
brew install hashicorp/tap/terraform
terraform --version

Windows

  1. Terraform公式サイトからダウンロード
  2. ZIPを解凍しPATHに追加
  3. コマンドプロンプトまたはPowerShellで確認:
terraform --version

実行結果例

Terraform v1.13.3

このように表示されればインストール成功です。

2. エディタの準備

VS Code使用時は以下の拡張機能を推奨:

  • HashiCorp Terraform(公式拡張機能)
    • Intellisense:コード補完機能
    • シンタックスハイライト:色分けで見やすく
    • コードナビゲーション:定義元へジャンプ可能

AWS環境構築

以下の構成を構築します:

  • VPC:独立したネットワーク環境(仮想的な自社専用ネットワーク)
  • パブリックサブネット:インターネットからアクセス可能な領域
  • EC2インスタンス:Webサーバー用仮想マシン(仮想サーバー)
  • セキュリティグループ:ファイアウォール設定(通信の許可/拒否ルール)

1. AWS CLIセットアップ

AWS CLIとは?
AWSをコマンドラインから操作するためのツールです。Terraformが裏側でAWSと通信する際に必要です。

# インストール(macOS)
brew install awscli

# 認証設定
aws configure

設定項目

項目 説明
Access Key ID AWSアカウントのアクセスキー(ユーザー名のようなもの) AKIAIOSFODNN7EXAMPLE
Secret Access Key シークレットキー(パスワードのようなもの) (機密情報のため非表示)
Default region デフォルトで使用するリージョン(データセンターの場所) ap-northeast-1(東京)
Default output format コマンド結果の出力形式 json

アクセスキーの取得方法

  1. AWSマネジメントコンソールにログイン
  2. 右上のユーザー名をクリック → 「セキュリティ認証情報」
  3. 「アクセスキー」セクションで「アクセスキーを作成」
  4. 表示されたキーをメモ(再表示不可なので注意!)

⚠️ セキュリティ注意:アクセスキーは厳重に管理してください。流出すると以下のリスクがあります:

  • 不正利用による高額請求(数百万円の被害例も)
  • リソースへの不正アクセス
  • データ漏洩

2. ディレクトリ構成

なぜファイルを分けるのか?
コードを役割ごとに分けることで、管理しやすくメンテナンス性が向上します。

terraform-aws/
├── main.tf          # リソース定義(VPC、EC2などの設定を記述)
├── variables.tf     # 変数定義(繰り返し使う値を変数として定義)
├── outputs.tf       # 出力値定義(作成したリソースのIPアドレスなどを表示)
└── terraform.tfvars # 変数値(実際の値を記述、機密情報を含むため.gitignore推奨)

3. コード例

main.tf

HCL(HashiCorp Configuration Language)とは?
Terraformで使用する専用の設定言語です。JSONに似た読みやすい構文が特徴です。

# Terraformのバージョンとプロバイダの指定
# プロバイダ:AWS、GCPなどのクラウドサービスと通信するためのプラグイン
terraform {
  required_version = ">= 1.5.0"  # Terraform本体のバージョン指定
  required_providers {
    aws = {
      source  = "hashicorp/aws"  # プロバイダの提供元
      version = "~> 5.0"         # プロバイダのバージョン(5.x系を使用)
    }
  }
}

# AWSプロバイダの設定
provider "aws" {
  region = var.aws_region  # variables.tfで定義した変数を参照
}

# VPC(Virtual Private Cloud)
# AWSアカウント内の仮想ネットワーク空間
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"  # IPアドレスの範囲(65,536個のIPアドレス)
  enable_dns_hostnames = true            # DNSホスト名を有効化
  enable_dns_support   = true            # DNS解決を有効化
  tags = { Name = "terraform-vpc" }      # 管理用のタグ(名前)
}

# パブリックサブネット
# VPC内の一部領域で、インターネットからアクセス可能なネットワーク
resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.main.id  # 上で作成したVPCのIDを参照
  cidr_block              = "10.0.1.0/24"    # 256個のIPアドレス
  availability_zone       = "${var.aws_region}a"  # アベイラビリティゾーン(物理的なデータセンター)
  map_public_ip_on_launch = true               # インスタンス起動時に自動でパブリックIP割り当て
  tags = { Name = "terraform-public-subnet" }
}

# インターネットゲートウェイ
# VPCとインターネットを接続するゲート
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id
  tags = { Name = "terraform-igw" }
}

# ルートテーブル
# ネットワークトラフィックの経路を定義
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 = "terraform-public-rt" }
}

# ルートテーブルとサブネットの関連付け
# サブネットにルートテーブルを適用
resource "aws_route_table_association" "public" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public.id
}

# セキュリティグループ
# ファイアウォールのルール定義(どのポートからの通信を許可するか)
resource "aws_security_group" "web" {
  name        = "terraform-web-sg"
  description = "Security group for web server"
  vpc_id      = aws_vpc.main.id

  # インバウンドルール(外部からの通信):HTTP
  ingress {
    from_port   = 80           # 開始ポート
    to_port     = 80           # 終了ポート
    protocol    = "tcp"        # プロトコル
    cidr_blocks = ["0.0.0.0/0"]  # すべてのIPアドレスから許可
    description = "Allow HTTP"
  }

  # インバウンドルール:SSH(サーバーにリモート接続するため)
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]  # 本番環境では自社IPのみに制限推奨
    description = "Allow SSH"
  }

  # アウトバウンドルール(サーバーから外部への通信)
  egress {
    from_port   = 0              # すべてのポート
    to_port     = 0
    protocol    = "-1"           # すべてのプロトコル
    cidr_blocks = ["0.0.0.0/0"]  # すべての宛先へ許可
  }

  tags = { Name = "terraform-web-sg" }
}

# EC2インスタンス(仮想サーバー)
resource "aws_instance" "web" {
  ami                    = var.ami_id  # Amazon Machine Image(OSのテンプレート)
  instance_type          = "t2.micro"  # インスタンスタイプ(CPU・メモリのスペック)
  subnet_id              = aws_subnet.public.id
  vpc_security_group_ids = [aws_security_group.web.id]
  tags = { Name = "terraform-web-server" }
}

variables.tf

変数を使うメリット

  • 同じ値を複数箇所で使う際、一箇所変更すれば全体に反映
  • 環境ごと(開発/本番)に値を切り替えやすい
variable "aws_region" {
  description = "AWS region"  # 変数の説明
  type        = string        # データ型(文字列)
  default     = "ap-northeast-1"  # デフォルト値(東京リージョン)
}

variable "ami_id" {
  description = "AMI ID for EC2"
  type        = string
  default     = "ami-0d52744d6551d851e"  # Amazon Linux 2023(東京リージョン用)
}

リージョンとは?
AWSのデータセンターの地理的な場所です。日本には東京(ap-northeast-1)と大阪(ap-northeast-3)があります。

📌 重要ポイント:AMI IDはリージョンごとに異なります。
最新のAMI IDはAWS Systems Manager Parameter StoreまたはAWS公式ドキュメントで確認してください。

outputs.tf

出力値とは?
terraform applyの実行後に表示される情報です。作成したリソースのIPアドレスなど、後で必要になる情報を出力します。

output "instance_public_ip" {
  description = "EC2のパブリックIP"
  value       = aws_instance.web.public_ip
}

output "vpc_id" {
  description = "VPC ID"
  value       = aws_vpc.main.id
}

4. 実行手順

Terraformの実行は3ステップ

  1. init(初期化)
  2. plan(実行計画の確認)
  3. apply(実際に作成)
# ステップ1:初期化(最初に1回だけ実行)
terraform init

何が起きる?

  • .terraformディレクトリが作成される
  • 必要なプロバイダ(AWSプラグイン)がダウンロードされる
  • 状態管理の準備が行われる
# ステップ2:実行プランの確認(必須!)
terraform plan

何が表示される?

  • +:新規作成されるリソース
  • -:削除されるリソース
  • ~:変更されるリソース

実行例

Terraform will perform the following actions:

  # aws_vpc.main will be created
  + resource "aws_vpc" "main" {
      + cidr_block = "10.0.0.0/16"
      ...
    }

Plan: 7 to add, 0 to change, 0 to destroy.

この出力を必ず確認してから次へ進みましょう。意図しないリソースが削除される事故を防げます。

# ステップ3:リソースの作成
terraform apply

確認プロンプトが表示されます:

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と入力(yだけでは不可)。

作成には数分かかります。以下のように表示されれば成功です:

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

Outputs:

instance_public_ip = "54.XXX.XXX.XXX"
vpc_id = "vpc-0a1b2c3d4e5f6g7h8"
# ステップ4:状態確認
terraform show

作成されたリソースの詳細情報が表示されます。

ブラウザで確認してみましょう

  1. AWSマネジメントコンソールにログイン
  2. EC2ダッシュボードを開く
  3. 「インスタンス」でterraform-web-serverが表示されることを確認
  4. 出力されたパブリックIPをブラウザで開いてアクセス確認
# ステップ5:リソースの削除(コスト削減のため必ず実行)
terraform destroy

確認プロンプトでyesと入力すると、作成したすべてのリソースが削除されます。

⚠️ 重要:検証後は必ずdestroyしてください。放置すると課金され続けます。


GCP環境構築

基本的な考え方はAWSと同じですが、サービス名や設定が異なります。

1. 課金の有効化は必須

GCPでは無料トライアル中でも、ほとんどのリソース(Compute Engine、VPCなど)を使用するには課金を有効化する必要があります。課金を有効化しないと以下のエラーが発生します
Error: Error creating instance: googleapi: Error 403: Compute Engine API has not been used 
in project [PROJECT_ID] before or it is disabled.

課金有効化の手順

  1. Coocle Cloud Consoleにアクセス
  2. 左上のナビゲーションメニューから「お支払い」選択
  3. 「請求先アカウントをリンク」をクリック
  4. クレジットカード情報を登録(無料トライアル中は対象のサービスでは自動課金されません)

2.無料トライアルの活用

・初回登録時に$300分のクレジットが付与されます
・90日間有効
・クレジット消費後も自動的に課金されることはありません。

3.無料枠(Always Free)

トライアル終了後も以下のリソースは永続的に無料で利用可能
・1つのe2-microインスタンス(Compute Engine)
・5GB/月のStandardStorage(Cloud Storage)
・1TBのクエリ処理(Big Query)
など
詳細は以下を参照
Google Cloudの無料トライアルと無料枠付きのプロダクトについて(Google公式)


以下は、具体的な手順です。

1. Google Cloud SDKセットアップ

Google Cloud SDKとは?
GCPをコマンドラインから操作するためのツール群です。

# インストール(macOS)
brew install --cask google-cloud-sdk

# 初期化(ブラウザが開き、Googleアカウントで認証)
gcloud init

# アプリケーションデフォルト認証の設定
gcloud auth application-default login

2. プロジェクト準備

GCPのプロジェクトとは?
リソースを管理する論理的な単位です。AWSアカウントに相当します。

# プロジェクト作成
# your-project-idは一意である必要があります(全世界で重複不可)
gcloud projects create your-project-id --name="My Terraform Project"

# 作成したプロジェクトを使用するように設定
gcloud config set project your-project-id

# 必要なAPIの有効化
# Compute Engine API:仮想マシンを作成するために必要
gcloud services enable compute.googleapis.com
# Resource Manager API:プロジェクト管理に必要
gcloud services enable cloudresourcemanager.googleapis.com

APIの有効化とは?
GCPでは各サービスを使う前にAPIを有効化する必要があります。初回のみ実行すればOKです。

3. サービスアカウント作成

サービスアカウントとは?
アプリケーション(今回はTerraform)がGCPを操作するための専用アカウントです。人間用のGoogleアカウントとは別物です。

# サービスアカウント作成
gcloud iam service-accounts create terraform \
  --display-name="Terraform Service Account"

# 権限付与(本番環境では最小権限に絞る)
# roles/editor:プロジェクト内のほとんどのリソースを作成・変更・削除可能
gcloud projects add-iam-policy-binding your-project-id \
  --member="serviceAccount:terraform@your-project-id.iam.gserviceaccount.com" \
  --role="roles/editor"

# 認証キーの作成(JSONファイルとしてダウンロード)
gcloud iam service-accounts keys create terraform-key.json \
  --iam-account=terraform@your-project-id.iam.gserviceaccount.com

実行後の確認
現在のディレクトリにterraform-key.jsonが作成されます。このファイルをTerraformから読み込みます。

⚠️ セキュリティ注意terraform-key.json.gitignoreに追加し、GitHubなどに絶対にプッシュしないでください。

4. コード例

main.tf(GCP版)

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 5.0"
    }
  }
}

provider "google" {
  credentials = file("terraform-key.json")  # サービスアカウントキーを読み込み
  project     = var.project_id
  region      = var.region
}

# VPCネットワーク
resource "google_compute_network" "vpc" {
  name                    = "terraform-vpc"
  auto_create_subnetworks = false  # サブネットを手動で作成
}

# サブネット
resource "google_compute_subnetwork" "subnet" {
  name                     = "terraform-subnet"
  ip_cidr_range            = "10.0.1.0/24"
  region                   = var.region
  network                  = google_compute_network.vpc.id
  private_ip_google_access = true  # Google APIへのプライベート接続を許可
}

# ファイアウォールルール:SSH
resource "google_compute_firewall" "ssh" {
  name    = "terraform-allow-ssh"
  network = google_compute_network.vpc.name
  
  allow {
    protocol = "tcp"
    ports    = ["22"]
  }
  
  source_ranges = ["0.0.0.0/0"]  # 本番環境では制限推奨
  target_tags   = ["ssh"]  # このタグを持つインスタンスに適用
}

# ファイアウォールルール:HTTP/HTTPS
resource "google_compute_firewall" "http" {
  name    = "terraform-allow-http"
  network = google_compute_network.vpc.name
  
  allow {
    protocol = "tcp"
    ports    = ["80", "443"]
  }
  
  source_ranges = ["0.0.0.0/0"]
  target_tags   = ["http"]
}

# GCEインスタンス(仮想マシン)
resource "google_compute_instance" "web" {
  name         = "terraform-web-server"
  machine_type = "e2-micro"  # 無料利用枠対象のマシンタイプ
  zone         = "${var.region}-a"  # ゾーン(リージョン内の物理データセンター)

  # ブートディスク設定
  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-11"  # Debian 11 OSイメージ
      size  = 10  # ディスクサイズ(GB)
      type  = "pd-standard"  # 標準永続ディスク
    }
  }

  # ネットワークインターフェース設定
  network_interface {
    subnetwork = google_compute_subnetwork.subnet.id
    
    # 外部IPアドレスを割り当て
    access_config {
      // 空ブロックで自動割り当て(エフェメラルIP)
    }
  }

  # ネットワークタグ(ファイアウォールルールで使用)
  tags = ["ssh", "http"]

  # 起動時に実行するスクリプト(Nginxをインストール)
  metadata_startup_script = <<-EOF
    #!/bin/bash
    apt-get update
    apt-get install -y nginx
    systemctl start nginx
    systemctl enable nginx
    echo "<h1>Hello from Terraform!</h1>" > /var/www/html/index.html
  EOF

  # サービスアカウント設定
  service_account {
    scopes = ["cloud-platform"]  # すべてのGoogle Cloud APIへのアクセス権限
  }
}

variables.tf(GCP版)

variable "project_id" {
  description = "GCP Project ID"
  type        = string
}

variable "region" {
  description = "GCP region"
  type        = string
  default     = "asia-northeast1"  # 東京リージョン
}

GCPのリージョン一覧

  • asia-northeast1:東京
  • asia-northeast2:大阪
  • us-central1:アイオワ(アメリカ)

outputs.tf(GCP版)

⚠️ 修正:正しい記法

output "instance_external_ip" {
  description = "GCEの外部IP"
  # 正しい書き方(配列アクセス)
  value       = google_compute_instance.web.network_interface.access_config.nat_ip
}

output "vpc_name" {
  description = "VPC名"
  value       = google_compute_network.vpc.name
}

output "ssh_command" {
  description = "SSH接続コマンド"
  value       = "gcloud compute ssh ${google_compute_instance.web.name} --zone=${google_compute_instance.web.zone}"
}

元の記述の誤り

# ❌ 間違い(ドット記法では配列にアクセスできない)
value = google_compute_instance.web.network_interface.access_config.nat_ip

# ✅ 正しい(配列インデックス指定が必要)
value = google_compute_instance.web.network_interface.access_config.nat_ip

terraform.tfvars

project_id = "your-project-id"  # 実際のプロジェクトIDに置き換え
region     = "asia-northeast1"

5. 実行手順

AWSと同じ流れです:

terraform init
terraform plan    # 必ず確認!
terraform apply   # yesと入力
terraform show    # 作成されたリソース確認
terraform destroy # 削除

GCPコンソールでの確認

  1. Google Cloud Consoleにアクセス
  2. プロジェクトを選択
  3. 「Compute Engine」→「VMインスタンス」で確認
  4. 外部IPをブラウザで開いて「Hello from Terraform!」が表示されることを確認

ベストプラクティス

セキュリティ

1. 認証情報の管理

.gitignoreに必ず追加

# Terraform変数ファイル(機密情報を含む可能性)
*.tfvars

# Terraform状態ファイル(リソースIDなどを含む)
*.tfstate
*.tfstate.backup

# Terraformプラグインディレクトリ
.terraform/

# GCPサービスアカウントキー
terraform-key.json

# AWSキーペア
*.pem

なぜ.gitignoreに追加?
これらのファイルには以下のような機密情報が含まれます:

  • AWSアクセスキー
  • GCPサービスアカウントキー
  • リソースのIDや内部IP
  • データベースパスワード

GitHubに誤ってプッシュすると、数分で自動スキャンされ悪用される可能性があります。

2. 最小権限の原則

本番環境では必要最小限の権限のみ付与します。流出事故や設定ミス対策として重要です。

なぜ最小権限が重要?

  • 万が一キーが流出しても被害を最小化
  • 誤操作による重要リソースの削除を防止
  • セキュリティ監査での指摘を回避

AWS IAMポリシー例(EC2とVPCのみ操作可能):

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "ec2:*",
      "vpc:*"
    ],
    "Resource": "*"
  }]
}

❌ 避けるべき例

{
  "Effect": "Allow",
  "Action": "*",  # すべての操作を許可(危険!)
  "Resource": "*"
}

3. ファイアウォール厳格化

開発環境0.0.0.0/0(すべてのIPから接続可能)でも可
本番環境:特定IPに制限必須

# 本番環境用のセキュリティグループ例
ingress {
  from_port   = 22
  to_port     = 22
  protocol    = "tcp"
  cidr_blocks = ["203.0.113.0/24"]  # 自社オフィスIPなど
  description = "SSH from office only"
}

IPアドレス範囲の指定方法

  • 203.0.113.10/32:単一のIPアドレス
  • 203.0.113.0/24:256個のIPアドレス(203.0.113.0~203.0.113.255)
  • 0.0.0.0/0:すべてのIPアドレス(全世界)

コード管理

1. モジュール化

モジュールとは?
再利用可能なTerraformコードのまとまりです。関数のようなイメージです。

terraform-project/
├── modules/             # 再利用可能なモジュール
│   ├── vpc/            # VPC作成モジュール
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── outputs.tf
│   └── ec2/            # EC2作成モジュール
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf
└── environments/       # 環境ごとの設定
    ├── dev/           # 開発環境
    │   └── main.tf
    └── prod/          # 本番環境
        └── main.tf

メリット

  • 同じコードを複数環境で再利用
  • 変更が一箇所で済む
  • チーム内でのコード共有が容易

2. 環境ごとの変数管理

なぜ環境を分ける?
開発環境では小さいインスタンス、本番環境では大きいインスタンスを使うなど、環境ごとに設定を変えるためです。

# dev.tfvars(開発環境)
environment   = "development"
instance_type = "t2.micro"      # 小さいインスタンス
db_size       = 20              # 小さいディスク

# prod.tfvars(本番環境)
environment   = "production"
instance_type = "t3.medium"     # 大きいインスタンス
db_size       = 100             # 大きいディスク

実行方法

# 開発環境に適用
terraform apply -var-file="dev.tfvars"

# 本番環境に適用
terraform apply -var-file="prod.tfvars"

3. 状態ファイルのリモート管理

状態ファイルとは?
Terraformが管理しているリソースの現在の状態を記録したファイルです。デフォルトではローカルにterraform.tfstateとして保存されます。

なぜリモート管理が必要?

  • チーム開発:複数人で同じインフラを管理する場合、状態を共有する必要
  • バックアップ:ローカルファイルが消えるとインフラ管理ができなくなる
  • ロック機能:同時実行を防ぎ、競合を回避

AWS S3バックエンド例

terraform {
  backend "s3" {
    bucket         = "my-terraform-state"      # S3バケット名
    key            = "prod/terraform.tfstate"  # ファイルパス
    region         = "ap-northeast-1"
    encrypt        = true                      # 暗号化を有効化
    dynamodb_table = "terraform-lock"          # ロック管理用テーブル
  }
}

事前準備

  1. S3バケットmy-terraform-stateを作成
  2. DynamoDBテーブルterraform-lockを作成(プライマリキー:LockID

GCS バックエンド例

terraform {
  backend "gcs" {
    bucket = "my-terraform-state"  # GCSバケット名
    prefix = "prod"                # プレフィックス
  }
}

事前準備

  1. GCSバケットmy-terraform-stateを作成

トラブルシューティング

実際に遭遇しやすいエラーと解決方法をまとめます。

1. 状態ファイルのロック

エラーメッセージ

Error: Error locking state: Error acquiring the state lock

原因
前回のterraform applyが異常終了(Ctrl+Cで中断など)し、ロックファイルが残っている状態です。

解決方法

# エラーメッセージに表示されるLock IDをコピー
terraform force-unlock <LOCK_ID>

# 例
terraform force-unlock a1b2c3d4-e5f6-7890-abcd-ef1234567890

注意:他の人が実行中でないことを確認してから実行してください。

2. プロバイダ設定エラー

エラーメッセージ

Error: Provider configuration not present

原因
プロバイダの設定が正しく初期化されていない、または.terraformディレクトリが破損しています。

解決方法

# プロバイダを再初期化
terraform init -reconfigure

-reconfigureオプションで既存の設定を無視して再初期化します。

3. AWS認証エラー

エラーメッセージ

Error: error configuring Terraform AWS Provider: no valid credential sources

原因
AWS認証情報が設定されていない、または期限切れです。

確認方法

# 現在の認証情報を確認
aws sts get-caller-identity

正常な場合の出力例

{
    "UserId": "AIDAI...",
    "Account": "123456789012",
    "Arn": "arn:aws:iam::123456789012:user/terraform-user"
}

解決方法

# 認証情報を再設定
aws configure

Access Key IDとSecret Access Keyを再入力してください。

4. GCP認証エラー

エラーメッセージ

Error: google: could not find default credentials

原因
GCP認証情報が設定されていない、またはサービスアカウントキーのパスが間違っています。

解決方法

# 方法1:アプリケーションデフォルト認証を再設定
gcloud auth application-default login

# 方法2:サービスアカウントキーのパスを環境変数で指定
export GOOGLE_APPLICATION_CREDENTIALS="./terraform-key.json"

# パスが正しいか確認
ls -l terraform-key.json

terraform-key.jsonの場所
main.tfと同じディレクトリに配置してください。

5. リソース削除失敗

エラーメッセージ

Error: Error deleting VPC: DependencyViolation: The vpc 'vpc-xxx' has dependencies and cannot be deleted

原因
VPCを削除しようとしているが、VPC内にサブネットやEC2インスタンスなどの依存リソースが残っている状態です。

なぜ起きる?

  • 手動で追加したリソースがある
  • terraform destroyが途中で中断された
  • Terraformで管理していないリソースが存在

解決方法1:再度destroyを実行

# 依存関係を解決して削除
terraform destroy -auto-approve

解決方法2:手動で削除

# VPCに紐づくリソースを確認
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=terraform-vpc"

# AWSコンソールから手動で削除
# 1. EC2インスタンスを削除
# 2. サブネットを削除
# 3. VPCを削除

GCPの場合

# プロジェクト内のすべてのリソースを確認
gcloud compute instances list
gcloud compute networks list

# 必要に応じて手動削除
gcloud compute instances delete terraform-web-server --zone=asia-northeast1-a

まとめ

調査で得られた知見

  1. Terraformは学習コストに見合う価値がある
    最初は覚えることが多いですが、一度習得すれば:

    • 同じ環境を何度でも再現可能
    • ヒューマンエラーを削減
    • 変更履歴がGitで管理できる
  2. マルチクラウド対応が現実的
    AWS・GCPで同じツール・同じ思考法を使えるため:

    • スキルの横展開が容易
    • クラウドベンダーロックインを回避
    • 複数クラウドの統一管理が可能
  3. コードレビューが可能になる
    インフラもアプリケーションと同様に:

    • Pull Requestでレビュー
    • 変更内容の可視化
    • チーム全体での品質向上
  4. 状態管理の重要性
    本番環境では:

    • 必ずリモートバックエンド(S3/GCS)を使用
    • 状態ファイルのバックアップを取得
    • ロック機能で同時実行を防止

参考資料


おわりに

クラウド環境構築の必要性から始まったTerraform調査でしたが、Infrastructure as Codeの価値を実感できました。

⚠️ 重要な注意事項

  1. 検証後は必ずリソースを削除

    terraform destroy
    

    放置すると継続的に課金されます。

  2. 認証情報の管理を徹底

    • .gitignoreに追加
    • GitHubには絶対にプッシュしない
    • 定期的にローテーション
  3. 本番環境では慎重に

    • 必ずterraform planで確認
    • 重要なリソースにはprevent_destroyを設定
    • バックアップを取得してから実行

この記事が同じような課題を抱えている方の参考になれば幸いです。

質問や改善点があれば、コメント欄でお気軽にお知らせください!

72
71
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
72
71

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?