ユーザーデータを使ってEC2構築作業を楽にする

EC2を作成後に毎回同様の設定変更をする運用でしたが、「ユーザーデータ」機能を活用して作業時間を短縮できましたので、備忘としてやり方を記載したいと思います。

##対象
OS: Redhat6.7

##手順概要
1. 元となるEC2に必要な処理を書いたShellscryptを配置
2. 1. のEC2インスタンスからAMIを作成
3. 以後、EC2インスタンス作成時に2. のAMIとユーザーデータを指定
4. 完成

実際はもっと色々設定変更を行っているのですが、例として下記の自動化に絞って書きたいと思います。
・/etc/hosts　の変更
・/etc/sysconfig/network　の変更

これらのファイルを

```terminal:/etc/hosts(変更前)
127.0.0.1   yaseinohost_number localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
```

```terminal:/etc/sysconfig/network（変更前）
NETWORKING=yes
HOSTNAME=yaseinohost_number
NETWORKING_IPV6=no
NOZEROCONF=yes
```

このように変更したい（「number」の部分を数字に置き換えたい）

```terminal:/etc/hosts(変更後)
127.0.0.1   yaseinohost_100 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
```

```terminal:/etc/sysconfig/network（変更後）
NETWORKING=yes
HOSTNAME=yaseinohost_100
NETWORKING_IPV6=no
NOZEROCONF=yes
```

##手順


####1. 元となるEC2にShellScriptを配置します

```shell:/home/ec2-user/script/autoconfig.sh
#!/bin/sh -x

#Get SecurityGroupName from meta-data and extract number
number=`curl -s http://169.254.169.254/latest/meta-data/security-groups |sed -e 's/yaseino-//g'  -e 's/-SG//g'`

#Modify file "/etc/hosts"
cp -ip /etc/hosts /etc/hosts`date "+%Y%m%d_%H%M%S"`
sed -i -e "s/number/${number}/g" /etc/hosts
cat /etc/hosts

#Modify file "/etc/sysconfig/network"
cp -ip /etc/sysconfig/network /etc/sysconfig/network`date "+%Y%m%d_%H%M%S"`
sed -i -e "s/number/${number}/g" /etc/sysconfig/network
cat /etc/sysconfig/network
```

***解説：***
「number」に入れる数字はセキュリティグループ名の数字と合わせたいため、meta-dataから取得しました。

```
#meta-dataからセキュリティグループ名を取得できる
$curl -s http://169.254.169.254/latest/meta-data/security-groups
yaseino-100-SG
#さらにsedで不要な文字列をカット
$curl -s http://169.254.169.254/latest/meta-data/security-groups |sed -e "s/yaseino-//g"  -e "s/-SG//g"
100
```

セキュリティグループ以外にも、meta-dataから色々な値が取得可能です。

```
$ curl -s http://169.254.169.254/latest/meta-data/
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
events/
hostname
identity-credentials/
instance-action
instance-id
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups
```

数字が取得出来たら、あとは各ファイルの内容をsedで書き換えるだけです。


また、/etc/cloud/cloud.cfgに下記を定義しておきます、
(インスタンスの初回起動時にip-XX-XX-XX-XXというPrivate IPを元にしたホスト名に変更されてしまうため）

```
preserve_hostname: True
```


####2. EC2からAMIを作成します
AWSマネジメントコンソール>EC2>にて手順1. のインスタンスを選択し、
アクション>イメージ>イメージの作成

####3. 以後、新しいEC2インスタンス作成時に2. のAMIとユーザーデータを指定
Cloudformationのテンプレート（YAML形式）

```yaml:create_ec2.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'AWS CloudFormation Template for EC2'
----
省略
----
Resources:
  MyEC2instance:
    Type: "AWS::EC2::Instance"
    Properties:
      ImageId: !Ref 'ImageId'　　#手順2. で作成したAMIを指定
      InstanceType: !Ref 'InstanceType'
      SubnetId: !Ref 'SubnetID'
      DisableApiTermination: False
      BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeType: gp2
            VolumeSize: !Ref 'StorageSize'
      SecurityGroupIds: !GetAtt 'MyLinuxEC2SecurityGroups.GroupId'
      KeyName: !Ref 'Keyname'
      Tags: 
        - Key: Name
          Value: !Ref 'Hostname'
      UserData:
        Fn::Base64: !Sub |
          #cloud-config
          runcmd:
           - /home/ec2-user/script/auto_setting01.sh >/home/ec2-user/script/auto_setting.log 2>&1
           - reboot
----
省略
----
```

***解説：***
・「UserData:」プロパティを使用しています。
・#cloud-configを宣言してruncmd: にそのままコマンドが書けます。
・#!/bin/bashを宣言すれば、直接シェルスクリプトを実行することもできます。
・#cloud-configと#!/bin/bashを両方実行するには、少しコツがいるようです。
https://dev.classmethod.jp/cloud/aws/cloud-init-use-shell-and-cloud-config/
・設定を反映させるためにrebootしています。
・Cloudformationからではなく直接EC2を作成する場合も、ユーザーデータの記述が可能です。
　（EC2作成途中画面>高度な詳細>ユーザーデータ）
![高度な設定_userdata.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130739/3e2f5781-b796-027d-93ac-2f93af104f73.png)



####4. 完成
EC2が作成されたあと、ユーザーデータに記載した処理が自動的に実行されます。
その分少しだけ作成完了まで時間がかかりました。

出力されたログを確認してみます。
上手く動いたようです。

```text:/home/ec2-user/script/auto_setting.log
++ curl -s http://169.254.169.254/latest/meta-data/security-groups
++ sed -e s/yaseino-//g -e s/-SG//g
+ number=100
++ date +%Y%m%d_%H%M%S
+ cp -ip /etc/hosts /etc/hosts20191025_031836
+ sed -i -e s/number/100/g /etc/hosts
+ cat /etc/hosts
127.0.0.1   yaseinohost_100 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
++ date +%Y%m%d_%H%M%S
+ cp -ip /etc/sysconfig/network /etc/sysconfig/network20191025_031836
+ sed -i -e s/number/100/g /etc/sysconfig/network
+ cat /etc/sysconfig/network
NETWORKING=yes
HOSTNAME=yaseinohost_100
NETWORKING_IPV6=no
NOZEROCONF=yes
```

実際にファイルも確認してみます。

```terminal:/etc/hosts
127.0.0.1   yaseinohost_100 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
```

```terminal:/etc/sysconfig/network
NETWORKING=yes
HOSTNAME=yaseinohost_100
NETWORKING_IPV6=no
NOZEROCONF=yes
```