Building images

Docker images are basically filesystems bundled with parameters to use at runtime. The filesystem is usually a small part of a Linux Userland, with enough files to start the desired process. Docker provides tooling to build these images, generally based on very small, preexisting base images. The tooling uses a Dockerfile as the input, which is a plain text file with directives. This file is parsed by the docker build command, and we can parse it via the docker_image module. The remaining examples will be from a CentOS 7 virtual machine using Docker version 1.13.1, with the cowsay and nginx packages added, so that running the container will provide a web server that will display something from cowsay.

First, we'll need a Dockerfile. This file needs to live in a path that Ansible can read, and we're going to put it in the same directory as my playbooks. The Dockerfile content will be very simple. We'll need to define a base image, a command to run to install the necessary software, some minimal configuration of software, a port to expose, and a default action for running a container with this image:

FROM docker.io/fedora:29 
 
RUN dnf install -y cowsay nginx 
RUN echo "daemon off;" >> /etc/nginx/nginx.conf 
RUN cowsay boop > /usr/share/nginx/html/index.html 
 
EXPOSE 80 
 
CMD /usr/sbin/nginx 

The build process performs the following steps:

The playbook to build and use the image can live in the same directory. We'll name it docker-interact.yaml. This playbook will operate on localhost, and will have two tasks; one will be to build the image using docker_image, and the other will be to launch the container using docker_container:

--- 
- name: build an image 
  hosts: localhost 
  gather_facts: false 
 
  tasks: 
    - name: build that image 
      docker_image: 
        path: . 
        state: present 
        name: fedora-moo 
 
    - name: start the container 
      docker_container: 
        name: playbook-container 
        image: fedora-moo 
        ports: 8080:80 
        state: started 

Now, if you've been using AWX on the same host as this like I have, you will already have a few Docker containers running. Luckily, none of these are based on Fedora, so we can easily use the --filter parameters with Docker to exclude anything that doesn't have the term fedora in the image name, making the output easier to interpret, as shown in the following screenshots:

Now, let's run the playbook to build the image and start a container using that image:

The verbosity of this playbook execution was reduced to save screen space. Our output simply shows that the task to build the image resulted in a change, as did the task to start the container. A quick check of running containers and available images should reflect our work:

We can test the functionality of our container by using curl to access the web server, which should show us a cow saying boop:

In this manner, we have already shown how easy it is to interact with Docker using Ansible. However, this example is still based on using a native Dockerfile, and, as we progress through this chapter, we'll see some more advanced Ansible usage that removes the need for this.