8000 GitHub - composepack/composepack: Dynamic templating and packaging for Docker Compose. Manage complex configurations with values.yaml defaults and overrides. · GitHub
[go: up one dir, main page]

Skip to content

composepack/composepack

Repository files navigation

ComposePack

English | 简体中文

🧩 Pack your Compose, ship it anywhere.
The power of Helm-style configuration for Docker Compose.

ComposePack banner

CI Status Latest Release License GitHub stars

Docker Compose is the standard for running multi-container applications, but it lacks templating, dynamic configuration, and clean packaging. Teams often struggle with giant YAML files, manual copy-pasting across environments, and complex .env file management.

ComposePack fixes this.

It brings a modern templating engine, overridable config system, and a packaging workflow to Docker Compose—while remaining 100% compatible with the standard Docker CLI.

Why ComposePack?

  • 📝 Go-Style Templates: Write dynamic Compose files with logic (if, range, etc.).
  • ⚙️ Structured Config: Ship clean values.yaml defaults and allow user overrides.
  • 📦 Real Packaging: Distribute your app as a versioned, installable .cpack chart.
  • 🔐 Reproducible Releases: Render isolated, self-contained release directories.
  • 🚀 Native Runtime: Under the hood, it's just docker compose.

⚖️ ComposePack vs. Docker Compose

Feature Docker Compose ComposePack
Templating ❌ (Variables only) ✅ (Full logic)
Config Model ❌ (Flat .env) ✅ (Values.yaml)
Packaging ✅ (Charts)
Environment Isolation ✅ (Release Dirs)
Drift Detection ✅ (Diff command)
Runtime Engine

📚 Table of Contents


⚡ Quick 60-Second Demo

# 1. Scaffold a chart
composepack init charts/demo --name demo --version 0.1.0

# 2. Install it into a release with your own values
composepack install charts/demo --name myapp -f values-prod.yaml --auto-start

# 3. Watch logs
composepack logs myapp --follow

That’s it: templated config + reproducible runtime on top of plain Docker Compose.


📦 Installation

ComposePack is a single binary with no external dependencies other than Docker & Docker Compose.

Homebrew (macOS/Linux)

  • If you’ve tapped composepack/tap already:
brew install composepack
  • First time using the tap:
brew tap composepack/tap
brew install composepack

Note: once accepted to homebrew-core, brew install composepack will work without a tap on macOS and Linux.

Docker Image (CI/CD)

For use in GitHub Actions, GitLab CI, or other containerized environments:

# Use the official image
docker run --rm garearc/composepack:latest --version

# Or pin to a specific version
docker run --rm garearc/composepack:v1.0.0 --version

Example GitHub Actions workflow:

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install and run composepack
        run: |
          docker run --rm \
            -v ${{ github.workspace }}:/workspace \
            -w /workspace \
            garearc/composepack:latest \
            install charts/myapp --name prod

The image is multi-arch (supports linux/amd64 and linux/arm64) and is automatically published to Docker Hub on every release.

macOS / Linux (curl)

curl -fsSL https://raw.githubusercontent.com/composepack/composepack/main/scripts/install.sh | bash
  • Installs to /usr/local/bin/composepack or falls back to ~/.local/bin/composepack
  • Override install directory with COMPOSEPACK_INSTALL_DIR

Uninstall:

./scripts/uninstall.sh

Windows (PowerShell)

./scripts/install.ps1 -Version v1.0.0 -InstallDir "$env:ProgramFiles\ComposePack"

Uninstall:

./scripts/uninstall.ps1

Build from source

git clone https://github.com/composepack/composepack.git
cd composepack
make build

make generate runs go generate ./... for Wire and other providers.


🧠 How It Works (High-Level)

ComposePack flow

  • You define a chart (templated Compose + assets).
  • Users pass values (values.yaml, --set, env vars).
  • ComposePack renders everything into a self-contained release directory.
  • Docker Compose runs exclusively from that directory.

🚀 How to Use

ComposePack has two kinds of users:

  • Chart Creators (Shippers) → build and package charts
  • Chart Users (Consumers) → install and run charts

Below is the workflow for each.


🛠️ For Chart Creators (Shippers)

(for teams packaging their applications)

1️⃣ Create a new chart (scaffolding)

composepack init charts/example --name example --version 0.1.0

This generates something like:

charts/example/
  Chart.yaml
  values.yaml
  templates/
    compose/00-app.tpl.yaml
    files/config/message.txt.tpl
    helpers/_helpers.tpl
  files/
    config/

2️⃣ Template / render your chart locally

composepack template dev --chart charts/example

This renders templates but does not create or modify a release.

3️⃣ Install your chart to test it

composepack install charts/example --name dev --auto-start

This builds .cpack-releases/dev/ and runs docker compose up inside it.

4️⃣ Package your chart for distribution

composepack package charts/example --destination dist/

Creates:

dist/example-0.1.0.cpack.tgz

You can also customize the output name:

composepack package charts/example --output dist/example.cpack.tgz

