Files
Gondulf/docs/decisions/ADR-009-podman-container-engine-support.md
Phil Skentelbery 01dcaba86b feat(deploy): merge Phase 5a deployment configuration
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>
2025-11-21 19:16:54 -07:00

238 lines
8.2 KiB
Markdown

# 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