Testing Ansible in a Docker Container: How to Configure Networking

DevOpsDevOps Tools

YOUR COSMETIC CARE STARTS HERE

Find the Best Cosmetic Hospitals

Trusted • Curated • Easy

Looking for the right place for a cosmetic procedure? Explore top cosmetic hospitals in one place and choose with confidence.

“Small steps lead to big changes — today is a perfect day to begin.”

Explore Cosmetic Hospitals Compare hospitals, services & options quickly.

✓ Shortlist providers • ✓ Review options • ✓ Take the next step with confidence

Original context: Docker for Mac. The networking behaviour described here is most pronounced on macOS, but the underlying Docker networking concepts apply generally.

The Problem

A common goal when learning or testing Ansible is to spin up a small cluster of Docker containers: one container acting as the Ansible control node and one or more containers acting as managed targets. The setup seems straightforward, but many people hit the same wall immediately: Ansible reports that every target is UNREACHABLE.

A typical error looks like this:

fatal: [127.0.0.1]: UNREACHABLE! => {"changed": false, "msg": "[Errno None] Unable to connect to port 9800 on 127.0.0.1", "unreachable": true}Code language: PHP (php)

The Ansible inventory (hosts file) in this scenario looks like:

[docker-hosts]
127.0.0.1:9800
127.0.0.1:9801Code language: CSS (css)

And a minimal playbook.yml targeting those hosts:

---
- hosts: docker-hosts
  remote_user: root
  become: yes
  become_method: sudo

  tasks:
    - name: pulling docker image
      docker_image:
        name: centos

Run with:

ansible-playbook playbook.yml -f 10Code language: CSS (css)

Both 127.0.0.1 and 0.0.0.0 fail as target addresses. Here is why, and how to fix it.

Why 127.0.0.1 Does Not Work Between Containers

Inside any Docker container, 127.0.0.1 (loopback) refers to that container itself, not to the Docker host and not to any sibling container. When the Ansible control container tries to SSH to 127.0.0.1:9800, it is attempting to connect to a port on its own loopback interface — which has nothing listening on it.

Even if you published the target containers’ SSH ports to the Docker host (e.g., -p 9800:22), the host’s loopback is a separate network namespace from the container’s loopback. On Linux you might be able to reach the host via the default bridge gateway IP, but on Docker for Mac there is an additional networking layer (a Linux VM) that makes 127.0.0.1 from inside a container even less reliable for this purpose.

Solution 1: Use a User-Defined Docker Bridge Network

The cleanest approach is to put all containers on the same user-defined bridge network. Docker then provides automatic DNS resolution by container name, so you can address targets by name rather than by IP address.

Step 1 — Create a dedicated network

docker network create ansible-test

Step 2 — Start the target containers on that network

docker run -d --name target1 --network ansible-test --rm centos:latest /usr/sbin/sshd -D
docker run -d --name target2 --network ansible-test --rm centos:latest /usr/sbin/sshd -D

Note: A base CentOS image does not run SSH by default. You will need a custom image that installs and configures openssh-server and sets up SSH keys. See Solution 3 below for an alternative that avoids SSH entirely.

Step 3 — Start the Ansible control container on the same network

docker run -it --name ansible-control --network ansible-test --rm your-ansible-image bash

Step 4 — Update the Ansible inventory to use container names

[docker-hosts]
target1
target2Code language: CSS (css)

Docker’s embedded DNS resolves target1 and target2 to the correct container IP addresses automatically. No port mapping to the host is required.

Solution 2: Use Docker Compose to Manage the Network Automatically

Docker Compose creates a dedicated bridge network for each project by default, so all services within one Compose file can reach each other by service name.

version: "3"
services:
  ansible-control:
    image: your-ansible-image
    depends_on:
      - target1
      - target2
    volumes:
      - ./playbooks:/playbooks

  target1:
    image: your-ssh-enabled-centos-image

  target2:
    image: your-ssh-enabled-centos-imageCode language: PHP (php)

Your Ansible inventory then simply references target1 and target2 by service name.

Solution 3: Use the Docker Connection Plugin Instead of SSH

If the goal is purely to test Ansible playbooks against containers (rather than to test SSH connectivity itself), you can skip SSH altogether. Ansible ships with a docker connection plugin that uses docker exec internally.

Set the connection type in your inventory:

[docker-hosts]
target1 ansible_connection=docker
target2 ansible_connection=docker

With this approach:

  • No SSH daemon is needed in the target containers.
  • No port publishing or network configuration is required.
  • The Ansible control node must be able to run docker exec — either by running on the Docker host itself, or by mounting the Docker socket into the control container (-v /var/run/docker.sock:/var/run/docker.sock).

Why Port-Mapping to the Host Is Not Enough on Its Own

Some guides suggest publishing SSH ports to the host (e.g., -p 9800:22 -p 9801:22) and then pointing Ansible at the host’s IP. This can work when Ansible runs directly on the host, because the host’s loopback or LAN IP is reachable. However, when Ansible itself runs inside a container, the situation changes:

  • On Linux, the default Docker bridge gateway (typically 172.17.0.1) is the host’s bridge IP and is reachable from containers. You could use that IP in the inventory.
  • On Docker for Mac, the Docker engine runs inside a Linux VM. The host’s localhost is not directly reachable from inside a container using 127.0.0.1. Docker for Mac provides the special hostname host.docker.internal to reach the host machine, but this adds unnecessary complexity.

Using a user-defined network (Solution 1) or the Docker connection plugin (Solution 3) avoids all of this complexity.

Summary

ApproachNeeds SSH in target?Works on Docker for Mac?Complexity
User-defined bridge network + SSHYesYesLow
Docker Compose network + SSHYesYesLow
Docker connection plugin (docker exec)NoYesVery low
Port-map to host + host IP in inventoryYesFragileMedium

For most local Ansible testing workflows, a user-defined Docker network with container-name-based inventory, or the docker connection plugin, is the recommended approach. Avoid addressing sibling containers via 127.0.0.1 — it refers to the container’s own loopback, not to any other container or to the host.

0 0 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
0
Would love your thoughts, please comment.x