Kumogata2 を使って ALB を含む環境を作ってみた

ELB

こんにちは、菅野です。
シーズンオフという事で、シュラフを洗濯しにコインランドリーに来ています。
待ち時間はたっぷりあるので、の〜んびりといきましょう。

はじめに

今回のブログエントリーは、10月14日に「夜ノDevelopers.IO」と題して開催した勉強会でお話する為に
Kumogata2 を使って ALB を作成できるかを検証した時の内容となります。

Kumogata2とは

クックパッドの菅原さん作のコマンドラインツールで、CloudFormation のスタックを作成できます。
特徴としては、

  • Ruby で書ける
    • コメントを書けます
    • ファイルを分ける事が可能
    • ループもできる(今回出番無し)
  • create オプションでスタックの作成が可能
    • 可能ですが今回使ってません
  • JSON へのコンバートが可能
    • create オプションを使わないでこればっかり使ってます
    • デザインテンプレートにも使えるし、S3 にアップロードすればでバージョン管理できるので

作成する構成

デザインテンプレートに作ってもらった構成図です。
SS-構成図

ファイル構成

こんな感じになりました
メインは alb.rb で、その中で他の3ファイルを include しています

  • alb.rb( ALB 設定ファイル)
  • alb-network.rb(ネットワーク設定ファイル)
  • alb-securitygroup.rb(セキュリティグループ設定ファイル)
  • alb-ec2.rb( EC2 設定ファイル)

alb-network.rb(ネットワーク設定ファイル)

