# Podman Role **Bootstrap containerized applications with Podman in minutes.** ## 🚀 Quick Start ### 1. Basic Setup ```yaml - hosts: servers roles: - podman ``` ### 2. Run Your First Container ```yaml - hosts: servers roles: - role: podman vars: podman_containers: - name: nginx image: nginx:latest ports: - "80:80" ``` ### 3. Common Patterns **Web application with database:** ```yaml podman_containers: - name: webapp image: myapp:latest ports: - "8080:8080" env: DATABASE_URL: "postgresql://postgres@db:5432/app" - name: postgres image: postgres:15 volumes: - "db-data:/var/lib/postgresql/data" env: POSTGRES_DB: app POSTGRES_PASSWORD: secret podman_volumes: - name: db-data ``` **That's it!** Podman will be installed, configured, and your containers will be running with systemd services automatically created. --- ## 📋 Requirements - **Ansible**: 2.11+ - **Target OS**: Ubuntu 20.04+, Debian 11+ - **Collection**: `containers.podman` (auto-installed) --- ## 🔧 Configuration Guide ### Management Modes (Quadlet vs Systemd) This role automatically selects the best management engine based on your operating system version: - **Quadlet** (Default for Debian 13+): Uses Podman's native systemd generator via `.container` files. This is the modern, preferred method. - **Systemd** (Default for Debian < 13): Uses legacy `podman generate systemd` to create service units. The determination is controlled by the logic in `defaults/main.yml`: ```yaml # Auto-detected. True for Debian 13+, False otherwise. podman_use_quadlet: "{{ ... }}" # Sets default state to 'quadlet' or 'started'/'present' accordingly podman_mode: ... ``` **Recommendation:** Do **not** set `state` explicitly in your variables (e.g., `podman_containers`) unless you have a specific reason. The role's defaults will ensure the correct state is applied for your OS version. Users can still manually control defaults if needed: ```yaml # Force Quadlet usage on older systems (if supported) podman_use_quadlet: true # Or customize default options podman_container_defaults: quadlet_options: - "AutoUpdate=registry" - | [Install] WantedBy=default.target ``` If you prefer the standard imperative approach (similar to `docker run`) regardless of OS, you can override the defaults or set `state: started` on individual items. ### Resource Definition The variables `podman_containers`, `podman_networks`, `podman_volumes`, and `podman_pods` accept standard parameters from the [containers.podman](https://docs.ansible.com/ansible/latest/collections/containers/podman/index.html) collection. #### Containers ```yaml podman_containers: - name: nginx image: nginx:latest ports: ["80:80"] volumes: - "html_vol:/usr/share/nginx/html" - "./local_conf:/etc/nginx/conf.d:ro" env: NGINX_HOST: example.com # Quadlet-specific options can be added as a list quadlet_options: - "AutoUpdate=registry" ``` #### Networks ```yaml podman_networks: - name: app_net subnet: "10.0.0.0/24" gateway: "10.0.0.1" dns: ["8.8.8.8"] ``` #### Volumes ```yaml podman_volumes: - name: db_data # state defaults to 'quadlet' ``` #### Pods ```yaml podman_pods: - name: app_pod ports: ["8080:80"] share: "net,ipc" ``` ### Advanced Configuration #### Registry & Security Policy ```yaml # Basic registry setup (development) podman_policy_default_type: "insecureAcceptAnything" podman_policy_reject_unknown_registries: false # Production security (with signatures) podman_policy_default_type: "reject" podman_policy_reject_unknown_registries: true podman_policy_trusted_registries: - registry: "docker.io" type: "insecureAcceptAnything" unqualified_search: true - registry: "internal.company.com" type: "signedBy" keyPath: "/etc/pki/containers/company.gpg" insecure: false mirror: - location: "backup.company.com" # Additional registries (for special mirror/proxy configurations) podman_registries_additional: - location: "internal-mirror.company.com" insecure: false blocked: false mirror: - location: "docker.io" insecure: false ``` #### Systemd Service Generation ```yaml # Global systemd settings podman_generate_systemd: true podman_systemd_options: restart_policy: always stop_timeout: 120 after: ["network.target"] wants: ["network-online.target"] container_prefix: "container-" pod_prefix: "pod-" ``` #### Container Defaults ```yaml # Auto-remove containers when they exit (applies to all containers unless overridden) podman_auto_remove: true ``` #### Resource Cleanup ```yaml # Auto-cleanup unused resources podman_prune_enabled: true podman_prune_options: container: true # Remove stopped containers image: true # Remove unused images network: true # Remove unused networks volume: true # Remove unused volumes system: true # Full system cleanup ``` #### Storage Configuration ```yaml podman_configure_storage: true podman_storage_driver: overlay podman_storage_graphroot: /var/lib/containers/storage podman_storage_runroot: /run/containers/storage ``` #### API & Socket Services ```yaml podman_enable_socket: true # Enable Podman socket podman_enable_api_service: true # Enable REST API podman_enable_auto_update: true # Enable automatic container updates ``` > **Note:** When using `podman_enable_auto_update`, containers must use **fully qualified image names** including the registry (e.g., `docker.io/postgres:15` instead of `postgres:15`) and should have `AutoUpdate=registry` in their `quadlet_options` or be configured with Quadlet state. --- ## 🏷️ Available Tags Run specific parts of the role: ```bash # Install only ansible-playbook -t podman-install playbook.yml # Configure only ansible-playbook -t podman-configure playbook.yml # Manage containers only ansible-playbook -t podman-containers playbook.yml # Manage networks only ansible-playbook -t podman-networks playbook.yml ``` **Available tags:** - `podman` - Run everything - `podman-install` - Package installation - `podman-configure` - Configuration files - `podman-services` - System services - `podman-networks` - Network management - `podman-volumes` - Volume management - `podman-pods` - Pod management - `podman-containers` - Container management - `podman-systemd` - Systemd service generation - `podman-prune` - Resource cleanup --- ## 📚 Example Playbooks ### Development Environment ```yaml - hosts: dev-servers roles: - role: podman vars: # Permissive for development podman_policy_default_type: "insecureAcceptAnything" podman_enable_socket: true podman_containers: - name: dev-web image: nginx:latest ports: - "8080:80" volumes: - "./web:/usr/share/nginx/html" ``` ### Production Environment ```yaml - hosts: prod-servers roles: - role: podman vars: # Strict security for production podman_policy_default_type: "reject" podman_policy_reject_unknown_registries: true podman_policy_trusted_registries: - registry: "registry.company.com" type: "signedBy" keyPath: "/etc/pki/containers/prod.gpg" podman_containers: - name: prod-app image: registry.company.com/app:v1.2.3 restart_policy: always memory: "2g" cpu_shares: 2048 healthcheck: test: ["CMD", "curl", "-f", "http://localhost/health"] interval: 30s timeout: 10s retries: 3 ``` ### Multi-Service Application ```yaml - hosts: app-servers roles: - role: podman vars: podman_networks: - name: app-network subnet: "172.20.0.0/16" podman_volumes: - name: postgres-data - name: redis-data - name: app-uploads podman_containers: # Database - name: postgres image: postgres:15 networks: - app-network volumes: - "postgres-data:/var/lib/postgresql/data" env: POSTGRES_DB: myapp POSTGRES_PASSWORD: "{{ vault_db_password }}" # Cache - name: redis image: redis:7-alpine networks: - app-network volumes: - "redis-data:/data" # Application - name: app image: myapp:latest networks: - app-network ports: - "80:8080" volumes: - "app-uploads:/app/uploads" env: DATABASE_URL: "postgresql://postgres:{{ vault_db_password }}@postgres:5432/myapp" REDIS_URL: "redis://redis:6379" ``` --- ## 📄 License MIT ## 👤 Author Daniel Akulenok