Skip to content

hrodrig/kzero

Repository files navigation

kzero

Version GitHub release Go License: MIT Ask DeepWiki CI codecov gghstats clones pkg.go.dev Go Report Card deps.dev Security CodeQL

Repo: github.com/hrodrig/kzero · Releases: Releases · DeepWiki: hrodrig/kzero

Badges: Version is a static badge aligned with the repo VERSION file (next release target). GitHub release shows the latest published tag on GitHub; it can lag the VERSION file until a release is cut. Go matches go.mod. License points at this repository’s license file. Ask DeepWiki links to DeepWiki AI-generated docs for this repository (see also badge maker). CI, Security, and CodeQL reflect GitHub Actions workflows. codecov tracks coverage uploaded from CI. pkg.go.dev, Go Report Card, and deps.dev summarize the Go module and dependencies. gghstats clones shows Git clone traffic for this repo (see gghstats).

kzero overview — declarative Kubernetes workload orchestration (pipelines, hooks, workload step types)

Terminal demo (recorded with VHS; source docs/demo.tape, config docs/demo-kzero.yaml):

kzero CLI — analyze and dry-run down (terminal recording)

Regenerate from the repo root: docs/README.md — Terminal demo.

Declarative Kubernetes workload orchestration: ordered down / up (and reset) pipelines from YAML, with phase hooks, optional per-step pre / post scripts, kubectl scale targets, Helm release helper scripts, and custom steps.

Releases (GitHub Releases) ship standalone binaries and archives (.tar.gz / .zip), Linux .deb / .rpm, Docker images on ghcr.io/hrodrig/kzero (distroless runtime — see Install or update), and Homebrew when published there. This repository does not ship Helm charts as a release artifact. Optional operator-focused extras live in kzero-selfhosted.

Behavior, schema, and acceptance criteria are defined in docs/SPECIFICATIONS.md. Planned work (prioritized): docs/ROADMAP.md. Diagrams (Mermaid): docs/diagrams.md.

Table of contents


Features

  • Configuration-first (schema_version: "1.0"): pipelines and hooks live in config, not hardcoded playbooks.
  • Commands: analyze, down, up, reset, version (reset = full down then up; if down fails, up does not run).
  • Phase hooks: pre-down, post-down, pre-up, post-up, on-error (shell script paths).
  • Per-step hooks (pre / post): optional shell scripts for a single pipeline step—run immediately before and after that step’s main action; post runs only if the main action succeeds.
  • Step types: compact refs (deployment.ns/name, statefulset.ns/name), release.ns/name (scripts under helm.workspace), and custom: ./script.sh (with optional sibling pre / post keys on the same YAML mapping). DaemonSet is not supported as a built-in kind because kubectl scale rejects it (no /scale subresource); use a custom: step with kubectl patch to set a nodeSelector that drains the pods.
  • Run modes: dry-run (plan only, no cluster mutations) and live.

Libraries (see go.mod): Cobra v1.10.2, Viper v1.21.0.

↑ Back to top

Requirements

  • kubectl on PATH (or set command.kubectl in YAML) with a kubeconfig that can reach the target cluster
  • RBAC sufficient for the operations in your pipelines (for example get/patch/scale on workloads, Helm if you use release.* steps)
  • helm on PATH when you use release.namespace/name steps (or set command.helm); not required for workload-only configs
  • Go 1.26.3+ if you build from source (make build) or use go install

↑ Back to top

Install or update

Pre-built .deb, .rpm, .tar.gz (and .zip on Windows), plus multi-arch container images on ghcr.io/hrodrig/kzero, are on GitHub Releases and latest release. The release badge at the top of this README shows the current tag at a glance.

Why not a single latest URL for every file? GitHub’s …/releases/latest/download/<file> only works if the asset filename is identical on every release. GoReleaser here uses the git tag (with v) in Linux package and archive basenames (for example kzero_v0.2.2_linux_amd64.deb), while the download path is still …/download/v0.2.2/…. Pick names from the release page, use the snippet below, or use the badge.

Install latest .deb (Debian / Ubuntu, amd64)

