AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

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

ItemValue
GA2024-05-22
Supported until2026-05
Default kernel6.6 LTS
libcmusl
InitOpenRC
Package managerapk

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

See also: How to install Ansible in Alpine Linux 3.20 — Ansible install

Inventory

[alpine]
alpine-01.example.com

[alpine:vars]
ansible_user=root
ansible_python_interpreter=/usr/bin/python3

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

See also: How to install Ansible in Alpine Linux

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

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"

See also: Install Docker in Debian-like systems - Ansible module apt_key, apt_repository and apt

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 via raw 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.

Installing Ansible on Alpine Linux

# Install via apk
apk add ansible

# Or minimal install
apk add python3 py3-pip
pip3 install ansible

# Verify
ansible --version

Alpine Package Management

- name: Manage Alpine Linux 3.20
  hosts: alpine
  become: true
  vars:
    ansible_python_interpreter: /usr/bin/python3
  tasks:
    - name: Install packages via apk
      community.general.apk:
        name:
          - nginx
          - git
          - curl
          - openssh
          - sudo
        state: present
        update_cache: true

    - name: Enable and start services
      ansible.builtin.service:
        name: "{{ item }}"
        state: started
        enabled: true
      loop:
        - nginx
        - sshd

    - name: Add community repository
      ansible.builtin.lineinfile:
        path: /etc/apk/repositories
        line: "https://dl-cdn.alpinelinux.org/alpine/v3.20/community"
        state: present

Alpine Firewall (iptables)

    - name: Install iptables
      community.general.apk:
        name: iptables
        state: present

    - name: Allow SSH
      ansible.builtin.iptables:
        chain: INPUT
        protocol: tcp
        destination_port: "22"
        jump: ACCEPT

FAQ

Alpine's minimal size (~5MB base) makes it ideal for container images. Ansible can manage Alpine containers or build Alpine-based images with consistent configuration.

Does Alpine use systemd?

No. Alpine uses OpenRC as its init system. The ansible.builtin.service module works with OpenRC. Use rc-update commands for service management.

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home