docker
packer

PackerでDockerイメージを作成してQuay.ioにpushする

More than 3 years have passed since last update.

Packerを使うとDockerfileを使わずにChefやPuppetからDockerのイメージを作成することができる(詳しくは"Packerを使ってChef/Puppet/AnsibleでDockerのイメージをつくる"に書いた).ChefとかPuppetのような資産が既にある場合は,それを使うのも良い(インフラCIでベースDockerイメージだけChefで作ってしまってみたいなことも考えているが,まだ試し中).

イメージができたら,次はそのイメージをどこかにホストする必要がある.また業務で利用するなら認証機構のちゃんとしたプライベートレジストリを使いたい.Dockerのイメージの保存先の選択肢は,今のところ以下の3つがある.

まず、自分でdocker-registryを運用するのはしんどいのでやめた方が良い.次にDockerHubは,Dockerが提供しているRegistryで,プライベートレポジトリを作成することもできる.Quay.ioはCoreOSが買収したDockerのプライベートRegistryサービス.

DockerHubとQuay.ioの違いを簡単に書くと,DockerHubは安く(プライベートレポジトリ1つは無料で使える),大抵の機能は使えるが,たまにpending地獄になってビルドが遅いとかが発生したりする.Quay.ioはまあまあ値段はする(DockerHubの倍くらい)が,Dockerhubと同等の機能がありながら,1つのレポジトリに複数のユーザを追加したり,GitのブランチでAutomated Buildを指定したり,Squashイメージを提供したり,ダッシュボードでイメージの差分を確認したり,などなど面白い機能が多い.

Packerはイメージ作成後にそれをレジストにpushする機能を持っている.インターネットを見渡した限り,その方法を書いている記事は見当たらなかったので,簡単に書いておく.今回はquay.ioを例に使う.


PackerとDocker

まず,簡単にPackerとDockerについて.PackerがDockerイメージの作成でやってくれるのは以下


  • ベースとなるDockerイメージのpull(builder)

  • Dockerイメージのprovision(provisioner)

  • Docekrイメージのタグつけ,レジストリへのpush(post-processor)

"Packerを使ってChef/Puppet/AnsibleでDockerのイメージをつくる"に書いたので今回は詳しく書かないが,Packerが面白いのは,provisionerで,ChefやAnsible,Puppetどれでも適用できること.いろんなマシンイメージを同じように扱えること.

今回は,builderやpost-processerでレジストリ(Quay.io)とやりとりするための設定方法について書く.なおQuay.io以外でも同じようにできる.


machine.json

例えば,公式のDockerHubからベースとなるubuntuイメージを取得して(認証は必要ない),完成したイメージをQuay.ioにpushする(認証が必要)ためのmachine.jsonは以下のようになる.


machine.json

{     

"builders":[
{
"type": "docker",
"image": "ubuntu:latest",
"commit": true
}
],

"post-processors": [
[
{
"type": "docker-tag",
"repository": "quay.io/tcnksm/base",
"tag": "latest"
},

{
"type": "docker-push",
"login": true,
"login_server": "quay.io",
"login_username": "YOUR_NAME",
"login_password": "YOUR_PASSWORD",
"login_email": "YOUR_EMAIL"
}

]
]
}


post-processorでprovisionの終わったDockerイメージをどうするかを定義する.docker-tagでレポジトリの名前をつけてcommitし、docker-pushで実際にイメージをレジストリにpushする.

Quay.ioを使う場合は、レポジトリの名前は,quoy.io/<username>/<reponame>とする.push先の認証設定はdocker-pushにおいてlogin_server, registry_username, login_password, login_emailを全て書けばよい.

ベースのDockerイメージをプライベートレポジトリからpullしたいときは,同じ項目をbuildersに書けばよい.


Packerの設定ファイルでの認証情報の扱い

設定ファイルに認証情報を直接書くべきではない.実行時に切り替えられるとよい.Packerでは以下の2つの方法が使える.


  • 環境変数を使う

  • 別ファイルに切り出す


環境変数を使う

環境変数を使うにはmachine.jsonを以下のように書き換える.


machine.json

{

"variables":{
"registry_username": "{{ env `REGISTRY_USERNAME`}}",
"registry_password": "{{ env `REGISTRY_PASSWORD`}}",
"registry_email": "{{ env `REGISTRY_EMAIL`}}"
},

"builders":[
{
"type": "docker",
"image": "ubuntu:12.04",
"commit": true
}
],

"post-processors": [
[
{
"type": "docker-tag",
"repository": "quay.io/tcnksm/base",
"tag": "latest"
},

{
"type": "docker-push",
"login": true,
"login_server": "quay.io",
"login_username": "{{user `registry_username`}}",
"login_password": "{{user `registry_password`}}",
"login_email": "{{user `registry_email`}}"
}

]
]
}


まず,variablesという項目を追加し,そこに参照したい変数と初期値を定義する.ここに定義した値は他の設定項目からテンプレートとして"{{user VALUE}}"という形で参照できるようになる.そしてvariablesに与える値を"{{env ENV_VALUE}}"とすれば,環境変数でその値を設定できるようになる.

実行は以下のようにすればよい.

$ REGISTRY_USERNAME=<YOUR_NAME> \

REGISTRY_PASSWORD=<YOUR_PASS> \
REGISTRY_EMAIL=<YOUR_EMAIL> \
packer build machine.json

"{{env ENV_VALUE}}"を書けるのがvariablesセクションに限定されているのはとても良い.値がどうやって設定されるか混乱しないし,入力ソースも一箇所なので追跡もしやすい.


別ファイルに切り出す

実行時に毎回環境変数を設定するのは面倒くさい.認証情報をファイルに切り出して(もちろんレポジトリにはpushしない),それを使う方法もある.以下のように-var-fileというオプションを使う.

$ cat variables.json

{
"registry_username": "YOUR_NAME",
"registry_password": "YOUR_PASS",
"registry_email": "YOUR_EMAIL"
}

$ packer build -var-file=variables.json machines.json


まとめ

Packerを使ってDockerのイメージを作成し、それをプライベートレポジトリにpushする方法について書いた.また、Packerで認証情報を安全に取り扱う方法についても書いた.