registry.bud.studio/charts), so you do not need access to the source
repository.
Your configuration lives in a GitOps repo you own. This page contains every
file that repo needs, written for an environment called production on
bud.example.com.
Already run managed databases (Azure Database for PostgreSQL, Cosmos DB,
external Kafka/ClickHouse, etc.) and want a single Helm install instead of
in-cluster dependencies? Follow the Deployment Guide,
it installs only the
bud chart pointed at your external services.How it works
The config repo has three moving parts:Application in
apps/<environment>.yaml. It syncs appsets/<environment>.yaml, and that
ApplicationSet generates one ArgoCD Application per component, named
<environment>-<component>.
Components
ArgoCD manages itself as the
argocd component, so after the bootstrap the
ArgoCD install is upgraded the same way as everything else.
How value files are layered
Each generated Application joins two sources: the OCI chart, and your Git repo mounted as$values for the value files (the templatePatch at the bottom
of the ApplicationSet). Each component lists its value files in order; later
files win. For example, postgres:
- Paths without
$values/(such asexample.minimal.yaml) resolve inside the chart itself: ready-made minimal profiles shipped with each dependency chart. values.budruntime.yaml,values.yamland thevalues.minimal*.yamlprofiles are the shared, environment-neutral baseline. Do not edit them per environment.values.<environment>.yamlis your public overlay.secrets.<environment>.yamlis SOPS-encrypted.
argocd chart bakes
helm-secrets + sops + age into
the ArgoCD repo-server, and the age private key is supplied through the
chart’s sopsAgeKeys value. ArgoCD therefore decrypts every
secrets.<environment>.yaml in-cluster, and nothing is stored in plaintext.
TLS profiles
See Self-signed or internal-CA TLS for how
the CA profiles work.
Syncs are manual by default. The ApplicationSet sets
syncPolicy.automated.enabled: false (with selfHeal: true), deliberate for
production: a Git push never changes a cluster until someone syncs. Flip it to
true if you want hands-off reconciliation. Either way, the addon charts
install operators (CloudNativePG, Strimzi, Altinity, Percona, …) whose
CRDs must exist before the database custom resources apply, so expect a few
Applications to show Degraded/Progressing on the first sync and converge on
a retry.Prerequisites
Option A, Install with budctl (recommended)
budctl generates the repo described in Option B
for you: it writes the shared values and your environment’s files, generates
coordinated credentials for every component, encrypts each secret file with
SOPS, and commits the result to your repo.
Run the guided installer:
production, budctl writes:
apps/production.yamlandappsets/production.yamlvalues/<component>/values.production.yaml- SOPS-encrypted
values/<component>/secrets.production.yaml - a
productionrule in.sops.yaml
--tls mode decides whether
cert-manager and Kyverno are added (see TLS profiles). Bud Studio
is the only optional add-on.
Then continue at Verify.
Option B, Install manually
Use this path when you can’t runbudctl. You create the repo by hand from the
files on this page. Replace production with your environment name,
bud.example.com with your domain, and
https://github.com/example-org/bud-foundry-config.git with your repo.
Step 1, Create your config repo
.gitignore, the age key and installer state must stay out of Git:
apps/production.yaml is the bootstrap “app of apps”, a single Application
that tells ArgoCD to apply your ApplicationSet from Git:
apps/production.yaml
appsets/production.yaml lists every component, its chart, version and
value files. Drop the kyverno element, and adjust the cert-manager value
files, if you are not using a self-signed or internal CA (see
TLS profiles).
appsets/production.yaml
appsets/production.yaml
appsets/production.yaml
bud.studio/control-plane nodes, the users and databases Bud
expects in each datastore, the Keycloak realm and clients, and the SeaweedFS
buckets. The passwords in them are placeholders that your
secrets.production.yaml files override.
values/argocd/values.budruntime.yaml
values/argocd/values.budruntime.yaml
values/argocd/values.budruntime.yaml
values/dapr/values.yaml
values/dapr/values.yaml
values/dapr/values.yaml
values/kafka/values.budruntime.yaml
values/kafka/values.budruntime.yaml
values/kafka/values.budruntime.yaml
values/mongodb/values.budruntime.yaml
values/mongodb/values.budruntime.yaml
values/mongodb/values.budruntime.yaml
values/cert-manager/values.budruntime.yaml
values/cert-manager/values.budruntime.yaml
values/cert-manager/values.budruntime.yaml
values/kyverno/values.budruntime.yaml
values/kyverno/values.budruntime.yaml
values/kyverno/values.budruntime.yaml
values/clickhouse/values.budruntime.yaml
values/clickhouse/values.budruntime.yaml
values/clickhouse/values.budruntime.yaml
values/postgres/values.budruntime.yaml
values/postgres/values.budruntime.yaml
values/postgres/values.budruntime.yaml
values/postgres/values.minimal.budruntime.yaml
values/postgres/values.minimal.budruntime.yaml
values/postgres/values.minimal.budruntime.yaml
values/seaweedfs/values.budruntime.yaml
values/seaweedfs/values.budruntime.yaml
values/seaweedfs/values.budruntime.yaml
values/valkey/values.yaml
values/valkey/values.yaml
values/valkey/values.yaml
values/valkey/values.minimal.yaml
values/valkey/values.minimal.yaml
values/valkey/values.minimal.yaml
values/valkey/values.budruntime.yaml
values/valkey/values.budruntime.yaml
values/valkey/values.budruntime.yaml
values/keycloak/values.budruntime.yaml
values/keycloak/values.budruntime.yaml
values/keycloak/values.budruntime.yaml
values/cert-manager/values.selfsigned-ca.yaml
and values/kyverno/values.inject-ca.yaml, are listed in full under
Self-signed or internal-CA TLS.
Step 2, Generate an age key and wire up SOPS
Generate a keypair for the environment (and optionally one per admin):.sops.yaml so the environment’s secrets files
encrypt to it:
argocd chart’s
sopsAgeKeys value, itself stored SOPS-encrypted:
secrets.*.yaml your ApplicationSet references is
decrypted transparently by the repo-server’s helm-secrets wrapper.
Step 3, Environment values
Your public overlays. The shared baseline already carries the defaults, so these stay small.values/argocd/values.production.yaml sets the ArgoCD hostname, registers
your repo, and creates the AppProject the ApplicationSet targets (the
projects key must match spec.template.spec.project):
values/argocd/values.production.yaml
values/bud/values.production.yaml is the platform’s cluster config;
everything else falls back to chart defaults. global.ingress.hosts.root is
the only host you set: every service sub-host (admin., app., auth.,
s3., …) derives from it. ingress.https: internal means cert-manager
issues the certificates and they terminate in-cluster; use external when an
upstream LB/WAF terminates TLS, or disabled for plain HTTP.
values/bud/values.production.yaml
buddoc, askbud, budpipeline,
…) can be trimmed with microservices.<name>.enabled: false for a
smaller footprint.
values/keycloak/values.production.yaml sets the auth host and the redirect
and logout URIs of the frontend clients:
values/keycloak/values.production.yaml
values/seaweedfs/values.production.yaml sets the S3 host and sizes the
model-registry bucket to match storage.budmodelRegistry.size:
values/seaweedfs/values.production.yaml
You only edit a handful of values. The bud chart’s defaults already point
the application at the in-cluster databases this guide deploys
(
pooler-rw.postgres, clickhouse-clickhouse.clickhouse,
mongodb-rs0.mongodb, valkey-master.valkey). Leave the
externalServices.*.host keys at their defaults, those are only changed for
the managed-database path in the Deployment Guide.Step 4, Secrets
Everysecrets.production.yaml the ApplicationSet references must exist:
argocd (from Step 2), kafka, mongodb, clickhouse, postgres,
seaweedfs, valkey, keycloak, bud and opensandbox (plus cert-manager
for an imported CA).
For the datastores and Keycloak, override the placeholder passwords from the
shared baseline: the users.*.password entries (postgres, clickhouse, kafka,
mongodb), identity.bud.accessKey/secretKey (seaweedfs), auth.password
(valkey), and the Keycloak client secrets and root user credentials.
For values/bud/secrets.production.yaml, the per-key reference, what each
secret is for and how to generate it, lives in the deployment guide; the set is
the same regardless of install method:
- Registry pull credentials
- Per-service secrets you must change
(admin login,
AES_KEY_HEX,PASSWORD_SALT, redirect-flow session/client secrets, RSA keypair, Dapr crypto keys, Novu secrets) - OIDC identity provider
Self-signed or internal-CA TLS
A public ACME issuer needs publicly resolvable hosts, so air-gapped and internal deployments issue certificates from a CA of their own instead. This takes two charts:cert-manager (with trust-manager) to issue the certificates and
publish a trust bundle, and kyverno to inject that bundle into the
platform’s pods. Without the injection the services do not trust the new CA,
and calls between them fail on certificate verification.
values/cert-manager/values.selfsigned-ca.yaml creates a 10-year
self-signed root, an issuer that signs from it, and a trust-manager Bundle
that distributes the root to workloads:
values/cert-manager/values.selfsigned-ca.yaml
selfsigned exists only to sign the root
Certificate, and selfsigned-ca (backed by that root) is what actually issues
the leaf certificates. The Bundle writes the public roots plus your own root
into a ca-pemstore ConfigMap in every namespace; Kyverno mounts it into pods
(see below), so nothing in the platform has to learn the certificate
individually. Clients outside the cluster (browsers, curl) will not trust
these certificates until you distribute the root from the selfsigned-ca-root
secret to their trust stores.
values/kyverno/values.inject-ca.yaml defines a Kyverno ClusterPolicy
that mutates every pod created in the bud and bud-* namespaces: it mounts
the ca-pemstore ConfigMap at /etc/ssl/certs/cafebabe-ca.pem and sets the
environment variables each runtime (OpenSSL, Node.js, Python, pip, curl, git)
uses to find a CA bundle:
values/kyverno/values.inject-ca.yaml
kyverno before the bud chart, or restart
the platform’s workloads once the policy is active. The bundle also ships a
PKCS#12 copy (cafebabe-ca.p12) for JVM trust stores.
Also trusting an existing internal CA? Add its certificate to the bundle’s
sources in a values/cert-manager/values.production.yaml, and list that file
after values.selfsigned-ca.yaml in the cert-manager element of the
ApplicationSet:
sources is a list, and Helm replaces lists rather than merging them, so
the overlay restates the two entries from values.selfsigned-ca.yaml and
appends the third. This only adds the internal CA to what the cluster
trusts. To have that CA issue the certificates as well, store its
certificate and key in a secret (in secrets.production.yaml), point an issuer
at it (issuers.<name>.ca.secretName, the same shape as selfsigned-ca), and
set cert-manager.ingressShim.defaultIssuerName to that issuer.
Public ACME instead. Drop
values.selfsigned-ca.yaml and the kyverno
element, define an ACME issuer under issuers: in
values/cert-manager/values.production.yaml, and set
cert-manager.ingressShim.defaultIssuerName to it. With an HTTP-01 issuer every
ingress host must be publicly resolvable and reachable on port 80; a DNS-01
issuer needs a DNS-provider API token in secrets.production.yaml. If certs
stay Ready=False, check kubectl -n bud describe certificate <name> and
kubectl -n bud get challenge.Step 5, Bootstrap ArgoCD
The ApplicationSet manages ArgoCD itself (theproduction-argocd Application),
but the very first install must come from your machine: ArgoCD cannot decrypt
your secrets until the chart has delivered the age key. Install the argocd
chart with the same value files its ApplicationSet element references. The
release name must be argocd so the Application adopts it afterwards:
production-argocd completes (Step 6), ArgoCD is
self-managed: future ArgoCD upgrades are a targetRevision bump in your
ApplicationSet.
Step 6, Apply the bootstrap Application and sync
argocd CLI) and sync:
bootstrap, appliesappsets/production.yaml, which generates theproduction-*Applications.production-argocd, adopts the Helm install from Step 5.- The addons (
production-dapr,production-cert-manager,production-kyverno,production-postgres,production-clickhouse,production-kafka,production-mongodb,production-seaweedfs,production-valkey), a few may showDegradeduntil their operators’ CRDs establish; re-sync and they converge. production-keycloak, thenproduction-budandproduction-opensandboxlast, once the databases are up.
automated (see
How it works).
Verify
Running within ~5–10 minutes of the Applications
going Healthy. Backend pods run a Dapr sidecar, so expect 2/2 READY for most
of them.
Optional add-ons
Add one to your environment by appending an element toappsets/<environment>.yaml (name, namespace, repoURL
registry.bud.studio/charts, chart, targetRevision, valueFiles), exactly
like the required ones.
Storage is still required, just not from
openebs. The databases need a
working StorageClass either way. openebs is one way to provide it; a cloud
CSI driver is another. Set storage.budmodelRegistry.className (Step 3) to
whichever your cluster offers.Post-installation
Openhttps://admin.<your-domain> (e.g. https://admin.bud.example.com) and log
in with the SUPER_USER_EMAIL / SUPER_USER_PASSWORD from
values/bud/secrets.<environment>.yaml (with budctl, the email is the
--admin-email you passed).
With the self-signed TLS profile, browsers will not trust the certificates until
you import the root from the selfsigned-ca-root secret in the cert-manager
namespace.
Upgrading
Bump the element’stargetRevision in appsets/<environment>.yaml (e.g. bud
to a new chart version), commit, and sync.
Uninstalling
Common pitfalls
- An Application errors with
Error decrypting/ helm-secrets failures, the age key invalues/argocd/secrets.<environment>.yaml(sopsAgeKeys) does not match the recipients yoursecrets.*.yamlfiles were encrypted to. Re-check.sops.yamland re-encrypt (sops updatekeys <file>). - Addon Applications stuck
Degradedon first sync, usually the operator CRDs not yet established. Re-sync after a minute; the ApplicationSet usesServerSideApply=trueso large CRDs apply cleanly. - Backend pods crash-loop on DB connection, almost always a password
mismatch between a datastore’s secrets and
values/bud/secrets.<environment>.yaml(see the warning in Step 4). - Service-to-service calls fail certificate verification with a self-signed
or internal CA, the Kyverno policy only mutates pods created after it is
active. Sync
kyvernofirst, then restart thebudworkloads. registries.registry.bud.studiocredentials are required even on clusters that mirror images locally, the chart still creates the imagePullSecret referenced by every Deployment.budmetricsClickHouse database name must bemetrics, it is hardcoded. See the Deployment Guide.
Next steps
Deployment Guide
Per-service secret & config reference; managed-database install path.
Helm Configuration
Full list of chart values and overrides.