Packer + itamaeでDockerfileのないDockerライフ

Dockerは **Dockerfile** という独自のDSLで記載されたファイルからDockerイメージを作成するのだが、
普段かいてるitamae使えないかなと思ったらどうやら Packerというものと組み合わえるといけるらしい

[Packerを使ってChef/Puppet/AnsibleでDockerのイメージをつくる](http://deeeet.com/writing/2014/03/02/build-docker-image-by-packer/)

ただ僕が普段使っているのはItamae。。。Packerでは現状対応してないという。

## Packerとは？
VagrantとかTerafformとかを作っているHashicorp社製のソフトウェア

https://www.packer.io/

複数のプラットフォームのマシン、コンテナイメージを1つの設定ファイルから作成できる。

### 身近な例でいうと
AMIの作成をコマンド一発で作れるようになる。
他にもbuild先を切り替えるとGCEとかVMwareとかのイメージが作れるようになる

## お題
rubyの2.3.1が動いていてrailsで `rails new` したての時に出るwelcomeページを出す。
なおrailsのプロジェクトはローカルにある状態からスタートする。

※ rubyとかrailsは公式のdockerイメージがあるけど、今回は身近なものを題材にしたかっためこちらにしました　

今回やったものはすべてここにpushしてあります
https://github.com/hatappi/packer-docker-sample

## Dockerfile -> Dockerイメージ
Dockerに関してはrubyのDockerイメージがあるので、それに上乗せする形で作る。
やってることはだいたい見てだいたい分かるとは思う。
`ADD?`  `RUN?` なんだろうはググってください

```lang:Dockerfile
FROM ruby:2.3.1
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN mkdir /work
WORKDIR /work
ADD ./rails /work
RUN bundle install

EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
```

最終的にCMDでrails serverを指定しているのでrunした時にrails serverが立ち上がる

```sh
$ docker build -t [image name] .
$ docker run -p 3000:3000 [image name]
```

## Packer -> Dockerイメージ
まず全体的な流れからいくと
ubuntuのイメージを落としてきて

1. railsプロジェクトをアップロード
2. rbenvをいれて2.3.1をインストール
3. bundle install

を行う。
2からitamaeを使用する。
itamaeに関してはレシピごとマシンにアップロードして `itamae local` する

### Packerの構成

Packerには大きく **builders** と **provisioners** と **post-processors** で構成される。

- builders
  - Packerのコアの部分。何を元に何を出力したいのかが記載される。今回はDockerなので元イメージは何か？出力パスは何か？を記載する
- provisioners
  - プロビジョニングの設定。shellとかPuppet, Ansible, Chefなどの指定をここで行う。
- post-processors
  - ここはbuildが終わった後の処理を記載する。今回だとdocker imageの名前を指定してimportしたり、S3にファイルをアップロードしたり出来る。

これらの設定をPackerでは一つのファイルに記載する。

### Packerの設定ファイルのJSON
Packerではprovisionersでitamaeが提供されていないので、自分でやってあげる必要があって
itamaeとかのレシピをアップロードしてサーバー上で `itamae local` してあげる流れになる

今回はrubyが入っていないイメージを選択したのでitamaeを動かすために[itamae_setup.sh](https://github.com/hatappi/packer-docker-sample/blob/master/packer/scripts/ubuntu/itamae_setup.sh)で一旦rubyをpackageからインストールしてます

```lang:manifest.json
{
    "builders":[{
        "type": "docker",
        "image": "ubuntu:14.04.5",
        "export_path": "image.tar"
    }],
    "provisioners": [
        {
            "type": "shell",
            "inline": [
                "mkdir -p /infra",
                "chmod a+w /infra"
            ]
        },
        {
            "type": "file",
            "source": "./",
            "destination": "/infra"
        },
        {
            "type": "file",
            "source": "../rails",
            "destination": "/"
        },
        {
            "type": "shell",
            "inline": [
                "sh /infra/scripts/ubuntu/setup.sh",
                "cd /infra/itamae && bundle install --path vendor/bundle",
                "cd /infra/itamae && bundle exec itamae local /infra/itamae/roles/ubuntu/default.rb",
                "sh /infra/scripts/ubuntu/cleanup.sh"
            ]
        }
    ],
    "post-processors": [{
        "type": "docker-import",
        "repository": "packer-docker-sample/rails"
    }]
}
```

### Packer実行
command 一発

```sh
$ packer build manifest.json
```

あとは下記のようなコマンドを叩いてあげれば終わり

```
docker run -p 3000:3000 -w /rails -it [image name] /bin/bash -lc '/rails/bin/rails s -b 0.0.0.0'
```

## まとめ
実はitamaeにはDockerイメージを作成する `itamae docker` コマンドがある。
ただPackerはbuidlerの部分を変えてあげればAWSのAMIにもなるし、post-processorsを指定すれば
イメージをdocker hubにpushとかも出来る単にイメージを作成するだけではないので良さ気。

今回はrails serverするだけだったので結果的にDockerfileの方がシンプルになってしまったけど
設定ファイルかいたり細かいとこしだすときっとPacker + itamaeが良いじゃんってなるはず。

あと今回rubyを使うプロジェクトだったから良いものの毎回itamae localするために対象マシンにrubyをインストールするのは
時間もかかるし無駄だなと思う。でもitamaeは書きたい。