Halloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowHalloween DealsAmazon USOctober picks are moving - compare before checkoutAmazon US: current deals, useful picks and tech finds.See Picks×
VGSOURCES
Get listed

AnsiblePATCH 2026.10.15

How to Install and Set Up Docker on a Server With Ansible (Ubuntu, Debian and RHEL)

By VGSources Team 12 min read

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The reliable pattern is to let Ansible configure Docker from Docker’s official repository, install the Engine and its companion packages, enable the service, install the community.docker collection and Python SDK in the correct execution context, then manage containers declaratively. The playbook below separates Debian-family and RHEL-family tasks, verifies the daemon with a disposable test container, and includes the firewall, version-pinning and troubleshooting details that commonly determine whether a rollout is safe.

What this setup produces

After a successful run, each target server has Docker Engine installed from a repository you control, the daemon enabled at boot and running now, and an Ansible environment capable of calling Docker’s API. You can then create and update containers with community.docker.docker_container or deploy a multi-container application with the collection’s Compose v2 modules.

As an Amazon Associate I earn from qualifying purchases.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Repository and signing-key configuration is repeatable.
  • The packages docker-ce, docker-ce-cli, containerd.io, docker-buildx-plugin and docker-compose-plugin are installed.
  • The service is enabled and started through Ansible rather than an ad-hoc shell command.
  • A hello-world run confirms that the daemon can pull and start an image.
  • Collection, Python-SDK and interpreter requirements are explicit.

Check support before writing tasks

Docker publishes a Linux support matrix because repository paths, package names and CPU architectures differ by distribution. Confirm the exact distribution release and architecture reported by each host before applying a play. Debian’s current installation guidance lists Debian Trixie 13 and Bookworm 12; Docker’s RHEL guidance lists maintained RHEL 8, 9 and 10. Derivatives may need the codename of their upstream release rather than the derivative’s own name.

Target family Package tool Repository workflow Important qualification
Debian and Ubuntu apt Install the keyring, add an apt source, refresh metadata, then install Docker packages. Use the codename and architecture accepted by Docker’s current Linux support matrix. Derivatives can require a matching upstream codename.
RHEL dnf Add Docker’s RPM repository, refresh metadata and install the Engine package set. The current Docker manual covers RHEL 8, 9 and 10; verify architecture support for your release.
Other Linux distributions Distribution-specific Keep repository URLs, package names and architecture mappings in variables. Do not assume that a Debian or RHEL task applies to another distribution.

Use facts gathered by Ansible to fail early when a host is outside your tested matrix. For example:

- name: Stop on unsupported operating systems
  ansible.builtin.assert:
    that:
      - ansible_facts.os_family in ['Debian', 'RedHat']
    fail_msg: 'This play supports only Debian-family and RHEL-family hosts.'

- name: Display release and architecture for review
  ansible.builtin.debug:
    msg:
      - 'Distribution: {{ ansible_facts.distribution }} {{ ansible_facts.distribution_version }}'
      - 'Release codename: {{ ansible_facts.lsb.codename | default("not reported") }}'
      - 'Architecture: {{ ansible_facts.architecture }}'

Map every architecture explicitly in your variables. Support varies by platform, so an x86_64 value that works on one release is not evidence that an ARM value is available on another.

Choose repository and version policies

Official repository versus distribution packages

Docker’s repository installation is the documented path for ongoing installation and update workflows. Distribution repositories can be older or split the package set differently. If you intentionally use distribution packages, change the package list and validation to match that distribution; do not mix packages from both sources on one host.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Latest packages versus pinned packages

An unqualified package state such as present follows whatever version the configured repository currently offers. That is convenient for a new server but can introduce an unplanned Engine or containerd change. For reproducible environments, pin package versions in variables, record the chosen versions in inventory or group variables, and upgrade them in a scheduled change. A pin applies only when that exact version is still available in the repository.

Repository values as variables

Keep the repository line, key URL, keyring path, architecture mapping and release name in variables rather than embedding them throughout tasks. Populate those values from Docker’s current installation page for the target release. This avoids silently using an obsolete codename or repository layout when a distribution moves to a new release.

