Skip to content

Extending images

Create a derived image when automation needs extra operating-system packages, Python libraries, Galaxy collections, roles, or wrapper scripts. Pin the base tag so builds are reproducible.

This guide uses:

FROM willhallonline/ansible:2.21-alpine-3.24

See image tags for available variants.

Do not bake secrets

Do not copy SSH keys, Vault passwords, cloud credentials, or private tokens into Dockerfiles. Inject secrets at runtime with mounts or CI secrets.

Add OS packages

FROM willhallonline/ansible:2.21-alpine-3.24

USER root
RUN apk add --no-cache \
      git \
      openssh-client \
      rsync \
      curl \
      jq

WORKDIR /ansible
FROM willhallonline/ansible:2.20-ubuntu-24.04

USER root
RUN apt-get update \
 && apt-get install -y --no-install-recommends \
      git \
      openssh-client \
      rsync \
      curl \
      jq \
 && rm -rf /var/lib/apt/lists/*

WORKDIR /ansible
FROM willhallonline/ansible:2.18-rockylinux-10

USER root
RUN dnf install -y \
      git \
      openssh-clients \
      rsync \
      curl \
      jq \
 && dnf clean all

WORKDIR /ansible

Build:

docker build -t registry.example.com/platform/ansible:2.21-alpine .

Add Python libraries

FROM willhallonline/ansible:2.21-alpine-3.24

RUN pip install --no-cache-dir \
      boto3 \
      botocore \
      netaddr \
      pywinrm \
      kubernetes

WORKDIR /ansible

Common control-node libraries:

  • boto3 and botocore for AWS
  • netaddr for IP address filters
  • pywinrm for Windows hosts
  • kubernetes for Kubernetes modules
  • requests for HTTP APIs

Install Galaxy collections

FROM willhallonline/ansible:2.21-alpine-3.24

WORKDIR /build
COPY requirements.yml requirements.yml
RUN ansible-galaxy collection install \
      -r requirements.yml \
      -p /usr/share/ansible/collections

ENV ANSIBLE_COLLECTIONS_PATH=/usr/share/ansible/collections
WORKDIR /ansible

Example requirements.yml:

collections:
  - name: community.general
    version: 9.5.0
  - name: ansible.posix
    version: 1.6.2
  - name: kubernetes.core
    version: 3.2.0

Install roles

FROM willhallonline/ansible:2.21-alpine-3.24

WORKDIR /build
COPY requirements.yml requirements.yml
RUN ansible-galaxy role install \
      -r requirements.yml \
      -p /usr/share/ansible/roles

ENV ANSIBLE_ROLES_PATH=/usr/share/ansible/roles
WORKDIR /ansible

Combine OS, Python, and Galaxy content

FROM willhallonline/ansible:2.21-alpine-3.24

USER root
RUN apk add --no-cache git openssh-client rsync jq

RUN pip install --no-cache-dir boto3 netaddr pywinrm kubernetes

WORKDIR /build
COPY requirements.yml requirements.yml
RUN ansible-galaxy collection install -r requirements.yml -p /usr/share/ansible/collections

ENV ANSIBLE_COLLECTIONS_PATH=/usr/share/ansible/collections
WORKDIR /ansible

Run your derived image:

docker run --rm -it \
  -v $(pwd):/ansible \
  --workdir=/ansible \
  registry.example.com/platform/ansible:2.21-custom \
  ansible-playbook -i inventory.ini site.yml

Custom entrypoint

FROM willhallonline/ansible:2.21-alpine-3.24

COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

WORKDIR /ansible
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["ansible-playbook", "site.yml"]

Example entrypoint:

#!/bin/sh
set -e

if [ -f requirements.yml ]; then
  ansible-galaxy collection install -r requirements.yml -p collections
fi

exec "$@"

Note

Keep entrypoints simple and visible. Hidden setup can make CI failures harder to diagnose.

Multi-stage builds

FROM willhallonline/ansible:2.21-alpine-3.24 AS builder

USER root
RUN apk add --no-cache build-base python3-dev
RUN pip wheel --wheel-dir /wheels cryptography

FROM willhallonline/ansible:2.21-alpine-3.24

COPY --from=builder /wheels /wheels
RUN pip install --no-cache-dir /wheels/* \
 && rm -rf /wheels

WORKDIR /ansible

Use this pattern when build tools are needed only temporarily.

Pin and push

docker build -t registry.example.com/platform/ansible:2.21.4-20260714 .
docker push registry.example.com/platform/ansible:2.21.4-20260714

Use the pushed image in Compose or CI:

services:
  ansible:
    image: registry.example.com/platform/ansible:2.21.4-20260714
    working_dir: /ansible
    volumes:
      - .:/ansible