0
0

【AWS】AmazonLinux2023のEC2をスケジュール起動するCloudformationテンプレート

Posted at

概要

Amazon Linux 2023でEC2(ssh)サーバを平日8:00-20:00の間起動するCloudformationテンプレートを作成しました。

起動テンプレートのUserdataやLambda、autoscalingを使って実装している記事もありましたが、UIからも管理しやすいCloudwatchRuleで運用する方針としています。

前提

VPC/Subnet関連は、他のスタックで作成済みの前提です。

また、AL2023のAMIの詳細については以下をご参考ください。

サンプルテンプレート

AWSTemplateFormatVersion: 2010-09-09

################################################################################
# Parameters
################################################################################
Parameters:
  ########################################
  # Common
  ########################################
  SystemTag:
    Type: String
    Default: "sample"
  SampleIP:
    Type: String
    Default: "111.222.333.444/32"

  ########################################
  # EC2
  ########################################
  Ec2InstanceType:
    Type: String
    Default: "t3.micro"
  Ec2InstanceAMI:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
  Ec2EbsVolumeSize1:
    Type: Number
    Default: 10

################################################################################
# Resources
################################################################################
Resources:

  SshRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          -
            Effect: "Allow"
            Principal:
              Service:
                - "ec2.amazonaws.com"
                - "codedeploy.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonEC2FullAccess
        - arn:aws:iam::aws:policy/AmazonRDSFullAccess
        - arn:aws:iam::aws:policy/AWSCodeDeployFullAccess
        - arn:aws:iam::aws:policy/IAMFullAccess
        - arn:aws:iam::aws:policy/AmazonSSMFullAccess  

  SshSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      GroupName: !Sub ${SystemTag}-SSH
      GroupDescription: !Sub ${SystemTag}-SSH
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref SampleIP
      VpcId: !ImportValue VpcSample # Vpc/Subnet関連は他で作成してインポート
      Tags:
        - Key: Name
          Value: !Sub ${SystemTag}-SSH

  EC2InstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      Path: "/"
      Roles:
        - !Ref SshRole

  SshEc2Template:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateData:
        IamInstanceProfile:
          Arn: !GetAtt EC2InstanceProfile.Arn
        NetworkInterfaces:
            - AssociatePublicIpAddress: true
              DeleteOnTermination: true
              DeviceIndex: 0
              SubnetId: !ImportValue PublicSubnet1 # Vpc/Subnet関連は他で作成してインポート
              Groups: !Ref SshSecurityGroup
        InstanceInitiatedShutdownBehavior: "stop"
        ImageId: !Ref Ec2InstanceAMI
        KeyName: !Sub ${SystemTag}-ssh # KeyPairはマネコンから手動作成
        Monitoring:
          Enabled: false
        CreditSpecification:
          CpuCredits: "standard"
        InstanceType: !Ref Ec2InstanceType
        BlockDeviceMappings:
          - DeviceName: "/dev/xvda"
            Ebs:
              VolumeSize: !Ref Ec2EbsVolumeSize1
              VolumeType: "gp2"
              DeleteOnTermination: false            
        UserData:
          Fn::Base64: |
            #!/bin/bash

            timedatectl set-timezone Asia/Tokyo

            # MySQL Client
            dnf -y localinstall https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm
            dnf config-manager --disable mysql80-community
            dnf config-manager --enable mysql57-community
            dnf install -y mysql

            if ! command -v aws &> /dev/null
            then
                dnf install -y unzip
                cd /tmp
                curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
                unzip awscliv2.zip
                sudo ./aws/install
            fi

  Ec2Instance:
    Type: AWS::EC2::Instance
    Properties:
      LaunchTemplate:
        LaunchTemplateId: !Ref "SshEc2Template"
        Version: !GetAtt "SshEc2Template.LatestVersionNumber"
      Tags:
        - Key: Name
          Value: !Sub ${SystemTag}-SSH

  ElasticIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
      Tags:
      - Key: Name
        Value: !Sub ${SystemTag}-SSH

  ElasticIPAssociate:
   Type: AWS::EC2::EIPAssociation
   Properties: 
     AllocationId: !GetAtt ElasticIP.AllocationId
     InstanceId: !Ref Ec2Instance

もし、このEC2を平日8:00-20:00の間だけ起動したい、という場合は以下を追加すればOKです。Cron式はUTC表記になっているので気を付けてください。

  CloudWatchEventsRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - 
            Effect: Allow
            Principal:
              Service:
                - events.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: "/"
      RoleName: CloudWatchEventsRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMFullAccess
        - arn:aws:iam::aws:policy/AmazonRDSFullAccess
        - arn:aws:iam::aws:policy/AmazonEC2FullAccess

  SSHEventRuleEc2Start:
    Type: AWS::Events::Rule
    Properties:
      Name: EventRuleEc2Start-SSH-sample
      Description: 'Rules for starting sample-SSH ec2 instance'
      ScheduleExpression: cron(0 23 ? * SUN-THU *)
      State: ENABLED
      EventBusName: default
      Targets:
        - Id: !Sub SSHEventRuleEc2Start-${SystemTag}-ssh
          Arn: "arn:aws:ssm:ap-northeast-1::automation-definition/AWS-StartEC2Instance:$DEFAULT"
          RoleArn: !GetAtt CloudWatchEventsRole.Arn
          Input: !Sub '{"InstanceId":["${Ec2Instance}"]}'

  SSHEventRuleEc2Stop:
    Type: AWS::Events::Rule
    Properties:
      Name: EventRuleEc2Stop-SSH-sample
      Description: 'Rules for stopping sample-SSH ec2 instance'
      ScheduleExpression: cron(0 11 * * ? *)
      State: ENABLED
      EventBusName: default
      Targets:
        - Id: !Sub SSHEventRuleEc2Stop-${SystemTag}-ssh
          Arn: "arn:aws:ssm:ap-northeast-1::automation-definition/AWS-StopEC2Instance:$DEFAULT"
          RoleArn: !GetAtt CloudWatchEventsRole.Arn
          Input: !Sub '{"InstanceId":["${Ec2Instance}"]}'

補足1: AL2023のUserdata

Amazon Linux 2023は、以前のバージョンのAmazon Linuxとは異なり、yumではなくdnfパッケージマネージャーを使用します。AL2のようにyum updateとしても更新されません。

dnfyumの後継であり、より高速で依存関係の解決が改善されているとのこと。
基本的に、従来のyumコマンドをdnfに置き換えればOKです。

また、AL2023ではデフォルトでAWS CLI v2系がインストールされています。念の為、既にインストールされているかどうかを確認し、インストールされていない場合のみインストールプロセスを実行するようにしています。

補足2:セキュリティグループの位置

EC2インスタンスを作成する際に、インスタンスレベルでのセキュリティグループとネットワークインターフェースを同時に指定しようとした場合に以下のエラーが発生しました。

Resource handler returned message: "Network interfaces and an instance-level security groups may not be specified on the same request

ネットワークインターフェースを明示的に指定する場合、そのネットワークインターフェースにセキュリティグループを割り当てる必要があり、インスタンスレベルで別途セキュリティグループを指定するとエラーになるのです。

上述の通り、NetworkInterfaces以下にセキュリティグループの指定があれば問題ありません。

参考:

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0