You can host that .cpack.tgz on HTTP(S), ship it as an artifact, or check it into your internal distribution system.


🧑‍💻 For Chart Users (Consumers)

(for customers or internal developers consuming charts)

1️⃣ Install from a packaged chart (or local dir)

composepack install example.cpack.tgz --name myapp -f custom-values.yaml --auto-start

install accepts:

  • A local .cpack.tgz archive
  • A local chart directory
  • An HTTP/HTTPS URL pointing to a packaged chart

2️⃣ Manage your deployment

composepack up myapp
composepack down myapp --volumes
composepack logs myapp --follow
composepack ps myapp
composepack template myapp
composepack diff myapp --chart <chart-source>

All runtime files for this release live in:

.cpack-releases/myapp/
  docker-compose.yaml
  files/
  release.json

If needed, you can cd into this folder and run docker compose manually.

Want to run these commands from somewhere else? Pass --runtime-dir to point directly at the release folder:

composepack up myapp --runtime-dir /opt/releases/myapp
composepack logs myapp --runtime-dir /opt/releases/myapp --follow

3️⃣ Preview changes before deploying (Drift Detection)

Before running install or up, you can see what would change:

# If release exists, chart source is auto-resolved
composepack diff myapp

# Or compare against a different chart
composepack diff myapp --chart charts/myapp-v2

This shows:

  • What services would be added, removed, or modified
  • Changes to the docker-compose.yaml configuration
  • File differences (with --show-files)

Example output:

📝 Docker Compose Changes:

-     image: myapp:v1.0
+     image: myapp:v2.0

⚠️  Affected Services:
  • myapp-api (modified)

Note: In the examples above, myapp is the release name (the name you gave to your deployment). The chart source is auto-resolved from the release metadata, so you typically don't need to specify --chart unless comparing against a different chart.

This helps you answer: "Will running install now restart my database?"


🧩 Template Basics

ComposePack uses Go templates — the same templating style many Helm users already know.

Example:

# templates/compose/00-app.tpl.yaml
services:
  app:
    image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
    environment:
      DB_HOST: "{{ .Values.db.host }}"
      DB_PASSWORD: "{{ env "DB_PASSWORD" }}"

You have access to:

  • .Values — merged system + user values
  • .Env — environment variables
  • .Release — name, version, metadata
  • Standard Go template functions (default, include, quote, toJson, etc.)

If your team already uses Helm templates, the learning curve is almost zero.


📂 Chart Layout & File Types

This section explains what lives where inside a chart and how ComposePack treats those files.

High-level layout

A typical chart looks like this:

myapp/
  Chart.yaml
  values.yaml
  templates/
    compose/
      00-app.tpl.yaml
      10-worker.tpl.yaml
    files/
      config/app.env.tpl
    helpers/
      _helpers.tpl
  files/
    config/
    scripts/

Key files & directories

Chart.yaml

  • Required

  • Metadata about the chart:

    • name: string (required)
    • version: string (required)
    • description: string
    • maintainers: []string
  • Used by ComposePack to identify the chart and write release.json.

values.yaml

  • Required
  • Default system-level configuration for the chart.
  • Users can layer their own values-*.yaml or --set overrides on top.
  • Think of this as “what the product ships with” vs “what users customize.”

