Automate Docker with Ansible deployments

I recently made some tutorials about Ansible, which is an awesome tool to automate infrastructure. And also Docker, which is a containerizing engine to make deployments easier and more secure. In this tutorial, we will bring those two amazing tools together. Because we’re using Ansible and Docker to automate web server deployments.

I always like easy management for all my Docker Servers and automatic updates. Therefore, we’re deploying Portainer, which is a nice tool to manage Docker containers. And also Watchtower to update them all automatically.

I’m using a Linux Server, based on Ubuntu 20.04 LTS in this tutorial. But you can also use any other Distribution if you like.

Pre-Requisites for Ansible and Docker

Before we can start, it’s important to run the latest version of Ansible. Because you won’t always get the newest version on all Linux Distributions. On Ubuntu 20.04 LTS for example, you only get version 2.9.6 of Ansible. But because the Docker extension requires at least Ansible in version 2.10. We need to update it!

Update Ansible to the latest version

If you have installed Ansible in previous versions and want to update version 2.10, you need to remove the old version first! Because Ansible changed the update procedure fundamentally from version 2.9.x to 2.10. I needed to remove the old packages with apt.

sudo apt remove ansible

When you removed all previously installed versions of ansible, you need to install it with the python package manager (pip), to get the latest version! Also, make sure you’re not running this command with sudo.

python3 -m pip install ansible

Also make sure you add this line to your .bashrc or .zshrc file!

export PATH=$PATH:$HOME/.local/bin

Install the Docker Galaxy Extension for Ansible

Now, we can install the Ansible Galaxy Extension to manage Docker containers on remote servers. Simply execute the following command.

ansible-galaxy collection install community.docker

Configure our Ansible Environment

Let’s start configuring our Ansible Environment. Because we need to set up an ansible.cfg and inventory file in our project folder to tell Ansible how to connect to our remote server. The inventory file is a simple text file that just contains the IP address of our server.

This is a template for the ansible configuration file.

[defaults]

inventory = inventory

host_key_checking = False  # optional: removes the SSH prompt 

deprecation_warnings=False  # optional: removes deprecation warning in playbooks

remote_user = <remote-user>
private_key_file = <remote-user-private-key-file>

If everything is configured correctly, you can test the connection with the following command.

ansible all -m ping

Install Docker on our remote Server

If we have configured our Ansible Environment, we can install all necessary components on our remote server. Because I installed a fresh new Ubuntu 20.04 LTS server, we need to install Docker first. And also the Docker Python SDK is required by Ansible to run containers on remote servers. Therefore, you have two options to install everything on the remote server.

Option 1: Manual installation of all components

When you want to install the components manually, just have a look at the Docker Installation Documentation. You also need to install Python, the Python Package Manager, and the Docker SDK.

Option 2: Install Docker with an Ansible Playbook

Since we already have configured Ansible to manage our remote server, why shouldn’t we use it? Because I’ve already prepared an Ansible Playbook, you can just download and run it. You will find this Playbook in my GitHub Repository Ansible-Boilerplates, and it will install Docker and the Python Docker SDK for you.

Run Portainer with Ansible

Now we’re ready to deploy our first Docker container with Ansible! Create a new Ansible Playbook YAML file in your project folder, that should look like this.

---
- hosts: all
  become: yes
  tasks:

    - name: Deploy Portainer
      community.docker.docker_container:
        name: portainer
        image: portainer/portainer-ce
        ports:
          - "9000:9000"
          - "8000:8000"
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
          - portainer_data:/data
        restart_policy: always

To run the Ansible Playbook, simply execute the following command in the shell.

ansible-playbook <playbook-file.yaml>

If everything runs successful, you should see something like this.

And if we try to access our remote server on port 9000, we can see that Portainer is now running succesful.

Install Watchtower with Ansible

To run our second Docker container, we simply can just add another task inside the same Ansible Playbook. Because Ansible will take care of which Containers are already deployed and if there are any changes to be made. And it only re-deploys containers if there are changes being made.

    - name: Deploy Watchtower
      community.docker.docker_container:
        name: watchtower
        image: containrrr/watchtower
        command: --schedule "0 0 4 * * *" --debug
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
        restart_policy: always

Simply run the Playbook with the same command above again. You can see that the task “Portainer” is not executed again, only our new task “Watchtower”.

Deploy a WordPress Blog with Ansible and Docker

Let’s also deploy two more containers, to automate the deployment of my webserver. Because I want to run a WordPress Blog on this server, we execute the following Playbook.

We also need to create a new Network before running the Containers. Otherwise, WordPress will not be able to connect to the Database Container. Therefore we also need to attach them to the same Network.

---
- hosts: all
  become: yes
  tasks:

    - name: Create Network
      community.docker.docker_network:
        name: wordpress

    - name: Deploy Wordpress
      community.docker.docker_container:
        name: wordpress
        image: wordpress:latest
        ports:
          - "80:80"
        networks:
          - name: wordpress
        volumes:
          - wordpress:/var/www/html
        env:
          WORDPRESS_DB_HOST: "db"
          WORDPRESS_DB_USER: "exampleuser"
          WORDPRESS_DB_PASSWORD: "examplepass"
          WORDPRESS_DB_NAME: "exampledb"
        restart_policy: always

    - name: Deploy MYSQL
      community.docker.docker_container:
        name: db
        image: mysql:5.7
        networks:
          - name: wordpress
        volumes:
          - db:/var/lib/mysql
        env:
          MYSQL_DATABASE: "exampledb"
          MYSQL_USER: "exampleuser"
          MYSQL_PASSWORD: "examplepass"
          MYSQL_RANDOM_ROOT_PASSWORD: '1'
        restart_policy: always

If everything was successful, you can see that our WordPress Blog is running!

Leave a Comment

I accept the Privacy Policy