Build Docker Images with Packer and Ansible
Recently someone asked me where a good place is to get started learning tools like docker, packer and ansible. I did some quick googling and didn’t find what I thought were really good, in-depth tutorials so I decided to write one myself!
Getting Started
This tutorial assumes you are working with OSX although you should be able to accomplish the same results on a linux workstation by seeking out the packages required for your platform.
To get started, let’s install the following tools. If you don’t already have homebrew installed I recommend installing it first.
- Install packer. You can install it via
brew install packer
. - Install Docker.
- Install ansible (
brew install ansible
).
Our First Packer Template
The goal of this tutorial is to get a packer template together that will build a docker image using ansible to provision it. With that in mind, we’re going start by first dipping our toes into packer and use the docker builder, the local shell provisioner and finally a docker post-processor to export docker image with a single file added to /root
.
{ "builders": [{ "type": "docker", "image": "ubuntu:16.04", "commit": "true" }], "provisioners": [ { "type": "shell", "inline": ["echo 'hello!' > /root/foo"] } ], "post-processors": [ [ { "type": "docker-tag", "repository": "jamescarr/demo", "tag": "0.1" } ] ] }
Save this as template.json and run packer build template.json
. Once the build finishes you should be able to run the docker image and inspect it.
jamescarr@Jamess-MacBook-Pro-2 ~/Projects/docker-ansible [13:11:49] > $ docker run -it jamescarr/demo:0.1 bash ⬡ 6.2.2 root@bec87474b4a7:/# ls /root foo root@bec87474b4a7:/# cat /root/foo hello!
Adding Ansible
Next, let’s swap out our shell provisioner with ansible. There are two options you can go with, ansible-local or ansible-remote. The difference here is that ansible-local will run on the target (in this case, in a docker container) while ansible remote will run on your local machine against the target (typically over ssh). Basically your needs will determine which you want to use. If you want ansible on the target image (perhaps to render templates on container start) then ansible-local
is the right path to go while ansible-remote
is great if we want to use ansible to provision the image but want to leave ansible off of the resulting image.
This one will be a rather big change… we need to use docker
as the ansible_connection
as the default will try to connect over ssh and transfer files via scp… obviously this won’t work in docker unless our container runs an ssh server! So we need to instruct ansible to use the docker connection driver to connect. This also requires us to create a consistent hostname, so we define a container name to use when building. We also use the shell provisioner again to install python since ansible will require python on the target and the docker image doesn’t have it by default.
Here’s the updated template.json:
{ "variables": { "ansible_host": "default", "ansible_connection": "docker" }, "builders": [ { "type": "docker", "image": "ubuntu:16.04", "commit": "true", "run_command": [ "-d", "-i", "-t", "--name", "{{user `ansible_host`}}", "{{.Image}}", "/bin/bash" ] } ], "provisioners": [ { "type": "shell", "inline": [ "apt-get update", "apt-get install python -yq" ] }, { "type": "ansible", "user": "root", "playbook_file": "./playbook.yml", "extra_arguments": [ "--extra-vars", "ansible_host={{user `ansible_host`}} ansible_connection={{user `ansible_connection`}}" ] } ], "post-processors": [ [ { "type": "docker-tag", "repository": "jamescarr/demo", "tag": "0.1" } ] ] }
And the new playbook.yml
file which has a single task that uses copy to generate a file similar to what we created previously with the shell provisioner.
--- - name: A demo to run ansible in a docker container hosts: all tasks: - name: Add a file to root's home dir copy: dest: /root/foo content: Hello World! owner: root
Run packer build template.json
and once it completes, let’s test it out.
jamescarr@Jamess-MacBook-Pro-2 ~/Projects/docker-ansible [13:47:00] > $ docker run -it jamescarr/demo:0.1 bash ⬡ 6.2.2 [±master ●●] root@2c46ddf2d657:/# cat /root/foo Hello World!root@2c46ddf2d657:/# ^C (failed reverse-i-search)`pa': ^C root@2c46ddf2d657:/# exit exit
Next Up
I hope this has been a good quick overview on getting started using packer, ansible and docker. This didn’t really produce much useful aside from introducing the pieces and providing a foundation to start with. Tomorrow’s post I’ll tackle some larger “real world” solutions and how to make this a bit more dynamic!
Reference: | Build Docker Images with Packer and Ansible from our WCG partner James Carr at the James Carr blog. |