本文へジャンプ

インフラをコード化!
CloudFormationとTerraformを使ってEC2をデプロイしてみた

Posted by MSM

皆様こんにちは!
MDのバックエンドとインフラを担当しておりますMSMと申します。

最近はSAAを取得するためにAWSの学習に勤しんでおります。
何としても1回で合格したいですね。

そこで今回選んだテーマは、自身の知識整理も兼ねてAWSにも深く関わりのある
「Infrastructure as Code(IaC)」です。

Infrastructure as Code(IaC)

IaCとは、簡単に言うとAWSやGCP, Azureなどのクラウドサービスのリソースを、コード化し、管理できるようにすることです。

従来の方法では、サーバやネットワークの設定を全てコンソールから手動で行うことが多かったと思います。

しかし、インフラ構成が複雑化した場合や長く放置されていた場合に、稼働中のリソースをコンソールから1つずつ把握・管理するのは大変な作業になります。

そこで、そのインフラ構成図をコードとして作成・管理することで、インフラの構成に変更があった場合や、インフラ構成そのものを把握したいときに、簡単に管理・把握することができます。

そして最大の特徴は、テンプレートのコードを元に複数のクラウドリソースをまとめて自動デプロイすることができるという点です。

今回は、以下に説明する2つの代表的なIaCサービスで、同じインフラ構成のテンプレートを作成し、デプロイしたEC2からHello Worldしてみたいと思います。

AWS CloudFormation

AWS CloudFormation

  • AWSの公式IaCサービス。jsonまたはyaml形式のファイルで記述する。
  • テンプレートを作成し、コンソール画面またはAWS CLIからリソースのデプロイが可能。
  • GCPやAzureといった他社のクラウドサービスのリソースには対応していない。

HashiCorp Terraform

HashiCorp Terraform

  • HashiCorp社が提供するIaCサービス。
  • tfファイルという独自の拡張子を使用している。
  • Go言語によって開発されている
  • マルチベンダー対応

準備

以下のツールをそれぞれお使いのPCにインストールしてください。
インストール手順の解説は本記事では省略します。

コードからのデプロイ

それでは、実際に二つのツールを使ってそれぞれデプロイしてみましょう。

Cloudformationによるデプロイ

まずはCloudFormationのテンプレートを作成して、デプロイしてみましょう。

CloudFormationのテンプレートファイルは yaml または json が選択できますが、僕個人としては読みやすいyamlファイルの方で作成します。

  • cloudformation.yaml
---
Parameters:
  Ec2ImageId:
    Type: AWS::SSM::Parameter::Value
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

Resources:
  CFEC2:
    Type: AWS::EC2::Instance
    Properties:
      AvailabilityZone: ap-northeast-1a
      ImageId: !Ref Ec2ImageId
      InstanceType: t2.micro
      Tags:
      - Key: Name
        Value: instance_from_cf
      SecurityGroups:
        - !Ref CFSecurityGroup
      UserData:
        Fn::Base64: |
          #!/bin/bash
          yum update -y
          yum install -y httpd.x86_64
          systemctl start httpd.service
          systemctl enable httpd.service
          echo "Hello World from CF" > /var/www/html/index.html

  # our EC2 security group
  CFSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: security group for CluodFormation
      Tags:
        - Key: Name
          Value: "sg_for_cf"
      SecurityGroupIngress:
      - CidrIp: 0.0.0.0/0
        FromPort: 22
        IpProtocol: tcp
        ToPort: 22
      - CidrIp: 0.0.0.0/0
        FromPort: '80'
        IpProtocol: tcp
        ToPort: '80'

作成したCFテンプレートはAWS CLIを使用して、以下のコマンドでデプロイすることができます。

コマンドの実行はCFのテンプレートファイルがあるディレクトリを指定して実行します。
引数profileに指定するユーザは適宜変更してください。

aws --profile terraform cloudformation deploy --template cf.yaml --stack-name ec2-from-cf

