Deploy and Managing Docker Containers with Ansible

By Anurag Singh

Updated on Nov 20, 2024

Deploy and Managing Docker Containers with Ansible

In this tutorial, we'll see how to deploy and managing Docker containers with Ansible, including an introduction to Docker modules in Ansible, writing playbooks to deploy and manage containers, and automating multi-container deployments.

Introduction

Ansible is a powerful automation tool that helps you automate the management of servers, applications, and IT infrastructure. Docker, on the other hand, is a containerization platform that allows you to package applications and their dependencies into lightweight, portable containers. Together, Ansible and Docker form a strong pair for DevOps automation, allowing you to orchestrate the deployment and management of Docker containers effortlessly.

Prerequisites

  • Ubuntu 24.04 installed dedicated server or KVM VPS.
  • 1 control server.
  • 2 target servers.
  • A basic understanding of YAML and Ansible playbooks.

Deploy and Managing Docker Containers with Ansible

Step 1: Install Docker on Target Servers

We need to install Docker on all target servers. Execute following commands on each target servers:

# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

Install Docker:

sudo apt-get install docker-ce

Step 2: Set Up SSH Access

We need to setup a SSH access between the remote servers to ensure you can SSH into your managed nodes without a password prompt. This can be achieved by setting up SSH keys.

Generate SSH Keys (if not already done)

On your system, generate an SSH key pair (if you don’t have one already):

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

This will create a pair of files:

  • ~/.ssh/id_rsa (private key)
  • ~/.ssh/id_rsa.pub (public key)

Copy the Public Key to Remote Servers

You need to copy the public key to the remote servers to enable passwordless SSH access. Use the ssh-copy-id command:

ssh-copy-id username@remote_server_ip

Replace username with the remote user’s name and remote_server_ip with the IP address of your remote server. Repeat this step for each remote server.

Test SSH access to ensure you can connect without a password:

ssh username@remote_server_ip

If you can connect without being prompted for a password, SSH access is correctly set up. Now exit the current connection and back to main server.

Step 3: Create Project and Python Environment

Next, let's create a directory for Ansible

mkdir ansible-project && cd ansible-project

Now, create a Python environment:

If Python environment is not installed, install it using following command (Replace the Python version with your installed Python version): 

apt install python3.10-venv 

Execute following command to create Python environment:

python3 -m venv venv

Activate Python environment:

source venv/bin/activate

Python Docker module (docker-py) installed and install Ansible. You can install it with:

pip install docker ansible

Setting Up Ansible to Manage Docker

Ansible Inventory:

Make sure your target machines are defined in the Ansible inventory file. Here's an example of a simple inventory file:

nano inventory

Add following content:

[docker_hosts]
server1 ansible_host=192.168.1.10 ansible_python_interpreter=/usr/bin/python3
server2 ansible_host=192.168.1.11 ansible_python_interpreter=/usr/bin/python3

Note: Replace 192.168.1.10 and 192.168.1.11 with your server IP and hostname

Docker Modules in Ansible

Ansible provides dedicated modules to interact with Docker. Here are the main modules we'll be using:

  • docker_container: Manage the lifecycle of Docker containers.
  • docker_image: Manage Docker images (pull, build, remove, etc.).
  • docker_network: Manage Docker networks.
  • docker_volume: Manage Docker volumes.

Ensure that you have the community.docker collection installed for these modules:

ansible-galaxy collection install community.docker

Step 4: Writing a Basic Playbook to Deploy a Docker Container

Create a simple playbook to deploy an Nginx container on a target machine.

Create a new playbook file named deploy_nginx.yml:

nano deploy_nginx.yml

Add following content:

---
- name: Deploy Nginx Container with Ansible
  hosts: docker_hosts
  become: true
  tasks:
    - name: Pull the Nginx image
      community.docker.docker_image:
        name: nginx
        source: pull
    
    - name: Deploy Nginx container
      community.docker.docker_container:
        name: my_nginx
        image: nginx
        ports:
          - "8080:80"
        state: started