# Latest published release tag (python3 or jq). Linux .deb basename includes the tag WITH "v".
TAG="$(curl -fsSL https://api.github.com/repos/hrodrig/kzero/releases/latest | python3 -c 'import json,sys; print(json.load(sys.stdin)["tag_name"])')"
# Alternative: TAG="$(curl -fsSL https://api.github.com/repos/hrodrig/kzero/releases/latest | jq -r .tag_name)"

[ -n "$TAG" ] || { echo "Could not resolve tag (empty). Install python3 or jq, or set TAG manually from the Releases page." >&2; exit 1; }

DEB="kzero_${TAG}_linux_amd64.deb"
URL="https://github.com/hrodrig/kzero/releases/download/${TAG}/${DEB}"
TMP="/tmp/${DEB}"

# Download to /tmp so user _apt can read the file (apt often cannot read ~/.deb when $HOME is mode 700).
if ! curl -fsSL "$URL" -o "$TMP"; then
  echo "Download failed (curl exit $?). Check URL: $URL" >&2
  exit 1
fi
if [ ! -f "$TMP" ]; then
  echo "Expected $TMP after download — not found." >&2
  exit 1
fi
sudo apt install "$TMP"

Paste the block as a whole, or chain with &&, so apt does not run after a failed curl. curl -f (via -fsSL) exits non‑zero on HTTP errors (404, etc.).

apt + _apt / “Permission denied” under $HOME: if you curl the .deb into ~ and run sudo apt install ./kzero_….deb, Debian/Ubuntu may warn that _apt cannot read the file (home directory not world-executable). Use /tmp as above, or sudo cp "$DEB" /tmp/ then sudo apt install "/tmp/$DEB".

Empty TAG: if jq/python3 failed, you get .../download//kzero__linux_amd64.deb and a broken filename.

.deb / .rpm install kzero to /usr/bin and place /etc/kzero/kzero.yaml (from the sample; config|noreplace on upgrades). The CLI defaults to ./kzero.yaml when --config is omitted—use kzero --config /etc/kzero/kzero.yaml … after install, or copy that file to ./kzero.yaml. Use linux_arm64 in the download filename on ARM64 Linux.

Fixed-tag examples (copy from the release page if you prefer)

Format Example (tag v0.2.2 in the URL path; artifact basename includes the same v0.2.2)
.deb curl -fsSL -o /tmp/kzero_v0.2.2_linux_amd64.deb https://github.com/hrodrig/kzero/releases/download/v0.2.2/kzero_v0.2.2_linux_amd64.deb then sudo apt install /tmp/kzero_v0.2.2_linux_amd64.deb
.rpm curl -fsSLO https://github.com/hrodrig/kzero/releases/download/v0.2.2/kzero_v0.2.2_linux_amd64.rpm then sudo rpm -Uvh kzero_v0.2.2_linux_amd64.rpm or sudo dnf install ./kzero_v0.2.2_linux_amd64.rpm
.tar.gz (Linux) curl -fsSLO https://github.com/hrodrig/kzero/releases/download/v0.2.2/kzero_v0.2.2_linux_amd64.tar.gz then tar xzf kzero_v0.2.2_linux_amd64.tar.gz and run ./kzero from the extracted tree (see share/examples/kzero/kzero.sample.yml)
.tar.gz (macOS) curl -fsSLO https://github.com/hrodrig/kzero/releases/download/v0.2.2/kzero_v0.2.2_darwin_amd64.tar.gz (or …_darwin_arm64.tar.gz on Apple silicon)

Update: download a newer release and run the same install command again (rpm -Uvh, apt install over the .deb, or replace the tarball tree).

Windows: use the .zip asset for your arch (for example kzero_v0.2.2_windows_amd64.zip), unpack, run kzero.exe where kubectl is available.

Docker: docker pull ghcr.io/hrodrig/kzero:v0.2.2 (match the image tag to the release you want). Published images use gcr.io/distroless/static-debian12:nonroot (static kzero binary only: no shell, no BusyBox/Alpine runtime). Dockerfile in this repo uses the same final stage. Package: ghcr.io/hrodrig/kzero.

Homebrew and BSD packaging helpers: when published, see Releases and contrib/README.md.

Then run kzero --config /etc/kzero/kzero.yaml analyze (or follow Quick start to build from a clone).

↑ Back to top

Quick start

make build
./bin/kzero --help
./bin/kzero analyze --config configs/kzero.sample.yml