CFでデプロイした場合はコンソールにスタックとして登録され、作成されたリソースが一覧として確認することができます。

cf-stack.png

デプロイに成功すると、指定した内容のEC2とSGが作成されます。

cf-ec2.png cf-sg.png

EC2のパブリックIPを開くとhtmlファイルを確認することができます。

cf-hello.png

作成したリソースは以下のコマンドで削除しましょう。

 aws --profile terraform cloudformation delete-stack  --stack-name ec2-from-cf

Terraformによるデプロイ

Terraformは以下のディレクトリ構成で構築します。

root_dir
├── main.tf
├── terraform.tfvars
└── versions.tf

Terraformはバージョンによって仕様が異なる部分があるので、インストールしているterraformのバージョンに合わせて要求バージョンを指定します。

  • versions.tf
terraform {
  required_version = ">= 0.14"
}

AWSのアカウントにアクセスするためのユーザの鍵情報は terraform.tfvars に記述しましょう。

  • terraform.tfvars
ACCESS_KEY = "XXXXXXXXXXXXXXX"
SECRET_KEY = "YYYYYYYYYYYYYYY"
  • main.tf
provider "aws" {
  access_key = var.ACCESS_KEY
  secret_key = var.SECRET_KEY
  region     = "ap-northeast-1"
}

variable "ACCESS_KEY" { 
      type = string
}

variable "SECRET_KEY" { 
      type = string
}

data aws_ssm_parameter amzn2_ami {
  name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
}


resource "aws_instance" "myinstance" {
  ami = data.aws_ssm_parameter.amzn2_ami.value
  instance_type = "t2.micro"
  vpc_security_group_ids = [aws_security_group.tf-sg.id]

  user_data = <<-EOF
    #!/bin/bash
    yum update -y
    yum install -y httpd.x86_64
    systemctl start httpd.service
    systemctl enable httpd.service
    echo "Hello World from TF" > /var/www/html/index.html
  EOF

  tags = {
        Name = "instance_from_terraforms"
    }

}

resource "aws_security_group" "tf-sg" {
    name = "sg_for_tf"
    description = "security group for Terraform"
    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"]
    }
}

ファイルの準備ができたら以下のコマンドを実行していきます。

terraform init
terraform apply

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: yes

CFと同様に指定したEC2インスタンス・SGの確認ができました。

tf-ec2.png tf-sg.png

こちらも同様にIPへアクセスすると、htmlページの確認ができました。

tf-hello.png

作成したリソースの後始末は、以下のコマンドを実行します。
テンプレートから作成した全てのリソースを削除します.

terraform destroy

削除確認の質問が出るので、yesを回答します。

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

それぞれの長所・短所(個人的な感想)

CloudFormation

長所

  • AWS のコンソールからもデプロイが可能
  • AWS CLIが使えればそのままCLIからの実行が可能
  • デプロイ中のプロセスがコンソールで確認できる
  • テンプレートで作成したリソースは単体で削除できないので、誤った削除を防ぐことができる

短所

  • 使用できるクラウドベンダーがAWSのみ
  • yamlでも少しファイルの見通しが悪く感じる

Terraform

長所

  • コードの見通しが良い
  • 実行環境の構築が簡単
  • 様々なベンダーに対応(AWS, GCP, Azure, etc...)

短所

  • Terraformで作成したリソースの進捗状況がコンソールで確認できない
  • バージョンごとの仕様変更が大きい
  • コンソールからリソースを消せてしまうので、ローカルのtfファイルの内容と矛盾する可能性がある

終わりに

いかがだったでしょうか?
インフラをコード化することで、リソースの設定やリソース同士の繋がりが明確になりますね。

実務でのインフラ管理だけでなく、

  • SAAなどの資格をとるときにハンズオン形式に学習したものをコード化する
  • 実験的に色々なインフラ構成を試したい

といったような使い方もできるのではないでしょうか。

それでは今回はこの辺で!

Happy Coding!

参考記事:

Recent Entries
MD EVENT REPORT
What's Hot?