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

# Azure Kubernetes Service

> Deploy Bifrost to an existing Azure Kubernetes Service cluster

This guide deploys Bifrost to an existing AKS cluster using the Helm chart. It covers the Bifrost image, secrets, storage, database connection, service exposure, verification, and scaling.

<Note>
  The Helm configuration is validated in the repository. The complete guide is not continuously exercised in a live Azure subscription, so test the selected values in a non-production cluster before rollout.
</Note>

## Bifrost on AKS

| Bifrost setting   | AKS configuration                                                                                                                           |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| Container         | OSS or supplied Enterprise image on `linux/amd64` or `linux/arm64` Linux nodes                                                              |
| HTTP and health   | `ClusterIP` Service on `8080/TCP`; `GET /health`                                                                                            |
| SQLite (OSS only) | One replica and a `ReadWriteOnce` managed disk or another compatible CSI volume                                                             |
| PostgreSQL        | PostgreSQL 16 or later reachable from the cluster, inside or outside Azure                                                                  |
| External access   | Gateway API, ingress, Service `LoadBalancer`, service mesh, Application Gateway, or external proxy                                          |
| Enterprise mesh   | Kubernetes discovery plus bidirectional `10101/TCP+UDP` and `10102/TCP`                                                                     |
| Image pull        | Public Docker Hub for OSS; customer Enterprise registry federation/pull secret from [Enterprise Azure](/deployment-guides/enterprise/azure) |

Bifrost Enterprise requires PostgreSQL 16 or later for both stores and does not support SQLite. The SQLite path below is available only for OSS deployments.

## Deploy Bifrost

The commands below use an existing AKS cluster and PostgreSQL database. Run them from Bash after replacing every value inside angle brackets.

### Step 1: Connect to AKS

```bash theme={null}
export AZURE_RESOURCE_GROUP='<AZURE_RESOURCE_GROUP>'
export AKS_CLUSTER='<AKS_CLUSTER_NAME>'
export BIFROST_VERSION='<BIFROST_VERSION>'
az aks get-credentials \
  --resource-group "${AZURE_RESOURCE_GROUP}" \
  --name "${AKS_CLUSTER}"

kubectl get nodes
helm version
```

Continue only after the nodes report `Ready`.

### Step 2: Create secrets and Helm values

The encryption key protects persisted credentials. Create it once, keep it unchanged after Bifrost writes encrypted data, and use the same value for every replica. Replacing the key makes existing encrypted values unreadable.

```bash theme={null}
kubectl create namespace bifrost \
  --dry-run=client -o yaml | kubectl apply -f -

read -r -s -p 'Stable Bifrost encryption key: ' BIFROST_ENCRYPTION_KEY; echo
kubectl create secret generic bifrost-encryption \
  --namespace bifrost \
  --from-literal=encryption-key="${BIFROST_ENCRYPTION_KEY}" \
  --dry-run=client -o yaml | kubectl apply -f -
unset BIFROST_ENCRYPTION_KEY
```

Choose the storage configuration for this deployment:

