🤖

初めてのTerraform

に公開

はじめに

前回の記事でAmazon RDSの検証で作成した環境をTerraformで再現し、
同じ検証ができるかどうかを確認します。

検証概要

前回作成したWebサーバ用のEC2にTerraformをインストールし、
Terraformを実行して前回行った検証が問題なく実施できるか確認します。

前提

  • VPCやルートテーブル等のネットワーク系は新規で作成するものとします。
  • 前回に引き続きAIなどを参考に検証を行っています。

事前準備

AMI作成

前回作成したEC2より、AMI(Amazon Machine Image)を作成
EC2の画面よりEC2を選択し、アクション > イメージとテンプレート > イメージを作成 を選択

AMI名を入力して「イメージを作成」を選択

Terraformインストール

実行用のEC2にて下記実施

sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
sudo dnf -y install terraform

AWS CLI インストール

実行用のEC2にて下記実施

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update

接続情報セットアップ

aws configure
AWS Access Key ID [None]: <APIキーを入力>
AWS Secret Access Key [None]: <シークレットキーを入力>
Default region name [None]: ap-northeast-1
Default output format [None]: json

Terraformセットアップ

構成ファイル作成

mkdir learn-terraform-get-started-aws
cd learn-terraform-get-started-aws/
terraform.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.92"
    }
  }

  required_version = ">= 1.2"
}
main.tf(長いので折りたたんでいます)
main.tf
provider "aws" {
  region = "ap-northeast-1" # 東京リージョン
}

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "main-vpc"
  }
}

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"
  }
}

resource "aws_subnet" "private" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "ap-northeast-1a"
  tags = {
    Name = "private-subnet"
  }
}

resource "aws_subnet" "private_b" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.3.0/24"
  availability_zone = "ap-northeast-1c"
  tags = {
    Name = "private-subnet-b"
  }
}

resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.main.id
}

resource "aws_route_table" "public_rt" {
  vpc_id = aws_vpc.main.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id
  }
}

resource "aws_route_table_association" "public_assoc" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public_rt.id
}

resource "aws_security_group" "ec2_sg" {
  name        = "ec2-sg"
  description = "Allow SSH and HTTP"
  vpc_id      = aws_vpc.main.id

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  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"]
  }
}

resource "aws_security_group" "rds_sg" {
  name        = "rds-sg"
  description = "Allow MySQL access from EC2"
  vpc_id      = aws_vpc.main.id

  ingress {
    from_port       = 3306
    to_port         = 3306
    protocol        = "tcp"
    security_groups = [aws_security_group.ec2_sg.id]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_instance" "web" {
  ami           = "ami-0f9f11beacc7b567a" # Amazon Linux 2 (東京)
  instance_type = "t3.micro"
  subnet_id     = aws_subnet.public.id

  vpc_security_group_ids = [aws_security_group.ec2_sg.id]
  key_name = "Test"

  tags = {
    Name = "web-server-teraform"
  }
}

resource "aws_db_instance" "mysql" {
  allocated_storage    = 20
  engine               = "mysql"
  engine_version       = "8.0"
  instance_class       = "db.t4g.micro"
  username             = "<RDSユーザ>"
  password             = "<RDSパスワード>"
  db_subnet_group_name = aws_db_subnet_group.mysql_subnet.name
  vpc_security_group_ids = [aws_security_group.rds_sg.id]
  skip_final_snapshot  = true
}

resource "aws_db_subnet_group" "mysql_subnet" {
  name       = "mysql-subnet-group"
  subnet_ids = [
    aws_subnet.private.id,
    aws_subnet.private_b.id
  ]

  tags = {
    Name = "mysql-subnet-group"
  }
}
outputs.tf
output "ec2_public_ip" {
  value = aws_instance.web.public_ip
}

output "rds_endpoint" {
  value = aws_db_instance.mysql.endpoint
}

Terraformコード確認/実行

実行前のコード確認

terraform plan

実行(途中確認が求められるため、yesと入力)

terraform apply

Terraform作成後の確認

EC2

Amazon RDS

※前検証で作成したRDSは削除済み

VPC

サブネット

ルートテーブル

インターネットゲートウェイ

Terraform作成後のセットアップ

Terraformで作成したEC2にて下記実施

テーブルの作成

mysql -h <新規作成したRDSのIPアドレスorFQDN> -u admin -p

CREATE DATABASE testdb;
USE testdb;
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100)
);

app.pyの修正(DBアクセス先やユーザ情報など)

app.py
db = pymysql.connect(
    host='<RDSのIPアドレスorFQDN>',
    user='<RDSユーザ>',
    password='<RDSパスワード>',
    database='testdb'
)

検証実施

次の前回と同様の検証内容のため詳細は割愛しますが、
同じ検証ができることを確認しました。
https://zenn.dev/pdtanabe/articles/2e422f3a14c0e4#検証

検証完了後にTerraform環境削除

途中確認が求められるため、「yes」と入力

terraform destroy

削除状況確認

EC2

Amazon RDS

VPC

サブネット

ルートテーブル

インターネットゲートウェイ

所感

最初の下準備があるものの、コマンド1つで検証環境を丸々再現できるのはとても便利でした。
またtfファイルに記載するコードもそこまで特殊な記載方法ではないので、
検証していて理解のしやすさ追加しやすさがとてもありがたかったです。

この辺はAIにお願いするのがとても楽でした。
もちろん最初から100点満点ではなくterraform実行時にエラーもでましたが、
エラー時のコード修正も含めて1時間ほどで環境作成までできました。
引き続き経験を積んでいって、操作感覚をつかんでいきたいです。

株式会社プログデンス
設定によりコメント欄が無効化されています