この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
コンセプト
ALBの構築作業を行っているとALBの設定の検証を行いたい局面があると思います。
そんなとき毎回EC2立てて、ターゲットグループ作って、ALB作ってと作業をするのは冗長なのでCloudFormationテンプレート一つで簡単に構築できるようにしました。
本番で使うには色々と不足している部分もあるかと思いますが、検証に使う分にはミニマルで使いやすいのではないかと思います。
構成
本テンプレートで作成できる環境は以下のようなものです。
EC2は1台でパブリックサブネットに配置しています。 これはEC2にSessionManagerにNATゲートウェイなしで接続するためです。
EC2インスタンスではNginxが起動します。 EC2のOSはAmazonLinux2です。
テンプレート
alb.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: ALB and Nginx on EC2
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-vpc
PublicSubnet0:
Type: AWS::EC2::Subnet
DependsOn: AttachGateway
Properties:
VpcId: !Ref VPC
AvailabilityZone: ap-northeast-1a
CidrBlock: 10.0.0.0/24
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-public-1a-subnet
PublicSubnet1:
Type: AWS::EC2::Subnet
DependsOn: AttachGateway
Properties:
VpcId: !Ref VPC
AvailabilityZone: ap-northeast-1c
CidrBlock: 10.0.1.0/24
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-public-1c-subnet
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-igw
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
PublicRouteTable:
Type: AWS::EC2::RouteTable
DependsOn: AttachGateway
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-public-rt
PublicRoute:
Type: AWS::EC2::Route
DependsOn: AttachGateway
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnet0RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet0
RouteTableId: !Ref PublicRouteTable
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet1
RouteTableId: !Ref PublicRouteTable
ALBSecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupDescription: "ALB SG"
GroupName: !Sub ${AWS::StackName}-alb-sg
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-alb-sg
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
EC2SecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupDescription: "EC2 SG"
GroupName: !Sub ${AWS::StackName}-ec2-sg
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-ec2-sg
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref ALBSecurityGroup
EC2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: "/"
Roles:
- !Ref EC2Role
InstanceProfileName: !Sub ${AWS::StackName}-ec2-profile
EC2Role:
Type: "AWS::IAM::Role"
Properties:
Path: "/"
RoleName: !Sub ${AWS::StackName}-ec2-role
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-ec2-role
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
KeyPair:
Type: 'AWS::EC2::KeyPair'
Properties:
KeyName: !Sub ${AWS::StackName}-keypair
WebServer:
Type: AWS::EC2::Instance
Properties:
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-web
InstanceType: t3.nano
BlockDeviceMappings:
- DeviceName: /dev/sda1
Ebs:
VolumeType: gp3
VolumeSize: 8
DeleteOnTermination: true
Encrypted: true
NetworkInterfaces:
- AssociatePublicIpAddress: "true"
DeviceIndex: "0"
GroupSet:
- !Ref EC2SecurityGroup
SubnetId: !Ref PublicSubnet0
ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}'
IamInstanceProfile: !Ref EC2InstanceProfile
KeyName: !Ref KeyPair
DisableApiTermination: false
EbsOptimized: true
UserData:
Fn::Base64: |
#!/bin/bash
sudo amazon-linux-extras install nginx1
sudo systemctl enable nginx
sudo systemctl start nginx
ALB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Type: "application"
Scheme: "internet-facing"
Name: !Sub ${AWS::StackName}-alb
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-alb
IpAddressType: ipv4
Subnets:
- !Ref PublicSubnet0
- !Ref PublicSubnet1
SecurityGroups:
- !Ref ALBSecurityGroup
ListenerHTTP:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
LoadBalancerArn: !Ref ALB
Port: 80
Protocol: HTTP
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub ${AWS::StackName}-tg
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-tg
Port: 80
Protocol: HTTP
Matcher:
HttpCode: '200'
VpcId: !Ref VPC
TargetType: instance
Targets:
- Id: !Ref WebServer
Outputs:
ALBURL:
Description: ALB endpoint URL
Value: !Join
- ""
- - http://
- !GetAtt ALB.DNSName
使い方
デプロイ
今回はテンプレートにパラメータは設定していないので、そのままスタック名だけ決めてデプロイすれば問題ありません。
デプロイ途中で以下のような警告が表示されると思いますが、これはSessionManagerでEC2にアクセスする用のIAMロールを作成しているためです。 スタックの作成が完了すると「{スタック名}-xxx」といった感じでリソースが作成されます。
ALBへのアクセス
スタックの出力にALBのURLが表示されているのでここにアクセスすればNginxにアクセス可能です。
正しくデプロイされていれば以下のようなページが表示されるはずです。
今回はACMなどのリソースあとで作るものとし、HTTPS用のリスナーは定義していません。(セキュリティグループは開けてあります)
削除
ALBやEC2の削除保護は無効にしてあるのでスタックを削除すれば同じく削除されます。
EC2への接続
今回はEC2へのアクセスはセッションマネージャーの利用を想定し、それ用のロールも付与してあります。
もし、SSHなどで直接アクセスしたい場合はパラメータストアにキーペアが保存してあるのでそこから取得可能です。 パラメータストアを確認すると「/ec2/keypair/key-xxx」といったパラメータが作成されてます。 こちらのキーペアをコピペしてファイルに貼り付ければ利用可能です。
最後に
これで検証を行う際すぐにALBを用意できるようになりました。 作ったり消したりしながらALBの検証を行っていきたいと思います。