AWS再入門2018 上級者でもたまに忘れる!? AWS CloudFormation 小ネタ編
こんにちは。池田です。札幌では八重桜がちらほら咲き始めてきました。道産子にもようやく屋外焼肉シーズンがやってまいりました。 ※ ハマりポイントというよりは「これ忘れることあるよねー」という意図でしたので、タイトルと本文の一部を追記・変更しました。
はじめに
早速ですが問題です。マネジメントコンソールにてテスト用の新規VPNとサブネット2つを作成し、下記の(某所からコピーしてちょっとカスタマイズした)AWS CloudFormationテンプレート(225行)を実行したところ、図のようなエラーにより失敗してしまいました。その原因と、最も簡単に解決するためのテンプレート修正方法を見つけられるでしょうか。制限時間は5分です。ではスクロールし過ぎのネタバレに気をつけてご覧ください。
AWSTemplateFormatVersion: 2010-09-09 Description: >- Test Template. Parameters: VpcId: Type: 'AWS::EC2::VPC::Id' Description: VpcId of your existing Virtual Private Cloud (VPC) Subnets: Type: 'List<AWS::EC2::Subnet::Id>' Description: The list of SubnetIds in your Virtual Private Cloud (VPC) InstanceType: Description: WebServer EC2 instance type Type: String Default: t2.micro AllowedValues: - t2.nano - t2.micro - t2.small ConstraintDescription: must be a valid EC2 instance type. KeyName: Description: Name of an existing EC2 KeyPair to enable SSH access to the instances Type: 'AWS::EC2::KeyPair::KeyName' ConstraintDescription: must be the name of an existing EC2 KeyPair. SSHLocation: Description: The IP address range that can be used to SSH to the EC2 instances Type: String MinLength: '9' MaxLength: '18' Default: 0.0.0.0/0 AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})' ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x. Mappings: AWSInstanceType2Arch: t2.nano: Arch: HVM64 t2.micro: Arch: HVM64 t2.small: Arch: HVM64 AWSInstanceType2NATArch: t2.nano: Arch: NATHVM64 t2.micro: Arch: NATHVM64 t2.small: Arch: NATHVM64 AWSRegionArch2AMI: ap-northeast-1: PV64: ami-3e42b65f HVM64: ami-ceafcba8 HVMG2: ami-edfd658b Resources: WebServerGroup: Type: 'AWS::AutoScaling::AutoScalingGroup' Properties: VPCZoneIdentifier: !Ref Subnets LaunchConfigurationName: !Ref LaunchConfig MinSize: '2' MaxSize: '2' TargetGroupARNs: - !Ref ALBTargetGroup CreationPolicy: ResourceSignal: Timeout: PT15M UpdatePolicy: AutoScalingRollingUpdate: MinInstancesInService: '1' MaxBatchSize: '1' PauseTime: PT15M WaitOnResourceSignals: 'true' LaunchConfig: Type: 'AWS::AutoScaling::LaunchConfiguration' Metadata: Comment: Install a simple application 'AWS::CloudFormation::Init': config: packages: yum: httpd: [] files: /var/www/html/index.html: content: !Join - |+ - - >- <h3>You have successfully launched the AWS CloudFormation test.</h3> mode: '000644' owner: root group: root /etc/cfn/cfn-hup.conf: content: !Join - '' - - | [main] - stack= - !Ref 'AWS::StackId' - |+ - region= - !Ref 'AWS::Region' - |+ mode: '000400' owner: root group: root /etc/cfn/hooks.d/cfn-auto-reloader.conf: content: !Join - '' - - | [cfn-auto-reloader-hook] - | triggers=post.update - > path=Resources.LaunchConfig.Metadata.AWS::CloudFormation::Init - 'action=/opt/aws/bin/cfn-init -v ' - ' --stack ' - !Ref 'AWS::StackName' - ' --resource LaunchConfig ' - ' --region ' - !Ref 'AWS::Region' - |+ - | runas=root mode: '000400' owner: root group: root services: sysvinit: httpd: enabled: 'true' ensureRunning: 'true' cfn-hup: enabled: 'true' ensureRunning: 'true' files: - /etc/cfn/cfn-hup.conf - /etc/cfn/hooks.d/cfn-auto-reloader.conf Properties: ImageId: !FindInMap - AWSRegionArch2AMI - !Ref 'AWS::Region' - !FindInMap - AWSInstanceType2Arch - !Ref InstanceType - Arch SecurityGroups: - !Ref InstanceSecurityGroup InstanceType: !Ref InstanceType KeyName: !Ref KeyName UserData: !Base64 'Fn::Join': - '' - - | #!/bin/bash -xe - | yum update -y aws-cfn-bootstrap - '/opt/aws/bin/cfn-init -v ' - ' --stack ' - !Ref 'AWS::StackName' - ' --resource LaunchConfig ' - ' --region ' - !Ref 'AWS::Region' - |+ - '/opt/aws/bin/cfn-signal -e $? ' - ' --stack ' - !Ref 'AWS::StackName' - ' --resource WebServerGroup ' - ' --region ' - !Ref 'AWS::Region' - |+ ApplicationLoadBalancer: Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer' Properties: Subnets: !Ref Subnets SecurityGroups: - !Ref InstanceSecurityGroup ALBListener: Type: 'AWS::ElasticLoadBalancingV2::Listener' Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref ALBTargetGroup LoadBalancerArn: !Ref ApplicationLoadBalancer Port: '80' Protocol: HTTP ALBTargetGroup: Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' Properties: HealthCheckIntervalSeconds: 30 HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 3 Port: 80 Protocol: HTTP UnhealthyThresholdCount: 5 VpcId: !Ref VpcId InstanceSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: Enable SSH access and HTTP access on the inbound port SecurityGroupIngress: - IpProtocol: tcp FromPort: '80' ToPort: '80' CidrIp: !Ref SSHLocation - IpProtocol: tcp FromPort: '22' ToPort: '22' CidrIp: !Ref SSHLocation VpcId: !Ref VpcId Outputs: URL: Description: URL of the website Value: !Join - '' - - 'http://' - !GetAtt - ApplicationLoadBalancer - DNSName
正解
原因はわかりましたでしょうか。実は初心者に限らずとも、つい見落としがちなミスが原因でした。
Properties: AssociatePublicIpAddress: true ImageId: !FindInMap - AWSRegionArch2AMI - !Ref 'AWS::Region' - !FindInMap - AWSInstanceType2Arch - !Ref InstanceType - Arch
AssociatePublicIpAddress VPC の Amazon EC2 インスタンスで、Auto Scaling グループのインスタンスがパブリック IP アドレスを受け取るかどうかを示します。true の場合には、Auto Scaling の各インスタンスが一意のパブリック IP を受け取ります。 AWS::AutoScaling::LaunchConfiguration
そうです。CloudFormationにより作成されたEC2インスタンスにパブリックIPアドレスが割り当てられていないことで、yumコマンドが完了せず、インスタンス作成のsuccessシグナルが送られないままタイムアウトが発生し、ロールバックされていたのでした。
まとめ
慣れたつもりでヒョイヒョイっとコピペして使うと、こういううっかりミスに遭遇して(マネジメントコンソールに表示される簡易エラー表示からは連想できずに)ハマってしまうことがあるよね。新規作成したVPC側の設定忘れはよくやらかすわー。などという話題がオフィスで出たのでご紹介でした。 ※ 他にもサブネットを作成するときにPublic IPの自動付与をしておく、NAT経由で外部との通信が可能となるようにするなど、複数の解消方法はありますが、もっとも簡単な(テンプレートに1行追記するだけで済む)方法を今回の正解とさせていただきました。