このファイルで作成するリソースは以下となります。

  • VPC( albVpc
    • Name は「alb-vpc」
  • インターネットゲートウェイ( albIgw
    • Name は「alb-igw」
  • インターネットゲートウェイを VPC にアタッチする設定
    • VPC は「 albVpc 」を指定
    • インターネットゲートウェイは「 albIgw 」を指定
  • ルートテーブル( albRtt
    • Name は「alb-rtt」
    • VPC は「 albVpc 」を指定
  • ルート( albRt
    • ルートテーブルは「 albRtt 」を指定
    • ゲートウェイは「 albIgw 」を指定
  • サブネット( albSubnetA
    • Name は「alb-sub-a」
    • VPC は「 albVpc 」を指定
  • サブネットとルートテーブルの接続設定( albSubnetAToRtt
    • サブネットは「 albSubnetA 」を指定
    • ルートテーブルは「 albRtt 」を指定
  • サブネット( albSubnetC
    • Name は「alb-sub-c」
    • VPC は「 albVpc 」を指定
  • サブネットとルートテーブルの接続設定( albSubnetCToRtt
    • サブネットは「 albSubnetC 」を指定
    • ルートテーブルは「 albRtt 」を指定
# VPC
albVpc do
    Type "AWS::EC2::VPC"

    Properties do
        Tags [
            _{
                Key     "Name"
                Value   "alb-vpc"
            },
        ]
        CidrBlock           "10.10.0.0/21"
        EnableDnsHostnames  "true"
    end
end


# InternetGateway
albIgw do
    Type "AWS::EC2::InternetGateway"

    Properties do
        Tags [
            _{
                Key     "Name"
                Value   "alb-igw"
            },
        ]
    end
end
albIgwToVpc do
    Type "AWS::EC2::VPCGatewayAttachment"

    Properties do
        InternetGatewayId   { Ref "albIgw" }
        VpcId               { Ref "albVpc" }
    end
end


# RouteTable
albRtt do
    Type "AWS::EC2::RouteTable"

    Properties do
        Tags [
            _{
                Key     "Name"
                Value   "alb-rtt"
            },
        ]
        VpcId { Ref "albVpc" }
    end
end
albRt do
    Type "AWS::EC2::Route"

    Properties do
        DestinationCidrBlock    "0.0.0.0/0"
        GatewayId               { Ref "albIgw" }
        RouteTableId            { Ref "albRtt" }
    end
end


# Subnet in AZ-a
albSubnetA do
    Type "AWS::EC2::Subnet"

    Properties do
        Tags [
            _{
                Key     "Name"
                Value   "alb-sub-a"
            },
        ]
        AvailabilityZone    "ap-northeast-1a"
        CidrBlock           "10.10.0.0/24"
        MapPublicIpOnLaunch "true"
        VpcId               { Ref "albVpc" }
    end
end
albSubnetAToRtt do
    Type "AWS::EC2::SubnetRouteTableAssociation"

    Properties do
        SubnetId        { Ref "albSubnetA" }
        RouteTableId    { Ref "albRtt" }
    end
end


# Subnet in AZ-c
albSubnetC do
    Type "AWS::EC2::Subnet"

    Properties do
        Tags [
            _{
                Key     "Name"
                Value   "alb-sub-c"
            },
        ]
        AvailabilityZone    "ap-northeast-1c"
        CidrBlock           "10.10.1.0/24"
        MapPublicIpOnLaunch "true"
        VpcId               { Ref "albVpc" }
    end
end
albSubnetCToRtt do
    Type "AWS::EC2::SubnetRouteTableAssociation"

    Properties do
        SubnetId        { Ref "albSubnetC" }
        RouteTableId    { Ref "albRtt" }
    end
end

alb-securitygroup.rb(セキュリティグループ設定ファイル)

このファイルではセキュリティグループを設定します。

  • セキュリティグループ( albSgWeb
    • Name は「alb-sg-web」
    • VPC は「 albVpc 」を指定
    • 80 ポートだけを許可
# SecurityGroup
albSgWeb do
    Type "AWS::EC2::SecurityGroup"

    Properties do
        Tags [
            _{
                Key     "Name"
                Value   "alb-sg-web"
            },
        ]
        GroupDescription    "Enable HTTP access from internet"
        SecurityGroupIngress [
            _{
                IpProtocol  "tcp"
                FromPort    "80"
                ToPort      "80"
                CidrIp      "0.0.0.0/0"
            },
        ]
        VpcId   { Ref   "albVpc" }
    end
end

alb-ec2.rb( EC2 設定ファイル)

このファイルでは EC2 インスタンスを設定します。

  • EC2 インスタンス( albEc2
    • Name は「alb-ec2」
    • イメージ ID にパラメータの「 AMIID 」を指定
    • キー名にパラメータの「 KeyPair 」を指定
    • セキュリティグループは「 albSgWeb 」を指定
    • サブネットは「 albSubnetA 」を指定
    • ユーザーデータで apache のインストール、index.html ファイルの作成を行い apache を起動
# EC2
albEc2 do
    Type "AWS::EC2::Instance"

    Properties do
        ImageId         { Ref   "AMIID" }
        InstanceType    "t2.nano"
        KeyName         { Ref   "KeyPair" }
        SecurityGroupIds [
            _{ Ref  "albSgWeb" },
        ]
        SubnetId        { Ref   "albSubnetA" }
        Tags [
            _{
                Key     "Name"
                Value   "alb-ec2"
            },
        ]
        Tenancy         "default"
        UserData do
            Fn__Base64 (<<-EOS).undent
                #!/bin/bash
                yum install -y httpd
                echo "OK" > /var/www/html/index.html
                service httpd start
            EOS
        end
    end
end

alb.rb( ALB 設定ファイル)

このファイルをメインとしましたので、パラメータの指定と他のファイルの include を行っています。

  • パラメータの指定
    • 今回はキーペアの指定とAMI の ID の指定だけを可能としました
  • ネットワーク用ファイルの include
  • セキュリティグループ用ファイルの include
  • EC2 インスタンス用ファイルの include
  • ターゲットグループの設定( albTarget
    • Name は「tg-web」
    • ターゲットとして「 albEc2 」を指定
  • ALB の設定(alb)
    • Name は「alb-web」
    • 必ず二つの AZ にあるサブネットを指定しなくてはいけないので、「 albSubnetA 」と「 albSubnetC 」を指定
    • セキュリティグループは「 albSgWeb 」を指定
  • リスナーの設定( albListener
    • ロードバランサーは「 alb 」を指定
    • ターゲットグループは「 albTarget 」を指定
template do
    AWSTemplateFormatVersion "2010-09-09"

    # パラメータ
    Parameters do
        KeyPair {
            Type  "AWS::EC2::KeyPair::KeyName"
        }
        AMIID   {
            Default     "ami-374db956"
            Description "Input Amazon Linux Image ID"
            Type        "AWS::EC2::Image::Id"
        }
    end

    # リソース
    Resources do
        # ネットワーク
        _include './alb-network.rb'

        # セキュリティグループ
        _include './alb-securitygroup.rb'

        # EC2
        _include './alb-ec2.rb'

        # ターゲットグループ
        albTarget do
            Type "AWS::ElasticLoadBalancingV2::TargetGroup"

            # プロパティ
            Properties do
                Name        "tg-web"
                Protocol    "HTTP"
                Port        "80"
                VpcId       { Ref   "albVpc" }
                TargetGroupAttributes [
                    _{
                        Key     "deregistration_delay.timeout_seconds"
                        Value   "300"
                    },
                    _{
                        Key     "stickiness.enabled"
                        Value   "false"
                    },
                    _{
                        Key     "stickiness.type"
                        Value   "lb_cookie"
                    },
                    _{
                        Key     "stickiness.lb_cookie.duration_seconds"
                        Value   "86400"
                    },
                ]

                # EC2 インスタンス
                Targets [
                    _{
                        Id      { Ref   "albEc2" }
                        Port    "80"
                    },
                ]

                # ヘルスチェック
                HealthCheckProtocol         "HTTP"
                HealthCheckPath             "/index.html"
                HealthCheckPort             "traffic-port"
                HealthyThresholdCount       "5"
                UnhealthyThresholdCount     "2"
                HealthCheckTimeoutSeconds   "5"
                HealthCheckIntervalSeconds  "300"
                Matcher                     { HttpCode  "200" }
            end

        end

        # alb
        alb do
            Type "AWS::ElasticLoadBalancingV2::LoadBalancer"
            Properties do
                Name        "alb-web"
                Scheme      "internet-facing"
                Subnets [
                    _{ Ref  "albSubnetA" },
                    _{ Ref  "albSubnetC" },
                ]
                SecurityGroups [
                    _{ Ref  "albSgWeb" },
                ]
                LoadBalancerAttributes [
                    _{
                        Key     "deletion_protection.enabled"
                        Value   "false"
                    },
                    _{
                        Key     "idle_timeout.timeout_seconds"
                        Value   "60"
                    },
                    _{
                        Key     "access_logs.s3.enabled"
                        Value   "false"
                    },
                ]
            end
        end

        # Listener
        albListener do
            Type "AWS::ElasticLoadBalancingV2::Listener"
            Properties do
                LoadBalancerArn { Ref   "alb" }
                Protocol    "HTTP"
                Port        "80"
                DefaultActions [
                    _{
                        TargetGroupArn  { Ref   "albTarget" }
                        Type            "forward"
                    },
                ]
            end
        end
    end
end

テンプレートファイル作成後

テンプレートファイルが完成したら以下の作業を行います

検証

作成した設定ファイルに問題が無いか検証します

$ kumogata2 validate -r ap-northeast-1 ./alb.rb
Template validated successfully

コンバート

作成した Ruby のファイルから JSON ファイルを作成します

$ kumogata2 convert -r ap-northeast-1 alb.rb > ./alb.json

S3 へアップロード

JSON ファイルを作成したら S3 へアップロードします。

  • メリット
    • 自動でバージョニングしてくれる
    • CFn で簡単に指定できる
$ aws s3 cp ./alb.json s3://バケット名/alb.json
upload: ./alb.json to s3://バケット名/alb.json

CFn でスタック作成

先ほどアップロードした JSON ファイルを使ってスタックを作成してみます。

  • S3 にアップロードしたファイルを指定
    スクリーンショット_2016-10-16_22_25_08

  • スタック名と KeyPair を指定
    スクリーンショット_2016-10-16_22_33_30

  • 無事作成完了
    スクリーンショット_2016-10-16_22_38_20

  • できあがった ALB です
    スクリーンショット_2016-10-16_22_39_13

  • ALB の DNS 名にブラウザでアクセスしてみます
    「OK」と表示されましたので問題無く構築された事が確認できました
    スクリーンショット 2016-10-16 22.45.27

さいごに

いかがでしたでしょうか。
Kumogata2 を使う事によるメリットや新しい AWS リソースであっても問題無い事がわかっていただけたと思います。
是非一度お試しください。

参考ページ

これらのページを参考にさせていただきました。
ありがとうございました。
Kumogata2
CloudFormationでALBを構築する