Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,11 @@ ComposeFlux is a Go application that implements a GitOps reconciliation loop for
```
cmd/composeflux/ # Main binary entry point (CLI setup via kong)
cmd/prune-playground/ # Dev scratch binary
internal/metrics/ # Prometheus metric definitions (promauto counters)
internal/reconcile/ # Core reconciliation logic (private to module)
pkg/dockercompose/ # Docker Compose SDK wrapper (exported)
pkg/secrets/ # Secrets manager integrations (Bitwarden, Infisical) — optional
pkg/source/ # Git client (go-git)
docs/ # MkDocs documentation
docs/dashboards/ # Grafana dashboard JSON and screenshot
```

---
Expand Down Expand Up @@ -176,16 +174,6 @@ ctx.FatalIfErrorf(ctx.Run())

---

## Observability

- Prometheus metrics defined in `internal/metrics/metrics.go` using `promauto.NewCounterVec`.
- All counters use `stack_name` as the sole label to avoid high cardinality.
- Metrics are incremented in reconciler paths (`Sync`, `SyncImages`, `Prune`) — never in the Docker Compose client layer.
- The `/metrics` HTTP endpoint is served from `cmd/composeflux/run.go` (daemon mode only).
- Grafana dashboard JSON lives in `docs/dashboards/` with a `${DS_PROMETHEUS}` variable datasource for portability.

---

## CI / GitHub Actions

- **`ci.yml`**: Runs `golangci-lint` on all pull requests. Run `task lint` locally before opening a PR.
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ and automatically deploy your Docker stacks—all without manual intervention.
| Secrets Management | Optional Bitwarden Secrets Manager and Infisical support |
| Automatic Image Updates | Scheduled registry checks redeploy stacks when newer images are available |
| Flexible Configuration | Startup order and shared environment variables |
| Prometheus Metrics | Built-in metrics endpoint for deployment, image update, and prune observability |
| Simple & Headless | No UI, no backend database |

