Post

Ansible Lab in Docker

Ansible Lab in Docker

If you are not familiar with docker setup, please take a look at my previous post Docker - Ultimate Installation Guide.

Docker containers offer a lightweight, efficient way to create a local testing environment for Ansible. Unlike full virtual machines, containers allow you to set up isolated systems on your machine without the need for a hypervisor. This guide will walk you through creating a lab consisting of an Ansible master node and two managed nodes (Ubuntu and Rocky Linux) using Docker Compose. The environment will be configured in a way allowing Ansible to connect to the managed hosts via ssh and perform basic commands or run playbooks.

Project Structure

The project will include the following files:

1
2
3
4
5
6
ansible_lab/
├── ansible/            # Directory for Ansible playbooks and configuration
├── docker-compose.yml  # Docker Compose configuration
├── dockerfile.master   # Dockerfile for Ansible Master
├── dockerfile.ubuntu   # Dockerfile for managed Ubuntu node
└── dockerfile.rocky    # Dockerfile for managed Rocky Linux node

Creating Dockerfiles for Containers

Dockerfile for Ansible Master

Create a Dockerfile specific to Ansible Master. Create a file called: dockerfile.master:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
FROM ubuntu:latest

RUN apt-get update && apt-get install -y openssh-server sudo software-properties-common && apt-get clean

RUN add-apt-repository --yes --update ppa:ansible/ansible && \
    apt-get update && \
    apt-get install -y ansible

RUN useradd -m -s /bin/bash ansible && \
    echo "ansible:ansible" | chpasswd && \
    usermod -aG sudo ansible

RUN mkdir /var/run/sshd && ssh-keygen -A \
    && mkdir /home/ansible/.ssh \
    && chown -R ansible:ansible /home/ansible/.ssh

RUN echo "PermitRootLogin no" >> /etc/ssh/sshd_config && \
    echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config && \
    echo "AllowUsers ansible" >> /etc/ssh/sshd_config

RUN chmod 644 /etc/ssh/sshd_config

EXPOSE 22
WORKDIR /home/ansible/playbooks
RUN mkdir -p /home/ansible/playbooks && chown -R ansible:ansible /home/ansible/playbooks
CMD ["/usr/sbin/sshd", "-D"]

Dockerfile for Ubuntu Managed Host

Create a Dockerfile for Ubuntu Managed Host. Create a file called: dockerfile.ubuntu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
FROM ubuntu:latest

# Install necessary packages
RUN apt update && apt install -y \
    openssh-server \
    sudo \
    python3 \
    python3-pip \
    ansible && \
    apt clean

# Create a technical user
RUN useradd -m -s /bin/bash ansible && \
    echo "ansible:ansible" | chpasswd && \
    usermod -aG sudo ansible

# Configure SSH
RUN mkdir /var/run/sshd && \
    mkdir /home/ansible/.ssh && \
    chown -R ansible:ansible /home/ansible/.ssh

RUN echo "PermitRootLogin no" >> /etc/ssh/sshd_config && \
    echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config && \
    echo "AllowUsers ansible" >> /etc/ssh/sshd_config

EXPOSE 22
WORKDIR /home/ansible

CMD ["/usr/sbin/sshd", "-D"]

Dockerfile for Rocky Managed Host

Create a Dockerfile specific to Rocky Linux. Create a file called: dockerfile.rocky:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
FROM rockylinux:9

# Install necessary packages
RUN dnf update -y && dnf install -y openssh-server sudo python3 && dnf clean all

# Create a technical user
RUN useradd -m -s /bin/bash ansible && echo "ansible:ansible" | chpasswd && usermod -aG wheel ansible

# Configure SSH
RUN mkdir /var/run/sshd && ssh-keygen -A \
    && mkdir -p /home/ansible/.ssh \
    && chown -R ansible:ansible /home/ansible/.ssh

RUN echo "PermitRootLogin no" >> /etc/ssh/sshd_config && \
    echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config && \
    echo "AllowUsers ansible" >> /etc/ssh/sshd_config && \
    chmod 644 /etc/ssh/sshd_config

EXPOSE 22
WORKDIR /home/ansible

CMD ["/usr/sbin/sshd", "-D"]

Creating the Docker Compose File

The docker-compose.yml file will define the Ansible environment with the following setup:

  • A dedicated bridge network with static IP addresses for each container.
  • Separate services for the Ansible Master and managed hosts.

Create the docker-compose.yml file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
version: '3.9'
services:
  ansible-master:
    build:
      context: .
      dockerfile: dockerfile.master
    container_name: lab-ansible-master
    hostname: ansible-master
    networks:
      - ansible_net
    tty: true

  ubuntu-managed:
    build:
      context: .
      dockerfile: dockerfile.ubuntu
    container_name: lab-ubuntu-managed
    hostname: ubuntu-managed
    networks:
      - ansible_net
    tty: true

  rocky-managed:
    build:
      context: .
      dockerfile: dockerfile.rocky
    container_name: lab-rocky-managed
    hostname: rocky-managed
    networks:
      - ansible_net
    tty: true

networks:
  ansible_net:
    driver: bridge

Deploying the Environment

Build and run the containers:

1
$ docker-compose up --build -d

Verify if containers were created:

1
$ docker ps

Configuring the Ansible Inventory

First of all, we need to make sure, what ip address of our containers are. Look for the conatiners names from the previous step and check ip address of each one of them:

1
$ docker inspect <container-id> | grep "IPAddress"

Access the Ansible Master container:

1
$ docker exec -it lab-ansible-master bash

Create an Ansible inventory file:

  • paste ip addresses obtained in the previous step
  • paste password for ansible user
1
2
3
4
5
6
7
8
9
10
11
ansible@ansible-master:~$ cat /home/ansible/inventory 
[all:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_user=ansible
ansible_password=ansible

[ubuntu_managed]
ubuntu-managed ansible_host=<ip> ansible_port=2223

[rocky_managed]
rocky-managed ansible_host=<ip> ansible_port=2224

Testing the Environment

Confirm that Ansible is installed:

1
$ ansible --version

Test connectivity to the managed hosts using the ping module:

1
$ ansible -i /home/ansible/inventory all -m ping

Expected Output (ip addresses may vary, depending on your setup):

1
2
3
4
5
6
7
8
9
172.26.0.3 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

172.26.0.2 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

This tutorial demonstrates how to set up a lightweight Ansible testing lab using Docker containers. By defining custom Dockerfiles and using Docker Compose, you can replicate this environment on your local machine, experiment with playbooks, and practice configuration management across different Linux distributions.

This post is licensed under CC BY 4.0 by the author.