10分で理解するPacker

# [Packer](https://www.packer.io/) とは
サーバーイメージを作成するためのツールです
AWSであればAMI、Azureであれば arm を作成します

Vagrant を開発している [HashiCorp社](https://www.hashicorp.com/) が開発しているツールなので使用感は Vagrant と同じような感じです

構築済みのサーバーイメージをAMIとして作成しておき、これをベースとしてインスタンスを立ち上げるのはよくあるパターンだと思います
※ **"ゴールデンイメージ"** というインフラパターンらしいです

ただ、このAMIがどうやって作られたか？がわからなくなりがちなのですが、Packerを使うことでAMI構築手順を全てコード化することができます

# TL;DR
json ファイルに定義内容を記述し、```$ packer build hoge.json ``` を実行するだけで定義内容の通りに自動でサーバーイメージを作成してくれます

# インストール
以下に従って OS 毎のビルド済みバイナリをダウンロードしてきてパスを通すだけです
https://www.packer.io/downloads.html

## Mac の場合
Mac の場合は Homebrew でインストールできます

```text:Homebrewでpackerインストール
$ brew update
$ brew install packer
```

# AWS での使い方
## 事前準備
###  IAM ユーザーを作る
aws cli を利用するための アクセスキーを取得します
管理者に依頼して IAM ユーザーを作成してもらってください
https://console.aws.amazon.com/iam/home?#/home

利用したい AWS サービス(EC2だけかな？)に対しての操作権限をつけてもらう必要があります

### AWS CLI をセットアップする
以下を参考に aws コマンドを使えるように設定する
http://docs.aws.amazon.com/ja_jp/streams/latest/dev/kinesis-tutorial-cli-installation.html

```$ aws configure``` で認証情報をセットした後であれば、Pakcer からはこのAWS認証情報を参照してくれます
※```~/.aws/credentials``` にAWSの認証情報が保存されます

## AMIを作成する
## 1. json ファイルを作成する
例として以下の AMI を作成する定義を見てみましょう

|項目|設定値|メモ|
| --- | --- | --- |
| リージョン | ap-northeast-1 (東京) |  |
| ベースのAMI | 公式 ubuntu 16.04 の最新版 |  |
| インスタンスタイプ | t2.micro |  |
| ssh ユーザー名 | ubuntu |  |
| AMIの名前 | Packer test  YYYY-MM-DDThh-mm-ssZ | 作成時のタイムスタンプがセットされる |
| ディスク |30GB、gp2 の EBS を /dev/sda1 として接続  |  |
| 初期化コマンド |apt update を実行してから python-simplejson をインストール|

この AMI 定義は以下のように  json ファイルで書きます
定義できる項目は packer のドキュメントを参照のこと
https://www.packer.io/docs/builders/amazon.html

``` packer-example.json
{
  "builders": [{
    "type": "amazon-ebs",
    "region": "ap-northeast-1",
    "source_ami_filter": {
      "filters": {
        "virtualization-type": "hvm",
        "name": "*ubuntu-xenial-16.04-amd64-server-*",
        "root-device-type": "ebs"
      },
      "owners": ["099720109477"],
      "most_recent": true
    },
    "instance_type": "t2.micro",
    "ssh_username": "ubuntu",
    "ami_name": "Packer Test {{isotime | clean_ami_name}}",
    "launch_block_device_mappings": [{
      "delete_on_termination": true,
      "device_name": "/dev/sda1",
      "volume_size": 10,
      "volume_type": "gp2"
    }]
  }],
  "provisioners": [{
    "type": "shell",
    "inline": [
      "sudo apt update",
      "sudo apt install -y python-simplejson",
      "sudo echo `date`' - packer provisioned this AMI' > /home/ubuntu/packer_provisioners"
    ]
  }]
}

```

## 2. 構文チェック
```$ packer validate``` を実行すると構文チェックされます

``` 構文チェックを実行
$ packer validate packer-example.json
```

以下のメッセージが出力されれば構文チェックはOKです

```
Template validated successfully.
```

もしエラーがある場合はエラーメッセージが出力されます

```
$ packer build packer-example.json 
Failed to parse template: Error parsing JSON: invalid character '"' after object key:value pair
At line 4, column 6 (offset 49):
    3:     "type": "amazon-ebs"
    4:     "
           ^
```

## 3. ビルド実行
```$ packer build``` を実行して AMI をビルドします

```
$ packer build packer-example.json
```
初期化タスクの内容にもよりますが AMI ビルドには数分かかります
以下のように ```AMIs were created``` と出力されればビルド成功です

```
・・・
Build 'amazon-ebs' finished.

==> Builds finished. The artifacts of successful builds are:
--> amazon-ebs: AMIs were created:
ap-northeast-1: ami-c5f49528
```

ビルド中 EC2 のコンソールを開くと "Packer Builder" というインスタンスが起動されて、このインスタンス内で処理が実行され定義した内容の AMI が作成されます

![packer_aws_1.jpg](https://qiita-image-store.s3.amazonaws.com/0/43699/c989c1e2-b791-7c9c-a66a-8657ed6d6bae.jpeg)


ビルドが完了すると以下のように AMI が追加されていることが確認できます
![packer_aws_2.jpg](https://qiita-image-store.s3.amazonaws.com/0/43699/4a24a766-ad95-804c-ff31-0192c47fa616.jpeg)


## [Advanced] イメージの初期化処理を Ansible でやる
packer で **provisioners** で設定したタスクによりイメージの初期化を行うことができます
https://www.packer.io/docs/provisioners/index.html

↑のサンプルでは  Shell Provisioner を使うことで、イメージとなるインスタンスの内部で指定されたシェルコマンドが実行されていたということです

Ansible Provisioner というのを使うと、初期化タスクを ansible に任せることができます
先ほどの ```packer-example.json``` を修正し Provisioner に ansible を指定します
`playbook_file` に指定された playbook に沿って ansible が実行されます
※playbook の書き方はここでは割愛します

``` packer-ansible.json
{
  "builders": [{
    "type": "amazon-ebs",
    "region": "ap-northeast-1",
    "source_ami_filter": {
      "filters": {
        "virtualization-type": "hvm",
        "name": "*ubuntu-xenial-16.04-amd64-server-*",
        "root-device-type": "ebs"
      },
      "owners": ["099720109477"],
      "most_recent": true
    },
    "instance_type": "t2.micro",
    "ssh_username": "ubuntu",
    "ami_name": "Packer Ansible Example {{isotime | clean_ami_name}}",
    "launch_block_device_mappings": [{
      "delete_on_termination": true,
      "device_name": "/dev/sda1",
      "volume_size": 30,
      "volume_type": "gp2"
    }]
  }],
  "provisioners": [{
    "type": "shell",
    "inline": [
      "sudo apt update",
      "sudo apt install -y python-simplejson"
    ]
  }, {
    "type": "ansible",
    "playbook_file": "./ansible/playbook.yml"
  }]
}

```