383 lines
9.0 KiB
Markdown
383 lines
9.0 KiB
Markdown
# 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 <podman@valid.dk>
|