init
This commit is contained in:
273
README.md
Normal file
273
README.md
Normal file
@@ -0,0 +1,273 @@
|
||||
Podman
|
||||
======
|
||||
|
||||
This Ansible role installs and configures Podman container runtime, and provides comprehensive container, pod, network, and volume management capabilities.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
- Ansible 2.11 or higher
|
||||
- Target systems: Ubuntu 20.04+, Debian 11+
|
||||
- containers.podman collection (for container management tasks)
|
||||
|
||||
Role Variables
|
||||
--------------
|
||||
|
||||
### Installation Variables
|
||||
|
||||
* `podman_install_from_repo`: Install from official repositories (default: `true`)
|
||||
* `podman_packages`: List of core Podman packages to install
|
||||
* `podman_additional_packages`: Additional packages for full container support
|
||||
|
||||
### Configuration Variables
|
||||
|
||||
* `podman_configure_registries`: Configure container registries (default: `true`)
|
||||
* `podman_registries_conf_path`: Path to registries configuration (default: `/etc/containers/registries.conf`)
|
||||
* `podman_registries_additional`: Additional registry configurations for special cases
|
||||
|
||||
**Note**: Registry configuration is now unified with the image signature policy through `podman_policy_trusted_registries`. Each registry in the policy configuration includes both security settings (signature verification) and registry behavior (insecure, blocked, unqualified search).
|
||||
|
||||
* `podman_configure_storage`: Configure storage settings (default: `true`)
|
||||
* `podman_storage_conf_path`: Path to storage configuration (default: `/etc/containers/storage.conf`)
|
||||
* `podman_storage_driver`: Storage driver to use (default: `overlay`)
|
||||
* `podman_storage_runroot`: Runtime storage path (default: `/run/containers/storage`)
|
||||
* `podman_storage_graphroot`: Persistent storage path (default: `/var/lib/containers/storage`)
|
||||
|
||||
* `podman_configure_policy`: Configure container policy (default: `true`)
|
||||
* `podman_policy_path`: Path to policy configuration (default: `/etc/containers/policy.json`)
|
||||
|
||||
### Image Signature Policy Variables
|
||||
|
||||
* `podman_policy_default_type`: Default policy for unlisted registries (`"insecureAcceptAnything"` or `"reject"`)
|
||||
* `podman_policy_reject_unknown_registries`: Reject images from unlisted registries (default: `false`)
|
||||
* `podman_policy_trusted_registries`: Unified registry configuration for both policy and registries.conf
|
||||
|
||||
Each registry in `podman_policy_trusted_registries` supports:
|
||||
|
||||
**Security Policy Options:**
|
||||
- `type`: Verification type (`"insecureAcceptAnything"`, `"signedBy"`, `"reject"`)
|
||||
- `keyPath`: Path to GPG key file (for `signedBy` type)
|
||||
- `keyData`: Inline GPG key data (alternative to `keyPath`)
|
||||
|
||||
**Registry Configuration Options:**
|
||||
- `insecure`: Allow insecure (HTTP) connections (default: `false`)
|
||||
- `blocked`: Block access to this registry (default: `false`)
|
||||
- `unqualified_search`: Include in unqualified image searches (default: `true`)
|
||||
- `mirror`: List of mirror registries for redundancy/performance
|
||||
|
||||
```yaml
|
||||
# Unified registry and policy configuration
|
||||
podman_policy_trusted_registries:
|
||||
- registry: "docker.io"
|
||||
# Policy settings
|
||||
type: "insecureAcceptAnything"
|
||||
# Registry settings
|
||||
insecure: false
|
||||
blocked: false
|
||||
unqualified_search: true
|
||||
|
||||
- registry: "internal-registry.company.com"
|
||||
# Policy settings
|
||||
type: "signedBy"
|
||||
keyPath: "/etc/pki/containers/company.gpg"
|
||||
# Registry settings
|
||||
insecure: false
|
||||
blocked: false
|
||||
unqualified_search: true
|
||||
# Mirror configuration
|
||||
mirror:
|
||||
- location: "backup-registry.company.com"
|
||||
insecure: false
|
||||
|
||||
# Development configuration (default)
|
||||
podman_policy_default_type: "insecureAcceptAnything"
|
||||
podman_policy_reject_unknown_registries: false
|
||||
|
||||
# Production configuration with signature verification
|
||||
podman_policy_default_type: "reject"
|
||||
podman_policy_reject_unknown_registries: true
|
||||
```
|
||||
|
||||
### Service Variables
|
||||
|
||||
* `podman_enable_socket`: Enable Podman socket service (default: `false`)
|
||||
* `podman_enable_api_service`: Enable Podman API service (default: `false`)
|
||||
|
||||
### Container Management Variables
|
||||
|
||||
```yaml
|
||||
podman_containers:
|
||||
- name: nginx
|
||||
image: docker.io/nginx:latest
|
||||
state: started
|
||||
ports:
|
||||
- "8080:80"
|
||||
volumes:
|
||||
- "/etc/nginx/conf.d:/etc/nginx/conf.d:ro"
|
||||
env:
|
||||
NGINX_HOST: example.com
|
||||
restart_policy: always
|
||||
user: nginx
|
||||
networks:
|
||||
- podman
|
||||
labels:
|
||||
app: webserver
|
||||
version: "1.0"
|
||||
```
|
||||
|
||||
### Network Management Variables
|
||||
|
||||
```yaml
|
||||
podman_networks:
|
||||
- name: app-network
|
||||
driver: bridge
|
||||
subnet: "10.89.0.0/24"
|
||||
gateway: "10.89.0.1"
|
||||
state: present
|
||||
internal: false
|
||||
disable_dns: false
|
||||
dns:
|
||||
- "8.8.8.8"
|
||||
options:
|
||||
mtu: 1500
|
||||
vlan: 100
|
||||
ipam_driver: "host-local"
|
||||
interface_name: "podman1"
|
||||
route:
|
||||
- "10.10.0.0/16,192.168.1.1"
|
||||
- name: macvlan-net
|
||||
driver: macvlan
|
||||
macvlan: "eth0"
|
||||
subnet: "192.168.1.0/24"
|
||||
- name: ipv6-net
|
||||
driver: bridge
|
||||
subnet: "fd00::/64"
|
||||
ipv6: true
|
||||
recreate: false
|
||||
```
|
||||
|
||||
### Volume Management Variables
|
||||
|
||||
```yaml
|
||||
podman_volumes:
|
||||
- name: app-data
|
||||
state: present
|
||||
driver: local
|
||||
labels:
|
||||
environment: production
|
||||
backup: daily
|
||||
options:
|
||||
- "device=/dev/sdb1"
|
||||
- "type=ext4"
|
||||
- "o=rw"
|
||||
- name: tmpfs-volume
|
||||
state: present
|
||||
driver: tmpfs
|
||||
options:
|
||||
- "tmpfs-size=100m"
|
||||
- "tmpfs-mode=1777"
|
||||
- name: quadlet-volume
|
||||
state: quadlet
|
||||
driver: local
|
||||
quadlet_filename: "custom-volume"
|
||||
quadlet_file_mode: "0640"
|
||||
quadlet_options:
|
||||
- "Group=192"
|
||||
- "Copy=true"
|
||||
recreate: false
|
||||
debug: false
|
||||
```
|
||||
|
||||
### Pod Management Variables
|
||||
|
||||
```yaml
|
||||
podman_pods:
|
||||
- name: webapp-pod
|
||||
state: started
|
||||
ports:
|
||||
- "8080:80"
|
||||
- "3306:3306"
|
||||
networks:
|
||||
- frontend
|
||||
hostname: webapp
|
||||
dns:
|
||||
- "8.8.8.8"
|
||||
labels:
|
||||
app: webapp
|
||||
tier: frontend
|
||||
volumes:
|
||||
- "webapp-data:/data"
|
||||
infra: true
|
||||
infra_image: "k8s.gcr.io/pause:3.1"
|
||||
memory: "2g"
|
||||
cpu_shares: "1024"
|
||||
security_opt:
|
||||
- "seccomp=unconfined"
|
||||
add_host:
|
||||
- "database.local:127.0.0.1"
|
||||
share: "net,ipc"
|
||||
userns: "auto"
|
||||
device:
|
||||
- "/dev/sda:/dev/xvda:rwm"
|
||||
sysctl:
|
||||
net.core.somaxconn: "1024"
|
||||
exit_policy: "stop"
|
||||
- name: quadlet-pod
|
||||
state: quadlet
|
||||
quadlet_filename: "custom-pod"
|
||||
quadlet_options:
|
||||
- "AutoUpdate=registry"
|
||||
generate_systemd:
|
||||
path: "/etc/systemd/system"
|
||||
restart_policy: "always"
|
||||
```
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
* `containers.podman` collection for container management tasks
|
||||
|
||||
Example Playbook
|
||||
----------------
|
||||
|
||||
```yaml
|
||||
- hosts: servers
|
||||
roles:
|
||||
- role: keepit.podman
|
||||
vars:
|
||||
podman_enable_socket: true
|
||||
podman_containers:
|
||||
- name: web-server
|
||||
image: nginx:latest
|
||||
state: started
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- "/var/www/html:/usr/share/nginx/html:ro"
|
||||
podman_networks:
|
||||
- name: web-network
|
||||
subnet: "172.20.0.0/16"
|
||||
```
|
||||
|
||||
Tags
|
||||
----
|
||||
|
||||
* `podman` - Run all tasks
|
||||
* `podman-install` - Install packages only
|
||||
* `podman-configure` - Configure Podman only
|
||||
* `podman-services` - Manage services only
|
||||
* `podman-networks` - Manage networks only
|
||||
* `podman-volumes` - Manage volumes only
|
||||
* `podman-pods` - Manage pods only
|
||||
* `podman-containers` - Manage containers only
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
MIT
|
||||
|
||||
Author Information
|
||||
------------------
|
||||
|
||||
Daniel Akulenok <dak@keepit.com>
|
||||
Keepit A/S
|
||||
603
defaults/main.yml
Normal file
603
defaults/main.yml
Normal file
@@ -0,0 +1,603 @@
|
||||
---
|
||||
# defaults file for podman
|
||||
|
||||
# Package installation
|
||||
podman_install_from_repo: true
|
||||
podman_packages:
|
||||
- podman
|
||||
- crun
|
||||
|
||||
# Podman configuration
|
||||
podman_configure_registries: true
|
||||
podman_registries_conf_path: /etc/containers/registries.conf
|
||||
|
||||
# Additional registries not included in policy configuration
|
||||
# Use this for registries that need special mirror or proxy configuration
|
||||
podman_registries_additional: []
|
||||
# Example:
|
||||
# podman_registries_additional:
|
||||
# - location: "internal-mirror.company.com"
|
||||
# insecure: false
|
||||
# blocked: false
|
||||
# mirror:
|
||||
# - location: "docker.io"
|
||||
# insecure: false
|
||||
|
||||
# Storage configuration
|
||||
podman_configure_storage: true
|
||||
podman_storage_conf_path: /etc/containers/storage.conf
|
||||
podman_storage_driver: overlay
|
||||
podman_storage_runroot: /run/containers/storage
|
||||
podman_storage_graphroot: /var/lib/containers/storage
|
||||
|
||||
# Policy configuration
|
||||
podman_configure_policy: true
|
||||
podman_policy_path: /etc/containers/policy.json
|
||||
|
||||
# Image signature policy settings
|
||||
# Default policy type: "insecureAcceptAnything" for development, "reject" for production
|
||||
podman_policy_default_type: "insecureAcceptAnything"
|
||||
|
||||
# Whether to reject images from unknown/unlisted registries
|
||||
podman_policy_reject_unknown_registries: false
|
||||
|
||||
# Trusted registries configuration
|
||||
# Each registry can have different trust levels and signature requirements
|
||||
# Plus registries.conf configuration options
|
||||
podman_policy_trusted_registries:
|
||||
# Docker Hub official images (library namespace)
|
||||
- registry: "docker.io/library"
|
||||
type: "insecureAcceptAnything"
|
||||
# Registry configuration
|
||||
insecure: false
|
||||
blocked: false
|
||||
unqualified_search: false # Don't search library namespace for unqualified images
|
||||
|
||||
# Docker Hub (all namespaces) - use with caution in production
|
||||
- registry: "docker.io"
|
||||
type: "insecureAcceptAnything"
|
||||
# Registry configuration
|
||||
insecure: false
|
||||
blocked: false
|
||||
unqualified_search: true # Primary search registry
|
||||
|
||||
# Red Hat's official registry
|
||||
- registry: "registry.redhat.io"
|
||||
type: "insecureAcceptAnything"
|
||||
# For production with signature verification:
|
||||
# type: "signedBy"
|
||||
# keyPath: "/etc/pki/containers/redhat.gpg"
|
||||
# Registry configuration
|
||||
insecure: false
|
||||
blocked: false
|
||||
unqualified_search: true
|
||||
|
||||
# Quay.io - Red Hat's container registry
|
||||
- registry: "quay.io"
|
||||
type: "insecureAcceptAnything"
|
||||
# Registry configuration
|
||||
insecure: false
|
||||
blocked: false
|
||||
unqualified_search: true
|
||||
|
||||
# Google Container Registry
|
||||
- registry: "gcr.io"
|
||||
type: "insecureAcceptAnything"
|
||||
# Registry configuration
|
||||
insecure: false
|
||||
blocked: false
|
||||
unqualified_search: true
|
||||
|
||||
# Microsoft Container Registry
|
||||
- registry: "mcr.microsoft.com"
|
||||
type: "insecureAcceptAnything"
|
||||
# Registry configuration
|
||||
insecure: false
|
||||
blocked: false
|
||||
unqualified_search: true
|
||||
|
||||
# Amazon ECR Public
|
||||
- registry: "public.ecr.aws"
|
||||
type: "insecureAcceptAnything"
|
||||
# Registry configuration
|
||||
insecure: false
|
||||
blocked: false
|
||||
unqualified_search: false # Not commonly used for unqualified searches
|
||||
|
||||
# GitHub Container Registry
|
||||
- registry: "ghcr.io"
|
||||
type: "insecureAcceptAnything"
|
||||
# Registry configuration
|
||||
insecure: false
|
||||
blocked: false
|
||||
unqualified_search: false # Not commonly used for unqualified searches
|
||||
|
||||
# GitLab Container Registry
|
||||
- registry: "registry.gitlab.com"
|
||||
type: "insecureAcceptAnything"
|
||||
# Registry configuration
|
||||
insecure: false
|
||||
blocked: false
|
||||
unqualified_search: false # Not commonly used for unqualified searches
|
||||
|
||||
# Example production configuration with signature verification:
|
||||
# podman_policy_default_type: "reject"
|
||||
# podman_policy_reject_unknown_registries: true
|
||||
# podman_policy_trusted_registries:
|
||||
# # Internal company registry with signature verification
|
||||
# - registry: "internal-registry.company.com"
|
||||
# type: "signedBy"
|
||||
# keyPath: "/etc/pki/containers/company.gpg"
|
||||
# # Registry configuration
|
||||
# insecure: false
|
||||
# blocked: false
|
||||
# unqualified_search: true
|
||||
# # Optional: mirror configuration
|
||||
# mirror:
|
||||
# - location: "backup-registry.company.com"
|
||||
# insecure: false
|
||||
#
|
||||
# # Red Hat registry with signature verification
|
||||
# - registry: "registry.redhat.io"
|
||||
# type: "signedBy"
|
||||
# keyPath: "/etc/pki/containers/redhat.gpg"
|
||||
# # Registry configuration
|
||||
# insecure: false
|
||||
# blocked: false
|
||||
# unqualified_search: true
|
||||
#
|
||||
# # Docker Hub official images only (more restrictive)
|
||||
# - registry: "docker.io/library"
|
||||
# type: "insecureAcceptAnything"
|
||||
# # Registry configuration
|
||||
# insecure: false
|
||||
# blocked: false
|
||||
# unqualified_search: false
|
||||
#
|
||||
# # Specific trusted namespaces
|
||||
# - registry: "quay.io/company"
|
||||
# type: "signedBy"
|
||||
# keyPath: "/etc/pki/containers/company.gpg"
|
||||
# # Registry configuration
|
||||
# insecure: false
|
||||
# blocked: false
|
||||
# unqualified_search: false
|
||||
|
||||
# Service management
|
||||
podman_enable_socket: false
|
||||
podman_enable_api_service: false
|
||||
|
||||
# Container management
|
||||
podman_containers: []
|
||||
# Example container configurations:
|
||||
# podman_containers:
|
||||
# # Basic web server container
|
||||
# - name: nginx
|
||||
# image: docker.io/nginx:latest
|
||||
# state: started
|
||||
# ports:
|
||||
# - "8080:80"
|
||||
# volumes:
|
||||
# - "/etc/nginx/conf.d:/etc/nginx/conf.d:ro"
|
||||
# env:
|
||||
# NGINX_HOST: example.com
|
||||
# restart_policy: always
|
||||
# user: nginx
|
||||
# networks:
|
||||
# - podman
|
||||
# labels:
|
||||
# app: webserver
|
||||
# version: "1.0"
|
||||
# working_dir: /app
|
||||
#
|
||||
# # Advanced container with comprehensive configuration
|
||||
# - name: app-server
|
||||
# image: registry.example.com/myapp:v1.2.3
|
||||
# state: started
|
||||
# # Basic runtime options
|
||||
# command: ["/app/start.sh", "--config", "/etc/app/config.yaml"]
|
||||
# entrypoint: "/entrypoint.sh"
|
||||
# user: "1000:1000"
|
||||
# working_dir: /app
|
||||
# hostname: app-server
|
||||
# detach: true
|
||||
# interactive: false
|
||||
# tty: false
|
||||
# auto_remove: false
|
||||
# privileged: false
|
||||
# read_only: false
|
||||
# read_only_tmpfs: true
|
||||
# init: true
|
||||
#
|
||||
# # Networking configuration
|
||||
# networks:
|
||||
# - frontend
|
||||
# - backend
|
||||
# ports:
|
||||
# - "8080:8080"
|
||||
# - "127.0.0.1:8081:8081/tcp"
|
||||
# publish_all: false
|
||||
# expose:
|
||||
# - "9000"
|
||||
# ip: "10.88.0.100"
|
||||
# mac_address: "02:42:ac:11:00:02"
|
||||
# network_aliases:
|
||||
# - app
|
||||
# - api
|
||||
# dns:
|
||||
# - "8.8.8.8"
|
||||
# - "1.1.1.1"
|
||||
# dns_options: "ndots:2"
|
||||
# dns_search:
|
||||
# - "example.com"
|
||||
# - "local"
|
||||
# add_hosts:
|
||||
# database: "192.168.1.100"
|
||||
# cache: "192.168.1.101"
|
||||
# no_hosts: false
|
||||
#
|
||||
# # Storage and volumes
|
||||
# volumes:
|
||||
# - "/data/app:/app/data:rw"
|
||||
# - "app-config:/etc/app:ro"
|
||||
# volumes_from:
|
||||
# - data-container
|
||||
# mounts:
|
||||
# - "type=bind,source=/host/path,destination=/container/path,ro"
|
||||
# tmpfs:
|
||||
# /tmp: "rw,size=100m,mode=1777"
|
||||
# /var/cache: "rw,size=50m"
|
||||
#
|
||||
# # Environment variables
|
||||
# env:
|
||||
# DATABASE_URL: "postgresql://user:pass@db:5432/myapp"
|
||||
# REDIS_URL: "redis://cache:6379/0"
|
||||
# LOG_LEVEL: "info"
|
||||
# FEATURE_FLAGS: "new_ui,api_v2"
|
||||
# env_files:
|
||||
# - "/etc/app/.env"
|
||||
# env_host: false
|
||||
# env_merge:
|
||||
# PATH: "/app/bin:$PATH"
|
||||
# unsetenv:
|
||||
# - "TEMP_VAR"
|
||||
#
|
||||
# # Resource constraints
|
||||
# memory: "2g"
|
||||
# memory_reservation: "1g"
|
||||
# memory_swap: "4g"
|
||||
# memory_swappiness: 60
|
||||
# cpus: "1.5"
|
||||
# cpu_shares: 1024
|
||||
# cpu_period: 100000
|
||||
# cpu_quota: 150000
|
||||
# cpuset_cpus: "0-1"
|
||||
# cpuset_mems: "0"
|
||||
# blkio_weight: 500
|
||||
# blkio_weight_device:
|
||||
# "/dev/sda": 600
|
||||
# oom_kill_disable: false
|
||||
# oom_score_adj: 500
|
||||
# pids_limit: "1000"
|
||||
#
|
||||
# # Device access
|
||||
# devices:
|
||||
# - "/dev/nvidia0:/dev/nvidia0:rwm"
|
||||
# - "/dev/sda:/dev/xvda:ro"
|
||||
# device_read_bps:
|
||||
# - "/dev/sda:1mb"
|
||||
# device_write_bps:
|
||||
# - "/dev/sda:1mb"
|
||||
# device_read_iops:
|
||||
# - "/dev/sda:1000"
|
||||
# device_write_iops:
|
||||
# - "/dev/sda:1000"
|
||||
# gpus: "all"
|
||||
#
|
||||
# # Security configuration
|
||||
# security_opt:
|
||||
# - "seccomp=unconfined"
|
||||
# - "label=type:container_runtime_t"
|
||||
# cap_add:
|
||||
# - "NET_ADMIN"
|
||||
# - "SYS_TIME"
|
||||
# cap_drop:
|
||||
# - "MKNOD"
|
||||
# - "AUDIT_WRITE"
|
||||
# userns: "host"
|
||||
# uidmap:
|
||||
# - "0:1000:1000"
|
||||
# gidmap:
|
||||
# - "0:1000:1000"
|
||||
# subuidname: "myuser"
|
||||
# subgidname: "myuser"
|
||||
# groups:
|
||||
# - "docker"
|
||||
# - "audio"
|
||||
#
|
||||
# # Namespaces
|
||||
# ipc_mode: "container:other-container"
|
||||
# pid_mode: "host"
|
||||
# uts: "host"
|
||||
# cgroupns: "host"
|
||||
#
|
||||
# # Cgroups
|
||||
# cgroups: "enabled"
|
||||
# cgroup_parent: "/system.slice"
|
||||
# cgroup_conf:
|
||||
# "memory.swappiness": "10"
|
||||
#
|
||||
# # System configuration
|
||||
# sysctl:
|
||||
# net.core.somaxconn: "1024"
|
||||
# kernel.shm_rmid_forced: "1"
|
||||
# systemd: "true"
|
||||
# ulimits:
|
||||
# - "nofile=65536:65536"
|
||||
# - "nproc=4096:4096"
|
||||
# umask: "0027"
|
||||
#
|
||||
# # Shared memory
|
||||
# shm_size: "128m"
|
||||
# shm_size_systemd: "64m"
|
||||
#
|
||||
# # Pod integration
|
||||
# pod: "app-pod"
|
||||
#
|
||||
# # Logging
|
||||
# log_driver: "journald"
|
||||
# log_options:
|
||||
# max_size: "10mb"
|
||||
# max_files: "3"
|
||||
# tag: "app-server"
|
||||
# log_level: "info"
|
||||
#
|
||||
# # Health checks
|
||||
# healthcheck: "curl -f http://localhost:8080/health || exit 1"
|
||||
# healthcheck_interval: "30s"
|
||||
# healthcheck_timeout: "10s"
|
||||
# healthcheck_start_period: "60s"
|
||||
# healthcheck_retries: 3
|
||||
# healthcheck_failure_action: "restart"
|
||||
# no_healthcheck: false
|
||||
#
|
||||
# # Startup health checks
|
||||
# health_startup_cmd: "curl -f http://localhost:8080/ready || exit 1"
|
||||
# health_startup_interval: "5s"
|
||||
# health_startup_timeout: "3s"
|
||||
# health_startup_retries: 20
|
||||
# health_startup_success: 1
|
||||
#
|
||||
# # Metadata
|
||||
# labels:
|
||||
# app: "myapp"
|
||||
# version: "1.2.3"
|
||||
# environment: "production"
|
||||
# maintainer: "team@example.com"
|
||||
# annotations:
|
||||
# "org.opencontainers.image.source": "https://github.com/example/myapp"
|
||||
#
|
||||
# # Container lifecycle
|
||||
# restart_policy: "on-failure:3"
|
||||
# restart_time: "10s"
|
||||
# stop_signal: 15
|
||||
# stop_time: "30s"
|
||||
# stop_timeout: 30
|
||||
# timeout: 0
|
||||
#
|
||||
# # Image options
|
||||
# pull: "missing"
|
||||
# image_strict: false
|
||||
# arch: "amd64"
|
||||
# platform: "linux/amd64"
|
||||
#
|
||||
# # Advanced options
|
||||
# timezone: "UTC"
|
||||
# requires:
|
||||
# - "database-container"
|
||||
#
|
||||
# # Systemd integration
|
||||
# generate_systemd:
|
||||
# path: "/etc/systemd/system"
|
||||
# restart_policy: "always"
|
||||
# stop_timeout: 120
|
||||
# names: true
|
||||
# container_prefix: "container"
|
||||
# new: false
|
||||
# no_header: false
|
||||
# wants:
|
||||
# - "network-online.target"
|
||||
# after:
|
||||
# - "network-online.target"
|
||||
# requires:
|
||||
# - "postgresql.service"
|
||||
#
|
||||
# # Control options
|
||||
# recreate: false
|
||||
# force_restart: false
|
||||
# debug: false
|
||||
#
|
||||
# # Database container with quadlet
|
||||
# - name: postgres
|
||||
# image: docker.io/postgres:15
|
||||
# state: quadlet
|
||||
# env:
|
||||
# POSTGRES_DB: myapp
|
||||
# POSTGRES_USER: appuser
|
||||
# POSTGRES_PASSWORD: secretpass
|
||||
# volumes:
|
||||
# - "postgres-data:/var/lib/postgresql/data"
|
||||
# ports:
|
||||
# - "5432:5432"
|
||||
# networks:
|
||||
# - backend
|
||||
# memory: "4g"
|
||||
# cpu_shares: 2048
|
||||
# healthcheck: "pg_isready -U appuser -d myapp"
|
||||
# healthcheck_interval: "10s"
|
||||
# healthcheck_timeout: "5s"
|
||||
# healthcheck_retries: 5
|
||||
# quadlet_dir: "/etc/containers/systemd"
|
||||
# quadlet_filename: "postgres-db"
|
||||
# quadlet_file_mode: "0640"
|
||||
# quadlet_options:
|
||||
# - "AutoUpdate=registry"
|
||||
# - "Pull=newer"
|
||||
# - |
|
||||
# [Install]
|
||||
# WantedBy=default.target
|
||||
#
|
||||
# # Privileged system container
|
||||
# - name: monitoring-agent
|
||||
# image: quay.io/prometheus/node-exporter:latest
|
||||
# state: started
|
||||
# privileged: true
|
||||
# read_only: true
|
||||
# pid_mode: "host"
|
||||
# networks:
|
||||
# - host
|
||||
# volumes:
|
||||
# - "/proc:/host/proc:ro"
|
||||
# - "/sys:/host/sys:ro"
|
||||
# - "/:/rootfs:ro"
|
||||
# command:
|
||||
# - "--path.procfs=/host/proc"
|
||||
# - "--path.sysfs=/host/sys"
|
||||
# - "--collector.filesystem.ignored-mount-points"
|
||||
# ports:
|
||||
# - "9100:9100"
|
||||
# restart_policy: "always"
|
||||
# user: "nobody"
|
||||
# cap_drop:
|
||||
# - "ALL"
|
||||
# security_opt:
|
||||
# - "no-new-privileges=true"
|
||||
|
||||
# Network management
|
||||
podman_networks: []
|
||||
# Example network configuration:
|
||||
# podman_networks:
|
||||
# - name: app-network
|
||||
# driver: bridge
|
||||
# subnet: "10.89.0.0/24"
|
||||
# gateway: "10.89.0.1"
|
||||
# state: present
|
||||
# - name: frontend-network
|
||||
# driver: bridge
|
||||
# subnet: "172.20.0.0/16"
|
||||
# gateway: "172.20.0.1"
|
||||
# internal: true
|
||||
# disable_dns: false
|
||||
# dns:
|
||||
# - "8.8.8.8"
|
||||
# - "8.8.4.4"
|
||||
# options:
|
||||
# mtu: 1500
|
||||
# vlan: 100
|
||||
# - name: macvlan-network
|
||||
# driver: macvlan
|
||||
# macvlan: "eth0"
|
||||
# subnet: "192.168.1.0/24"
|
||||
# gateway: "192.168.1.1"
|
||||
# ipam_driver: "host-local"
|
||||
# - name: ipv6-network
|
||||
# driver: bridge
|
||||
# subnet: "fd00::/64"
|
||||
# gateway: "fd00::1"
|
||||
# ipv6: true
|
||||
# route:
|
||||
# - "10.10.0.0/16,192.168.1.1"
|
||||
|
||||
# Volume management
|
||||
podman_volumes: []
|
||||
# Example volume configuration:
|
||||
# podman_volumes:
|
||||
# - name: app-data
|
||||
# state: present
|
||||
# driver: local
|
||||
# - name: database-volume
|
||||
# state: present
|
||||
# driver: local
|
||||
# labels:
|
||||
# environment: production
|
||||
# backup: daily
|
||||
# options:
|
||||
# - "device=/dev/sdb1"
|
||||
# - "type=ext4"
|
||||
# - "o=rw"
|
||||
# - name: tmpfs-volume
|
||||
# state: present
|
||||
# driver: tmpfs
|
||||
# options:
|
||||
# - "tmpfs-size=100m"
|
||||
# - "tmpfs-mode=1777"
|
||||
# - name: quadlet-volume
|
||||
# state: quadlet
|
||||
# driver: local
|
||||
# quadlet_filename: "custom-volume"
|
||||
# quadlet_file_mode: "0640"
|
||||
# quadlet_options:
|
||||
# - "Group=192"
|
||||
# - "Copy=true"
|
||||
# recreate: false
|
||||
# debug: false
|
||||
|
||||
# Pod management
|
||||
podman_pods: []
|
||||
# Example pod configuration:
|
||||
# podman_pods:
|
||||
# - name: webapp-pod
|
||||
# state: started
|
||||
# ports:
|
||||
# - "8080:80"
|
||||
# - "3306:3306"
|
||||
# networks:
|
||||
# - frontend
|
||||
# hostname: webapp
|
||||
# dns:
|
||||
# - "8.8.8.8"
|
||||
# - "8.8.4.4"
|
||||
# labels:
|
||||
# app: webapp
|
||||
# tier: frontend
|
||||
# volumes:
|
||||
# - "webapp-data:/data"
|
||||
# infra: true
|
||||
# infra_image: "k8s.gcr.io/pause:3.1"
|
||||
# - name: database-pod
|
||||
# state: created
|
||||
# networks:
|
||||
# - backend
|
||||
# security_opt:
|
||||
# - "seccomp=unconfined"
|
||||
# memory: "2g"
|
||||
# cpu_shares: "1024"
|
||||
# add_host:
|
||||
# - "database.local:127.0.0.1"
|
||||
# share: "net,ipc"
|
||||
# userns: "auto"
|
||||
# - name: monitoring-pod
|
||||
# state: started
|
||||
# ports:
|
||||
# - "9090:9090"
|
||||
# device:
|
||||
# - "/dev/sda:/dev/xvda:rwm"
|
||||
# sysctl:
|
||||
# net.core.somaxconn: "1024"
|
||||
# shm_size: "128m"
|
||||
# exit_policy: "stop"
|
||||
# - name: quadlet-pod
|
||||
# state: quadlet
|
||||
# ports:
|
||||
# - "4444:5555"
|
||||
# volumes:
|
||||
# - "/var/run/docker.sock:/var/run/docker.sock"
|
||||
# quadlet_dir: "/etc/containers/systemd"
|
||||
# quadlet_filename: "custom-pod"
|
||||
# quadlet_file_mode: "0640"
|
||||
# quadlet_options:
|
||||
# - "AutoUpdate=registry"
|
||||
# - "Pull=newer"
|
||||
# generate_systemd:
|
||||
# path: "/etc/systemd/system"
|
||||
# restart_policy: "always"
|
||||
8
handlers/main.yml
Normal file
8
handlers/main.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
# handlers file for podman
|
||||
|
||||
- name: Restart podman
|
||||
ansible.builtin.systemd:
|
||||
name: podman
|
||||
state: restarted
|
||||
listen: restart podman
|
||||
24
meta/main.yml
Normal file
24
meta/main.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
galaxy_info:
|
||||
role_name: podman
|
||||
author: Daniel Akulenok
|
||||
namespace: keepit
|
||||
description: Install and configure Podman container runtime and manage containers
|
||||
company: Keepit A/S
|
||||
license: MIT
|
||||
min_ansible_version: "2.11"
|
||||
platforms:
|
||||
- name: Ubuntu
|
||||
versions:
|
||||
- focal
|
||||
- jammy
|
||||
- name: Debian
|
||||
versions:
|
||||
- bullseye
|
||||
- bookworm
|
||||
galaxy_tags:
|
||||
- podman
|
||||
- containers
|
||||
- docker
|
||||
- oci
|
||||
dependencies: []
|
||||
5
meta/requirements.yml
Normal file
5
meta/requirements.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
# Collection requirements for the podman role
|
||||
collections:
|
||||
- name: containers.podman
|
||||
version: ">=1.10.0"
|
||||
17
molecule/default/converge.yml
Normal file
17
molecule/default/converge.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
- name: Converge - apply podman role
|
||||
hosts: all
|
||||
become: true
|
||||
vars:
|
||||
podman_install_from_repo: true
|
||||
podman_packages:
|
||||
- podman
|
||||
podman_configure_registries: true
|
||||
podman_configure_storage: true
|
||||
podman_configure_policy: true
|
||||
podman_enable_socket: false
|
||||
podman_enable_api_service: false
|
||||
podman_policy_default_type: "insecureAcceptAnything"
|
||||
podman_policy_trusted_registries: []
|
||||
roles:
|
||||
- name: podman
|
||||
30
molecule/default/molecule.yml
Normal file
30
molecule/default/molecule.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
dependency:
|
||||
name: galaxy
|
||||
driver:
|
||||
name: podman
|
||||
platform_defaults: &platform_defaults
|
||||
tmpfs:
|
||||
- /tmp
|
||||
- /run/lock
|
||||
volumes:
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup:ro
|
||||
command: /lib/systemd/systemd
|
||||
platforms:
|
||||
- name: debian-bullseye
|
||||
image: docker.io/jrei/systemd-debian:12
|
||||
<<: *platform_defaults
|
||||
- name: debian-bullseye
|
||||
image: docker.io/jrei/systemd-debian:13
|
||||
<<: *platform_defaults
|
||||
|
||||
provisioner:
|
||||
name: ansible
|
||||
lint:
|
||||
name: ansible-lint
|
||||
verifier:
|
||||
name: ansible
|
||||
lint: |
|
||||
set -e
|
||||
ansible-lint .
|
||||
yamllint .
|
||||
28
molecule/default/prepare.yml
Normal file
28
molecule/default/prepare.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
- name: Prepare instance for podman role testing
|
||||
hosts: all
|
||||
become: true
|
||||
tasks:
|
||||
- name: Ensure apt cache is up-to-date
|
||||
ansible.builtin.apt:
|
||||
update_cache: yes
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Install prerequisites used by the role/tests
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- apt-transport-https
|
||||
- ca-certificates
|
||||
- gnupg
|
||||
- lsb-release
|
||||
- curl
|
||||
state: present
|
||||
update_cache: false
|
||||
|
||||
- name: Install python3-venv and python3-pip for testinfra
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- python3-pip
|
||||
- python3-venv
|
||||
state: present
|
||||
update_cache: false
|
||||
3
molecule/default/requirements.yml
Normal file
3
molecule/default/requirements.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
---
|
||||
collections:
|
||||
- name: containers.podman
|
||||
BIN
molecule/default/tests/__pycache__/test_default.cpython-313.pyc
Normal file
BIN
molecule/default/tests/__pycache__/test_default.cpython-313.pyc
Normal file
Binary file not shown.
34
molecule/default/tests/test_default.py
Normal file
34
molecule/default/tests/test_default.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import os
|
||||
import testinfra.utils.ansible_runner
|
||||
|
||||
# Get hosts from Testinfra inventory created by Molecule
|
||||
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
|
||||
os.environ.get('MOLECULE_INVENTORY_FILE')
|
||||
).get_hosts('all')
|
||||
|
||||
|
||||
def test_podman_package_installed(host):
|
||||
pkg = host.package("podman")
|
||||
assert pkg.is_installed, "podman package should be installed"
|
||||
|
||||
|
||||
def test_podman_binary_executes(host):
|
||||
cmd = host.run("podman --version")
|
||||
assert cmd.rc == 0, f"podman not runnable: {cmd.stderr or cmd.stdout}"
|
||||
|
||||
|
||||
def test_containers_conf_exists(host):
|
||||
f = host.file("/etc/containers/registries.conf")
|
||||
assert f.exists, "/etc/containers/registries.conf should exist"
|
||||
|
||||
|
||||
def test_policy_json_exists(host):
|
||||
f = host.file("/etc/containers/policy.json")
|
||||
assert f.exists, "/etc/containers/policy.json should exist"
|
||||
|
||||
|
||||
def test_podman_config_file_valid_json(host):
|
||||
f = host.file("/etc/containers/policy.json")
|
||||
assert f.exists and f.size > 0
|
||||
cmd = host.run("python3 -c 'import json,sys;json.load(open(\"/etc/containers/policy.json\"))'")
|
||||
assert cmd.rc == 0, "policy.json should be valid JSON"
|
||||
58
tasks/configure.yml
Normal file
58
tasks/configure.yml
Normal file
@@ -0,0 +1,58 @@
|
||||
---
|
||||
# Configure Podman
|
||||
|
||||
- name: Ensure containers configuration directory exists
|
||||
ansible.builtin.file:
|
||||
path: /etc/containers
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
|
||||
- name: Configure container registries
|
||||
ansible.builtin.template:
|
||||
src: registries.conf.j2
|
||||
dest: "{{ podman_registries_conf_path }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
backup: true
|
||||
when: podman_configure_registries
|
||||
notify:
|
||||
- restart podman
|
||||
|
||||
- name: Configure container storage
|
||||
ansible.builtin.template:
|
||||
src: storage.conf.j2
|
||||
dest: "{{ podman_storage_conf_path }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
backup: true
|
||||
when: podman_configure_storage
|
||||
notify:
|
||||
- restart podman
|
||||
|
||||
- name: Configure container policy
|
||||
ansible.builtin.template:
|
||||
src: policy.json.j2
|
||||
dest: "{{ podman_policy_path }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
backup: true
|
||||
when: podman_configure_policy
|
||||
notify:
|
||||
- restart podman
|
||||
|
||||
- name: Ensure storage directories exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
loop:
|
||||
- "{{ podman_storage_runroot }}"
|
||||
- "{{ podman_storage_graphroot }}"
|
||||
when: podman_configure_storage
|
||||
241
tasks/containers.yml
Normal file
241
tasks/containers.yml
Normal file
@@ -0,0 +1,241 @@
|
||||
---
|
||||
# Manage Podman containers
|
||||
|
||||
- name: Manage Podman containers
|
||||
containers.podman.podman_container:
|
||||
name: "{{ item.name }}"
|
||||
image: "{{ item.image }}"
|
||||
state: "{{ item.state | default('present') }}"
|
||||
|
||||
# Basic container configuration
|
||||
command: "{{ item.command | default(omit) }}"
|
||||
entrypoint: "{{ item.entrypoint | default(omit) }}"
|
||||
user: "{{ item.user | default(omit) }}"
|
||||
workdir: "{{ item.working_dir | default(omit) }}"
|
||||
hostname: "{{ item.hostname | default(omit) }}"
|
||||
|
||||
# Container runtime options
|
||||
detach: "{{ item.detach | default(true) }}"
|
||||
interactive: "{{ item.interactive | default(false) }}"
|
||||
tty: "{{ item.tty | default(false) }}"
|
||||
rm: "{{ item.auto_remove | default(false) }}"
|
||||
rmi: "{{ item.remove_image | default(false) }}"
|
||||
privileged: "{{ item.privileged | default(false) }}"
|
||||
read_only: "{{ item.read_only | default(false) }}"
|
||||
read_only_tmpfs: "{{ item.read_only_tmpfs | default(true) }}"
|
||||
init: "{{ item.init | default(false) }}"
|
||||
init_path: "{{ item.init_path | default(omit) }}"
|
||||
|
||||
# Networking
|
||||
network: "{{ item.networks | default(omit) }}"
|
||||
publish: "{{ item.ports | default(omit) }}"
|
||||
publish_all: "{{ item.publish_all | default(false) }}"
|
||||
expose: "{{ item.expose | default(omit) }}"
|
||||
ip: "{{ item.ip | default(omit) }}"
|
||||
ip6: "{{ item.ip6 | default(omit) }}"
|
||||
mac_address: "{{ item.mac_address | default(omit) }}"
|
||||
network_aliases: "{{ item.network_aliases | default(omit) }}"
|
||||
dns: "{{ item.dns | default(omit) }}"
|
||||
dns_option: "{{ item.dns_options | default(omit) }}"
|
||||
dns_search: "{{ item.dns_search | default(omit) }}"
|
||||
etc_hosts: "{{ item.add_hosts | default(omit) }}"
|
||||
no_hosts: "{{ item.no_hosts | default(false) }}"
|
||||
|
||||
# Storage and volumes
|
||||
volume: "{{ item.volumes | default(omit) }}"
|
||||
volumes_from: "{{ item.volumes_from | default(omit) }}"
|
||||
mount: "{{ item.mounts | default(omit) }}"
|
||||
tmpfs: "{{ item.tmpfs | default(omit) }}"
|
||||
image_volume: "{{ item.image_volume | default(omit) }}"
|
||||
|
||||
# Environment variables
|
||||
env: "{{ item.env | default(omit) }}"
|
||||
env_file: "{{ item.env_files | default(omit) }}"
|
||||
env_host: "{{ item.env_host | default(false) }}"
|
||||
env_merge: "{{ item.env_merge | default(omit) }}"
|
||||
unsetenv: "{{ item.unsetenv | default(omit) }}"
|
||||
unsetenv_all: "{{ item.unsetenv_all | default(false) }}"
|
||||
|
||||
# Resource constraints
|
||||
memory: "{{ item.memory | default(omit) }}"
|
||||
memory_reservation: "{{ item.memory_reservation | default(omit) }}"
|
||||
memory_swap: "{{ item.memory_swap | default(omit) }}"
|
||||
memory_swappiness: "{{ item.memory_swappiness | default(omit) }}"
|
||||
kernel_memory: "{{ item.kernel_memory | default(omit) }}"
|
||||
cpus: "{{ item.cpus | default(omit) }}"
|
||||
cpu_shares: "{{ item.cpu_shares | default(omit) }}"
|
||||
cpu_period: "{{ item.cpu_period | default(omit) }}"
|
||||
cpu_quota: "{{ item.cpu_quota | default(omit) }}"
|
||||
cpu_rt_period: "{{ item.cpu_rt_period | default(omit) }}"
|
||||
cpu_rt_runtime: "{{ item.cpu_rt_runtime | default(omit) }}"
|
||||
cpuset_cpus: "{{ item.cpuset_cpus | default(omit) }}"
|
||||
cpuset_mems: "{{ item.cpuset_mems | default(omit) }}"
|
||||
blkio_weight: "{{ item.blkio_weight | default(omit) }}"
|
||||
blkio_weight_device: "{{ item.blkio_weight_device | default(omit) }}"
|
||||
oom_kill_disable: "{{ item.oom_kill_disable | default(false) }}"
|
||||
oom_score_adj: "{{ item.oom_score_adj | default(omit) }}"
|
||||
pids_limit: "{{ item.pids_limit | default(omit) }}"
|
||||
|
||||
# Device access
|
||||
device: "{{ item.devices | default(omit) }}"
|
||||
device_cgroup_rule: "{{ item.device_cgroup_rule | default(omit) }}"
|
||||
device_read_bps: "{{ item.device_read_bps | default(omit) }}"
|
||||
device_read_iops: "{{ item.device_read_iops | default(omit) }}"
|
||||
device_write_bps: "{{ item.device_write_bps | default(omit) }}"
|
||||
device_write_iops: "{{ item.device_write_iops | default(omit) }}"
|
||||
gpus: "{{ item.gpus | default(omit) }}"
|
||||
|
||||
# Security options
|
||||
security_opt: "{{ item.security_opt | default(omit) }}"
|
||||
cap_add: "{{ item.cap_add | default(omit) }}"
|
||||
cap_drop: "{{ item.cap_drop | default(omit) }}"
|
||||
seccomp_policy: "{{ item.seccomp_policy | default(omit) }}"
|
||||
userns: "{{ item.userns | default(omit) }}"
|
||||
uidmap: "{{ item.uidmap | default(omit) }}"
|
||||
gidmap: "{{ item.gidmap | default(omit) }}"
|
||||
subuidname: "{{ item.subuidname | default(omit) }}"
|
||||
subgidname: "{{ item.subgidname | default(omit) }}"
|
||||
group_add: "{{ item.groups | default(omit) }}"
|
||||
group_entry: "{{ item.group_entry | default(omit) }}"
|
||||
passwd: "{{ item.passwd | default(omit) }}"
|
||||
passwd_entry: "{{ item.passwd_entry | default(omit) }}"
|
||||
|
||||
# Namespaces
|
||||
ipc: "{{ item.ipc_mode | default(omit) }}"
|
||||
pid: "{{ item.pid_mode | default(omit) }}"
|
||||
uts: "{{ item.uts | default(omit) }}"
|
||||
cgroupns: "{{ item.cgroupns | default(omit) }}"
|
||||
|
||||
# Cgroups
|
||||
cgroups: "{{ item.cgroups | default(omit) }}"
|
||||
cgroup_parent: "{{ item.cgroup_parent | default(omit) }}"
|
||||
cgroup_conf: "{{ item.cgroup_conf | default(omit) }}"
|
||||
|
||||
# System configuration
|
||||
sysctl: "{{ item.sysctl | default(omit) }}"
|
||||
systemd: "{{ item.systemd | default(omit) }}"
|
||||
ulimit: "{{ item.ulimits | default(omit) }}"
|
||||
umask: "{{ item.umask | default(omit) }}"
|
||||
|
||||
# Shared memory and tmpfs
|
||||
shm_size: "{{ item.shm_size | default(omit) }}"
|
||||
shm_size_systemd: "{{ item.shm_size_systemd | default(omit) }}"
|
||||
|
||||
# Pods
|
||||
pod: "{{ item.pod | default(omit) }}"
|
||||
pod_id_file: "{{ item.pod_id_file | default(omit) }}"
|
||||
|
||||
# Logging
|
||||
log_driver: "{{ item.log_driver | default(omit) }}"
|
||||
log_opt: "{{ item.log_options | default(omit) }}"
|
||||
log_level: "{{ item.log_level | default(omit) }}"
|
||||
|
||||
# Health checks
|
||||
healthcheck: "{{ item.healthcheck | default(omit) }}"
|
||||
healthcheck_interval: "{{ item.healthcheck_interval | default(omit) }}"
|
||||
healthcheck_timeout: "{{ item.healthcheck_timeout | default(omit) }}"
|
||||
healthcheck_start_period: "{{ item.healthcheck_start_period | default(omit) }}"
|
||||
healthcheck_retries: "{{ item.healthcheck_retries | default(omit) }}"
|
||||
healthcheck_failure_action: "{{ item.healthcheck_failure_action | default(omit) }}"
|
||||
no_healthcheck: "{{ item.no_healthcheck | default(false) }}"
|
||||
|
||||
# Startup health checks
|
||||
health_startup_cmd: "{{ item.health_startup_cmd | default(omit) }}"
|
||||
health_startup_interval: "{{ item.health_startup_interval | default(omit) }}"
|
||||
health_startup_timeout: "{{ item.health_startup_timeout | default(omit) }}"
|
||||
health_startup_retries: "{{ item.health_startup_retries | default(omit) }}"
|
||||
health_startup_success: "{{ item.health_startup_success | default(omit) }}"
|
||||
|
||||
# Metadata and labels
|
||||
label: "{{ item.labels | default(omit) }}"
|
||||
label_file: "{{ item.label_file | default(omit) }}"
|
||||
annotation: "{{ item.annotations | default(omit) }}"
|
||||
|
||||
# Container lifecycle
|
||||
restart_policy: "{{ item.restart_policy | default('no') }}"
|
||||
restart_time: "{{ item.restart_time | default(omit) }}"
|
||||
stop_signal: "{{ item.stop_signal | default(omit) }}"
|
||||
stop_time: "{{ item.stop_time | default(omit) }}"
|
||||
stop_timeout: "{{ item.stop_timeout | default(omit) }}"
|
||||
timeout: "{{ item.timeout | default(omit) }}"
|
||||
|
||||
# Pull and image options
|
||||
pull: "{{ item.pull | default('missing') }}"
|
||||
image_strict: "{{ item.image_strict | default(false) }}"
|
||||
arch: "{{ item.arch | default(omit) }}"
|
||||
os: "{{ item.os | default(omit) }}"
|
||||
platform: "{{ item.platform | default(omit) }}"
|
||||
variant: "{{ item.variant | default(omit) }}"
|
||||
|
||||
# Registry and authentication
|
||||
authfile: "{{ item.authfile | default(omit) }}"
|
||||
tls_verify: "{{ item.tls_verify | default(omit) }}"
|
||||
decryption_key: "{{ item.decryption_key | default(omit) }}"
|
||||
|
||||
# File operations
|
||||
cidfile: "{{ item.cidfile | default(omit) }}"
|
||||
conmon_pidfile: "{{ item.conmon_pidfile | default(omit) }}"
|
||||
pid_file: "{{ item.pid_file | default(omit) }}"
|
||||
|
||||
# Special options
|
||||
attach: "{{ item.attach | default(omit) }}"
|
||||
detach_keys: "{{ item.detach_keys | default(omit) }}"
|
||||
sig_proxy: "{{ item.sig_proxy | default(true) }}"
|
||||
http_proxy: "{{ item.http_proxy | default(true) }}"
|
||||
|
||||
# Advanced options
|
||||
chrootdirs: "{{ item.chrootdirs | default(omit) }}"
|
||||
hooks_dir: "{{ item.hooks_dir | default(omit) }}"
|
||||
hostuser: "{{ item.hostuser | default(omit) }}"
|
||||
init_ctr: "{{ item.init_ctr | default(omit) }}"
|
||||
personality: "{{ item.personality | default(omit) }}"
|
||||
preserve_fd: "{{ item.preserve_fd | default(omit) }}"
|
||||
preserve_fds: "{{ item.preserve_fds | default(omit) }}"
|
||||
rdt_class: "{{ item.rdt_class | default(omit) }}"
|
||||
requires: "{{ item.requires | default(omit) }}"
|
||||
rootfs: "{{ item.rootfs | default(false) }}"
|
||||
sdnotify: "{{ item.sdnotify | default(omit) }}"
|
||||
secrets: "{{ item.secrets | default(omit) }}"
|
||||
timezone: "{{ item.timezone | default(omit) }}"
|
||||
|
||||
# Retry options
|
||||
retry: "{{ item.retry | default(omit) }}"
|
||||
retry_delay: "{{ item.retry_delay | default(omit) }}"
|
||||
|
||||
# Systemd generation
|
||||
generate_systemd: "{{ item.generate_systemd | default(omit) }}"
|
||||
|
||||
# Quadlet options
|
||||
quadlet_dir: "{{ item.quadlet_dir | default(omit) }}"
|
||||
quadlet_filename: "{{ item.quadlet_filename | default(omit) }}"
|
||||
quadlet_file_mode: "{{ item.quadlet_file_mode | default(omit) }}"
|
||||
quadlet_options: "{{ item.quadlet_options | default(omit) }}"
|
||||
|
||||
# Control options
|
||||
cmd_args: "{{ item.cmd_args | default(omit) }}"
|
||||
executable: "{{ item.executable | default('podman') }}"
|
||||
recreate: "{{ item.recreate | default(false) }}"
|
||||
force_restart: "{{ item.force_restart | default(false) }}"
|
||||
force_delete: "{{ item.force_delete | default(true) }}"
|
||||
delete_depend: "{{ item.delete_depend | default(false) }}"
|
||||
delete_time: "{{ item.delete_time | default(omit) }}"
|
||||
delete_volumes: "{{ item.delete_volumes | default(false) }}"
|
||||
debug: "{{ item.debug | default(false) }}"
|
||||
loop: "{{ podman_containers }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
register: podman_container_results
|
||||
|
||||
- name: Enable and start container systemd services
|
||||
ansible.builtin.systemd:
|
||||
name: "container-{{ item.item.name }}"
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: true
|
||||
loop: "{{ podman_container_results.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.name }}"
|
||||
when:
|
||||
- item.item.generate_systemd is defined
|
||||
- item.item.generate_systemd
|
||||
- item.item.state | default('present') in ['present', 'started']
|
||||
14
tasks/install.yml
Normal file
14
tasks/install.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
# Install Podman packages
|
||||
|
||||
- name: Update package cache (Debian/Ubuntu)
|
||||
ansible.builtin.apt:
|
||||
cache_valid_time: 3600
|
||||
when: ansible_os_family == "Debian"
|
||||
|
||||
- name: Install Podman and related packages
|
||||
ansible.builtin.package:
|
||||
name: "{{ podman_packages }}"
|
||||
state: present
|
||||
notify:
|
||||
- restart podman
|
||||
48
tasks/main.yml
Normal file
48
tasks/main.yml
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
# tasks file for podman
|
||||
|
||||
- name: Install Podman packages
|
||||
ansible.builtin.include_tasks: install.yml
|
||||
tags:
|
||||
- podman
|
||||
- podman-install
|
||||
|
||||
- name: Configure Podman
|
||||
ansible.builtin.include_tasks: configure.yml
|
||||
tags:
|
||||
- podman
|
||||
- podman-configure
|
||||
|
||||
- name: Manage Podman services
|
||||
ansible.builtin.include_tasks: services.yml
|
||||
tags:
|
||||
- podman
|
||||
- podman-services
|
||||
|
||||
- name: Manage Podman networks
|
||||
ansible.builtin.include_tasks: networks.yml
|
||||
when: podman_networks | length > 0
|
||||
tags:
|
||||
- podman
|
||||
- podman-networks
|
||||
|
||||
- name: Manage Podman volumes
|
||||
ansible.builtin.include_tasks: volumes.yml
|
||||
when: podman_volumes | length > 0
|
||||
tags:
|
||||
- podman
|
||||
- podman-volumes
|
||||
|
||||
- name: Manage Podman pods
|
||||
ansible.builtin.include_tasks: pods.yml
|
||||
when: podman_pods | length > 0
|
||||
tags:
|
||||
- podman
|
||||
- podman-pods
|
||||
|
||||
- name: Manage Podman containers
|
||||
ansible.builtin.include_tasks: containers.yml
|
||||
when: podman_containers | length > 0
|
||||
tags:
|
||||
- podman
|
||||
- podman-containers
|
||||
25
tasks/networks.yml
Normal file
25
tasks/networks.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
# Manage Podman networks
|
||||
|
||||
- name: Manage Podman networks
|
||||
containers.podman.podman_network:
|
||||
name: "{{ item.name }}"
|
||||
state: "{{ item.state | default('present') }}"
|
||||
driver: "{{ item.driver | default('bridge') }}"
|
||||
subnet: "{{ item.subnet | default(omit) }}"
|
||||
gateway: "{{ item.gateway | default(omit) }}"
|
||||
ip_range: "{{ item.ip_range | default(omit) }}"
|
||||
disable_dns: "{{ item.disable_dns | default(false) }}"
|
||||
internal: "{{ item.internal | default(false) }}"
|
||||
opt: "{{ item.options | default(omit) }}"
|
||||
dns: "{{ item.dns | default(omit) }}"
|
||||
interface_name: "{{ item.interface_name | default(omit) }}"
|
||||
ipam_driver: "{{ item.ipam_driver | default(omit) }}"
|
||||
ipv6: "{{ item.ipv6 | default(false) }}"
|
||||
macvlan: "{{ item.macvlan | default(omit) }}"
|
||||
net_config: "{{ item.net_config | default(omit) }}"
|
||||
route: "{{ item.route | default(omit) }}"
|
||||
recreate: "{{ item.recreate | default(false) }}"
|
||||
loop: "{{ podman_networks }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
66
tasks/pods.yml
Normal file
66
tasks/pods.yml
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
# Manage Podman pods
|
||||
|
||||
- name: Manage Podman pods
|
||||
containers.podman.podman_pod:
|
||||
name: "{{ item.name }}"
|
||||
state: "{{ item.state | default('created') }}"
|
||||
publish: "{{ item.ports | default(omit) }}"
|
||||
network: "{{ item.networks | default(omit) }}"
|
||||
volume: "{{ item.volumes | default(omit) }}"
|
||||
label: "{{ item.labels | default(omit) }}"
|
||||
hostname: "{{ item.hostname | default(omit) }}"
|
||||
infra: "{{ item.infra | default(true) }}"
|
||||
infra_image: "{{ item.infra_image | default(omit) }}"
|
||||
infra_command: "{{ item.infra_command | default(omit) }}"
|
||||
infra_name: "{{ item.infra_name | default(omit) }}"
|
||||
add_host: "{{ item.add_host | default(omit) }}"
|
||||
dns: "{{ item.dns | default(omit) }}"
|
||||
dns_opt: "{{ item.dns_opt | default(omit) }}"
|
||||
dns_search: "{{ item.dns_search | default(omit) }}"
|
||||
ip: "{{ item.ip | default(omit) }}"
|
||||
ip6: "{{ item.ip6 | default(omit) }}"
|
||||
mac_address: "{{ item.mac_address | default(omit) }}"
|
||||
no_hosts: "{{ item.no_hosts | default(false) }}"
|
||||
share: "{{ item.share | default(omit) }}"
|
||||
share_parent: "{{ item.share_parent | default(omit) }}"
|
||||
userns: "{{ item.userns | default(omit) }}"
|
||||
uidmap: "{{ item.uidmap | default(omit) }}"
|
||||
gidmap: "{{ item.gidmap | default(omit) }}"
|
||||
subuidname: "{{ item.subuidname | default(omit) }}"
|
||||
subgidname: "{{ item.subgidname | default(omit) }}"
|
||||
security_opt: "{{ item.security_opt | default(omit) }}"
|
||||
memory: "{{ item.memory | default(omit) }}"
|
||||
memory_swap: "{{ item.memory_swap | default(omit) }}"
|
||||
cpu_shares: "{{ item.cpu_shares | default(omit) }}"
|
||||
cpus: "{{ item.cpus | default(omit) }}"
|
||||
cpuset_cpus: "{{ item.cpuset_cpus | default(omit) }}"
|
||||
cpuset_mems: "{{ item.cpuset_mems | default(omit) }}"
|
||||
blkio_weight: "{{ item.blkio_weight | default(omit) }}"
|
||||
blkio_weight_device: "{{ item.blkio_weight_device | default(omit) }}"
|
||||
device: "{{ item.device | default(omit) }}"
|
||||
device_read_bps: "{{ item.device_read_bps | default(omit) }}"
|
||||
device_write_bps: "{{ item.device_write_bps | default(omit) }}"
|
||||
shm_size: "{{ item.shm_size | default(omit) }}"
|
||||
shm_size_systemd: "{{ item.shm_size_systemd | default(omit) }}"
|
||||
sysctl: "{{ item.sysctl | default(omit) }}"
|
||||
cgroup_parent: "{{ item.cgroup_parent | default(omit) }}"
|
||||
pid: "{{ item.pid | default(omit) }}"
|
||||
uts: "{{ item.uts | default(omit) }}"
|
||||
network_alias: "{{ item.network_alias | default(omit) }}"
|
||||
volumes_from: "{{ item.volumes_from | default(omit) }}"
|
||||
exit_policy: "{{ item.exit_policy | default(omit) }}"
|
||||
restart_policy: "{{ item.restart_policy | default(omit) }}"
|
||||
pod_id_file: "{{ item.pod_id_file | default(omit) }}"
|
||||
label_file: "{{ item.label_file | default(omit) }}"
|
||||
gpus: "{{ item.gpus | default(omit) }}"
|
||||
generate_systemd: "{{ item.generate_systemd | default(omit) }}"
|
||||
quadlet_dir: "{{ item.quadlet_dir | default(omit) }}"
|
||||
quadlet_filename: "{{ item.quadlet_filename | default(omit) }}"
|
||||
quadlet_file_mode: "{{ item.quadlet_file_mode | default(omit) }}"
|
||||
quadlet_options: "{{ item.quadlet_options | default(omit) }}"
|
||||
recreate: "{{ item.recreate | default(false) }}"
|
||||
debug: "{{ item.debug | default(false) }}"
|
||||
loop: "{{ podman_pods }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
32
tasks/services.yml
Normal file
32
tasks/services.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
# Manage Podman services
|
||||
|
||||
- name: Enable and start Podman socket
|
||||
ansible.builtin.systemd:
|
||||
name: podman.socket
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: true
|
||||
when: podman_enable_socket
|
||||
|
||||
- name: Disable Podman socket
|
||||
ansible.builtin.systemd:
|
||||
name: podman.socket
|
||||
enabled: false
|
||||
state: stopped
|
||||
when: not podman_enable_socket
|
||||
|
||||
- name: Enable and start Podman API service
|
||||
ansible.builtin.systemd:
|
||||
name: podman.service
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: true
|
||||
when: podman_enable_api_service
|
||||
|
||||
- name: Disable Podman API service
|
||||
ansible.builtin.systemd:
|
||||
name: podman.service
|
||||
enabled: false
|
||||
state: stopped
|
||||
when: not podman_enable_api_service
|
||||
19
tasks/volumes.yml
Normal file
19
tasks/volumes.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
# Manage Podman volumes
|
||||
|
||||
- name: Manage Podman volumes
|
||||
containers.podman.podman_volume:
|
||||
name: "{{ item.name }}"
|
||||
state: "{{ item.state | default('present') }}"
|
||||
driver: "{{ item.driver | default('local') }}"
|
||||
options: "{{ item.options | default(omit) }}"
|
||||
label: "{{ item.labels | default(omit) }}"
|
||||
debug: "{{ item.debug | default(false) }}"
|
||||
recreate: "{{ item.recreate | default(false) }}"
|
||||
quadlet_dir: "{{ item.quadlet_dir | default(omit) }}"
|
||||
quadlet_filename: "{{ item.quadlet_filename | default(omit) }}"
|
||||
quadlet_file_mode: "{{ item.quadlet_file_mode | default(omit) }}"
|
||||
quadlet_options: "{{ item.quadlet_options | default(omit) }}"
|
||||
loop: "{{ podman_volumes }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
37
templates/policy.json.j2
Normal file
37
templates/policy.json.j2
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"default": [
|
||||
{
|
||||
"type": "{{ podman_policy_default_type }}"
|
||||
}
|
||||
],
|
||||
"transports": {
|
||||
"docker-daemon": {
|
||||
"": [
|
||||
{
|
||||
"type": "insecureAcceptAnything"
|
||||
}
|
||||
]
|
||||
},
|
||||
"docker": {
|
||||
{% for registry in podman_policy_trusted_registries %}
|
||||
"{{ registry.registry }}": [
|
||||
{
|
||||
"type": "{{ registry.type }}"{% if registry.keyPath is defined %},
|
||||
"keyType": "{{ registry.keyType | default('GPGKeys') }}",
|
||||
"keyPath": "{{ registry.keyPath }}"{% endif %}{% if registry.keyData is defined %},
|
||||
"keyType": "{{ registry.keyType | default('GPGKeys') }}",
|
||||
"keyData": "{{ registry.keyData }}"{% endif %}{% if registry.signedIdentity is defined %},
|
||||
"signedIdentity": {{ registry.signedIdentity | to_json }}{% endif %}
|
||||
}
|
||||
]{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
{% if podman_policy_reject_unknown_registries %}
|
||||
"": [
|
||||
{
|
||||
"type": "reject"
|
||||
}
|
||||
]
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
}
|
||||
54
templates/registries.conf.j2
Normal file
54
templates/registries.conf.j2
Normal file
@@ -0,0 +1,54 @@
|
||||
# Configuration file for container registries
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# Unqualified image search registries
|
||||
# These registries will be searched when pulling images without a registry prefix
|
||||
unqualified-search-registries = [
|
||||
{% set registries = podman_policy_trusted_registries | selectattr('unqualified_search', 'defined') | selectattr('unqualified_search') | map(attribute='registry') | list %}
|
||||
{% if registries | length == 0 %}
|
||||
{% set registries = podman_policy_trusted_registries | map(attribute='registry') | list %}
|
||||
{% endif %}
|
||||
{% set base_registries = registries | map('regex_replace', '^([^/]+).*', '\\1') | list %}
|
||||
{% for registry in base_registries | unique %}
|
||||
"{{ registry }}"{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
]
|
||||
|
||||
{% for registry_config in podman_policy_trusted_registries %}
|
||||
# Registry: {{ registry_config.registry }}
|
||||
[[registry]]
|
||||
location = "{{ registry_config.registry }}"
|
||||
insecure = {{ registry_config.insecure | default(false) | lower }}
|
||||
blocked = {{ registry_config.blocked | default(false) | lower }}
|
||||
{% if registry_config.mirror is defined %}
|
||||
|
||||
# Mirror configuration for {{ registry_config.registry }}
|
||||
{% for mirror in registry_config.mirror %}
|
||||
[[registry.mirror]]
|
||||
location = "{{ mirror.location }}"
|
||||
insecure = {{ mirror.insecure | default(false) | lower }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if registry_config.prefix is defined %}
|
||||
prefix = "{{ registry_config.prefix }}"
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
# Additional registry configurations
|
||||
{% if podman_registries_additional is defined %}
|
||||
{% for registry in podman_registries_additional %}
|
||||
[[registry]]
|
||||
location = "{{ registry.location }}"
|
||||
insecure = {{ registry.insecure | default(false) | lower }}
|
||||
blocked = {{ registry.blocked | default(false) | lower }}
|
||||
{% if registry.mirror is defined %}
|
||||
{% for mirror in registry.mirror %}
|
||||
[[registry.mirror]]
|
||||
location = "{{ mirror.location }}"
|
||||
insecure = {{ mirror.insecure | default(false) | lower }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
13
templates/storage.conf.j2
Normal file
13
templates/storage.conf.j2
Normal file
@@ -0,0 +1,13 @@
|
||||
# Storage configuration for containers
|
||||
# {{ ansible_managed }}
|
||||
|
||||
[storage]
|
||||
driver = "{{ podman_storage_driver }}"
|
||||
runroot = "{{ podman_storage_runroot }}"
|
||||
graphroot = "{{ podman_storage_graphroot }}"
|
||||
|
||||
[storage.options]
|
||||
additionalimagestores = []
|
||||
|
||||
[storage.options.overlay]
|
||||
mountopt = "nodev,metacopy=on"
|
||||
14
vars/Debian.yml
Normal file
14
vars/Debian.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
# OS-specific variables for Debian/Ubuntu
|
||||
|
||||
# Package names may vary between distributions
|
||||
podman_packages:
|
||||
- podman
|
||||
- buildah
|
||||
- skopeo
|
||||
|
||||
podman_additional_packages:
|
||||
- crun
|
||||
- fuse-overlayfs
|
||||
- slirp4netns
|
||||
- uidmap
|
||||
Reference in New Issue
Block a user