Terraformで再現:実践編1(AWSでJenkinsを動かす)

 こんにちは。入社して2年目のエンジニアの石川です。この記事は前回の記事Terraform計画編の続きとなります。手順が非常に多いため、実行編は2回に分けて書こうと思います。1つのmain.tfに全ての作業を書くことが目標となっています。モジュール化やec2でjenkinsを動かすのは次回移行のTerraform実行編2などで行う予定です。 ←前回の記事(計画編)はこちら



Terraform modules

構築にはTerraform AWS modulesというTerraform modulesを利用しました。このTerraform modulesを利用することで、Terraformで初めてAWSを構築するという場合でも簡単に構築できるというメリットがあります。
メリットが分かりやすい部分ですと、vpcの作成でしょうか。本来であれば自分でIGW(Internet GateWay)などを作成するように書かなくてはならないのですが、Terraform AWS modulesを利用すれば明記せずとも自動で作成してくれます。ルートテーブルの設定もいりません。

構成図と構築する際の注意点

 前回作成した以下の構成図をもとに構築を進めていきました。


構築(VPC)

まずはVPCの構築です。

module "vpc" {

  source = "terraform-aws-modules/vpc/aws"

  name   = "sample-vpc"

  cidr   = "172.16.0.0/16"


  azs            = ["ap-northeast-1a", "ap-northeast-1c"]

  public_subnets = ["172.16.1.0/24", "172.16.0.0/24"]


  vpc_tags = {

    Terraform   = "true"

    Environment = "dev"

  }

}



構築(EC2が利用するセキュリティグループ)

次にEC2に適用するセキュリティグループの作成です。

インバウンドルールとして、80番ポート(http)への全てのアクセスの許可、22番ポート(ssh)への自分のIPアドレスからの許可を設定し、
アウトバウンドルールとして、このEC2から他へのアクセスを全て許可するようにしています。

sshはEC2インスタンスの状況を接続して確認するためのもので、必要がなくなれば取り除いて良いです。

from_portやto_portは解放するポートの範囲を指定するためだけのものです。
(from_portが10、to_portが15→10,11,12,13,14,15番のポートが開く。自分はずっとここを勘違いしていて苦労していました笑)

module "ec2_sg" {

  source = "terraform-aws-modules/security-group/aws"


  name        = "sample-ec2-sg"


  vpc_id = module.vpc.vpc_id


  ingress_with_cidr_blocks = [

    {

      from_port   = 80

      to_port     = 80

      protocol    = "tcp"

      cidr_blocks = "0.0.0.0/0"

    },

    {

      from_port   = 22

      to_port     = 22

      protocol    = "tcp"

      cidr_blocks = "{自分のIPアドレス}"

    }

  ]

  egress_with_cidr_blocks = [

    {

      from_port   = 0

      to_port     = 0

      protocol    = "-1"

      cidr_blocks = "0.0.0.0/0"

    }

  ]

}


構築(EC2)

次にEC2インスタンスの作成です。

EC2を起動し、起動した時に実行してほしいコマンドなどをnginx.shに書いています。

module "ec2_instance" {

  source                 = "terraform-aws-modules/ec2-instance/aws"

  name                   = "sample-instance"

  ami                    = "ami-02a2700d37baeef8b"

  instance_type          = "t2.micro"

  key_name               = "{既存のキーの名前}"

  monitoring             = true

  vpc_security_group_ids = [module.ec2_allow_alb_sg.security_group_id]

  subnet_id              = module.vpc.public_subnets[0]

 associate_public_ip_address = true


  user_data = file("${path.module}/nginx.sh")

}


nginx.shはこのような感じです。
今回は構築がきちんとできるかどうかを確認することがメインであるため、nginxを起動するだけの簡単な内容が書かれています。

#!/bin/bash

sudo yum update -y # システムを更新する

sudo yum install nginx -y # Nginxをインストールする

sudo systemctl start nginx # Nginxを起動する

sudo systemctl enable nginx # Nginxを自動起動に設定する


構築(ALBに適用するセキュリティグループ)

次にALBに適用するセキュリティグループの作成です。
最終的にはhttpsからのアクセスのみを許可する予定なので443番ポートも解放しておきます。