Run the playbook:

ansible-playbook -i inventory deploy_nginx.yml

This playbook pulls the latest Nginx image and starts an Nginx container, exposing it on port 8080.

Step 5: Managing Docker Containers with Ansible

You can manage the container’s state using the docker_container module. The state parameter can be started, stopped, restarted, or absent.

Updating the Nginx container:

- name: Update Nginx Container
  hosts: docker_hosts
  become: true
  tasks:
    - name: Stop the Nginx container
      community.docker.docker_container:
        name: my_nginx
        state: stopped

    - name: Remove the Nginx container
      community.docker.docker_container:
        name: my_nginx
        state: absent

    - name: Deploy updated Nginx container
      community.docker.docker_container:
        name: my_nginx
        image: nginx:latest
        ports:
          - "8080:80"
        state: started

Removing Containers:

- name: Remove All Unused Containers
  hosts: docker_hosts
  become: true
  tasks:
    - name: Remove stopped containers
      community.docker.docker_container:
        name: "{{ item }}"
        state: absent
      with_items:
        - my_nginx
        - old_container

Step 6: Automating Multi-Container Deployments with Ansible

For multi-container applications, you can use Ansible to orchestrate the deployment, ensuring dependencies are handled correctly.

Example Playbook for a WordPress and MySQL Deployment:

Create a file called wordpress_deploy.yml:

nano wordpress_deploy.yml

Add following content:

---
- name: Deploy WordPress and MySQL with Ansible
  hosts: docker_hosts
  become: true
  tasks:
    - name: Create a Docker network
      community.docker.docker_network:
        name: wordpress_network
    
    - name: Deploy MySQL container
      community.docker.docker_container:
        name: mysql_container
        image: mysql:8.0
        env:
          MYSQL_ROOT_PASSWORD: "your_root_password"
          MYSQL_DATABASE: "wordpress_db"
          MYSQL_USER: "wp_user"
          MYSQL_PASSWORD: "wp_password"
        networks:
          - name: wordpress_network
        volumes:
          - mysql_data:/var/lib/mysql
        state: started
    
    - name: Deploy WordPress container
      community.docker.docker_container:
        name: wordpress_container
        image: wordpress
        env:
          WORDPRESS_DB_HOST: "mysql_container"
          WORDPRESS_DB_USER: "wp_user"
          WORDPRESS_DB_PASSWORD: "wp_password"
          WORDPRESS_DB_NAME: "wordpress_db"
        ports:
          - "8080:80"
        networks:
          - name: wordpress_network
        state: started
    
    - name: Ensure data volumes exist
      community.docker.docker_volume:
        name: mysql_data

Run the Playbook:

ansible-playbook -i inventory wordpress_deploy.yml

This playbook does the following:

  • Creates a Docker network called wordpress_network.
  • Deploys a MySQL container with the necessary environment variables.
  • Deploys a WordPress container connected to the same network.
  • Uses a Docker volume for persistent MySQL storage.

Now you can access the WordPress website using your server IP 

http://<server_ip>:8080

Best Practices for Using Ansible with Docker

  • Use Docker Networks: Create dedicated Docker networks for each application to manage connectivity between containers.
  • Separate Configuration and Code: Use environment variables and volumes to keep your configuration separate from your containers.
  • Regular Clean-up: Use Ansible to remove unused images, containers, and volumes.
  • Version Control: Keep your Ansible playbooks under version control (e.g., Git) to track changes and roll back if necessary.
  • Use Tags: Implement tags in your playbooks to run specific tasks without executing the entire playbook.

Conclusion

Using Ansible to manage Docker containers is a powerful approach to automate deployment and orchestration tasks. With Ansible’s declarative playbooks, you can manage container lifecycles, deploy complex multi-container applications, and handle updates or scaling effortlessly. This guide provided a solid introduction to working with Docker containers using Ansible's Docker modules. Experiment with these examples and adjust them to your specific needs to master Ansible and Docker management.