Gluegent Blog

Gluegent Blog

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

  • 技術
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までお待ちください。
読んでいただきありがとうございました。

(石川)