PackerでAWSのAMIを色々作成する


## Packerとは？
* マシンイメージを自動的に作成するツール
  * マシンイメージはAWS(AMI)、Docker, Google, Azureなど対応

## 環境
* Amazon Linux AMI 2016.03.3

## インストール
* ver0.10.1 (2016/07/18現在最新バージョン)

```
sudo wget  https://releases.hashicorp.com/packer/0.10.1/packer_0.10.1_linux_amd64.zip
sudo unzip packer_0.10.1_linux_amd64.zip -d /opt/packer/
export PATH=/opt/packer:$PATH
echo 'export PATH=/opt/packer:$PATH' >> ~/.bashrc
```

## バージョン確認
```bash
packer version
#=> Packer v0.10.1
```
## 設定ファイル作成(最低限)
* AMIを作成する場合、最低限以下が必要
  * type(AWSの場合"amazon-ebs")
  * access_key(※aws configureやIAM roleを付与することで省略可)
  * secret_key(※aws configureやIAM roleを付与することで省略可)
  * 作成するAMI名
  * リージョン
  * 作成元のAMI
  * インスタンスタイプ
  * sshユーザ名(例：AmazonLinuxの場合、ec2-user, CentOSの場合、centos)
* VPC, Subnetを指定しない場合は、デフォルトVPCを使用。セキュリティグループや、キーペアはPackerが実行時に作成して、終わったら削除（それぞれ明示的に指定も可）

```json:minium.json
{
    "builders":
    [
        {
            "type": "amazon-ebs",
            "access_key": "xxxxxx",
            "secret_key": "xxxxxx",
            "ami_name": "test ami",
            "region": "ap-northeast-1",
            "source_ami": "ami-374db956",
            "instance_type": "t2.micro",
            "ssh_username": "ec2-user"
        }
    ],
    "provisioners": [
        {
            "type": "shell",
            "inline": [ "echo hello world" ]
        }
    ]
}
```

## 確認
```bash
packer validate minimum.json
```

```text:成功時
Template validated successfully.
```
```text:失敗時例(必須項目が無い場合)
Template validation failed. Errors are shown below.

Errors validating build 'amazon-ebs'. 2 error(s) occurred:

* An ssh_username must be specified
* An instance_type must be specified
```


## 実行
```bash
packer build minimum.json
```
```text:実行結果例
amazon-ebs output will be in this color.

==> amazon-ebs: Prevalidating AMI Name...
==> amazon-ebs: Inspecting the source AMI...
==> amazon-ebs: Creating temporary keypair: packer 578ce302-e01d-fab7-3f42-bba477c2671d
==> amazon-ebs: Creating temporary security group for this instance...
==> amazon-ebs: Authorizing access to port 22 the temporary security group...
==> amazon-ebs: Launching a source AWS instance...
    amazon-ebs: Instance ID: i-18db9087
==> amazon-ebs: Waiting for instance (i-18db9087) to become ready...
==> amazon-ebs: Waiting for SSH to become available...
==> amazon-ebs: Connected to SSH!
==> amazon-ebs: Provisioning with shell script: /tmp/packer-shell768722931
    amazon-ebs: hello world
==> amazon-ebs: Stopping the source instance...
==> amazon-ebs: Waiting for the instance to stop...
==> amazon-ebs: Creating the AMI: base 2016-07-18T14-09-06Z
    amazon-ebs: AMI: ami-64936a05
==> amazon-ebs: Waiting for AMI to become ready...
==> amazon-ebs: Terminating the source AWS instance...
==> amazon-ebs: Cleaning up any extra volumes...
==> amazon-ebs: No volumes to clean up, skipping
==> amazon-ebs: Deleting temporary security group...
==> amazon-ebs: Deleting temporary keypair...
Build 'amazon-ebs' finished.

==> Builds finished. The artifacts of successful builds are:
--> amazon-ebs: AMIs were created:

ap-northeast-1: ami-XXXXXXXX
```


## 実行設定

### デバッグしたい
* 通常はAMI作成 or 失敗するまではノンストップだが、```-debug```を指定することで、インスタンス起動中とかでログインとか可能

```
packer build minimum.json -debug
```

```text:debug実行
Debug mode enabled. Builds will not be parallelized.
amazon-ebs output will be in this color.

==> amazon-ebs: Prevalidating AMI Name...
==> amazon-ebs: Pausing after run of step 'StepPreValidate'. Press enter to continue.
```

