EC2のユーザーデータでS3に配置したシェルスクリプトを実行してみた

2022.08.17

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

EC2のユーザーデータを使って起動時に色々とインストールするのはよくあることだと思います。 今回はそのユーザーデータを任意に変更できるよう、S3に配置したシェルスクリプトをユーザーデータに読み込んで実行できるかを試してみました。

シェルスクリプトの準備

ユーザーデータとして読み込ませるシェルを準備し、S3に配置します。今回は以下のような「jq」をインストールするシェルスクリプトを準備しました。

ec2-template.sh

  #!/bin/bash
  sudo yum update -y
  sudo yum -y install jq

上記のシェルスクリプトを、今回は「dev-honda-ec2-test」バケットに保存しました。

CloudFormationテンプレート

EC2を起動するためのCloudFormationテンプレートを準備します。以下のようになりました。

AWSTemplateFormatVersion: '2010-09-09'
Description: 'EC2 template.'

Parameters:
  AmiID:
    Type: String
    Default: ami-0ecb2a61303230c9d
  Prefix:
    Type: String
  SubnetID:
    Type: String
  UserDataBucket:
    Type: String
  UserDataShell:
    Type: String

Resources:
  EC2IAMRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${Prefix}-ec2-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      Policies:
        -
          PolicyName: !Sub ${Prefix}-ec2-policy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              -
                Effect: "Allow"
                Action:
                  - s3:GetObject
                Resource:
                  - !Sub "arn:aws:s3:::dev-honda-ec2-test/*"

  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - Ref: EC2IAMRole
      InstanceProfileName: !Sub ${Prefix}-ec2-instance-profile

  Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref AmiID
      InstanceType: t2.micro
      IamInstanceProfile: !Ref EC2InstanceProfile
      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !Ref SubnetID
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          aws s3 cp s3://${UserDataBucket}/${UserDataShell} /tmp/${UserDataShell}
          chmod +x /tmp/${UserDataShell}
          ./tmp/${UserDataShell}
      Tags:     
        - Key: Name
          Value: !Sub ${Prefix}-ec2

「Parameters」ではEC2インスタンス名などに任意のプレフィックスを指定するための「Prefix」、EC2を起動するサブネットを指定する「SubnetID」、先に書いたシェルスクリプトの格納先バケットやスクリプト名を指定する「UserDataBucket」「UserDataShell」を用意しました。AMIは(執筆時時点の)東京リージョンのAmazon Linux 2のAMIである「ami-0ecb2a61303230c9d」をデフォルト値としています。

「Resources」ではEC2のインスタンスロールを作るための「EC2IAMRole」、EC2インスタンスを作成するための「Instance」などを定義しました。「EC2IAMRole」では、後ほどSession Managerでログインするための「AmazonSSMManagedInstanceCore」ポリシーと、S3からシェルスクリプトを取得するためのポリシーを定義しています。

「Instance」の「UserData」では、S3バケット内のシェルスクリプトを「/tmp」ディレクトリに取得して実行するためユーザーデータを定義しています。

実行してみる

上記のCloudFormationテンプレートを使い、実際にスタックを作成してみました。スタック作成時のパラメータは以下のようになりました。

キー
AmiID ami-0ecb2a61303230c9d
Prefix t-honda-test
SubnetID subnet-xxxx
UserDataBucket dev-ec2-test
UserDataShell ec2-template.sh

スタックのステータスが「CREATE_COMPLETE」となると、EC2インスタンスが作成されます。先にも書いたようにEC2インスタンスにはSession Managerでログインします。マネージメントコンソールよりEC2を選択し、「接続」ボタンを押すとターミナルが表示されます。

ターミナルでは以下のように「ls -l」でS3に配置したシェルスクリプトがダウンロードされているか、シェルスクリプトに記述した「jq」がインストールされているかを確認してみました。

S3に配置した「ec2-template.sh」がダウンロードされ、「jq」もインストールされているようです。

最後に

以上のようにS3に配置したシェルスクリプトをユーザーデータに読み込んで実行することができました。何かの役に立てば幸いです。

参考サイト