Anatomy of a Podman Stack
Each application will have a role and an accompanying playbook for deploying the role to a host.
The playbook will be arranged assuming that you are deploying in an environment identical to SR2’s
(i.e. FreeIPA domain join, NTP servers in our datacenter, Tailscale for monitoring) although the
role itself will usually make only basic assumptions about the hosting environment (e.g. podman
is installed, subuids and subgids are configured).
Within the role, the tasks file will work through a similar set of tasks for each application:
Configure the networks with the sr2c.podman.podman_networks role
Configure the host firewall using ansible.posix.firewalld
Configure “utility” services (e.g. nginx, PostgreSQL, MariaDB, Redis) using utility roles that include common boilerplate or required hardening
Configure the data locations that will be used as volumes with the podman_data role
Configure the containers for the application itself with the podman_stack role
Any post-startup application-specific configuration (e.g. runtime configuration of security policies)
For a hypothetical application myapp, the tasks file looks like this:
---
- name: Podman Myapp | PATCH | Configure the networks
ansible.builtin.include_role:
name: sr2c.podman.podman_networks
vars:
podman_networks_podman_rootless_user: "{{ podman_myapp_podman_rootless_user }}"
podman_networks_config: "{{ _podman_myapp_networks }}"
podman_networks_stop_units: [myapp.target]
- name: Podman Myapp | PATCH | Open the firewall for HTTP and HTTPS
ansible.posix.firewalld:
zone: public
service: "{{ item }}"
permanent: true
immediate: true
state: enabled
loop: [http, https]
become: true
- name: Podman Myapp | PATCH | Configure nginx
ansible.builtin.include_role:
name: sr2c.podman.podman_nginx
vars:
podman_nginx_podman_rootless_user: "{{ podman_myapp_podman_rootless_user }}"
podman_nginx_primary_hostname: "{{ podman_myapp_hostname }}"
podman_nginx_frontend_network: frontend
- name: Podman Myapp | PATCH | Configure the data locations
ansible.builtin.include_role:
name: sr2c.podman.podman_data
vars: {} # data locations and their permissions
- name: Podman Myapp | PATCH | Configure the application containers
ansible.builtin.include_role:
name: sr2c.podman.podman_stack
vars: {} # container quadlets and the stack slice and target
- name: Podman Myapp | PATCH | Apply the runtime security policy
ansible.builtin.command:
argv: [podman, exec, myapp, myapp-cli, policy, apply]
become: true
become_user: "{{ podman_myapp_podman_rootless_user }}"
register: _podman_myapp_policy
changed_when: _podman_myapp_policy.rc == 3
failed_when: _podman_myapp_policy.rc not in [0, 3]