### CSV形式で表示する
* ```-machine-readable```を指定することで、出力結果がCSV形式になる（なので人間には見にくい）

```
packer build minimum.json -machine-readable
```

```text:csv形式出力結果
1468852163,,ui,say,amazon-ebs output will be in this color.
1468852163,,ui,say,
1468852164,,ui,say,==> amazon-ebs: Prevalidating AMI Name...
1468852164,,ui,say,==> amazon-ebs: Inspecting the source AMI...
1468852164,,ui,say,==> amazon-ebs: Creating temporary keypair: packer 578ce7c3-9fd7-094c-cd2d-2fa2eef3fbaa
1468852164,,ui,say,==> amazon-ebs: Creating temporary security group for this instance...
1468852164,,ui,say,==> amazon-ebs: Authorizing access to port 22 the temporary security group...
....
```

### 設定値を外出し(コマンド)
* アクセスキーなどファイルに直接記載したくない場合は、jsonファイルに```{{user `変数名`}}```と記載して、```-var```を指定することで可能(複数指定可)

```json:variable.json
{
    "builders":
    [
        {
            "type": "amazon-ebs",
            "access_key": "{{user `aws_access_key`}}",
            "secret_key": "{{user `aws_secret_key`}}",
            "ami_name": "test ami",
            "region": "ap-northeast-1",
            "source_ami": "ami-374db956",
            "instance_type": "t2.micro",
            "ssh_username": "ec2-user"
        }
    ]
}
```

```
packer build -var 'aws_access_key=XXXX' -var 'aws_secret_key=XXXX' variable.json
```

### 設定値を外出し(ファイル)
* 外出ししたい情報はjsonファイルにすることも可。その場合は、```-var-file=<path>```で指定する

```json:credential.json
{
    "aws_access_key": "xxxx",
    "aws_secret_key": "xxxx"
}
```

```
packer build -var-file=credential.json variable.json
```

### 作成されたAMI IDを取得する
* 作成したAMI IDを後続の処理に使いたい場合は以下のようにすると取得可能

```bash
packer build minimum.json | tee output.log | tail -2 | head -2 | awk 'match($0, /ami-.*/) { print substr($0, RSTART, RLENGTH) }'
# => ami-xxxxxx
```


## provisioners設定 

### コマンドを実行する
* ```"type": "shell"``` + ```inline```で実行するコマンドを記述する（配列なので複数コマンド指定可）

```json
{
    "provisioners": [
        {
            "type": "shell",
            "inline": [
                "echo update yum",
                "sudo yum install -y yum-utils"
            ]
        }
    ]
}
```

### シェル（ファイル）を実行する
* ```"type": "shell"``` + ```script```で実行するファイルのパスを指定する

```json
{
    "provisioners": [
        {
            "type": "shell",
            "script": "test.sh"
        }
    ]
}
```

* 複数指定したい場合は```scripts```で指定する

```json
{
    "provisioners": [
        {
            "type": "shell",
            "scripts": [
              "test.sh",
              "test2.sh",
            ]
        }
    ]
}
```

### AMI(インスタンス)にファイル・フォルダをコピーする
* ```"type": "file"```を使い、```source```でコピー元ファイル・フォルダを指定し、```destination```でコピー先を指定する

```json
{
    "provisioners": [
        {
            "type": "file",
            "source": "sample.txt",
            "destination": "/home/ec2-user/sample.txt"
        },
        {
            "type": "file",
            "source": "sample_dir",
            "destination": "/home/ec2-user"
        }
    ]
}
```

## AMI設定

### AMIの名前に日付を入れる
* Packer実行時に既に同じAMI名があるとエラーになるので、日付とか入れてユニークにしたい場合は、```{{isotime | clean_ami_name}}```を入れる

```json
{ "ami_name": "Packer {{isotime | clean_ami_name}}" }
```

```text:作成されたAMI名(例)
Packer 2016-07-18T13-22-19Z
```

### tag設定
* タグは```run_tags```で指定する

```json
{
    "builders":
    [
        {
            "run_tags": {
                "status": "deploy",
                "packer": "false"
            }
        }
    ]
}
```

### ディスクサイズ設定
* デフォルトは8GBなので、例えば20GBにしたい場合は、以下のように設定する

```json
{
    "builders":
    [
        {
            "launch_block_device_mappings": [
                {
                    "device_name": "/dev/xvda",
                    "volume_size": 20
                }
            ]
        }
    ]
}
```

### 参考ページ
* https://gist.github.com/danrigsby/11354917