Ansible on Alpine Linux 3.20 Automation Complete Guide
By Luca Berton · Published 2024-01-01 · Category: installation
Automate Alpine Linux 3.20 with Ansible: apk, OpenRC, musl, BusyBox, Docker/Podman hosts, lightweight container images, hardening.
Alpine Linux 3.20 (released May 2024) is the minimal, musl-based, BusyBox-anchored distribution behind most container base images. It ships OpenRC instead of systemd, the apk package manager, kernel 6.6 LTS, Python 3.12, and OpenSSH 9.7. Support runs 2 years from GA. Ansible's role on Alpine is twofold: build container images and manage Alpine VMs / hypervisor hosts. This is the master Ansible guide for Alpine 3.20.
Alpine Linux 3.20 release facts
| Item | Value | |---|---| | GA | 2024-05-22 | | Supported until | 2026-05 | | Default kernel | 6.6 LTS | | libc | musl | | Init | OpenRC | | Package manager | apk |
See also: How to install Ansible in Alpine Linux 3.20 — Ansible install
Ansible-core compatibility
Use ansible-core 2.18 LTS. The managed node needs Python:
- name: Bootstrap Python on Alpine before any module runs
hosts: alpine
gather_facts: false
tasks:
- name: Install python3 (raw)
ansible.builtin.raw: apk add --no-cache python3 py3-pip
changed_when: false
Inventory
[alpine]
alpine-01.example.com
[alpine:vars]
ansible_user=root
ansible_python_interpreter=/usr/bin/python3
See also: How to install Ansible in Alpine Linux
Baseline playbook
- name: Alpine 3.20 baseline
hosts: alpine
tasks:
- name: Update apk index
community.general.apk: { update_cache: true }
- name: Upgrade all packages
community.general.apk: { upgrade: true }
- name: Install baseline packages
community.general.apk:
name:
- vim
- curl
- htop
- chrony
- openssh
- sudo
- openrc
- iptables
- cronie
state: present
- name: Enable services with OpenRC
community.general.runit: # placeholder
ansible.builtin.command: rc-update add {{ item }} default
register: rc
changed_when: "'added to runlevel' in rc.stdout"
loop:
- chronyd
- sshd
- cronie
Container engine setup (Podman or Docker)
- name: Install Podman on Alpine
hosts: alpine
tasks:
- name: Install podman
community.general.apk:
name: [podman, fuse-overlayfs, slirp4netns]
state: present
- name: Enable cgroups v2
ansible.builtin.lineinfile:
path: /etc/rc.conf
regexp: '^rc_cgroup_mode'
line: 'rc_cgroup_mode="unified"'
- name: Add containers user
ansible.builtin.user:
name: containers
shell: /bin/ash
create_home: true
See also: Install Docker in Debian-like systems - Ansible module apt_key, apt_repository and apt
OpenRC service authoring
- name: Custom OpenRC service for an app
hosts: alpine
tasks:
- name: Drop service file
ansible.builtin.copy:
dest: /etc/init.d/myapp
mode: "0755"
content: |
#!/sbin/openrc-run
name="myapp"
command="/usr/local/bin/myapp"
command_background=true
pidfile="/run/myapp.pid"
depend() {
need net
after firewall
}
- name: Add to default runlevel
ansible.builtin.command: rc-update add myapp default
register: rc
changed_when: "'added to runlevel' in rc.stdout"
- name: Start
ansible.builtin.command: rc-service myapp start
register: ss
changed_when: "'Starting' in ss.stdout"
Hardening
- name: SSH hardening on Alpine
hosts: alpine
handlers:
- name: restart sshd
ansible.builtin.command: rc-service sshd restart
tasks:
- name: Hardened sshd_config
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?{{ item.k }}'
line: '{{ item.k }} {{ item.v }}'
loop:
- { k: 'PermitRootLogin', v: 'no' }
- { k: 'PasswordAuthentication', v: 'no' }
notify: restart sshd
Best practices
• Always bootstrap Python viaraw before non-trivial tasks.
• Use community.general.apk not raw apk for idempotency.
• Pin Alpine versions in container Dockerfiles (alpine:3.20) to match VM hosts.
• Replace BusyBox with full coreutils only when scripts demand it; otherwise embrace minimalism.
Conclusion
Ansible on Alpine 3.20 needs slightly different patterns (raw Python bootstrap, OpenRC, apk) but delivers fast, lean hosts ideal for container runners, edge devices, and minimal VMs.
Category: installation