🛠️

Terraformに入門してみた〜インフラ構築も自動化したいねん!〜

2021/02/14に公開

モチベーション

最近、AWSの学習をしている。AWS CloudShellからコマンドを打ったり、マネジメントコンソールで画面をぽちぽちしてインフラを構築したが、「コマンドも画面ぽちぽちも面倒くさいのでコード書いて自動化したいなぁ」とイキりだす思うようになった。
AWSのインフラもコード書けないかと調べた結果、CloudFormationとTerraformの2つが見つかった。どうせならイキリ散らせそうな汎用性の高い方を使いたいと思い、Terraformを使って今後はインフラを構築することにした。

ゴール

今回作る予定の構成は以下。nginxをインストールし、初期画面が自分のPCに表示できるようになったら完成とする。

Terraformについて

本題に入る前にTerraformについて簡単に紹介する。この章では、以下のことを理解してもらえるよう説明する。

  • Terraformとは何か
  • Terraformを使うメリットは何か(独断と偏見)
  • どんな人がTerraformを使うと幸せになるのか(独断と偏見)

Terraformとは何か

まずは公式サイトに書かれていることを紹介する。

Terraform is an open-source infrastructure as code software tool that provides a consistent CLI workflow to manage hundreds of cloud services.
引用:https://www.terraform.io/

インフラをコードで表現するために使われるオープンソースのツールで、何百ものクラウドサービスを管理する一貫したCLIワークフローを提供しているらしい。複数のクラウドサービスを使ってシステムを構築する時にTerraform1つである程度のことができそうな点は魅力的。

Terraformを使うメリットは何か

メリットは、やはりインフラをコードで表現できることだと思う。インフラ構築をマネジメントコンソールやコマンドで行うと、どうしても構築速度が遅くなってしまう。また、同じような環境を複数作成するときはとてつもなく面倒に感じてしまう。seleniumなどを使って画面を自動操作させて構築すれば自動化できなくはないが、マネジメントコンソールは画面体裁がすぐに変わるのでコードの修正を頻繁に行わないといけない可能性があることを考えると、得策とは言えない。
その点、Terraformならコードを宣言的に書くことでインフラの定義を簡単にできるし、管理しやすい。変更したい項目があればコードの修正をするだけでいいのでコードの読み書きができる人にはこちらの方が使い勝手はいいのではないかと思う。

# インスタンスの定義例
resource "aws_instance" "example" {
  ami = "ami-0992fc94ca0f1415a"
  instance_type = "t2.micro"

  tags = {
    Name = "example"
  }
}

どんな人がTerraformを使うと幸せになれるのか

私が思うTerraformを使うと幸せになれる人は2パターンいると思うので紹介する。

  1. インフラ構築もコードを書きたい人
  2. 複数のクラウドサービスを使ってシステムを構築する人

それぞれ簡単に深掘りしていく。

インフラ構築もコードを書きたい人

一部のエンジニアには「画面ポチポチしながら環境構築するのは効率悪いからコード書いてPCに環境構築を実行させたい」なんて考える人もいるかと思う(私もこのタイプ)が、そのようなエンジニアにはTerraformを使うことをおすすめする。
環境構築をPCにやらせ、自分はその間コーヒーを飲みながらのんびりできるようになるのでQOL爆上がり待ったなしである。もし普通に環境構築すれば1時間かかるような環境であれば、銭湯にいく時間も作れるかもしれない。(さすがに銭湯いくのはリスク高いのでおすすめしないが)

複数のクラウドサービスを使ってシステムを構築する人

「複数のクラウドサービスを使うことがあるのか?」と疑問に思う人もいるかもしれないが、超巨大システムだと見かけることがあるかもしれない。(ちなみに私が関わっているシステムはAWSとGCPの両方使っている)
このときはTerraformの出番だ。1つのクラウドサービスだけで構成されるシステムの環境を構築するならそのサービスが提供しているIaCサービスを使えばいいが、複数のクラウドサービスで構成されるシステムの環境を構築する場合、2つのIaCサービスを使う必要がある。Terraformを使えば1つのIaCサービスで構築できるので学習コストが下がるし管理も楽になるのではないかと思う。(習得難易度は一旦無視している)

Terraformを使ってみる

Terraformのことが少しわかったところで、実際に使ってみようと思う。

環境

  • AWS
    • リージョン:ap-northeast-1
  • MacBook
    • 筐体:無印MacBook
    • OS:macOS Big Sur
  • Terraform
    • v0.14.6

セットアップ

AWS

まずはAWSのセットアップを行う。実際の設定方法はAWSの公式ドキュメントに詳しく書かれている。

Terraform

Homebrewでインストールする。

brew install terraform

インストールされたらバージョンを確認する。

terraform --version
Terraform v0.14.6

以前使ったCloudShellに比べると環境構築の難易度が上がったが、バキバキの超巨大Webシステムに比べると手順が単純だったので詰まることなく進めることができた。

構築する

設定が終了したら構築を開始する。今回の環境構築で設定するものは以下。

  1. VPC
  2. サブネット
  3. インターネットゲートウェイ
  4. ルートテーブル
  5. セキュリティグループ
  6. EC2
  7. アウトプット出力

コードの全体像

