Complete containerized deployment system with Docker/Podman support. Key features: - Multi-stage Dockerfile with Python 3.11-slim base - Docker Compose configurations for production and development - Nginx reverse proxy with security headers and rate limiting - Systemd service units for Docker, Podman, and docker-compose - Backup/restore scripts with integrity verification - Podman compatibility (ADR-009) All tests pass including Podman verification testing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
8.2 KiB
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:
-
UID Mapping: Rootless containers map UIDs differently than Docker
- Container UID 1000 maps to host user's subuid range
- Volume permissions require different handling
-
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
-
Compose Compatibility: podman-compose provides Docker Compose compatibility
- Not 100% feature-parity with docker-compose
- Some edge cases require workarounds
-
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
-
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:
- Container Images: Build OCI-compliant images that work with both podman and docker
- Compose Files: Provide compose files compatible with both podman-compose and docker-compose
- Volume Mounts: Use named volumes by default to avoid rootless permission issues
- Documentation: Provide parallel command examples for both podman and docker
- systemd Integration: Provide systemd unit generation for production deployments
- User Guidance: Document rootless mode as the recommended approach
- SELinux Support: Include :Z/:z labels where appropriate for SELinux systems
Consequences
Benefits
- Enhanced Security: Rootless containers significantly reduce attack surface
- No Daemon: Eliminates daemon as single point of failure and attack vector
- Better Resource Usage: No background daemon consuming resources
- Standard Compliance: OCI compliance ensures future compatibility
- Production Ready: systemd integration provides enterprise-grade service management
- User Choice: Supporting both engines gives operators flexibility
Challenges
- Documentation Complexity: Must document two command syntaxes
- Testing Burden: Must test with both podman and docker
- Feature Parity: Some docker-compose features may not work identically in podman-compose
- Learning Curve: Operators familiar with Docker must learn rootless considerations
- SELinux Complexity: Volume labeling adds complexity on SELinux-enabled systems
Migration Impact
- Existing Docker Users: Can continue using Docker without changes
- New Deployments: Encouraged to use Podman for security benefits
- Documentation: All examples show both podman and docker commands
- Scripts: Backup/restore scripts detect and support both engines
Technical Mitigations
- Abstraction: Use OCI-standard features that work identically
- Detection: Scripts auto-detect podman vs docker
- Defaults: Use patterns that work well in both engines
- Testing: CI/CD tests both podman and docker deployments
- Troubleshooting: Document common issues and solutions for both engines
Production Deployment Implications
Podman Production Deployment:
# 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):
# 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:
## Build Image
**Using Podman** (recommended):
```bash
podman build -t gondulf:latest .
Using Docker:
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):
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):
[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):
podman generate systemd --new --files --name gondulf
Command Detection in Scripts
Backup/restore scripts should detect available engine:
#!/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
- Kubernetes Compatibility: Podman's pod support could enable future k8s migration
- Multi-Container Pods: Could group nginx + gondulf in a single pod
- Container Security: Explore additional Podman security features (seccomp, capabilities)
- Image Distribution: Consider both Docker Hub and Quay.io for image hosting