Dockerfile: ansible, awscli, packer, terraform
Tags: docker, ansible, packer, terraform
Published: 2020-03-14 01:44:06

The other day I was asked to convert the shell scripts used to build out our AWS AMI images into ansible playbooks.  The issue, we use docker with the hashicorp/packer image, which doesn't have ansible.  That set me on this short journey to build a docker image that had the tools we needed, and then some.

For those that just want to jump to the good stuff, here's the links to my Github and Docker Hub repos.

{% github codebarber/ansible-packer-terraform no-readme %}

<center>[dockerhub: codebarber/ansible-packer-terraform](https://hub.docker.com/r/codebarber/ansible-packer-terraform)</center>


With docker the image is defined as layers in the build file called Dockerfile.  Additional layers are added as needed, and all these layers are steps taken to build your final docker image. 

So let's get started writing the dockerfile.  In the text editor of your choosing type:

```python
FROM ubuntu:bionic-20200219
```

This is the first layer instructing docker to pull that docker image as the base layer.

To allow easy version updates lets setup some arguments with defaults set by adding:

```python
ARG TERRAFORM_VERSION="0.12.23"
ARG ANSIBLE_VERSION="2.5.1"
ARG PACKER_VERSION="1.5.4"
ARG AWSCLI_VERSION="1.18.19"
```

Next we add the metadata for the docker image:

```python
LABEL maintainer="Codebarber <ernest@codebarber.com>"
LABEL terraform_version=${TERRAFORM_VERSION}
LABEL ansible_version=${ANSIBLE_VERSION}
LABEL aws_cli_version=${AWSCLI_VERSION}
```

You would obviously want to update maintainer if you'll be publishing your own version to Docker Hub.  So now we're coming to the next big layer.  Here we are installing the packages we want in our image.

Add:

```python
ENV DEBIAN_FRONTEND=noninteractive
ENV AWSCLI_VERSION=${AWSCLI_VERSION}
ENV TERRAFORM_VERSION=${TERRAFORM_VERSION}
ENV PACKER_VERSION=${PACKER_VERSION}
RUN apt-get update \
    && apt-get install -y ansible curl python3 python3-pip python3-boto unzip  \
    && pip3 install --upgrade awscli==${AWSCLI_VERSION} \
    && curl -LO https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip \
    && curl -LO https://releases.hashicorp.com/packer/${PACKER_VERSION}/packer_${PACKER_VERSION}_linux_amd64.zip \
    && unzip '*.zip' -d /usr/local/bin \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* *.zip
```

Above since we are using an ubuntu base image we'll use ubuntu tools and package names.  That pretty much completes our image, now we just need to set the command that will be run by this image by setting the CMD as the final step.  Here we'll tell our docker image to run bash.  This allows us to run multiple tools by passing the command and options to docker run command.

Add:

```python
CMD    ["/bin/bash"]
```

You can easily test it out by running the following command to get the version of tools installed.

```bash
$ docker run --rm codebarber/ansible-packer-terraform aws --version
aws-cli/1.18.19 Python/3.6.9 Linux/4.4.59+ botocore/1.15.19

$ docker run --rm codebarber/ansible-packer-terraform ansible --version
ansible 2.5.1
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/dist-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.17 (default, Nov  7 2019, 10:07:09) [GCC 7.4.0]

$ docker run --rm codebarber/ansible-packer-terraform packer -version
1.5.4

$ docker run --rm codebarber/ansible-packer-terraform terraform -version
Terraform v0.12.23
```

So just about now, you might be asking yourself, well this is great, but how do I get my config, keys, scripts, templates or playbooks into that image so it can do the work?  The nice thing about docker, is its ability to map volumes/folders into the container as it runs.  Here is how you can get your `~/.ssh`, `~/.aws`, and current directory mapped into your container.

Lets pretend you are inside your ansible folder on your host that contains the playbooks and roles.  In order to run that test-playbook.yml here's the command:

```bash
$ docker run --rm \
             -w /opt \
             -v $(pwd):/opt/ \
             -v ~/.aws:/root/.aws \
             -v ~/.ssh:/root/.ssh \
             codebarber/ansible-packer-terraform ansible test-playbook.yml
```

Explaining the flags in order:
--rm: tells docker to remove the container after it completes
-w: sets the working directory inside the container to /opt
-v: maps your current working directory into the containers /opt
-v: maps our .aws folder into the containers ${HOME}/.aws
-v: maps our .ssh folder into the containers ${HOME}/.ssh

I hope you find this information useful.

Have a great day!