templates/compose/*.tpl.yaml

  • Required folder

  • Each file is a templated Docker Compose fragment.

  • Must end with .tpl.yaml.

  • ComposePack:

    1. Renders these templates using .Values and .Env.
    2. Merges all rendered fragments into a single docker-compose.yaml per release.

Example:

templates/compose/
  00-core.tpl.yaml
  10-db.tpl.yaml
  20-api.tpl.yaml

templates/files/*.tpl

  • Optional.

  • Templated runtime assets:

    • config files
    • shell scripts
    • anything written to disk for containers to mount.
  • Must end with .tpl.

  • ComposePack:

    • Renders them
    • Drops the .tpl suffix
    • Writes them into the release’s files/ directory.

Example:

templates/files/
  config/app.env.tpl       -> files/config/app.env
  scripts/init.sh.tpl      -> files/scripts/init.sh

templates/helpers/*.tpl

  • Optional.
  • Reusable template snippets and helper functions.
  • Included via {{ include "helper.name" . }} from other templates.

Example:

templates/helpers/_helpers.tpl
{{- define "myapp.fullname" -}}
{{ printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" }}
{{- end -}}

files/

  • Optional.

  • Static assets that do not need templating.

  • Everything under files/ is copied as-is into the release’s files/ directory.

  • Good for:

    • static config
    • certificates
    • seed data
    • scripts that never change

Example:

files/
  config/defaults.json
  scripts/migrate.sh

In the release:

.cpack-releases/<name>/
  files/config/defaults.json
  files/scripts/migrate.sh

🏗️ Runtime Layout

For each release, ComposePack maintains a self-contained directory:

.cpack-releases/<release>/
  docker-compose.yaml   # merged compose file (all fragments combined)
  files/                # rendered & static assets referenced in templates
    config/...
    scripts/...
  release.json          # metadata: chart, version, values, environment, etc.

This is the only place Docker Compose runs from for that release.


📏 Runtime Rules & Gotchas

These are important design rules to keep your charts predictable and easy to debug.

1️⃣ All mountable assets live under ./files/ at runtime

In the release directory, all non-compose assets live under files/. That means all local volume paths in your Compose templates must be under ./files/....

Example:

# inside templates/compose/*.tpl.yaml
services:
  app:
    volumes:
      - ./files/config/app.env:/app/app.env:ro
      - ./files/scripts/init.sh:/docker-entrypoint.d/init.sh:ro

If you reference paths outside ./files/, your containers may fail to start because those files won’t exist in the runtime directory.


2️⃣ Suffix rules for templates

ComposePack relies on file suffixes to decide how to treat files:

  • Compose templates must end with .tpl.yaml

    • Example: 10-api.tpl.yaml
  • Other templated files must end with .tpl

    • Example: app.env.tpl, init.sh.tpl
  • Static assets that need no templating → put them under files/ without .tpl.

If the suffixes are wrong, files may be copied without rendering or ignored as compose fragments.


3️⃣ Runtime commands are bound to the release directory

ComposePack always runs Docker Compose from the release’s directory:

.cpack-releases/<release>/
  docker-compose.yaml
  files/

When you run:

composepack up myapp

it is equivalent to:

cd .cpack-releases/myapp
docker compose -f docker-compose.yaml up

You must cd into the correct directory that contains .cpack-releases or specify the right --runtime-dir, otherwise, ComposePack won’t see the right file and volumes.


📝 FAQ

Does ComposePack replace Docker Compose?

No. ComposePack wraps Docker Compose, it doesn’t replace it.

  • ComposePack handles: templating, values, chart packaging, release directories
  • Docker Compose handles: actually running the containers

You can always cd into .cpack-releases/<name>/ and run docker compose manually if you prefer.

What's the difference between chart name, release name, and chart source?

ComposePack uses three different types of names:

  • Chart Name - The name of the chart package (from Chart.yaml). Example: example
  • Release Name - The name you give to a deployment instance (via --name flag). Example: myapp, prod, staging
  • Chart Source - The path/URL where the chart is located. Example: charts/example, app.cpack.tgz

In practice:

  • When you run composepack install charts/example --name myapp:
    • charts/example = chart source (where the chart is)
    • example = chart name (from Chart.yaml)
    • myapp = release name (what you call this deployment)
  • After installation, you use the release name in commands:
    • composepack up myapp (not composepack up example)
    • composepack diff myapp (chart source is auto-resolved)

You can deploy the same chart multiple times with different release names (e.g., prod, staging, dev).

See docs/naming.md for detailed explanation.

Why not just use raw docker-compose and .env files?

.env is fine for small projects, but it has limits:

  • It’s flat (no nested structure)
  • It doesn’t distinguish system defaults from user overrides (chaining multiple .env files is super confusing and error-prone)
  • It’s hard to maintain across upgrades
  • You can’t easily ship a “product config” separate from customer config

ComposePack gives you:

  • default values.yaml for system defaults
  • user can specify their own values-*.yaml and --set overrides on top
  • a clear separation between what you ship and what users customize
  • a reproducible release directory for each environment

Why not use Helm?

Helm is great — but it’s designed for Kubernetes, not Docker Compose.

Use Helm when:

  • You’re deploying to a Kubernetes cluster
  • You’re already invested in K8s tooling and workflows

Use ComposePack when:

  • You want Helm-style templating and chart packaging
  • You want to stay on plain Docker Compose
  • You don’t want the operational overhead of running Kubernetes

Think of ComposePack as bringing the Helm experience to the Compose world.

Can I still run docker compose directly?

Yes. ComposePack writes everything into:

.cpack-releases/<release>/
  docker-compose.yaml
  files/
  release.json

If you prefer, you can:

cd .cpack-releases/<release>
docker compose up
docker compose ps
docker compose logs

ComposePack just standardizes how that directory is built.

Is ComposePack production ready?

Right now the project is early-stage and evolving.

It’s suitable for:

  • Experimentation
  • Internal tools
  • Early adopters who are comfortable reading Go code and contributing

If you rely on it in production, please:

  • Open issues for any problems
  • Share feedback on missing features
  • Consider contributing bugfixes or docs improvements 🙏

🤝 Contributing

We welcome issues and PRs!

Development workflow

make fmt
make test
make build
make generate
  • CI (.github/workflows/ci.yml) runs formatting, vetting, and tests on PRs and pushes to main.
  • Tag releases with:
git tag vX.Y.Z
git push --tags

This triggers cross-compiled binaries to be uploaded to GitHub Releases.


If you find ComposePack useful, consider ⭐ starring the repo — it helps others discover it!

About

Dynamic templating and packaging for Docker Compose. Manage complex configurations with values.yaml defaults and overrides.

Topics

Resources

License

Stars

Watchers

Forks

Contributors

0