概要
Packerとは、簡単に言うと、マシンイメージを作成するオーケストレーションツールです。
Dockerイメージや、AWSのAMIを作成することもできます。
Vagrantなどを作っている、hashicorpのツールです。
今回は、このPackerを使って、AnsibleのPlaybookからDockerイメージを作成します。
仕組み
仕組みを簡単に説明すると、Packerでビルド環境を定義し、Packerが立ち上げたDockerコンテナでlocalモードでAnsibleを実行し、出来上がったコンテナをイメージ化するという仕組みになります。
環境
- CentOS 7.5
- packer 1.3.2
packerのインストール
以下から環境にあったバイナリをダウンロードします。
https://www.packer.io/downloads.html
Linux環境なので、以下を使います。
$ curl -O https://releases.hashicorp.com/packer/1.3.2/packer_1.3.2_linux_amd64.zip
$ unzip packer_1.3.2_linux_amd64.zip
$ sudo cp packer /usr/local/bin
ディレクトリ構成
後述のpacker.jsonの内容と合わせてご確認いただければと思いますが、こういうディレクトリ構成でpackerの環境を作ります。
.
├── packer.json
├── playbooks/
│ ├── group_vars/
│ ├── roles/
│ ├── site.yml
│ └── inventories
│ ├── group_vars/
│ └── hosts.sample
└── vault-password-file
ビルド環境と内容を定義
ビルド環境と内容をjsonで定義します。
jsonファイルの名前は何でも構いませんが、ここではpackage.jsonとします。
{
"builders":[{
"type": "docker",
"image": "centos:7",
"export_path": "controller.tar",
"privileged": "true",
"run_command": ["-d", "-i", "-t", "{{.Image}}", "/sbin/init"]
}],
"provisioners":[{
"type": "shell",
"inline": [
"yum clean all",
"yum -y install epel-release",
"yum -y install PyYAML",
"yum -y install python-jinja2",
"yum -y install python-httplib2",
"yum -y install python-paramiko",
"yum -y install python-setuptools",
"yum -y install ansible",
"mkdir -p /tmp/ansible-local"
]
}, {
"type": "file",
"source": "playbooks/",
"destination": "/tmp/ansible-local"
}, {
"type": "file",
"source": "vault-password-file",
"destination": "/tmp/ansible-local/vault-password-file.txt"
}, {
"type": "ansible-local",
"playbook_file": "playbooks/site.yml",
"staging_directory": "/tmp/ansible-local",
"extra_arguments": [
"-i /tmp/ansible-local/inventories/hosts.sample",
"--vault-password-file=/tmp/ansible-local/vault-password-file.txt"
],
"clean_staging_directory": true
}],
"post-processors": [{
"type": "docker-import",
"repository": "myname/image_name",
"tag": "0.1"
}]
}
内容を簡単に説明します。
{
# Ansibleを実行するDocker環境を定義します。docker-composeと大体同じです。
"builders":[{
"type": "docker",
"image": "centos:7",
"export_path": "controller.tar",
"privileged": "true",
"run_command": ["-d", "-i", "-t", "{{.Image}}", "/sbin/init"]
}],
# Ansibleを実行する環境を構築します。Dockerfileに当たる部分です。
# Ansibleをインストールします。
# また、作業ディレクトリとして/tmp/ansible-localを作成します。
"provisioners":[{
"type": "shell",
"inline": [
"yum clean all",
"yum -y install epel-release",
"yum -y install PyYAML",
"yum -y install python-jinja2",
"yum -y install python-httplib2",
"yum -y install python-paramiko",
"yum -y install python-setuptools",
"yum -y install ansible",
"mkdir -p /tmp/ansible-local"
]
}, {
# こちらは、ホストOSのファイルをコンテナ内にコピーする定義です。
# Ansibleのファイルをすべてコピーします。
"type": "file",
# playbooks/{site.yml,roles,inventories,group_vars...}という構成だとします。
"source": "playbooks/",
# コンテナ内のコピー先ディレクトリです。
"destination": "/tmp/ansible-local"
}, {
# vaultファイルを複合するパスワードが書かれたファイルです。
"type": "file",
# ホストOSで、複合パスワードを平文で書いたものを用意してください。
"source": "vault-password-file.txt",
"destination": "/tmp/ansible-local/vault-password-file.txt"
}, {
# Ansible実行時の引数などの定義です。
# localモードで実行する場合は、ansible-local、sshの場合はansibleになります。
"type": "ansible-local",
# playbookのパスを指定します。
"playbook_file": "playbooks/site.yml",
# 以下にplaybookが設置されます。
"staging_directory": "/tmp/ansible-local",
"extra_arguments": [
# localモードの場合、ansibleが勝手に-iオプションを付与しますが、それだけでは、inventories以下にあるgroup_varsが読み込まれません。
# そのため、-iオプションが2つ付くことになりますが、以下でも定義します、。
# また、inventory fileのパスを、「inventory_file」ディレクティブとして定義できますが、そうするとstaging_directory直下にコピーされ、意図した挙動になりません。
"-i /tmp/ansible-local/inventories/hosts.sample",
# vaultの複合パスワードが書かれたファイルを指定します。
"--vault-password-file=/tmp/ansible-local/vault-password-file.txt"
],
# ビルド完了後に、staging_directoryを削除するかどうかのフラグです。defaultはfalseです。
"clean_staging_directory": true
}],
# 作成するDockerイメージの定義です。
"post-processors": [{
# Dockerイメージを作成し、ローカルに保存する。
"type": "docker-import",
# イメージ名
"repository": "myname/image_name",
# tag
"tag": "0.1"
}]
}
- その他のAnsible Provisionerのディレクティブは以下を参照
Ansible実行時の引数について
Dockerコンテナ内でroot権限でAnsibleを実行するので、sudoパスワードは不要です。
また、ansible-vaultの複合パスワードは、今回は--vault-password-file
でファイルで渡すようにします。(というか、interactiveなやり方がわかりません。)
ビルド実行
以下のコマンドを実行します。
$ sudo packer build -on-error=abort packer.json
そうすると、実際には以下のコマンドが実行されます。
$ cd /tmp/ansible-local && ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 \
ansible-playbook /tmp/ansible-local/site.yml \
--extra-vars "packer_build_name=docker packer_builder_type=docker packer_http_addr=" \
-i /tmp/ansible-local/inventories/hosts.sample \
--vault-password-file=/tmp/ansible-local/vault-password-file.txt \
-c local -i /tmp/ansible-local/packer-provisioner-ansible-local714008969
特にエラーがでなければ成功です。
Dockerイメージが作成されたか確認
ホストOS上にDockerイメージが作成されたことを確認します。
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
myname/image_name 0.1 xxxxxxxxxxxx 1 minutes ago 846MB
connection: docker
ansibleのplaybookにconnection: docker
という行を追加すると、docker containerへの接続となる。
https://hiyoko-infratech.hateblo.jp/entry/2017/12/31/191043
https://dev.classmethod.jp/server-side/os/ansible-docker-connection-plugin/
- hosts: test_servers
connection: docker
tasks:
- name: create directory
file:
path: /home/test/
state: directory
mode: 0755
- name: create file
file:
path: /home/test/test.txt
state: touch
mode: 0644
コマンドにoptionを付ける場合
$ ansible-playbook -i "ansible-sync-test," reproduce.yml -c docker