**[Full Documentation](https://veerendra2.github.io/composeflux/)** — Getting started, configuration, guides, and more.
Expand Down
42 changes: 0 additions & 42 deletions cmd/composeflux/run.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,7 @@
package main

import (
"context"
"fmt"
"log/slog"
"net"
"net/http"
"time"

"github.com/prometheus/client_golang/prometheus/promhttp"
)

type RunCmd struct {
CommonConfig `embed:""`
MetricsAddr string `name:"metrics-addr" help:"Prometheus metrics listen address. Empty to disable." env:"METRICS_ADDR" default:":9090" group:"Metrics Options:"`
}

func (r *RunCmd) AfterApply() error {
Expand All @@ -27,36 +15,6 @@ func (r *RunCmd) Run() error {
}
defer cleanup()

if r.MetricsAddr != "" {
ln, err := net.Listen("tcp", r.MetricsAddr)
if err != nil {
return fmt.Errorf("metrics server failed to bind %s: %w", r.MetricsAddr, err)
}

mux := http.NewServeMux()
mux.Handle("/metrics", promhttp.Handler())
srv := &http.Server{
Handler: mux,
ReadHeaderTimeout: 10 * time.Second,
}

go func() {
slog.Info("Starting metrics server", "addr", r.MetricsAddr)
if err := srv.Serve(ln); err != nil && err != http.ErrServerClosed {
slog.Error("Metrics server failed", "error", err)
}
}()

defer func() {
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(shutdownCtx); err != nil {
slog.Error("Metrics server shutdown failed", "error", err)
}
slog.Info("Metrics server stopped")
}()
}

rClient.Run(ctx)
return nil
}
57 changes: 0 additions & 57 deletions compose-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ services:
# GIT_CLONE_PATH: /opt/compose-stack
GIT_SSH_KEY_PATH: ${GIT_SSH_KEY_PATH:-/.ssh/composeflux_id_rsa}

# Metrics
METRICS_ADDR: ":9090"

# Logging
LOG_ADD_SOURCE: ${LOG_ADD_SOURCE}
LOG_LEVEL: ${LOG_LEVEL}
Expand All @@ -41,65 +38,11 @@ services:
# INFISICAL_SECRET_PATH: /
# INFISICAL_SITE_URL: https://app.infisical.com
hostname: composeflux
ports:
- 9090:9090
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ~/.ssh/composeflux_id_rsa:/tmp/composeflux_id_rsa
- compose-stack:/opt/compose-stack

prometheus:
image: prom/prometheus:latest
container_name: prometheus
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.retention.time=7d
configs:
- source: prometheus-config
target: /etc/prometheus/prometheus.yml
ports:
- 9091:9090
depends_on:
- composeflux

grafana:
image: grafana/grafana:latest
container_name: grafana
environment:
GF_SECURITY_ADMIN_USER: admin
GF_SECURITY_ADMIN_PASSWORD: admin
GF_AUTH_ANONYMOUS_ENABLED: "true"
GF_AUTH_ANONYMOUS_ORG_ROLE: Admin
configs:
- source: grafana-datasource
target: /etc/grafana/provisioning/datasources/prometheus.yml
ports:
- 3000:3000
depends_on:
- prometheus

configs:
prometheus-config:
content: |
global:
scrape_interval: 15s

scrape_configs:
- job_name: composeflux
static_configs:
- targets:
- composeflux:9090

grafana-datasource:
content: |
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true

volumes:
compose-stack:
name: compose-stack
9 changes: 1 addition & 8 deletions docs/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ Deploy ComposeFlux and manage Docker Compose stacks via GitOps.
| `LOG_ADD_SOURCE` | Add source location to logs | `false` |
| `REMOVE_ORPHANS` | Remove orphan containers during deploy | `true` |
| `PRUNE_INTERVAL` | Interval for periodic Docker resource pruning (images, volumes, build cache). Only runs when all managed stacks are healthy. Set to `0` to disable. | `24h` |
| `METRICS_ADDR` | Prometheus metrics listen address. Empty to disable. | `:9090` |

!!! warning

Expand Down Expand Up @@ -95,7 +94,7 @@ Run "composeflux <command> --help" for more information on a command.
Git repository for changes at configured intervals (default: 5 minutes).
- **`sync`** - One-shot sync and deploy. Manually triggers immediate synchronization. Useful when you update secrets in
your secrets manager but haven't made Git changes. See
[Hash-Based Change Detection](Introduction.md#hash-based-change-detection).
[Git Diff & Dependency Change Detection](Introduction.md#git-diff--dependency-change-detection).

```bash
# Daemon mode (initial sync at startup, then checks Git every 5 minutes)
Expand Down Expand Up @@ -186,12 +185,6 @@ services:
# LOG_LEVEL: info
# LOG_FORMAT: console # console or json

# Metrics
# METRICS_ADDR: ":9090" # Prometheus metrics endpoint, empty to disable

ports:
- "9090:9090" # Prometheus metrics

volumes:
- /var/run/docker.sock:/var/run/docker.sock

Expand Down
28 changes: 15 additions & 13 deletions docs/Introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ automatically deploys stacks when changes are detected.
ComposeFlux runs a Git sync loop in daemon mode (`run` command). It performs an initial sync at startup, then checks the
remote Git repository for changes and syncs again when updates are detected.

1. Pulls latest commits
1. Pulls latest commits and tracks changed file paths
2. Fetches secrets from secrets manager
3. Loads environment variables from [`stack.yml`](#stack-configuration) (if present)
4. Discovers compose stacks (one level deep in `STACK_PATH`)
5. Calculates SHA256 hash for each stack
6. Deploys stacks with changed hashes (respects [`startup_order`](#stack-configuration))
5. Builds dependency file set for each stack (compose files, include blocks, env files, mounted configs, secrets, build context)
6. Deploys stacks that have file updates or are missing from Docker (respects [`startup_order`](#stack-configuration))
7. Prunes stacks deleted from Git

Optionally, a separate cron-scheduled image update check (`IMAGE_UPDATE_SCHEDULE`) pulls new images and redeploys stacks
Expand All @@ -35,18 +35,20 @@ Two additional background loops run independently:
- **Docker resource prune** — prunes unused images, volumes, and build cache on `PRUNE_INTERVAL` (default: 24h), but
only when all managed stacks are healthy (see [Periodic Docker Resource Pruning](#periodic-docker-resource-pruning))

## Hash-Based Change Detection
## Git Diff & Dependency Change Detection

ComposeFlux uses a hash-based approach to decide whether a stack needs redeploying:
ComposeFlux uses a Git diff and dependency-tree-based approach to decide whether a stack needs redeploying:

- **Git Diff Path Matching**: ComposeFlux tracks modified, added, or deleted file paths between Git commits.
- **Dependency Tree Resolution**: Each stack's Compose project resolves all related file dependencies, including:
- Compose files and `include` directives
- Environment files (`env_file`)
- Mounted configuration files (`configs`) and secrets (`secrets`)
- Host bind mounts (`volumes`)
- Local build context and Dockerfiles (`build`)
- **Base / Overlay Support**: Changes in shared base directories (e.g., `base/app1` included by `overlays/prod/app1`) are automatically mapped to dependent stacks.
- **Targeted Redeployment**: A stack is redeployed only if any changed file in Git overlaps with its dependency file set, or if the stack is missing from Docker.

- SHA256 hash is calculated from the entire Compose project (after variable substitution with secrets)
- **Includes secrets**: The hash includes resolved secrets at sync time. If secrets change, you can run
`composeflux sync` (or wait for the next Git change) to fetch them and update the hash.
- To take full advantage of hash-based detection for app config changes, prefer Docker Compose
[`configs`](https://docs.docker.com/reference/compose-file/configs/) in your Compose files instead of mounting plain
app config files directly into containers.
- Stack is redeployed only when the hash changes; otherwise it is skipped (no unnecessary redeployment)
- Hash is stored in the `composeflux.stack-hash` label on deployed containers

## Image Update Exclusion

Expand Down
21 changes: 0 additions & 21 deletions docs/Metrics.md

This file was deleted.

Loading