<Tabs>
  <Tab title="PostgreSQL">
    ```bash theme={null}
    export POSTGRES_HOST='<POSTGRES_HOST>'
    export POSTGRES_PORT='5432'
    export POSTGRES_USER='<POSTGRES_USER>'
    export POSTGRES_DATABASE='<POSTGRES_DATABASE>'

    read -r -s -p 'PostgreSQL password: ' POSTGRES_PASSWORD; echo
    kubectl create secret generic postgres-credentials \
      --namespace bifrost \
      --from-literal=password="${POSTGRES_PASSWORD}" \
      --dry-run=client -o yaml | kubectl apply -f -
    unset POSTGRES_PASSWORD

    cat > bifrost-values.yaml <<EOF
    image:
      repository: docker.io/maximhq/bifrost
      tag: "${BIFROST_VERSION}"

    replicaCount: 1

    storage:
      mode: postgres

    postgresql:
      enabled: false
      external:
        enabled: true
        host: "${POSTGRES_HOST}"
        port: ${POSTGRES_PORT}
        user: "${POSTGRES_USER}"
        database: "${POSTGRES_DATABASE}"
        sslMode: require
        existingSecret: postgres-credentials
        passwordKey: password

    bifrost:
      encryptionKeySecret:
        name: bifrost-encryption
        key: encryption-key
    EOF
    ```

    This uses PostgreSQL for both Bifrost stores and does not create a Bifrost SQLite PVC. Enterprise customers should replace the image settings and registry authentication using the values supplied by Maxim.

    Azure Database for PostgreSQL is one Azure-hosted option. The database may instead be operated by the customer or another provider as long as the cluster can reach it.

    Verify connectivity from the cluster before installing Bifrost:

    ```bash theme={null}
    kubectl run postgres-check --namespace bifrost \
      --image=postgres:16-alpine --restart=Never \
      --env="PGHOST=${POSTGRES_HOST}" --env="PGPORT=${POSTGRES_PORT}" \
      --env="PGDATABASE=${POSTGRES_DATABASE}" --env="PGUSER=${POSTGRES_USER}" \
      --env="PGSSLMODE=require" \
      --command -- sleep 3600

    kubectl wait --namespace bifrost --for=condition=Ready pod/postgres-check --timeout=2m
    kubectl exec --namespace bifrost -it postgres-check -- psql \
      -c "SHOW server_version;" \
      -c "SHOW server_encoding;"
    kubectl delete pod --namespace bifrost postgres-check
    ```

    Enter the PostgreSQL password when psql prompts. A successful connection confirms DNS, TCP, TLS, and database authentication from the pod network. Confirm that `server_version` reports PostgreSQL 16 or later and `server_encoding` reports `UTF8`.
  </Tab>

  <Tab title="SQLite (OSS only)">
    This option is available only for OSS Bifrost. Use SQLite for a single replica and select a compatible ReadWriteOnce StorageClass such as an approved managed-disk CSI class.

    ```bash theme={null}
    kubectl get storageclass

    cat > bifrost-values.yaml <<EOF
    image:
      repository: docker.io/maximhq/bifrost
      tag: "${BIFROST_VERSION}"

    replicaCount: 1

    storage:
      mode: sqlite
      persistence:
        enabled: true
        accessMode: ReadWriteOnce
        size: 10Gi
        storageClass: "<STORAGE_CLASS>"

    bifrost:
      encryptionKeySecret:
        name: bifrost-encryption
        key: encryption-key
    EOF
    ```

    Replace `<STORAGE_CLASS>` with a class returned by `kubectl get storageclass`. This creates persistent `/app/data` storage for the OSS SQLite deployment. PostgreSQL is not required for this OSS option.
  </Tab>
</Tabs>

### Step 3: Install Bifrost

```bash theme={null}
helm repo add bifrost https://maximhq.github.io/bifrost/helm-charts
helm repo update

helm upgrade --install bifrost bifrost/bifrost \
  --namespace bifrost \
  --values bifrost-values.yaml \
  --atomic \
  --timeout 15m
```

### Step 4: Verify and access Bifrost

```bash theme={null}
kubectl wait --namespace bifrost \
  --for=condition=Ready pod \
  --selector=app.kubernetes.io/name=bifrost \
  --timeout=10m

kubectl get pods,service --namespace bifrost
```

Choose how you want to access the deployment:

