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:
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¶
Build:
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:
boto3andbotocorefor AWSnetaddrfor IP address filterspywinrmfor Windows hostskubernetesfor Kubernetes modulesrequestsfor 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