# ADR-009: Podman as Primary Container Engine Date: 2025-11-20 ## Status Accepted ## Context The Phase 5a deployment configuration was initially designed with Docker as the primary container engine. However, Podman has emerged as a compelling alternative with several security and operational advantages: **Podman Advantages**: - **Daemonless Architecture**: No background daemon required, reducing attack surface and resource overhead - **Rootless by Default**: Containers run without root privileges, significantly improving security posture - **OCI-Compliant**: Adheres to Open Container Initiative standards for maximum compatibility - **Pod Support**: Native pod abstraction (similar to Kubernetes) for logical container grouping - **Docker-Compatible**: Drop-in replacement for most Docker commands - **systemd Integration**: Native support for generating systemd units for production deployments **Key Technical Differences Requiring Design Consideration**: 1. **UID Mapping**: Rootless containers map UIDs differently than Docker - Container UID 1000 maps to host user's subuid range - Volume permissions require different handling 2. **Networking**: Different default network configuration - No docker0 bridge - Uses slirp4netns or netavark for rootless networking - Port binding below 1024 requires special configuration in rootless mode 3. **Compose Compatibility**: podman-compose provides Docker Compose compatibility - Not 100% feature-parity with docker-compose - Some edge cases require workarounds 4. **Volume Permissions**: Rootless mode has different SELinux and permission behaviors - May require :Z or :z labels on volume mounts (SELinux) - File ownership considerations in bind mounts 5. **systemd Integration**: Podman can generate systemd service units - Better integration with system service management - Auto-start on boot without additional configuration ## Decision We will **support Podman as the primary container engine** for Gondulf deployment, while maintaining Docker compatibility as an alternative. **Specific Design Decisions**: 1. **Container Images**: Build OCI-compliant images that work with both podman and docker 2. **Compose Files**: Provide compose files compatible with both podman-compose and docker-compose 3. **Volume Mounts**: Use named volumes by default to avoid rootless permission issues 4. **Documentation**: Provide parallel command examples for both podman and docker 5. **systemd Integration**: Provide systemd unit generation for production deployments 6. **User Guidance**: Document rootless mode as the recommended approach 7. **SELinux Support**: Include :Z/:z labels where appropriate for SELinux systems ## Consequences ### Benefits 1. **Enhanced Security**: Rootless containers significantly reduce attack surface 2. **No Daemon**: Eliminates daemon as single point of failure and attack vector 3. **Better Resource Usage**: No background daemon consuming resources 4. **Standard Compliance**: OCI compliance ensures future compatibility 5. **Production Ready**: systemd integration provides enterprise-grade service management 6. **User Choice**: Supporting both engines gives operators flexibility ### Challenges 1. **Documentation Complexity**: Must document two command syntaxes 2. **Testing Burden**: Must test with both podman and docker 3. **Feature Parity**: Some docker-compose features may not work identically in podman-compose 4. **Learning Curve**: Operators familiar with Docker must learn rootless considerations 5. **SELinux Complexity**: Volume labeling adds complexity on SELinux-enabled systems ### Migration Impact 1. **Existing Docker Users**: Can continue using Docker without changes 2. **New Deployments**: Encouraged to use Podman for security benefits 3. **Documentation**: All examples show both podman and docker commands 4. **Scripts**: Backup/restore scripts detect and support both engines ### Technical Mitigations 1. **Abstraction**: Use OCI-standard features that work identically 2. **Detection**: Scripts auto-detect podman vs docker 3. **Defaults**: Use patterns that work well in both engines 4. **Testing**: CI/CD tests both podman and docker deployments 5. **Troubleshooting**: Document common issues and solutions for both engines ### Production Deployment Implications **Podman Production Deployment**: ```bash # Build image podman build -t gondulf:latest . # Generate systemd unit podman generate systemd --new --files --name gondulf # Enable and start service sudo cp container-gondulf.service /etc/systemd/system/ sudo systemctl enable --now container-gondulf.service ``` **Docker Production Deployment** (unchanged): ```bash # Build and start docker-compose -f docker-compose.yml -f docker-compose.override.yml up -d # Enable auto-start docker-compose restart unless-stopped ``` ### Documentation Structure All deployment documentation will follow this pattern: ```markdown ## Build Image **Using Podman** (recommended): ```bash podman build -t gondulf:latest . ``` **Using Docker**: ```bash docker build -t gondulf:latest . ``` ``` ## Alternatives Considered ### Alternative 1: Docker Only **Rejected**: Misses opportunity to leverage Podman's security and operational benefits. Many modern Linux distributions are standardizing on Podman. ### Alternative 2: Podman Only **Rejected**: Too disruptive for existing Docker users. Docker remains widely deployed and understood. ### Alternative 3: Wrapper Scripts **Rejected**: Adds complexity without significant benefit. Direct command examples are clearer. ## Implementation Guidance ### Dockerfile Compatibility The existing Dockerfile design is already OCI-compliant and works with both engines. No changes required to Dockerfile structure. ### Compose File Compatibility Use compose file features that work in both docker-compose and podman-compose: - ✅ services, volumes, networks - ✅ environment variables - ✅ port mappings - ✅ health checks - ⚠️ depends_on with condition (docker-compose v3+, podman-compose limited) - ⚠️ profiles (docker-compose, podman-compose limited) **Mitigation**: Use compose file v3.8 features conservatively, test with both tools. ### Volume Permission Pattern **Named Volumes** (recommended, works in both): ```yaml volumes: gondulf_data:/data ``` **Bind Mounts with SELinux Label** (if needed): ```yaml volumes: - ./data:/data:Z # Z = private label (recommended) # or - ./data:/data:z # z = shared label ``` ### systemd Integration Provide instructions for both manual systemd units and podman-generated units: **Manual systemd Unit** (works for both): ```ini [Unit] Description=Gondulf IndieAuth Server After=network.target [Service] Type=simple ExecStart=/usr/bin/podman-compose -f /opt/gondulf/docker-compose.yml up ExecStop=/usr/bin/podman-compose -f /opt/gondulf/docker-compose.yml down Restart=always [Install] WantedBy=multi-user.target ``` **Podman-Generated Unit** (podman only): ```bash podman generate systemd --new --files --name gondulf ``` ### Command Detection in Scripts Backup/restore scripts should detect available engine: ```bash #!/bin/bash # Detect container engine if command -v podman &> /dev/null; then CONTAINER_ENGINE="podman" elif command -v docker &> /dev/null; then CONTAINER_ENGINE="docker" else echo "Error: Neither podman nor docker found" exit 1 fi # Use detected engine $CONTAINER_ENGINE exec gondulf sqlite3 /data/gondulf.db ".backup /tmp/backup.db" ``` ## References - Podman Documentation: https://docs.podman.io/ - Podman vs Docker: https://docs.podman.io/en/latest/markdown/podman.1.html - OCI Specification: https://opencontainers.org/ - podman-compose: https://github.com/containers/podman-compose - Rootless Containers: https://rootlesscontaine.rs/ - systemd Units with Podman: https://docs.podman.io/en/latest/markdown/podman-generate-systemd.1.html - SELinux Volume Labels: https://docs.podman.io/en/latest/markdown/podman-run.1.html#volume ## Future Considerations 1. **Kubernetes Compatibility**: Podman's pod support could enable future k8s migration 2. **Multi-Container Pods**: Could group nginx + gondulf in a single pod 3. **Container Security**: Explore additional Podman security features (seccomp, capabilities) 4. **Image Distribution**: Consider both Docker Hub and Quay.io for image hosting