<Tabs>
  <Tab title="Without a load balancer">
    ```bash theme={null}
    kubectl port-forward service/bifrost --namespace bifrost 8080:8080
    ```

    Keep that terminal open. In another terminal:

    ```bash theme={null}
    curl --fail --show-error http://127.0.0.1:8080/health
    ```
  </Tab>

  <Tab title="With a load balancer">
    ```bash theme={null}
    cat >> bifrost-values.yaml <<'EOF'

    service:
      type: LoadBalancer
    EOF

    helm upgrade bifrost bifrost/bifrost \
      --namespace bifrost \
      --values bifrost-values.yaml \
      --atomic \
      --timeout 15m

    kubectl get service bifrost --namespace bifrost --watch
    ```

    After `EXTERNAL-IP` displays an address, stop the watch and run:

    ```bash theme={null}
    export BIFROST_HOST="$(kubectl get service bifrost \
      --namespace bifrost \
      -o jsonpath='{.status.loadBalancer.ingress[0].hostname}{.status.loadBalancer.ingress[0].ip}')"

    curl --fail --show-error "http://${BIFROST_HOST}:8080/health"
    ```

    This creates an HTTP endpoint. Configure TLS through the selected Azure or Kubernetes frontend before exposing Bifrost to untrusted clients.

    <Note>
      AKS-managed Azure Load Balancers use a 30-minute TCP idle timeout by default. For streams that might remain idle longer, configure TCP keepalive or adjust the load balancer idle timeout.
    </Note>
  </Tab>

  <Tab title="With ingress">
    This example uses the [AKS application-routing add-on](https://learn.microsoft.com/en-us/azure/aks/app-routing). Enable the add-on before applying these values.

    ```bash theme={null}
    cat > ingress-values.yaml <<'EOF'
    service:
      type: ClusterIP

    ingress:
      enabled: true
      className: webapprouting.kubernetes.azure.com
      annotations:
        nginx.ingress.kubernetes.io/proxy-buffering: "off"
        nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
        nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
        nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
      hosts:
        - host: "<BIFROST_HOSTNAME>"
          paths:
            - path: /
              pathType: Prefix
    EOF

    helm upgrade bifrost bifrost/bifrost \
      --namespace bifrost \
      --values bifrost-values.yaml \
      --values ingress-values.yaml \
      --atomic \
      --timeout 15m

    kubectl get ingress --namespace bifrost --watch
    ```

    Point the hostname to the ingress address, configure TLS through the application-routing add-on or another certificate integration, and verify `https://<BIFROST_HOSTNAME>/health`.
  </Tab>
</Tabs>

## Scale Bifrost

* OSS with SQLite: one replica.
* OSS with database-managed configuration: one replica, or use [file-only OSS multinode](/deployment-guides/how-to/multinode).
* Enterprise: PostgreSQL plus [Cluster Mode and HA](/deployment-guides/helm/cluster), pod-discovery RBAC, and internal mesh ports.

Azure load balancing distributes requests but does not synchronize Bifrost state.

## Upgrade, troubleshooting, and production

Follow the [upgrade guidance](/deployment-guides/runtime-contract#upgrade-bifrost). Diagnose with:

```bash theme={null}
kubectl describe pod --namespace bifrost -l app.kubernetes.io/name=bifrost
kubectl get events --namespace bifrost --sort-by=.lastTimestamp
kubectl describe pvc --namespace bifrost
kubectl logs --namespace bifrost -l app.kubernetes.io/name=bifrost --tail=200
```

* Pending OSS SQLite pod: inspect the PVC, CSI driver, StorageClass, and zone/node-pool constraints.
* `ImagePullBackOff`: verify the image repository/tag and Enterprise registry token refresh.
* `/health` `503`: verify configured stores from the pod network and inspect startup logs.
* Fixed streaming cutoff: inspect all ingress, gateway, and Azure frontend timeouts/buffering.
* Missing Enterprise nodes: check pod-discovery RBAC and bidirectional cluster ports.

Complete the [deployment verification checklist](/deployment-guides/runtime-contract#verify-the-deployment) for database availability, backups, TLS, secrets, autoscaling, and monitoring. See [Enterprise clustering](/enterprise/clustering) when the deployment spans several clusters or regions.