docker_apt_repo_line: "deb [arch={{ docker_apt_arch }} signed-by=/etc/apt/keyrings/docker.asc] {{ docker_apt_repository }} {{ docker_apt_release }} stable"
docker_apt_key_url: '{{ docker_key_url_from_current_docker_documentation }}'
docker_rpm_repository: '{{ docker_rpm_repo_from_current_docker_documentation }}'
docker_package_state: present

The double-curly-brace values above are Ansible variables, not literal strings to pass to a package manager. Define them in inventory or group variables for each supported release.

Prepare the Ansible control environment

Inventory and privilege escalation

Place target addresses and the SSH user in inventory, and use privilege escalation for repository, package and service tasks. A minimal inventory can look like this:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
[docker_hosts]
node01 ansible_host=203.0.113.21
node02 ansible_host=203.0.113.22

[docker_hosts:vars]
ansible_user=admin
ansible_become=true

Use a dedicated administrative account with a narrowly managed SSH key. Confirm that Python is available on each target because Ansible modules execute there unless you deliberately use a different connection or interpreter.

Collection and core-version prerequisites

The Docker modules are not part of ansible-core. Install the separate collection before running a play:

ansible-galaxy collection install community.docker

Current community.docker documentation identifies collection version 5.4.0 and requires ansible-core 2.17.0 or newer. Check the installed versions in your execution environment and pin the collection in a requirements.yml file when repeatability matters:

collections:
  - name: community.docker
    version: 5.4.0

Use a virtual environment or an execution image so that the collection version and its dependencies are the same in CI and on an operator’s workstation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install the Docker SDK for Python in the right place

Most community.docker modules require the Docker SDK for Python on the machine where the module runs. With normal SSH execution, that is the target server, and the SDK must be installed into the Python interpreter selected by ansible_python_interpreter. Ansible plugins run in Ansible’s own context, so a plugin can instead require the SDK on the controller.

Make this explicit in inventory when a host has more than one Python installation:

docker_hosts:
  hosts:
    node01:
      ansible_python_interpreter: /usr/bin/python3

Install the SDK using the package-management method approved for your operating system or a controlled virtual environment. Avoid installing it into one interpreter while Ansible invokes another; a module failure that says the SDK is missing is often an interpreter mismatch rather than a Docker problem.

Install Docker on Debian and Ubuntu

The Debian-family branch follows Docker’s documented order: remove conflicting packages when present, create /etc/apt/keyrings, install the signing key with restrictive permissions, add the repository, refresh apt metadata, install the five Docker packages, and enable the service.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

1. Remove conflicting packages deliberately

Only remove packages that Docker identifies as conflicting for the release you are deploying. Keep this list in a variable so a host-specific exception is visible during review:

- name: Remove packages that conflict with Docker Engine
  ansible.builtin.apt:
    name: '{{ docker_conflicting_packages }}'
    state: absent
    purge: true
    update_cache: false
  when:
    - ansible_facts.os_family == 'Debian'
    - docker_conflicting_packages | length > 0

Do not use a broad package purge pattern. Removing an unrelated container runtime can interrupt existing workloads, so drain or migrate those workloads before applying this task.

2. Create the keyring and repository

- name: Install repository prerequisites
  ansible.builtin.apt:
    name:
      - ca-certificates
      - curl
    state: present
    update_cache: true

- name: Create apt keyring directory
  ansible.builtin.file:
    path: /etc/apt/keyrings
    state: directory
    owner: root
    group: root
    mode: '0755'

- name: Download Docker signing key
  ansible.builtin.get_url:
    url: '{{ docker_apt_key_url }}'
    dest: /etc/apt/keyrings/docker.asc
    owner: root
    group: root
    mode: '0644'

- name: Configure Docker apt repository
  ansible.builtin.apt_repository:
    repo: '{{ docker_apt_repo_line }}'
    filename: docker
    state: present
    update_cache: true

The keyring path and permissions matter: apt must be able to read the key, while the file remains owned by root. Ensure the release and architecture in docker_apt_repo_line match the host facts you validated earlier.

3. Install Engine, CLI, containerd and plugins

