Skip to content

GitOps controller for Docker Compose - Self-healing, Git-driven deployments without Kubernetes

License

Notifications You must be signed in to change notification settings

anuragxxd/conops

Repository files navigation

ConOps Logo
ConOps

GitOps for Docker Compose. Like Argo CD, but without Kubernetes.

GitHub stars Docker Pulls License Release

Point ConOps at a Git repo containing a docker-compose.yaml.
It clones, pulls, deploys, watches for new commits, detects container drift, and self-heals.
One binary. No cluster required.

Quick Start · Features · Usage Guide · Configuration · API


ConOps Demo

Quick Start

Run ConOps with a single command:

docker run \
  --name conops \
  -p 8080:8080 \
  -e CONOPS_RUNTIME_DIR=/tmp/conops-runtime \
  -v /tmp/conops-runtime:/tmp/conops-runtime \
  -v conops_data:/data \
  -v /var/run/docker.sock:/var/run/docker.sock \
  anurag1201/conops:latest

Open http://localhost:8080 and click New App.

Note: For production use, we recommended using Docker Compose.

Features

  • Git-driven deployments — push to your branch, ConOps handles the rest
  • Continuous reconciliation — configurable loop that keeps desired state in sync
  • Self-healing — detects missing, exited, or unhealthy containers and recovers
  • Docker preflight + fallback toolchain — checks Docker API compatibility before sync
  • Web UI — register apps, inspect status, view containers, trigger syncs, read logs
  • REST API + CLI — automate everything; nothing in the UI that the API can't do
  • Private repo support — GitHub deploy keys with AES-GCM encryption at rest
  • SQLite or PostgreSQL — SQLite for single-node, Postgres for production
  • Single binary — no runtime dependencies beyond Docker and Git

Usage Guide

ConOps can be managed in two ways: via the Web Dashboard or the REST API / CLI.

Method 1: Web Dashboard

The easiest way to get started. Navigate to http://localhost:8080.

  • Dashboard: View all registered applications and their current status (synced, syncing, pending, error).
  • New App: Click the button to register a repository. You'll need the Git URL, branch name, and path to the Compose file.
  • App Details: Click on any app to see its sync history, container health, and logs.
  • Actions: You can manually trigger a sync or delete an app directly from its card.

Method 2: REST API & CLI

ConOps is API-first. Every action available in the UI can be performed via the REST API.

CLI Tool (conops-ctl)

The conops-ctl CLI helps you manage applications from your terminal.

Installation:

# Install the latest version to /usr/local/bin
curl -sfL https://raw.githubusercontent.com/anuragxxd/conops/master/install.sh | sudo sh

Or download pre-built binaries from the Releases page.

Configuration: Set the controller URL if running remotely (defaults to http://localhost:8080):

export CONOPS_URL="http://conops.example.com:8080"

Commands:

# List all apps
./conops-ctl apps list

# Register an app (supports private repos via JSON)
./conops-ctl apps add app.json

# Get detailed status
./conops-ctl apps get <app-id>

# Update configuration (partial updates supported)
./conops-ctl apps update <app-id> --branch feature/login --poll-interval 1m

# Force immediate sync
./conops-ctl apps sync <app-id>

REST API

You can interact directly with the API using curl.

1. Register an App

curl -X POST http://localhost:8080/api/v1/apps/ \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Example App",
    "repo_url": "https://github.com/docker/awesome-compose",
    "repo_auth_method": "public",
    "branch": "master",
    "compose_path": "fastapi/compose.yaml",
    "poll_interval": "30s"
  }'

2. List Apps

curl http://localhost:8080/api/v1/apps/

3. Get App Details

curl http://localhost:8080/api/v1/apps/{id}

4. Force Sync

curl -X POST http://localhost:8080/api/v1/apps/{id}/sync

5. Update App

curl -X PATCH http://localhost:8080/api/v1/apps/{id} \
  -H "Content-Type: application/json" \
  -d '{ "poll_interval": "1m" }'

6. Delete App

curl -X DELETE http://localhost:8080/api/v1/apps/{id}

Configuration

All configuration is via environment variables.

Variable Default Description
DB_TYPE sqlite Storage backend: sqlite or postgres
DB_CONNECTION_STRING Required when using postgres
CONOPS_RECONCILE_INTERVAL 10s How often the reconciler runs
CONOPS_SYNC_TIMEOUT 5m Max duration for a single sync operation
CONOPS_RETRY_ERRORS false Auto-retry apps that entered error status
CONOPS_RUNTIME_DIR ./.conops-runtime Runtime checkout directory used for compose execution
CONOPS_TOOLS_DIR ./.conops-tools Cache directory for managed Docker CLI and Compose plugin downloads
CONOPS_ENCRYPTION_KEY 32-byte key (raw or base64) for deploy key encryption
CONOPS_ENCRYPTION_KEY_FILE /data/conops-encryption.key Path to read/write the encryption key

Production Setup

For production, we recommend running ConOps with Docker Compose to handle persistence and networking cleanly.

services:
  conops:
    image: anurag1201/conops:latest
    ports:
      - "8080:8080"
    environment:
      - CONOPS_RUNTIME_DIR=/tmp/conops-runtime
      - DB_TYPE=sqlite
    volumes:
      # Persist SQLite DB and encryption keys
      - conops_data:/data
      # Allow ConOps to manage sibling containers
      - /var/run/docker.sock:/var/run/docker.sock
      # Runtime directory for checkouts
      - /tmp/conops-runtime:/tmp/conops-runtime

volumes:
  conops_data:

Private Repositories

ConOps supports private GitHub/GitLab repositories via SSH deploy keys.

When registering an app via the API, set repo_auth_method to deploy_key and provide the private key:

curl -X POST http://localhost:8080/api/v1/apps/ \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Private App",
    "repo_url": "git@github.com:my-org/private-repo.git",
    "repo_auth_method": "deploy_key",
    "deploy_key": "-----BEGIN OPENSSH PRIVATE KEY-----\n...\n-----END OPENSSH PRIVATE KEY-----",
    "branch": "main",
    "compose_path": "docker-compose.yml"
  }'

Security: Deploy keys are encrypted at rest using AES-GCM. ConOps auto-generates an encryption key on first run, or you can provide your own via CONOPS_ENCRYPTION_KEY.

How It Works

                    ┌─────────────┐
                    │  Git Repo   │
                    └──────┬──────┘
                           │ poll
                    ┌──────▼──────┐
                    │ Git Watcher │──── new commit? ──→ mark pending
                    └─────────────┘
                           │
                    ┌──────▼──────┐
                    │ Reconciler  │──── clone/fetch → compose pull → compose up
                    └──────┬──────┘
                           │
                    ┌──────▼──────┐
                    │Drift Checker│──── container missing/exited/unhealthy? → requeue
                    └─────────────┘

Status flow: registeredpendingsyncingsynced.

ConOps separates change detection (Git watcher) from state application (reconciler). This keeps the control loop predictable and easy to reason about.

Development

# Run the controller locally
go run ./cmd/conops

# Build the CLI
go build -o bin/conops-ctl ./cmd/conops-ctl

# Run tests
go test ./...

License

MIT — see LICENSE.

About

GitOps controller for Docker Compose - Self-healing, Git-driven deployments without Kubernetes

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •