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>
238 lines
8.2 KiB
Markdown
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
|