Terraform EC2構築 × Ansible Nginxインストール

9 min read読了の目安(約8900字

Terraform構築

基本コマンド

# aws configure profile作成  profile名:default
$ aws configure --profile default

# aws configure 確認・編集
$ vim ~/.aws/credentials

# aws configure 削除
$ rm -r ~/.aws

# terraformでモジュール単位でリソース作成
$ terraform apply -target module.VPC

# Ansible Role作成
$ ansible-galaxy init nginx

ディレクトリ構成

├── backend.tf
├── main.tf
├── modules
│   ├── alb
│   │   ├── alb.tf
│   │   ├── outputs.tf
│   │   └── variables.tf
│   ├── ec2
│   │   ├── ec2.tf
│   │   └── variables.tf
│   ├── security_group
│   │   ├── outputs.tf
│   │   ├── security-group.tf
│   │   └── variables.tf
│   └── vpc
│       ├── outputs.tf
│       └── vpc.tf

backend.tf

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

terraform {
  backend "s3" {
    bucket                  = "tfstate-s3bucket"  // 事前にs3バケットを作成する
    key                     = "terraform.tfstate"
    shared_credentials_file = "~/.aws/credentials"
    profile                 = "default"           // 事前にprofile作成する
    region                  = "ap-northeast-1"
  }
}

main.tf

module vpc {
  source = "./modules/vpc"
}

module security_group {
  source = "./modules/security_group"

  config = {
    // vpc.tfでoutputする
    vpc_id      = module.vpc.vpc_id
  }
}

module ec2 {
  source = "./modules/ec2"

  config = {
    // vpc.tfでoutputする
    subnet-a_id = module.vpc.subnet-a_id
    subnet-c_id = module.vpc.subnet-c_id
    security_group_id = module.security_group.security_group_id
  }
}

module alb {
  source = "./modules/alb"

  config = {
    // vpc.tfでoutputする
    vpc_id      = module.vpc.vpc_id
    subnet-a_id = module.vpc.subnet-a_id
    subnet-c_id = module.vpc.subnet-c_id
    // security_group.tfでoutputする
    security_group_id = module.security_group.security_group_id
  }
}

vpcモジュール

## VPCの設定
resource "aws_vpc" "public-vpc" {
  cidr_block           = "10.0.0.0/16"
  instance_tenancy     = "default"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "public-vpc"
  }
}

##サブネットの作成
resource "aws_subnet" "public-subnet-a" {
  vpc_id            = aws_vpc.public-vpc.id
  cidr_block        = "10.0.16.0/24"
  availability_zone = "ap-northeast-1a"

  tags = {
    Name = "public-subnet-a"
  }
}

resource "aws_subnet" "public-subnet-c" {
  vpc_id            = aws_vpc.public-vpc.id
  cidr_block        = "10.0.32.0/24"
  availability_zone = "ap-northeast-1c"

  tags = {
    Name = "public-subnet-c"
  }
}


##ルートテーブルの追加(0.0.0.0/0)
resource "aws_route_table" "public-route" {
  vpc_id = aws_vpc.public-vpc.id

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

##ルートテーブルの追加
resource "aws_route_table_association" "puclic-subnet-a" {
  subnet_id = aws_subnet.public-subnet-a.id
  route_table_id = aws_route_table.public-route.id
}

resource "aws_route_table_association" "puclic-subnet-c" {
  subnet_id = aws_subnet.public-subnet-c.id
  route_table_id = aws_route_table.public-route.id
}

##ゲートウェイの設定
resource "aws_internet_gateway" "example_GW" {
  vpc_id = aws_vpc.public-vpc.id
}
output "vpc_id" {
  value = aws_vpc.public-vpc.id
}

output "subnet-a_id" {
  value = aws_subnet.public-subnet-a.id
}

output "subnet-c_id" {
  value = aws_subnet.public-subnet-c.id
}

security_groupモジュール

## security group
resource "aws_security_group" "example_SG" {
  name        = "example_SG"
  description = "example_SG"
  vpc_id      = var.config.vpc_id

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

  ingress {
    from_port   = 443
    to_port     = 443
    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"]
  }

  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    ipv6_cidr_blocks = ["::/0"]
  }

  tags = {
    Name = "example_SG"
  }
}
variable "config" {
  type = object({
    vpc_id      = string
 })
}
output "security_group_id" {
  value = aws_security_group.example_SG.id
}

