GitOps repo for bootstrapping Kubernetes clusters with ArgoCD using the App of Apps pattern.
Full documentation is available at the MkDocs site. To preview locally:
pip install mkdocs-material
mkdocs serveOnline documentation available at Cluster Boostrap Docs
Runtime:
kubectlconfigured with access to the target clusterhelm(for local template testing)sopsandage(for secrets encryption/decryption) orgit-crypt(alternative encryption backend)- SSH private key with read access to this repo
Development (optional):
go1.25+ (to build the CLI from source)task(Task runner)pre-commit(pre-commit hooks)
Replace the default user-cube/cluster-bootstrap with your organization and repository:
./cluster-bootstrap-cli/cluster-bootstrap-cli template customize --org mycompany --repo k8s-gitopsThis updates Git URLs, GitHub badges, Go module paths, and documentation throughout the codebase. See Template documentation for details.
Option A: Install globally with go install (recommended)
# From local source
go install ./cluster-bootstrap-cli
# Or from GitHub
go install github.com/user-cube/cluster-bootstrap/cluster-bootstrap-cli@latest
# Verify installation
cluster-bootstrap-cli --helpOption B: Build locally
task build
# Binary will be at: cluster-bootstrap-cli/cluster-bootstrap-cli
./cluster-bootstrap-cli/cluster-bootstrap-cli --helpOption C: Use task helper
task install
# Builds and installs to $(go env GOPATH)/bin./cluster-bootstrap-cli/cluster-bootstrap-cli init./cluster-bootstrap-cli/cluster-bootstrap-cli bootstrap devThis will:
- Decrypt environment secrets (SOPS + age by default, or git-crypt)
- Create the
argocdnamespace and SSH credentials secret - Install ArgoCD via Helm
- Deploy the root App of Apps Application
π‘ Idempotent by design: The bootstrap command can be safely run multiple times. It automatically detects existing resources and updates them instead of failing. Perfect for configuration updates or GitOps workflows.
The bootstrap command generates comprehensive reports with timing metrics, resource operations, and health check results:
# Default: Human-readable summary report
./cluster-bootstrap-cli/cluster-bootstrap bootstrap dev
# JSON report for automation/metrics collection
./cluster-bootstrap-cli/cluster-bootstrap bootstrap dev --report-format json
# Save report to file
./cluster-bootstrap-cli/cluster-bootstrap bootstrap dev --report-output bootstrap-report.jsonSee Bootstrap Reports documentation for details.
./cluster-bootstrap-cli/cluster-bootstrap init --provider git-crypt
./cluster-bootstrap-cli/cluster-bootstrap bootstrap dev --encryption git-cryptIf your Kubernetes manifests live in a subdirectory (e.g. k8s/), you need to configure both the CLI and values file:
- Update
apps/values.yamlto set the base path:
repo:
basePath: "k8s" # Set to your subdirectory name- Run bootstrap using either method:
From repository root:
./k8s/cli/cluster-bootstrap --base-dir ./k8s bootstrap dev \
--app-path k8s/apps \
--wait-for-health -vOr from inside the subdirectory (both work):
cd k8s
# Relative path
./cluster-bootstrap-cli/cluster-bootstrap bootstrap dev --app-path apps --wait-for-health -v
# Or full path
./cluster-bootstrap-cli/cluster-bootstrap bootstrap dev --app-path k8s/apps --wait-for-health -vKey points:
- The CLI automatically detects if you're in a Git subdirectory
- Works with both relative (
apps) and full paths (k8s/apps) - Strips prefixes intelligently for local validation
repo.basePath: "k8s"in values.yaml ensures component paths include the subdirectory prefix- Choose whichever feels most natural to you!
kubectl port-forward svc/argocd-server -n argocd 8080:443Get the initial admin password:
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath='{.data.password}' | base64 -dCLI bootstrap β ArgoCD + App of Apps (root Application)
β
apps/ (Helm chart with dynamic template)
β
components/argocd/ (self-managed ArgoCD)
components/xxx/ (other components)
ArgoCD manages itself β changes pushed to this repo are automatically synced.
The apps/ chart uses a single dynamic template that iterates over a components map defined in apps/values.yaml. Adding a new component requires only a new entry in the values β no template files to create or copy.
| Component | Namespace | Sync Wave | Description |
|---|---|---|---|
| ArgoCD | argocd |
0 | Self-managed GitOps controller |
| Vault | vault |
1 | Secrets management |
| External Secrets | external-secrets |
1 | Syncs external secrets into Kubernetes |
| Prometheus Operator CRDs | monitoring |
2 | CRDs for the monitoring stack |
| ArgoCD Repo Secret | argocd |
2 | SSH credentials for repo access |
| Reloader | reloader |
2 | Restarts pods on ConfigMap/Secret changes |
| Kube Prometheus Stack | monitoring |
3 | Prometheus monitoring stack |
| Trivy Operator | trivy-system |
3 | Vulnerability scanning |
| Command | Description |
|---|---|
bootstrap <env> |
Full cluster bootstrap (decrypt secrets, install ArgoCD, deploy App of Apps). Generates comprehensive reports with timing metrics and resource operations. Fully idempotent. |
template customize |
Customize the template with your organization and repository (replaces placeholders in configs, docs, and code) |
doctor |
Run prerequisite checks for tooling and cluster access |
status <env> |
Show cluster status and component information |
validate <env> |
Validate local config, secrets, and optional cluster access |
init |
Interactive setup for encryption config and secrets files |
vault-token |
Store Vault root token as Kubernetes secret |
gitcrypt-key |
Store git-crypt symmetric key as Kubernetes secret |
| Flag | Default | Description |
|---|---|---|
--base-dir |
. |
Base directory for repo content (local file resolution) |
-v, --verbose |
false |
Enable verbose output |
pre-commit installRun task --list to see all available tasks. The most common ones:
task test # Run Go tests with coverage
task lint # Run golangci-lint
task helm-lint # Lint Helm charts with templates
task fmt # Format Go source files
task vet # Run Go vet
task docs-serve # Serve MkDocs documentation locallySOPS (default): secrets.example.enc.yaml contains the expected secrets structure. To create a new environment:
cp secrets.example.enc.yaml secrets.myenv.enc.yaml
sops --encrypt --in-place secrets.myenv.enc.yamlOr use the CLI interactively: ./cluster-bootstrap-cli/cluster-bootstrap init myenv
git-crypt: Secrets are stored as plaintext YAML (secrets.<env>.yaml) and encrypted transparently by git-crypt on commit:
git-crypt init
./cluster-bootstrap-cli/cluster-bootstrap init --provider git-crypt myenvTo use a custom .sops.yaml path, set SOPS_CONFIG in your .env:
SOPS_CONFIG=/path/to/custom/.sops.yaml| Environment | Values File | Description |
|---|---|---|
| dev | apps/values/dev.yaml |
Local/development clusters, minimal resources |
| staging | apps/values/staging.yaml |
Pre-production, moderate resources |
| prod | apps/values/prod.yaml |
Production, HA configuration |
Environment files only need to set the environment key. Component defaults (namespace, sync wave, syncOptions, etc.) are defined in apps/values.yaml. To disable a component per environment:
# apps/values/dev.yaml
environment: dev
components:
trivy-operator:
enabled: false