Ansible Development using Docker
Date: February 15, 2020 Author: Brian HooperTLDR
I have been doing quite a bit of work with Ansible lately across several different projects. This snippet is a simple approach for setting up a development workflow for Ansible using Docker. This is helpful when you are needing to quickly iterate on projects that support different Operating Systems.
Configuration
Here are the steps we will be walking through today:
- Create new project directory
- Create docker sub-directory
- Create Dockerfile + Build Image for Amazon Linux (latest)
- Create Dockerfile + Build Image for Ubuntu Linux 18.04
- Create Dockerfile + Build Image for Ubuntu Linux 20.04
- Running Docker for Ansible Development
Create Project Structure
First we need to create our project:
mkdir ansible-docker
cd ansible-docker
mkdir docker
cd docker
mkdir amazon-latest
mkdir ubuntu-18.04
mkdir ubuntu-20.04
Ok, you should have the following basic structure:
/ansible-docker
|
|__ /docker
| |__ /amazon-latest
| |
| |__ /ubuntu-18.04
| |
| |__ /ubuntu-20.04
Dockerfile (Amazon Linux)
Ok, next let’s create a Dockerfile for Amazon Linux at /ansible-docker/docker/amazon-latest/Dockerfile
FROM amazonlinux:latest
# ARGUMENTS
ARG PYTHON_VERSION=3.7.7
# INSTALL PACKAGES
RUN yum update -y && yum install -y \
curl \
git \
jq \
make \
tar \
unzip \
wget \
which \
zip
# INSTALL PYTHON
RUN mkdir "$HOME/.pyenv" && \
git clone https://github.com/pyenv/pyenv.git "$HOME/.pyenv" && \
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc && \
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc && \
echo 'export PATH="$PYENV_ROOT/shims:$PATH"' >> ~/.bashrc && \
yum install -y \
gcc \
zlib-devel \
bzip2 \
bzip2-devel \
readline-devel \
sqlite \
sqlite-devel \
openssl-devel \
tk-devel \
libffi-devel && \
$HOME/.pyenv/bin/pyenv install $PYTHON_VERSION && \
$HOME/.pyenv/bin/pyenv global $PYTHON_VERSION && \
$HOME/.pyenv/shims/pip install --upgrade pip && \
$HOME/.pyenv/shims/pip install ansible
# COMMAND
CMD ["/bin/echo", "Hello Ansible"]
# ENTRYPOINT
ENTRYPOINT ["/bin/echo", "Hello Ansible"]
Dockerfile (Ubuntu Linux 18.04)
Ok, next let’s create a Dockerfile for Ubuntu Linux at /ansible-docker/docker/ubuntu-18.04/Dockerfile
FROM ubuntu:18.04
# ARGUMENTS
ARG TIME_ZONE=America/Chicago
ARG PYTHON_VERSION=3.7.7
# CONFIGURE TIMEZONE
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# INSTALL PACKAGES
RUN apt-get update -y && apt-get install -y \
curl \
git \
jq \
make \
unzip \
wget \
zip
# INSTALL PYTHON
RUN mkdir "$HOME/.pyenv" && \
git clone https://github.com/pyenv/pyenv.git "$HOME/.pyenv" && \
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc && \
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc && \
echo 'export PATH="$PYENV_ROOT/shims:$PATH"' >> ~/.bashrc && \
apt-get install -y --no-install-recommends \
build-essential \
libssl-dev \
zlib1g-dev \
libbz2-dev \
libreadline-dev \
libsqlite3-dev \
llvm \
libncurses5-dev \
xz-utils \
tk-dev \
libxml2-dev \
libxmlsec1-dev \
libffi-dev \
liblzma-dev && \
$HOME/.pyenv/bin/pyenv install $PYTHON_VERSION && \
$HOME/.pyenv/bin/pyenv global $PYTHON_VERSION && \
$HOME/.pyenv/shims/pip install --upgrade pip && \
$HOME/.pyenv/shims/pip install ansible
# COMMAND
CMD ["/bin/echo", "Hello Ansible running on Ubuntu 18.04"]
# ENTRYPOINT
ENTRYPOINT ["/bin/echo", "Hello Ansible running on Ubuntu 18.04"]
Dockerfile (Ubuntu Linux 20.04)
Ok, next let’s create a Dockerfile for Ubuntu Linux at /ansible-docker/docker/ubuntu-20.04/Dockerfile
FROM ubuntu:20.04
# ARGUMENTS
ARG TIME_ZONE=America/Chicago
ARG PYTHON_VERSION=3.7.7
# CONFIGURE TIMEZONE
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# INSTALL PACKAGES
RUN apt-get update -y && apt-get install -y \
curl \
git \
jq \
make \
unzip \
wget \
zip
# INSTALL PYTHON
RUN mkdir "$HOME/.pyenv" && \
git clone https://github.com/pyenv/pyenv.git "$HOME/.pyenv" && \
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc && \
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc && \
echo 'export PATH="$PYENV_ROOT/shims:$PATH"' >> ~/.bashrc && \
apt-get install -y --no-install-recommends \
build-essential \
libssl-dev \
zlib1g-dev \
libbz2-dev \
libreadline-dev \
libsqlite3-dev \
llvm \
libncurses5-dev \
xz-utils \
tk-dev \
libxml2-dev \
libxmlsec1-dev \
libffi-dev \
liblzma-dev && \
$HOME/.pyenv/bin/pyenv install $PYTHON_VERSION && \
$HOME/.pyenv/bin/pyenv global $PYTHON_VERSION && \
$HOME/.pyenv/shims/pip install --upgrade pip && \
$HOME/.pyenv/shims/pip install ansible
# COMMAND
CMD ["/bin/echo", "Hello Ansible running on Ubuntu 20.04"]
# ENTRYPOINT
ENTRYPOINT ["/bin/echo", "Hello Ansible running on Ubuntu 20.04"]
Building Docker Images
Ok, we should now have the following project structure:
/ansible-project
|
|__ /docker
| |__ /amazon-latest
| | |__ Dockerfile
| |
| |__ /ubuntu-18.04
| | |__ Dockerfile
| |
| |__ /ubuntu-20.04
| |__ Dockerfile
Now that we have our Dockerfiles, let’s build our Docker Container Images to facilitate Ansible Development
Build Amazon Linux Image
cd ./ansible-docker/docker/amazon-latest
docker build --tag amazon:latest-ansible .
Build Ubuntu Linux 18.04 Image
cd ./ansible-docker/docker/ubuntu-18.04
docker build --tag ubuntu:18.04-ansible .
Build Ubuntu Linux 20.04 Image
cd ./ansible-docker/docker/ubuntu-20.04
docker build --tag ubuntu:20.04-ansible .
Running Docker from Ansible Project
Using this basic structure within an Ansible project:
# Example
/ansible-project
|
| /ansible
| |__ /roles
| | |
| | |__ /sample
| | |__ /files
| | |__ /handlers
| | |__ /meta
| | |__ /tasks
| | |__ /vars
| |
| |__ /scripts
| |
| |__ playbook_sample.yaml
|
|__ /docker
| |__ /amazon-latest
| | |__ Dockerfile
| |
| |__ /ubuntu-18.04
| | |__ Dockerfile
| |
| |__ /ubuntu-20.04
| |__ Dockerfile
Here is an example playbook (playbook_sample.yaml):
---
# SAMPLE PLAYBOOK
- name: playbook_sample
hosts: localhost
connection: local
become: yes
roles:
- sample_role
We can run Docker and mount our working Ansible project directory as a volume:
# ANSIBLE DIRECTORY
cd ./ansible
# AMAZON LINUX
docker run --volume="$PWD:/var/ansible" -it --entrypoint /bin/bash amazon:latest-ansible
# UBUNTU LINUX 18.04
docker run --volume="$PWD:/var/ansible" -it --entrypoint /bin/bash ubuntu:18.04-ansible
# UBUNTU LINUX 20.04
docker run --volume="$PWD:/var/ansible" -it --entrypoint /bin/bash ubuntu:20.04-ansible
In the example above we are mounting the present working directory" $PWD
to /var/ansible
within the running container. So now, while working within the container running on our local machine, we can run our Ansible playbooks against a specific OS:Version and iterate on our design.
# USAGE:
# Note: While working in the container run the playbook from the local mounted volume
ansible-playbook -i "localhost," -c local /var/ansible/playbook_<name>.yaml --extra-vars "workspace=<environment>"
# EXAMPLE
ansible-playbook -i "localhost," -c local /var/ansible/playbook_sample.yaml --extra-vars "workspace=dev"
If you receive the following error related to python3-apt, you can specify the interpreter to use. I have observed this error when using apt
resources in a playbook:
# ERROR
{"changed": false, "msg": "Could not import python modules: apt, apt_pkg. Please install python3-apt package."}
# EXAMPLE
ansible-playbook -i "localhost," -c local /var/ansible/playbook_sample.yaml -e "ansible_python_interpreter=/usr/bin/python3"
Next
I have been using this basic setup to support several different projects and it has definitely helped with speeding up the feedback look when iterating on new designs. For future posts I plan on using this basic structure and setup to share some of the Ansible development that I am working on. More to come!
Resources
Let's Work Together
Let's Get Ship Done!
Handcrafted by a @KnownTraveler