コードの全体像を記載する。なお、今回は全体像を把握しやすくするため1つのモジュールに全ての設定を記載している。本来このように記載することは保守性や可読性を考えるとあまりよくないので本番ではモジュール化しておくことをおすすめする。
※細かい設定の箇所は公式ドキュメントを参照いただくと幸せになる。(公式ドキュメント丸投げマンと思われると悲しいのでここは時間がある時に加筆します)

# VPC
resource "aws_vpc" "my_web_vpc" {
  cidr_block = "10.0.0.0/21"
  enable_dns_support = true
  enable_dns_hostnames = true
  tags = {
      Name = "my_web_vpc"
  }
}

# パブリックサブネット01
resource "aws_subnet" "public_subnet1" {
  vpc_id = aws_vpc.my_web_vpc.id
  cidr_block = "10.0.0.0/24"
  availability_zone = "ap-northeast-1a"
  tags = {
    "Name" = "public_subnet1"
  }
}

# パブリックサブネット2
resource "aws_subnet" "public_subnet2" {
  vpc_id = aws_vpc.my_web_vpc.id
  cidr_block = "10.0.1.0/24"
  availability_zone = "ap-northeast-1c"
  tags = {
    "Name" = "public_subnet2"
  }
}

# プライベートサブネット1
resource "aws_subnet" "private_subnet1" {
  vpc_id = aws_vpc.my_web_vpc.id
  cidr_block = "10.0.2.0/24"
  availability_zone = "ap-northeast-1a"
  tags = {
    "Name" = "private_subnet1"
  }
}

# プライベートサブネット2
resource "aws_subnet" "private_subnet2" {
  vpc_id = aws_vpc.my_web_vpc.id
  cidr_block = "10.0.3.0/24"
  availability_zone = "ap-northeast-1c"
  tags = {
    "Name" = "private_subnet2"
  }
}

# インターネットゲートウェイ
resource "aws_internet_gateway" "web_ig_01" {
  vpc_id = aws_vpc.my_web_vpc.id
  tags = {
    "Name" = "web_ig_01"
  }
}

# ルートテーブル
resource "aws_route_table" "public_route" {
    vpc_id = aws_vpc.my_web_vpc.id
    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = aws_internet_gateway.web_ig_01.id
    }
}

# ルートテーブルを関連づける
resource "aws_route_table_association" "puclic-1" {
    subnet_id = aws_subnet.public_subnet1.id
    route_table_id = aws_route_table.public_route.id
}

# セキュリティグループ(パブリックサブネット01)
resource "aws_security_group" "http_sg_01" {
  name = "sg_web_01"
  vpc_id = aws_vpc.my_web_vpc.id
  
  # 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"]
  }
}

# EC2
resource "aws_instance" "web_server" {
  ami = "ami-0992fc94ca0f1415a"
  subnet_id = aws_subnet.public_subnet1.id
  instance_type = "t2.micro"
  vpc_security_group_ids = [ aws_security_group.http_sg_01.id ]
  associate_public_ip_address = "true"
  // ユーザー設定(nginxをインストールして起動させる)
  user_data = <<EOF
    #!/bin/bash
    sudo amazon-linux-extras install nginx1
    sudo cp -a /etc/nginx/nginx.conf /etc/nginx/nginx.conf.back
    sudo systemctl start nginx
    systemctl status nginx
  EOF
}

# アウトプット(DNS名を出力させる)
output "public_dns" {
  value = aws_instance.web_server.public_dns
}

実行してみる

terraform init

リソース作成に必要なバイナリファイルをダウンロードしてくれる。

terraform init

「Terraform has been successfully initialized!」が出力されると成功。

terraform plan

実行計画が出力される。自分が書いたコードからリソースをどうやって作成するのかがわかる。

terraform plan

以下のような出力が表示される。問題ないと判断したら実際にリソースを作成する。

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.web_server will be created
  + resource "aws_instance" "web_server" {
      + ami                          = "ami-0992fc94ca0f1415a"
      + arn                          = (known after apply)
      + associate_public_ip_address  = true
      + availability_zone            = (known after apply)
      + cpu_core_count               = (known after apply)
      + cpu_threads_per_core         = (known after apply)
      + get_password_data            = false
      + host_id                      = (known after apply)
      + id                           = (known after apply)
      + instance_state               = (known after apply)
      + instance_type                = "t2.micro"
    ......
    }

Plan: XX to add, XX to change, XX to destroy.

terraform apply

実行計画が想定どおりであることを確認した後、リソース作成を実行する。

terraform apply

改めて実行計画が表示され、実行していいか確認される。「yes」と入力すると実行する。

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.
  
  Enter a value: 

「Apply complete! Resources: XX added, XX changed, XX destroyed.」と出力されると成功。
念の為、マネジメントコンソールを確認する。

ちゃんとEC2が起動していることがわかった。

nginxが起動しているか確認


正常に起動できていることが確認できた。

環境の削除

お試しで作成した環境は使わなくなったらすぐに削除することをお勧めする。
destroyコマンドで環境の一発削除ができる。

terraform destroy

「Destroy complete! Resources: XX destroyed.」が出力されると削除が全て完了。

所感

今まで画面をぽちぽちして環境を構築していたが、Terraformを使うことでコードさえ書けば全て自動で実行してくれるこの爽快感がたまらなかった。これで私のQOLも爆上がり待ったなしである。TerraformにAWSの環境構築やってもらう間何をしようか考えるとワクワクが止まらない。
(「Terraformを完全に理解した」とイキリ散らすこともできるようになった)

まとめ

Terraformは神。

Discussion