CI/CD with docker-ansible¶
The willhallonline/ansible images package Ansible for repeatable automation in CI/CD systems. They are useful when you want the same Ansible runtime on laptops, pull requests, scheduled jobs, and production deployment pipelines.
Use this section to pick a CI system and copy a working pipeline shape. Each page shows a minimal example and a fuller lint → syntax check → deploy workflow.
Start with a pinned tag
Prefer an exact image tag such as willhallonline/ansible:2.21-alpine-3.24 in CI. Avoid latest for pipelines because an automatic image update can change Ansible, Python, or operating-system packages without a pull request.
Why run Ansible in a container in CI?¶
A containerised Ansible runtime gives you a stable toolchain:
- the same
ansible-playbookbinary in every job; - predictable versions of
ansible-core, theansiblepackage, andansible-lint; - no need to install Ansible on each CI worker;
- smaller pipeline setup scripts;
- easier upgrades by changing one image tag;
- repeatable behaviour across hosted and self-hosted runners.
The image name is:
Common tags include exact version/platform tags such as:
Convenience tags such as latest, alpine, and ubuntu are available, but they are best kept for local experiments or non-production jobs.
General pipeline pattern¶
Most CI systems can use the same three-stage shape:
- Lint: run
ansible-lintagainst playbooks, roles, and collections. - Syntax check: run
ansible-playbook --syntax-checkwith the same inventory and variables structure used by deployment. - Deploy: run
ansible-playbookonly for protected branches, tags, environments, or manually approved jobs.
A typical command sequence is:
ansible --version
ansible-galaxy collection install -r requirements.yml
ansible-lint
ansible-playbook -i inventories/staging/hosts.yml site.yml --syntax-check
ansible-playbook -i inventories/production/hosts.yml site.yml
If your repository uses roles instead of collections, install both role and collection requirements:
ansible-galaxy role install -r requirements.yml
ansible-galaxy collection install -r requirements.yml
See also:
- Image tags
- Ansible Vault
- Ansible lint
- SSH keys and authentication
- Galaxy roles and collections
- Security reference
Pin exact tags¶
Use exact tags in CI configuration:
Do not use this for production deployments:
Do not deploy from floating tags
Floating tags are convenient, but they turn every pipeline run into a possible Ansible runtime upgrade. Pin exact tags and update them intentionally.
Handle secrets deliberately¶
Ansible deployment jobs commonly need:
- an SSH private key;
- a Vault password or Vault identity file;
- cloud provider credentials;
- inventory-specific tokens.
Store those values in the CI system's secret store, not in the repository. Write secret files with restrictive permissions before running Ansible:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
cp "$SSH_PRIVATE_KEY_FILE" ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
printf '%s' "$ANSIBLE_VAULT_PASSWORD" > .vault-password
chmod 600 .vault-password
Then pass the Vault password file explicitly:
ansible-playbook -i inventories/production/hosts.yml site.yml \
--vault-password-file .vault-password
Prefer known_hosts over disabling checks
ANSIBLE_HOST_KEY_CHECKING=False is useful for short-lived test environments. Production deployment jobs should provision ~/.ssh/known_hosts with ssh-keyscan output or a checked-in known-hosts file that matches your infrastructure policy.
Common repository layout¶
The examples in this section assume a layout like this:
.
├── ansible.cfg
├── requirements.yml
├── site.yml
├── inventories/
│ ├── staging/
│ │ └── hosts.yml
│ └── production/
│ └── hosts.yml
├── group_vars/
└── roles/
Adjust inventory paths and playbook names to match your repository.
CI systems covered¶
| CI system | Container support | Secret features to use | Deployment gate pattern | Page |
|---|---|---|---|---|
| GitHub Actions | Job containers and Docker actions | Secrets, environments, OpenID Connect where appropriate | Branch filters, environments, required reviewers | GitHub Actions |
| GitLab CI | Job-level images | CI/CD variables, file variables, protected variables | rules, protected branches, environments |
GitLab CI |
| Bitbucket Pipelines | Step images | Repository/workspace variables, secured variables, SSH key settings | Branch pipelines and deployments | Bitbucket Pipelines |
| Azure Pipelines | Container jobs or docker run |
Secure files, variable groups, secret variables | Multi-stage approvals and environments | Azure Pipelines |
| Jenkins | Docker agents and inside blocks |
Credentials Binding plugin | Declarative stages, input gates, protected jobs | Jenkins |
| CircleCI | Docker executors | Contexts, project environment variables, add_ssh_keys |
Workflows with branch filters | CircleCI |
| Drone CI | Step images | Repository/org secrets with from_secret |
when filters and protected events |
Drone CI |
| Woodpecker CI | Step images | Secrets injected as environment variables | when branch/event filters |
Woodpecker CI |
Minimal portable commands¶
These commands appear throughout the examples. Keep them in scripts if you want each CI system to call the same logic.
Upgrade workflow¶
Treat image upgrades as normal dependency updates:
- Change
willhallonline/ansible:2.21-alpine-3.24to the target tag. - Run lint and syntax-check jobs on a pull request.
- Run a staging deployment.
- Promote the same commit to production.
- Keep a rollback commit ready if downstream collections or roles rely on old Ansible behaviour.
Troubleshooting checklist¶
- Run
ansible --versionin the job to confirm the image tag used. - Check
ansible.cfgpaths inside the container. - Confirm the CI workspace is mounted as the working directory.
- Verify SSH key permissions are
600and the.sshdirectory is700. - Print inventory hostnames with
ansible-inventory --listwhen debugging inventory parsing. - Use
--syntax-checkbefore deployment to catch YAML and playbook errors early. - Install Galaxy dependencies before linting when lint rules import collection plugins.
- Use protected variables for production secrets.
- Avoid echoing secret values; write them directly to files.
- Prefer environment approvals for production deployments.