逆に80番ポートを解放するルールはhttpsでのアクセスができることを確認した後に削除する予定です。

module "alb_sg" {

  source = "terraform-aws-modules/security-group/aws"


  name        = "sample-alb-sg"


  vpc_id = module.vpc.vpc_id


  ingress_with_cidr_blocks = [

    {

      from_port   = 80

      to_port     = 80

      protocol    = "tcp"

      cidr_blocks = "0.0.0.0/0"

    },

    {

      from_port   = 443

      to_port     = 443

      protocol    = "tcp"

      cidr_blocks = "0.0.0.0/0"

    }

  ]

  egress_with_cidr_blocks = [

    {

      from_port   = 0

      to_port     = 0

      protocol    = "-1"

      cidr_blocks = "0.0.0.0/0"

    }

  ]

}


構築(ALB)

次にALBの作成です。
ALBに対して80番、443番のアクセスがあった場合にそのアクセスを80番のアクセスとしてec2インスタンスに渡すようになっています。
最終的には80番からのアクセスは受け取らないようにするため、httpリスナーを取り除く予定です。

module "alb" {

  source = "terraform-aws-modules/alb/aws"


  name = "sample-alb"


  load_balancer_type = "application"


  vpc_id          = module.vpc.vpc_id

  subnets         = module.vpc.public_subnets

  security_groups = [module.alb_sg.security_group_id]


  target_groups = [

    {

      name_prefix      = "sm-"

      backend_protocol = "HTTP"

      backend_port     = 80

      target_type      = "instance"

      targets = {

        ec2_target = {

          target_id = module.ec2_instance.id

          port      = 80

        }

      }

    }

  ]

  http_tcp_listeners = [

    {

      port               = 80

      protocol           = "HTTP"

      target_group_index = 0

    }

  ]

  https_listeners = [

    {

      port               = 443

      protocol           = "HTTPS"

      certificate_arn    = module.acm.acm_certificate_arn

      target_group_index = 0

    }

  ]

}

ここまでの状況の問題点、エラーとここからどのように修正するか

今の問題点、エラーは

  • EC2は全てのhttpアクセスを受け取ってしまう

  • albのhttpsリスナーに適用するための証明書が存在していない

 となっています。そのためここからは

  • EC2はalbからのhttpアクセスのみを受け取るように修正する

  • albのhttpsリスナーに適用するための証明書を作成する

 が必要となります

構築(EC2がALB経由でアクセスするようにするためのセキュリティグループ)

次にEC2がALB経由でアクセスするようにするためのセキュリティグループの作成です。

EC2に適用するセキュリティグループのingress_with_source_security_group_idの80番ポートのアクセスを許可しているルールを修正します。

cidr_blocksではなく、source_security_group_idにalbに適用しているセキュリティグループを指定します。

  ingress_with_source_security_group_id = [

    {

      from_port                = 80

      to_port                  = 80

      protocol                 = "tcp"

      source_security_group_id = module.alb_sg.security_group_id

    }

  ]


構築(ACM、route53への追記)

次にalbのhttpsリスナーに設定する証明書の作成です。

証明書はドメイン名に対して発行されます。今回は既にルートドメインがあるので、サブドメインを作成し、それに対して証明書を発行します。

module "acm" {

  source = "terraform-aws-modules/acm/aws"


  domain_name = "sample.{ルートドメイン}"

  zone_id     = "{ルートドメインのホストゾーンID}"


  wait_for_validation = true

}


module "records" {

  source = "terraform-aws-modules/route53/aws//modules/records"


  zone_name = "{ルートドメイン}"


  records = [

    {

      name = "sample"

      type = "A"

      alias = {

        name    = "dualstack.${module.alb.lb_dns_name}"

        zone_id = module.alb.lb_zone_id

      }

    }

  ]


}


構築(ACM、route53への追記)

アクセスするときのドメイン名は、証明書発行時に指定したdomain_nameです。
このような画面が表示されていれば成功です。


まとめ

以上がTerraformの実行編1になります。今回はAWSに対して行う操作全てを1つのmain.tfに書いてみました。次回はec2でjenkinsを動かしたり、モジュール化していきます。実装編2までお待ちください。