> ## Documentation Index
> Fetch the complete documentation index at: https://docs.budecosystem.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Installation Guide

> Install Bud-Stack on Kubernetes with ArgoCD (GitOps) using the published OCI Helm charts

This guide installs the **complete Bud-Stack platform** — the application
plus its in-cluster dependencies (PostgreSQL, ClickHouse, Kafka, MongoDB,
Valkey, SeaweedFS, observability) — into an existing Kubernetes cluster
using **ArgoCD**. ArgoCD pulls every chart from the OCI registry, so you do
**not** need access to the source repository.

<Note>
  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](/developer-docs/deployment)
  — it installs only the `bud` chart pointed at your external services.
</Note>

## How it works

You apply two ArgoCD **ApplicationSets**, both sourcing charts from
`oci://registry.bud.studio/charts`:

| ApplicationSet   | Deploys                                                                                          | Namespace(s)      |
| ---------------- | ------------------------------------------------------------------------------------------------ | ----------------- |
| `cluster-addons` | dapr, cert-manager, cert-manager-issuer, postgres, clickhouse, kafka, mongodb, valkey, seaweedfs | one per addon     |
| `prod-apps`      | keycloak, **bud** (the platform)                                                                 | `keycloak`, `bud` |

The chart comes from the registry; your configuration (`values.yaml` + secrets)
comes from a source you control — a small **config repo** (recommended),
**inline** values, or the **CLI** ([Step 3](#step-3-mdash-choose-how-to-supply-configuration)).
Nothing proprietary lives in your config, and you never need credentials to
`bud-runtime`.

<Note>
  **Ordering.** The addon charts install operators (CloudNativePG, Strimzi,
  Altinity, Percona, …) whose CRDs must exist before the database
  custom-resources can apply. The charts do **not** use ArgoCD sync-waves;
  instead ArgoCD's `automated` + `selfHeal` sync policy **retries** failed syncs
  until each operator establishes its CRDs and the dependent resources converge.
  Expect a few Applications to show `Degraded`/`Progressing` on the first pass and
  self-heal within a few minutes — this is normal.
</Note>

## Prerequisites

| Requirement            | Notes                                                                                                                  |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Kubernetes 1.25+       | With a default `StorageClass` for PVCs                                                                                 |
| `kubectl`, `helm` 3.8+ | Helm must support OCI registries                                                                                       |
| ArgoCD installed       | You bootstrap it yourself (Step 2). Bud does not manage your ArgoCD.                                                   |
| Ingress controller     | Chart Ingresses default to `ingressClassName: traefik`                                                                 |
| Registry credentials   | Robot account for `registry.bud.studio`                                                                                |
| A config source        | A git repo you own (recommended) **or** inline values — see [Step 3](#step-3-mdash-choose-how-to-supply-configuration) |

## Step 1 — Get registry credentials

You need a read-only robot account for `registry.bud.studio` to let **both**
ArgoCD (chart pulls) and your cluster (image pulls) authenticate.

```bash theme={null}
helm registry login registry.bud.studio -u 'robot$yourname'
# password prompt — quote the username so the shell does not expand the $
```

## Step 2 — Install ArgoCD

If you don't already run ArgoCD, install it (any supported method works):

```bash theme={null}
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
```

Then register the OCI registry as a Helm repository credential so ArgoCD can
pull the charts:

```bash theme={null}
kubectl apply -n argocd -f - <<'EOF'
apiVersion: v1
kind: Secret
metadata:
  name: bud-charts-repo
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: repository
stringData:
  type: helm
  url: registry.bud.studio/charts
  enableOCI: "true"
  username: robot$yourname
  password: <token>
EOF
```

## Step 3 — Choose how to supply configuration

ArgoCD needs your `values.yaml` (Step 4) and `secrets.yaml` (Step 5). There are
three ways to provide them; pick based on **where your secrets end up**.

| Option                            | How                                                 | Secrets land in…                  | Use for                                                                   |
| --------------------------------- | --------------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------- |
| **Config git repo** (recommended) | A repo you own, joined to the chart with `$values`  | A repo (encryptable with SOPS)    | Real installs                                                             |
| **Inline `valuesObject`**         | Values written directly in the Application manifest | The manifest & etcd, in plaintext | Quick / demo, **non-secret** values only                                  |
| **CLI `--values`**                | `argocd app set <app> --values …` from your machine | ArgoCD's DB only (not git)        | Imperative single-Application flow, **not** the ApplicationSet flow below |

<Warning>
  **Why the repo is recommended.** The bud chart renders its own Kubernetes
  Secrets from the values you pass in, so DB passwords, the RSA private key, the
  registry token and OIDC secrets travel in the values stream. With **inline
  `valuesObject`** those secrets sit in plaintext inside the Application manifest
  and in etcd — and inline `valuesObject` also has
  [known bugs](https://github.com/argoproj/argo-cd/issues/17288) when used inside a
  templated ApplicationSet. Keep **secrets** in a private repo (optionally
  SOPS-encrypted). Inline is fine for the **non-secret** `values.yaml` if you
  prefer not to run a repo — see the note at the end of Step 6.
</Warning>

### Recommended: a config repo

The fastest start is to **fork the example repo**,
[`BudEcosystem/example-bud-foundry-config`](https://github.com/BudEcosystem/example-bud-foundry-config)
— it already contains the two ApplicationSets and the config layout this
guide uses:

```
example-bud-foundry-config/
└── argocd/
    ├── cluster-addons.yaml      # ApplicationSet (Step 6)
    ├── prod-apps.yaml           # ApplicationSet (Step 6)
    ├── bud/
    │   ├── values.yaml          # cluster config: ingress host, storage class
    │   └── secrets.example.yaml # copy to secrets.yaml, then fill in (Step 5)
    └── keycloak/
        └── values.yaml
```

After forking, set the `ref: values` source's `repoURL` in both ApplicationSets
to **your fork**, then edit the files under `argocd/`. The ApplicationSets
reference these via `$values`, which resolves to the **repo root** — hence
the paths are `$values/argocd/<app>/values.yaml`. Keep your fork **private** if
it will hold a real `secrets.yaml`.

<Note>
  **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](/developer-docs/deployment).
</Note>

## Step 4 — Cluster configuration (`argocd/bud/values.yaml`)

The mandatory non-secret values. Everything else falls back to chart defaults.

```yaml theme={null}
global:
  ingress:
    hosts:
      # Set ONLY this — all service sub-hosts derive from it.
      root: "bud.yourdomain.com"

ingress:
  enabled: true
  # internal = cert-manager issues + Traefik terminates TLS in-cluster (most setups).
  # external = an upstream LB/WAF terminates TLS; NO certs are issued in-cluster.
  # disabled = plain HTTP.
  https: internal          # external | internal | disabled

storage:
  budmodelRegistry:
    className: "fast-ssd"   # a StorageClass in your cluster — no safe default
    size: 300Gi            # size for the models you plan to host
```

See the [Deployment Guide → Cluster-level config](/developer-docs/deployment#step-4-mdash-application-secrets-amp-cluster-config)
for the full list of ingress/storage options.

<Note>
  **TLS with `https: internal`.** The chart annotates its Ingresses with
  `kubernetes.io/tls-acme: "true"`, which cert-manager's ingress-shim resolves to
  its default ClusterIssuer **`letsencrypt-http01`** — created by the
  **`cert-manager-issuer`** addon (in `cluster-addons`, so make sure it's enabled).
  That issuer uses the **HTTP-01** challenge, so every ingress host (`admin.<root>`,
  `app.<root>`, `gateway.<root>`, …) must be **publicly resolvable and reachable on
  port 80** for certificates to issue. If certs stay `Ready=False`, check
  `kubectl -n bud describe certificate <name>` and `kubectl -n bud get challenge`.
</Note>

## Step 5 — Application secrets (`argocd/bud/secrets.yaml`)

These are required for a new install and are **not** wired to external hosts.
The per-key reference — what each secret is for and how to generate it
— lives in the deployment guide; this is the same set regardless of
install method:

* [Registry pull credentials](/developer-docs/deployment#registry-pull-credentials)
* [Per-service secrets you must change](/developer-docs/deployment#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](/developer-docs/deployment#oidc-identity-provider)

<Warning>
  **Database password consistency.** Because the databases run **in-cluster**,
  the password you set for, say, Postgres in `argocd/bud/secrets.yaml` must match the
  password the `postgres` addon provisions the user with. Set each database
  password once and reference the **same value** in both the addon's config and
  `argocd/bud/secrets.yaml`. A mismatch shows up as backend pods failing to connect
  after they start.
</Warning>

<Note>
  **Storing secrets.** The simplest path is a `secrets.yaml` in a **private**
  config repo. To avoid plaintext secrets in git, encrypt the file with SOPS and
  enable the helm-secrets plugin in your ArgoCD — this is optional hardening,
  not required to get a working install.
</Note>

## Step 6 — Apply the ApplicationSets

The two ApplicationSets ship in your fork at `argocd/cluster-addons.yaml` and
`argocd/prod-apps.yaml`. `cluster-addons` deploys the required in-cluster
dependencies (dapr, cert-manager, cert-manager-issuer, postgres, clickhouse, kafka,
mongodb, valkey, seaweedfs); `prod-apps` deploys keycloak and the `bud` platform in a later
sync-wave. Each joins its OCI chart to your config via `$values`. (Storage and
observability add-ons are **optional** — see
[Optional add-ons](#optional-add-ons).)

```yaml theme={null}
# excerpt from argocd/prod-apps.yaml
      sources:
        - repoURL: registry.bud.studio/charts        # the chart (OCI)
          chart: "{{.name}}"
          targetRevision: "{{.version}}"             # bud 0.14.2, deps 0.1.0
          helm:
            valueFiles:
              - "$values/argocd/{{.name}}/values.yaml"
              - "$values/argocd/{{.name}}/secrets.yaml"
            ignoreMissingValueFiles: true
        - repoURL: https://github.com/YOUR_ORG/example-bud-foundry-config  # ← your fork
          targetRevision: main
          ref: values
```

Make sure the `ref: values` `repoURL` in **both** files points at your fork
(see [Step 3](#step-3-mdash-choose-how-to-supply-configuration)), then apply:

```bash theme={null}
kubectl apply -f argocd/cluster-addons.yaml
kubectl apply -f argocd/prod-apps.yaml
```

ArgoCD now reconciles everything. The addons converge first; the operators may
cause a few transient `Degraded` states that self-heal (see
[How it works](#how-it-works)). `prod-apps` is annotated to apply after the
addons.

<Note>
  **No config repo? Inline the non-secret values.** If you'd rather not fork a
  config repo, drop the second (`ref: values`) source and the `$values/...`
  `valueFiles`, and inline the non-secret `values.yaml` with `valuesObject`
  instead:

  ```yaml theme={null}
        sources:
          - repoURL: registry.bud.studio/charts
            chart: bud
            targetRevision: "0.14.2"
            helm:
              releaseName: bud
              valuesObject:
                global:
                  ingress:
                    hosts:
                      root: "bud.yourdomain.com"
                storage:
                  budmodelRegistry:
                    className: "fast-ssd"
  ```

  Keep **secrets** out of the manifest — pre-create them as Kubernetes
  Secrets the chart consumes, or use the repo path for `secrets.yaml`. Inline
  `valuesObject` is best used in a single **Application** (not a templated
  ApplicationSet) to avoid the templating
  [caveats](https://github.com/argoproj/argo-cd/issues/17288) noted in Step 3.
</Note>

## Step 7 — Verify

```bash theme={null}
# Watch ArgoCD reconcile every Application to Synced / Healthy
kubectl get applications -n argocd

# Once healthy, check the platform pods
kubectl -n bud get pods
kubectl -n bud get ingress
```

All pods should reach `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

These charts are published alongside the required ones but are **not** part of
the base install — whether you need them depends on your cluster and your
operational preferences. To enable one, add it to `cluster-addons.yaml` (an
element `{ name: <addon>, namespace: <addon> }`) just like a required addon.

| Add-on    | What it provides                                                              | When you need it                                                                                                                                             |
| --------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `openebs` | A storage provisioner / `StorageClass` (Mayastor, LVM, ZFS, hostpath)         | **Only if your cluster has no `StorageClass`** — e.g. bare metal with raw disks. Managed clusters (EKS/AKS/GKE) already provide one; skip it.                |
| `otel`    | OpenTelemetry **operator** + a node-level collector for cluster/infra metrics | Infra-level observability only. The platform ships its **own** app-telemetry collector (traces/metrics → ClickHouse), so the application works without this. |
| `signoz`  | Observability dashboards UI (traces, logs, metrics)                           | A console for viewing telemetry. Nothing in the platform depends on it.                                                                                      |

<Note>
  **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.*.className` (Step 4) to whichever your
  cluster offers.
</Note>

## Post-installation

Navigate to your configured domain (e.g. `https://admin.bud.yourdomain.com`) and
log in with the `SUPER_USER_EMAIL` / `SUPER_USER_PASSWORD` you set in
`argocd/bud/secrets.yaml`.

## Upgrading

Bump `targetRevision` in the ApplicationSet (e.g. the `bud` element to a new
chart version) and commit. ArgoCD rolls out the change on its next sync.

## Uninstalling

```bash theme={null}
kubectl delete -f argocd/prod-apps.yaml
kubectl delete -f argocd/cluster-addons.yaml
# Optionally remove namespaces and PVCs
kubectl delete namespace bud keycloak postgres clickhouse kafka mongodb valkey seaweedfs dapr-system cert-manager
# plus any optional add-on namespaces you enabled: openebs otel signoz
```

## Common pitfalls

* **`kubectl apply` of an ApplicationSet fails with `no matches for kind
  "ApplicationSet"`** — your ArgoCD install registered the `Application`
  CRD but not the `ApplicationSet` one (some install variants split them).
  Install the CRD for **your ArgoCD version**, and use **`--server-side`** —
  the CRD's schema exceeds the 256 KB `last-applied-configuration`
  annotation limit, so a plain `kubectl apply` errors with
  `metadata.annotations: Too long`:
  ```bash theme={null}
  kubectl apply --server-side -f \
    https://raw.githubusercontent.com/argoproj/argo-cd/<version>/manifests/crds/applicationset-crd.yaml
  ```
* **Addon Applications stuck `Degraded` on first sync** — usually the
  operator CRDs not yet established. ArgoCD `selfHeal` retries; give it a few
  minutes. If it persists, sync the operator's Application manually first.
* **Backend pods crash-loop on DB connection** — almost always a
  database password mismatch between the addon and `argocd/bud/secrets.yaml` (see the
  Step 5 warning).
* **`registries.registry.bud.studio` credentials are required** even on
  clusters that mirror images locally — the chart still creates the
  imagePullSecret referenced by every Deployment.
* **`budmetrics` ClickHouse database name must be `metrics`** — it is
  hardcoded. See the [Deployment Guide](/developer-docs/deployment#clickhouse).

## Next steps

<CardGroup cols={2}>
  <Card title="Deployment Guide" icon="cloud-arrow-up" href="/developer-docs/deployment">
    Per-service secret & config reference; managed-database install path.
  </Card>

  <Card title="Helm Configuration" icon="gear" href="/developer-docs/helm-configuration">
    Full list of chart values and overrides.
  </Card>
</CardGroup>