EC2モジュール

##EC2(example_EC2)
resource "aws_instance" "example_EC2" {
  ami                     = var.ami
  instance_type           = var.instance_type
  disable_api_termination = false
  key_name                = "EC2-key"
  vpc_security_group_ids  = [var.config.security_group_id]
  subnet_id             = var.config.subnet-a_id

  root_block_device {
    volume_type = "gp2"
    volume_size = var.volume_size
  }

  tags = {
    Name = "example_EC2"
  }
}

##EIP(example_EC2)
resource "aws_eip" "example_EC2" {
  instance = "${aws_instance.example_EC2.id}"
  vpc      = true
}
variable "config" {
  type = object({
    subnet-a_id = string
    subnet-c_id = string
    security_group_id = string
  })
}

variable "ami" {
  default = "ami-XXXXXXXXXXXX"
}

variable "instance_type" {
  default = "t2.micro"
}

variable "volume_size" {
  default = "8"
}

ALBモジュール

resource "aws_alb" "alb" {
  name                       = "alb"
  security_groups            = [var.config.security_group_id]
  subnets                    = [var.config.subnet-a_id, var.config.subnet-c_id]
  internal                   = false
  enable_deletion_protection = false
}

resource "aws_alb_target_group" "target-group" {
  name        = "target-group"
  depends_on  = [aws_alb.alb]
  port        = 80
  protocol    = "HTTP"
  vpc_id      = var.config.vpc_id
  target_type = "ip"

  health_check {
    protocol            = "HTTP"
    path                = "/ping"
    port                = 80
    unhealthy_threshold = 5
    timeout             = 5
    interval            = 10
    matcher             = 200
  }
}

resource "aws_alb_listener" "listener" {
  load_balancer_arn = aws_alb.alb.arn
  port              = 80
  protocol          = "HTTP"

  default_action {
    target_group_arn = aws_alb_target_group.target-group.arn
    type             = "forward"
  }
}

resource "aws_alb_listener_rule" "rule" {
  depends_on   = [aws_alb_target_group.target-group]
  listener_arn = aws_alb_listener.listener.arn
  priority     = 100

  action {
    type             = "forward"
    target_group_arn = aws_alb_target_group.target-group.arn
  }
  condition {
    path_pattern {
      values = ["*"]
    }
  }
}
variable "config" {
  type = object({
    vpc_id = string
    subnet-a_id = string
    subnet-c_id = string
    security_group_id = string
  })
}
output "dns_name" {
  value = aws_alb.alb.dns_name
}

ansible構築

ディレクトリ構成

Role作成

$ ansible-galaxy init nginx
├── nginx
│   ├── README.md
│   ├── defaults
│   │   └── main.yml
│   ├── files
│   ├── handlers
│   │   └── main.yml
│   ├── meta
│   │   └── main.yml
│   ├── tasks
│   │   └── main.yml
│   ├── templates
│   ├── tests
│   │   ├── inventory
│   │   └── test.yml
│   └── vars
│       └── main.yml
├── playbook.yml
├── aws_ec2.yml

aws_ec2.yml

plugin: aws_ec2

aws_access_key_id: XXXXXXXX
aws_secret_access_key: XXXXXXXX
aws_security_token:

regions:
  - ap-northeast-1
hostnames:
  - tag:Name
groups:
  nginx: "'<EC2インスタンス名>' in tags.Name"
compose:
  ansible_host: public_ip_address

playbook.yml

- hosts: nginx
  become: true

  vars_files:
    - ./nginx/vars/main.yml
  roles:
    - nginx

Nginx Role

- name: Enable amzn2extra-nginx1.12 repository
  shell: amazon-linux-extras enable nginx1.12
  changed_when: false

- name: Install Nginx packages from amazon-linux-extras
  yum:
    name: nginx
    state: present
# vars file for nginx
ansible_ssh_user: ec2-user
ansible_ssh_private_key_file: ~/.ssh/EC2-key.pem

実行コマンド

$ ansible-playbook -i aws_ec2.yml playbook.yml

参考文献