- name: Install Docker Engine and plugins
  ansible.builtin.apt:
    name:
      - docker-ce
      - docker-ce-cli
      - containerd.io
      - docker-buildx-plugin
      - docker-compose-plugin
    state: '{{ docker_package_state }}'
    update_cache: true

If you pin versions, assign each package its exact repository version instead of assuming all five packages share the same version string. Keep the selected versions together in variables so upgrades are intentional.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

4. Enable and start the daemon

- name: Enable and start Docker
  ansible.builtin.service:
    name: docker
    enabled: true
    state: started

Install Docker on RHEL

RHEL uses the same high-level sequence but with dnf and Docker’s RPM repository. The current Docker documentation covers RHEL 8, 9 and 10; verify the exact repository path and architecture before rollout.

1. Remove conflicting packages and add the RPM repository

- name: Remove conflicting RPM packages
  ansible.builtin.dnf:
    name: '{{ docker_conflicting_packages }}'
    state: absent
  when:
    - ansible_facts.os_family == 'RedHat'
    - docker_conflicting_packages | length > 0

- name: Configure Docker RPM repository
  ansible.builtin.yum_repository:
    name: docker-ce-stable
    description: Docker CE Stable
    baseurl: '{{ docker_rpm_repository }}'
    enabled: true
    gpgcheck: true
    gpgkey: '{{ docker_rpm_key_url }}'
    state: present

Use the repository and key values published for your RHEL release. A repository task is idempotent: it changes the file only when its declared content differs.

2. Install packages and start Docker

- name: Install Docker Engine and plugins on RHEL-family hosts
  ansible.builtin.dnf:
    name:
      - docker-ce
      - docker-ce-cli
      - containerd.io
      - docker-buildx-plugin
      - docker-compose-plugin
    state: '{{ docker_package_state }}'
    update_cache: true

- name: Enable and start Docker on RHEL-family hosts
  ansible.builtin.service:
    name: docker
    enabled: true
    state: started

If your organization uses a mirror, preserve signature verification and document the mirror’s synchronization policy. Do not silently fall back to an unverified package source.

Verify the installation

Check service state on the host

Run the equivalent checks manually when diagnosing a failed play:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
systemctl status docker
systemctl is-enabled docker

The first command should show an active service; the second should report that it is enabled for boot. If the service is inactive, inspect the unit log before rerunning Ansible:

journalctl -u docker --no-pager -n 100

Run Docker’s disposable test container

docker run hello-world

Docker states that this command downloads a test image, creates and runs a container, prints a confirmation message and exits. It tests image retrieval, the daemon, container creation and basic runtime execution without leaving a long-running workload.

You can make the check part of the play while preserving a useful failure message:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
- name: Run Docker smoke test
  ansible.builtin.command: docker run --rm hello-world
  register: docker_hello_world
  changed_when: true

- name: Show Docker smoke-test output
  ansible.builtin.debug:
    var: docker_hello_world.stdout

Use --rm for a clean test container. A failure to pull points toward DNS, proxy or registry egress; a failure to connect points toward the service, socket permissions or the selected Python/API context.

Manage containers with Ansible

Use community.docker.docker_container for individual services. The module supports check mode and requires Docker API 1.25 or newer. Declare the desired state instead of scripting a sequence of docker run and docker rm commands.

- name: Run an example web service
  community.docker.docker_container:
    name: example-web
    image: nginx:stable
    state: started
    restart_policy: unless-stopped
    published_ports:
      - '8080:80'
    pull: true

Run the play in check mode before changing a production host:

ansible-playbook -i inventory site.yml --check --diff

Check mode predicts changes but cannot validate every runtime behavior. Follow it with a controlled apply and inspect the resulting container:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
docker ps
 docker inspect example-web

Keep image tags and environment values in variables. For production, prefer a reviewed immutable image reference or digest, define resource and health settings appropriate to the workload, and decide how secrets are injected rather than placing credentials directly in a playbook.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Use Compose modules for multi-container applications

A database, application and reverse proxy that share networks and volumes are a multi-container workload. Use the collection’s Compose v2 modules for that relationship instead of creating each container independently and attempting to reproduce networking by hand. Keep the Compose definition in source control, pass only the intended project directory, and run it through Ansible so project state is repeatable.