On FreeBSD, use gmake (or plain make, which forwards to GNU Make via the stub Makefile).

Copy and edit configs/kzero.sample.yml (or use --config / ./kzero.yaml). Override values via environment variables with the KZERO_ prefix (see Viper / sample file comments).

If you installed from Releases or go install (below), use kzero on your PATH instead of ./bin/kzero.

Install with Go

From any machine with Go 1.26.3+ (installs to $(go env GOPATH)/bin; ensure that directory is on your PATH):

go install github.com/hrodrig/kzero/cmd/kzero@latest

Use a release tag instead of @latest if you want a pinned version (for example @v0.2.2). Module reference: pkg.go.dev/github.com/hrodrig/kzero.

↑ Back to top

First run

kzero reads one YAML file per invocation. If you omit --config, it loads ./kzero.yaml from the current working directory (there is no automatic search under /etc—after a .deb/.rpm install use kzero --config /etc/kzero/kzero.yaml … or copy that file to ./kzero.yaml).

  1. Start from configs/kzero.sample.yml in a clone, from share/examples/kzero/kzero.sample.yml inside a release tarball, or from /etc/kzero/kzero.yaml after a Linux package install.
  2. Keep run.mode: dry-run until kzero analyze and pipeline plans match what you expect; switch to live only when ready (docs/SPECIFICATIONS.md).
  3. Set command.kubectl / command.helm to absolute paths for cron or minimal environments.
cp configs/kzero.sample.yml kzero.yaml
# Edit kzero.yaml: cluster, pipelines, helm.workspace, hook paths, notify, run.*
kzero analyze
kzero down

↑ Back to top

Usage examples

Paths use ./bin/kzero after make build. If you installed from Releases or go install, use kzero on your PATH the same way.

Plan only (analyze, down / up in dry-run)

kzero analyze --config ./kzero.yaml
# With run.mode: dry-run in YAML:
kzero down --config ./kzero.yaml

Explicit config path

kzero analyze --config /path/to/prod/kzero.yaml
kzero up --config /path/to/prod/kzero.yaml

reset (down then up)

kzero reset --config ./kzero.yaml

If down fails, up is not executed (see RunReset).

Version metadata

kzero version

↑ Back to top

Configuration reference

Full schema, validation, and acceptance criteria: docs/SPECIFICATIONS.md. Annotated sample: configs/kzero.sample.yml.

Block / key Purpose
schema_version Must be 1.0 today.
cluster Metadata (name, environment, …) for labels and notifications.
helm workspace: directory with <release>.sh scripts and values for release.ns/name steps.
command Optional paths for kubectl and helm.
hooks Optional global scripts: pre-down, post-down, pre-up, post-up, on-error.
notify Optional slack / discord blocks (see SPEC).
pipelines See pipelines below.
retry See retry below.
run See run below.

run

Key Purpose
mode dry-run (log plan only) or live (execute kubectl / helm). Required.
timeout Wall-clock budget for a full down, up, or reset (Go duration, e.g. 25m).
kubeconfig Path passed to kubectl / helm; empty uses the process environment / default kubeconfig search.
worker_concurrency Integer in the schema; the v1 engine runs pipeline steps sequentially in YAML order. Parsed and stored for forward compatibility—see SPEC — Current engine.
operation_timeout Per-operation ceiling (e.g. 45s) for individual kubectl/helm calls inside a step.

retry

Key Purpose
attempts Declared retry count (integer).
delay Backoff between attempts (Go duration, e.g. 8s).

The engine does not retry failed steps yet; keys are part of the contract. See SPEC — Current engine.

pipelines

  • down and up are ordered lists. Each item is either:
    • a string step reference: deployment.ns/name, statefulset.ns/name, release.ns/name (DaemonSet is not a built-in kind — see Features); or
    • a single-key map whose key is one of the above or custom, with optional fields beside that key (see below).
  • release.* steps require helm.workspace to point at the directory of <release>.sh scripts (see SPEC and sample).

Optional fields on a map step (same YAML mapping as the step ref, alongside pre / post):

Field Applies to Purpose
pre / post workload, release, custom Shell scripts run immediately before / after the main action; post only if the main action succeeds.
replicas mainly up / scale targets Target replica count (integer).
wait_for_ready workloads with readiness If true, wait for rollout / ready condition (see SPEC).
timeout step-level override Go duration string (e.g. 10m) for that step’s bounded wait / operations.

