Quad-Ops is a lightweight GitOps framework for Podman containers managed by Quadlet. It watches Git repositories for standard Docker Compose files and automatically converts them into systemd unit files to run your containers.
For comprehensive documentation, visit https://trly.github.io/quad-ops/
- GitOps workflow - Monitor multiple Git repositories for container configurations
- Standard Docker Compose - Full support for Docker Compose files (services, networks, volumes, secrets)
- Cross-platform - Works on Linux (systemd/Quadlet) and macOS (launchd) with Podman
- Smart change detection - SHA256-based detection prevents unnecessary service restarts
- Init containers - Run initialization containers before main services start (similar to Kubernetes)
- Intelligent restarts - Only restarts services whose artifacts actually changed
- Podman-specific features - Support for exposing secrets as environment variables
- Flexible deployment - Works in both system-wide and user (rootless) modes
- Production-ready - Built with dependency injection, comprehensive test coverage (582+ tests)
Quad-Ops converts standard Docker Compose files to Podman Quadlet units. It supports all container runtime features that work with standalone Podman.
Core container configuration:
image,build,command,entrypoint,working_dir,user,hostname
Environment and labels:
environment,env_file,labels,annotations
Networking:
networks(bridge, host, custom networks)ports(host mode only)dns,dns_search,dns_opt,extra_hostsnetwork_mode(bridge, host, none, container:name)
Storage:
volumes(bind mounts, named volumes, tmpfs)secretswith file/content/environment sourcesconfigswith file/content/environment sources
Resources:
memory,cpu_shares,cpu_quota,cpu_periodpids_limit,shm_size,sysctls,ulimits
Security:
cap_add,cap_drop,privileged,security_opt,read_onlygroup_add,pidmode,ipcmode,cgroup_parent
Devices and hardware:
devices,device_cgroup_rulesruntime(e.g., nvidia for GPU support)
Health and lifecycle:
healthcheck(test, interval, timeout, retries, start_period)restart(maps to systemd restart policies)stop_signal,stop_grace_perioddepends_on(maps to systemd After/Requires)
Secrets and configs:
- File sources (
file: ./secret.txt) - Content sources (
content: "secret data") - Environment sources (
environment: SECRET_VAR) - NOT supported: Swarm driver (
external: truewithdriver)
Resource constraints:
deploy.resources.limits(memory, cpus, pids)deploy.resources.reservations(partial - depends on cgroups v2)
Dependency conditions:
- All
depends_onconditions (service_started,service_healthy,service_completed_successfully) map to systemdAfter+Requires - No health-based startup gating (Quadlet limitation)
Logging:
- Supported:
journald,k8s-file,none,passthrough - NOT supported: Custom drivers not supported by Podman
Standard Compose fields:
volumes_from- Use named volumes or bind mountsstdin_open,tty- Interactive mode not practical in systemd unitsextends- Use YAML anchors or include directives
Quad-Ops is NOT a Swarm orchestrator. These features are rejected with validation errors:
deploy.mode: global- Multi-node replicationdeploy.replicas > 1- Multi-instance servicesdeploy.placement- Node placement constraintsdeploy.update_config,deploy.rollback_config- Rolling updatesdeploy.endpoint_mode(vip/dnsrr) - Swarm service discoveryports.mode: ingress- Swarm load balancing (usemode: host)configs/secretswithdriverfield - Swarm secret store
For these features, use:
- Kubernetes - Cloud-native orchestration with full feature set
- Nomad - Lightweight orchestrator for VMs and containers
- Docker Swarm - If you need Swarm-specific features
Use quad-ops validate to check your Compose files for unsupported features.
Reference: Podman Quadlet Documentation
Quad-Ops enforces strict naming requirements for project and service names per Docker Compose specification.
Pattern: ^[a-z0-9][a-z0-9_-]*$
- Must start with lowercase letter or digit
- Can contain only: lowercase letters, digits, dashes, underscores
- Examples:
myproject,my-project,my_project,project123
Pattern: ^[a-zA-Z0-9][a-zA-Z0-9_.-]*$
- Must start with alphanumeric character (upper or lowercase)
- Can contain: alphanumeric, dashes, underscores, periods
- Examples:
web,Web,web-api,web.api,Service123
Invalid names are rejected with clear error messages.
Quad-Ops supports declaring dependencies on services in other projects using the x-quad-ops-depends-on extension field.
# project-app/compose.yml
name: app
services:
backend:
image: myapp:latest
x-quad-ops-depends-on:
- project: infrastructure
service: proxy
optional: false # Fail if not found
- project: monitoring
service: prometheus
optional: true # Warn if not found
depends_on:
- redis # Intra-project dependency
redis:
image: redis:latest- Validation - Quad-Ops validates that external services exist before deployment
- Ordering - External dependencies are included in topological startup ordering
- Platform integration - Maps to systemd
After/Requiresor launchdDependsOn - Optional dependencies - Can be marked as optional (warn if missing instead of failing)
Requirements:
- External service must already be deployed (use
quad-ops upin dependency project first) - Project and service names must follow naming requirements
- Works on both Linux (systemd) and macOS (launchd)
Quad-Ops uses a clean, modular architecture with clear separation of concerns:
Docker Compose → Service Specs → Platform Artifacts → Service Lifecycle
↓ ↓ ↓ ↓
Reader Converter Renderer Lifecycle
Manager
- Compose Reader - Parses Docker Compose YAML files
- Spec Converter - Converts to platform-agnostic service specifications
- Platform Renderer - Generates platform-specific artifacts (Quadlet units on Linux, launchd plists on macOS)
- Lifecycle Manager - Manages service start/stop/restart via systemd or launchd
- Change Detection - SHA256 hashing ensures only changed services restart
This architecture makes it easy to:
- Add new platforms (Windows services, etc.)
- Test components in isolation with dependency injection
- Understand and maintain the codebase
For detailed architecture information, see ARCHITECTURE.md.
repositories:
- name: quad-ops-compose # Repository name (required)
url: "https://github.com/example/repo.git" # Git repository URL (required)
ref: "main" # Git reference to checkout: branch, tag, or commit hash (optional)
composeDir: "compose" # Subdirectory where Docker Compose files are located (optional)# Clone the repository
git clone https://github.com/trly/quad-ops.git
cd quad-ops
# Install task runner (if not already installed)
# macOS: brew install go-task/tap/go-task
# Linux: sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b ~/.local/bin
# Build, lint, test, and format (all-in-one)
task build
# Individual commands
task test # Run all tests
task lint # Run golangci-lint
task fmt # Format code
go build -o quad-ops cmd/quad-ops/main.go # Build binary onlyLinux and macOS are both supported with automatic platform detection:
# System-wide installation (Linux and macOS)
curl -fsSL https://raw.githubusercontent.com/trly/quad-ops/main/install.sh | bash
# User installation (rootless containers)
curl -fsSL https://raw.githubusercontent.com/trly/quad-ops/main/install.sh | bash -s -- --userThe installer automatically:
- Detects your platform (Linux/macOS) and architecture (amd64/arm64)
- Downloads and verifies the correct binary
- Installs systemd services (Linux only)
- Sets up example configuration files
# Build the binary
go build -o quad-ops cmd/quad-ops/main.go
# Move to system directory
sudo mv quad-ops /usr/local/bin/
# Copy the example config file
sudo mkdir -p /etc/quad-ops
sudo cp configs/config.yaml.example /etc/quad-ops/config.yaml
# Linux only: Install the systemd service file (optional)
sudo cp build/quad-ops.service /etc/systemd/system/quad-ops.service
sudo systemctl daemon-reload
sudo systemctl enable --now quad-ops