Choose individual container tasks when services have independent lifecycles or when you need fine-grained per-container checks. Choose Compose when the application’s value comes from its declared networks, volumes, dependencies and coordinated configuration.

Make the playbook safe to rerun

  • Use declarative modules for files, repositories, packages, services and containers. Avoid shell commands except for a narrowly defined smoke test or an operation with no suitable module.
  • Set repository files and keyring permissions explicitly so drift is corrected on the next run.
  • Keep package and collection versions in variables or requirements files when reproducibility matters.
  • Run check mode in CI, then apply to a disposable host before production.
  • Separate installation from workload deployment with tags such as docker_install and containers.
  • Schedule upgrades deliberately. Test Engine, containerd, Compose and image changes together when compatibility is important.

A second run should report no changes for already-correct repository, package, service and container state. Unexpected changes usually indicate an unpinned repository, a changing image tag, an interpreter mismatch or a task that is not idempotent.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Firewall and port-exposure security

Docker warns that published container ports can bypass host rules managed only through uncomplicated firewall or firewalld abstractions. Before publishing a port, review the host firewall policy and the path Docker uses for packet filtering. Place custom filtering in the supported iptables or ip6tables path, including the DOCKER-USER chain where appropriate, rather than editing Docker-generated chains that the daemon may rewrite.

  • Publish only ports that clients genuinely need.
  • Bind an application to a specific host address when it must not listen on every interface.
  • Restrict administrative ports at the network edge and in host policy.
  • Test access from an untrusted network, not only from localhost.
  • Document every published port in the same variables that define the container.

A successful docker run does not prove that exposure is safe; it proves only that the daemon can start the container.

Troubleshoot common failures

Repository or key errors

If apt reports that a repository has no installation candidate, check the release codename, architecture selector, keyring path and repository file content. On RHEL, inspect the enabled repository and its GPG configuration. A derivative distribution may need its upstream codename, as Docker’s Debian instructions note.

Package conflicts

List installed container-runtime packages before removing anything. Stop dependent workloads, remove only the documented conflicts, refresh metadata and rerun the package task. Do not purge a package merely because its name resembles a Docker component.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Daemon starts and then exits

Read journalctl -u docker and verify storage availability, daemon configuration syntax and the containerd package. A service task can be correct while a local configuration file prevents startup.

“Docker SDK is not installed”

Print the interpreter Ansible selected, install the SDK into that interpreter and rerun a module in verbose mode. Remember that normal modules execute on targets, while plugins use Ansible’s own context.

API-version or module errors

Confirm that the Docker API exposed by the daemon is at least 1.25 and that the installed collection matches your ansible-core version. Reinstall the pinned collection in the same environment that runs the playbook.

Container starts but is unreachable

Inspect the published-port mapping, container logs, listening address inside the container and host firewall rules. A port can be correctly published yet blocked by policy, or the process can be listening only on loopback inside the container.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Operational checklist

  1. Record each host’s distribution release, architecture and intended repository values.
  2. Confirm that the release appears in Docker’s current support documentation.
  3. Install and pin the community.docker collection; verify ansible-core 2.17.0 or newer for the current collection documentation.
  4. Install the Docker SDK for Python in the interpreter used by target-side modules.
  5. Run the Debian-family or RHEL-family repository tasks, never both on one host.
  6. Install docker-ce, docker-ce-cli, containerd.io, docker-buildx-plugin and docker-compose-plugin.
  7. Enable and start the service, then verify with systemctl status docker.
  8. Run docker run hello-world as the smoke test.
  9. Apply container definitions in check mode, review changes, then deploy.
  10. Review every published port against the host firewall and the DOCKER-USER policy.
  11. Record package, collection and image versions, and upgrade them through a planned change.

Final decision

Ansible is a strong fit for Docker server setup when repository configuration, package state, service lifecycle, Python dependencies and workloads are all declared in one repeatable workflow. Use the official repository branch that matches the host family, validate release and architecture first, keep versions intentional, and treat published ports as a firewall design decision rather than a container-only setting.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

AnsibleDebianDevOpsDockerLinux serversRHELUbuntu

Leave a reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.