↑ Back to top

Environment and precedence

  • KZERO_ environment variables override values from the loaded YAML (Viper AutomaticEnv). Nested keys use underscores (for example run.modeKZERO_RUN_MODE).
  • --config /path/to/kzero.yaml selects that file explicitly. When omitted, the default file is ./kzero.yaml (must exist; there is no built-in fallback path).

↑ Back to top

Troubleshooting

read config: … or “cannot find the file”

kzero always loads a real file path. With no --config, that path is ./kzero.yaml relative to the current working directory. Fix: cd to the directory that contains kzero.yaml, pass --config /absolute/path/kzero.yaml, or copy configs/kzero.sample.yml / /etc/kzero/kzero.yaml to ./kzero.yaml.

run.mode must be one of: dry-run, live

Only those two literals are accepted (see validation in internal/config/load.go). Check for typos, quotes, or trailing spaces in YAML.

helm.workspace is required when pipelines include release steps

Any release.ns/name entry requires helm.workspace in the root config. Set it to the directory that contains your <release>.sh scripts, or remove release.* steps if you are not using Helm-driven releases.

reset never ran up / pipeline stopped halfway

reset runs down then up under one run.timeout. If down returns an error, up is skipped (RunReset). Inspect the down failure (hooks, RBAC, or a failing step) before re-running.

↑ Back to top

Security note

  • run.mode: live performs real cluster mutations (kubectl / helm as configured). Stay on dry-run until reviews pass.
  • Hooks (hooks.*, per-step pre/post, custom:) run as the same OS user that invokes kzero. Only reference scripts you trust; treat changes like production code.
  • Use least-privilege RBAC for the kube identity in use; pipeline steps may scale, delete, or upgrade workloads depending on your YAML.

See SECURITY.md for reporting vulnerabilities.

↑ Back to top

Releases and CI

  1. Work on develop; merge to main when ready.
  2. Before tagging: run make release-check (requires Docker): semver VERSION, make lint (gofmt, go vet, gocyclo ≤14), make test, make security (govulncheck), make docker-scan (Grype on the image; use GRYPE_FAIL_ON to tune the gate, default high).
  3. On main: create an annotated tag (e.g. git tag -a v0.2.2 -m "Release 0.2.2") and git push origin v0.2.2. The Release workflow runs make release-check then GoReleaser (binaries + ghcr.io/hrodrig/kzero).
  4. Local release after checks: make release (same as CI tail; main branch only).

Snapshot builds (no git tag): make snapshot → artifacts under dist/ (archives .tar.gz / .zip, Linux .deb / .rpm, checksums). See contrib/README.md for packaging notes.

↑ Back to top

Development

make test
make lint
make build

See CONTRIBUTING.md and CHANGELOG.md. Security reporting: SECURITY.md.

↑ Back to top

Per-step pre / post (example)

Use this when something must happen between ordered steps—for example, run a script while a StatefulSet is still running, then scale that StatefulSet to zero in the same step:

pipelines:
  down:
    - deployment.app/worker
    - statefulset.data/job-queue:
        pre: ./hooks/pre-scale-purge.sh

Here pre-scale-purge.sh runs before kubectl scale for job-queue (so the pod can still accept kubectl exec or similar). Optional post runs after a successful scale (or other main action for that step).

Custom step with hooks (same list item, multiple keys):

    - custom: ./hooks/maintenance.sh
      pre: ./hooks/before-maintenance.sh
      post: ./hooks/after-maintenance.sh

↑ Back to top

Get involved

Found kzero useful? We'd love your help to make it better. You can:

  • Report bugs or suggest featuresopen an issue
  • Contribute code — see CONTRIBUTING.md for how to submit a pull request
  • Star the repo — it helps others discover kzero

Thanks for using kzero.

↑ Back to top

License

See LICENSE.

↑ Back to top

About

Go CLI for declarative Kubernetes pipelines (down, up, reset). Turn start-over into a checked-in playbook: return workloads to a known initialization state—ordered scale-down and bring-up for Deployments, StatefulSets, Helm release steps, and custom scripts.

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors