Installation
The Avatar platform is packaged as a Helm chart, so it can be deployed into a Kubernetes cluster you already operate. All the architecture components — the API, the web client, the Dask scheduler and workers, the object store and the Authentik identity provider — are installed by that single chart.
Follow the steps below to deploy the Avatar platform into your cluster.
The chart deliberately does not create cluster infrastructure. It expects an ingress controller, a StorageClass, a PostgreSQL server and pull credentials to exist already, and it creates everything that runs on top of them — including the Avatar and Authentik databases. The prerequisites below list the split in full.
Cluster prerequisites
Go through the requirements shared by both self-hosted paths, then check that everything in this list exists before you install.
- Kubernetes cluster
- An ingress-nginx controller, with a LoadBalancer (or NodePort, or MetalLB) in front of it
- A default
StorageClass— the object store runs as StatefulSets with PersistentVolumeClaims - A CNI that enforces
NetworkPolicy(Calico, Cilium, …), if you want network isolation -
kubectlandhelm(v3) configured against the cluster
- Network and TLS configuration
- A domain name pointing at the load balancer. Every public URL the chart hands the API, the web client and Authentik is derived from this one name.
- A
kubernetes.io/tlsSecret holding the certificate for that domain, in the release namespace. The chart never creates it. - If that certificate was issued by a private or internal Certificate Authority, the CA
certificate itself — it has to be passed to the API as
api.caBundle, or logins fail - An SMTP server reachable from the cluster, for password resets and invitations
- Octopize has provided you with your quay.io credentials
- Database
- A PostgreSQL server reachable from the cluster
- An administrative account on it. Both the Avatar database and Authentik's are created for you, using that account.
- Network
- The flows listed in the shared Requirements are open.
The Helm chart artifact is pulled from
quay.ioas well.
- The flows listed in the shared Requirements are open.
The Helm chart artifact is pulled from
What the chart creates for you
- The Avatar database, its role, its tables and the first organization.
- Authentik's role, its database and its extensions. Set
authentikDatabase.createDatabase: falseif a DBA has already created them. - The object store, when
seaweedfs.enabledis true. - The Ingress objects and every public URL handed to the API, the web client and Authentik.
On the database side you supply a server and an admin account, and nothing else.
If you run an ingress controller other than ingress-nginx, set ingress.enabled: false and create
your own Ingress objects. The URLs stay the same either way.
Container images
The images and their sizes are listed in Requirements.
The avatar-service-api and avatar-web images are private, and so is avatar-connector if
you enable the database connector. Octopize provides you with the
quay.io credentials upon contract signature; the chart takes them as a base64-encoded Docker
config.json in imageCredentials.dockerConfigJson, and creates the docker-local-pull-secret
Secret from it:
base64 -w0 < ~/.docker/config.json
Prepare a values file
The chart ships a complete, working example values file. Pull the chart and copy it:
helm pull oci://quay.io/octopize/helm/services-api/avatar --version <version> --untar
cp avatar/example-values.yaml my-values.yaml
Every PLACEHOLDER_ in that file has to be replaced, and each one carries the command that
generates it.
The archive also contains a script that makes the credentials for you. Run it, and give the file that it writes to Helm after your own values file:
cd avatar && bash scripts/generate-secrets.sh
Use bash, and not ./. Helm packages each file with mode 0644, so the copy in the archive is not
executable. Helm obeys the last --values file, so avatar-secrets.yaml replaces these keys in
my-values.yaml. Keep the keys out of my-values.yaml, give the generated file to each upgrade,
and keep it. See
Generating the secrets.
The script does not make the values that belong to your own infrastructure. You still set these yourself. At a minimum, set:
| Value | What it is |
|---|---|
ingress.host | The domain the platform is served on |
ingress.tls.secretName | An existing kubernetes.io/tls Secret for that domain |
imageCredentials.dockerConfigJson | base64 of a Docker config.json with quay.io/octopize credentials |
api.image.tag | The API image tag |
web.image.tag | The web client image tag |
database.host / database.port | Your PostgreSQL server |
database.adminUsername / database.adminPassword | Admin credentials, used once to create the databases |
api.config.organizationName | Your organization's name |
smtp.host and the other SMTP values | Your SMTP server |
See Configuration for the full values reference.
For a namespace enforcing the restricted Pod Security Standard, apply the
example-values-restricted.yaml overlay on top of your own file with a second --values — see
Restricted Pod Security Standard.
dask.scheduler.image.taganddask.worker.image.tagmust equalapi.image.tag.storage.sseKekis generated once and never changed. When migrating an existing SeaweedFS, copy the value out of the old filer — see SeaweedFS encryption. Write it intoavatar-secrets.yamlif you used the script, because Helm obeys that file last.
You set the four sso values one time. The API authenticates with clientId and clientSecret,
and the bundled Authentik blueprint registers the same OAuth provider. apiToken and
webhookSecret revoke the API keys of a user that you disable or delete in Authentik. Helm cannot
write into the values of a subchart, so the AVATAR_AUTHENTIK_BLUEPRINT_* entries under
authentik.global.env refer to the objects that the chart writes these four values into. Leave
those entries as example-values.yaml has them. See SSO.
api.caBundleIf your domain's certificate was issued by an internal or self-signed authority, every login fails
with CERTIFICATE_VERIFY_FAILED until you set
api.caBundle.
Install
helm install avatar oci://quay.io/octopize/helm/services-api/avatar \
--version <version> \
--namespace avatar --create-namespace \
--values my-values.yaml
A missing required value fails the render with a message naming it, so an install that reports success has at least been given a complete configuration. The chart then prints the routing table for the deployment.
Watch it come up
kubectl -n avatar get pods -w
The Authentik pods sit in Init:0/1 until their database answers. That is the wait-for-db init
container doing its job, not a hang — read the bootstrap Job's logs to see where it is:
kubectl -n avatar get jobs
kubectl -n avatar logs job/avatar-authentik-db-init-<chart-version>
The Job is cleaned up after it finishes (authentikDatabase.ttlSecondsAfterFinished), so read its
logs while it is still there.
Create the first Authentik admin
An install where nobody has been through this flow has an identity provider nobody can administer.
Unlike the Docker installation, the chart does not set the
AUTHENTIK_BOOTSTRAP_* variables — Octopize does
not hold your identity provider's admin credential. Go through Authentik's own flow instead:
https://<ingress.host>/sso/if/flow/initial-setup/
Set the akadmin password there. That account then administers users, groups and the OAuth
provider the Avatar API talks to — see
User management.
Do it promptly: until you do, the flow is reachable by anyone who can reach the deployment. It stops working once the first admin exists.
Log in
Browse to https://<ingress.host>/web. You are sent to Authentik to log in, and land back in the
Avatar interface.
Next steps
Once the stack is running, confirm everything is healthy by following the Verification & Troubleshooting guide.
To let your users copy and anonymize databases with database runs, enable the database connector. It is off by default.
Trying it out on a local cluster
For an evaluation, the same values file installs on a single-node cluster — minikube, kind, k3s — with a handful of changes. There is nothing Avatar-specific about them; they are what a laptop cannot provide:
- Enable an ingress controller and a default StorageClass. On minikube:
minikube addons enable ingress default-storageclass storage-provisioner. - Point
ingress.hostat a name that resolves to the cluster —<cluster-ip>.nip.ioworks without touching DNS. - Set
ingress.tls.enabled: falseand leaveingress.tls.secretNameempty. Every URL then useshttp://— fine for an evaluation, never for production. - Run a PostgreSQL in the cluster and point
database.hostat its Service. - Point the SMTP values at a local mail catcher. Mail has to work even locally, or user creation fails.
- Shrink
seaweedfs.volume.dataDirs[0].sizeanddask.worker.replicas, and match the-allowedOriginsarguments to yourhttp://host. - Clear the SeaweedFS pod anti-affinity (
seaweedfs.master.affinity,.volume.affinity,.filer.affinityset to""), which a single-node cluster cannot satisfy.
Everything else is unchanged from the example values file. The first-admin flow is still required.
Air-gapped deployments
First go through the air-gapped checklist shared by
both paths: mirrored images, the chart archive (helm pull … --untar, then install from the local
directory), a local certificate and an internal SMTP server.
Then point the images at your mirror with global.imageRegistry:
global:
imageRegistry: registry.internal.example
It covers the API, the web client and SeaweedFS. Four more take their registry as part of a larger
string and have to be pointed at the mirror by hand: dask.scheduler.image.repository,
dask.worker.image.repository, authentik.global.image.repository and authentikDatabase.image.
Then turn off the two outbound calls the platform would otherwise make:
api:
config:
compatibilityMappingUrl: "disabled"
sentry:
enabled: false
For detailed information about mirroring the Authentik images, refer to the Authentik air-gapped documentation.