Install in an air-gapped cluster
Install Omnia in a cluster that cannot reach ghcr.io, pulling every image from a registry you run.
Prerequisites
Section titled “Prerequisites”- A machine with internet access, a checkout of the Omnia repository at the release tag you want,
helm(v3) andskopeo. - A container registry the cluster can pull from, and
skopeoon a machine that can push to it. - The Helm install prerequisites for the cluster itself.
-
On the connected machine, build the bundle for the version you are installing:
Terminal window make airgap-bundle VERSION=0.9.0This writes
dist/omnia-airgap-0.9.0/anddist/omnia-airgap-0.9.0.tar. The bundle holds:Path Contents oci/Every image, all platforms, in an OCI image layout images.txtThe source reference of each image charts/omnia-<version>.tgzwith its subcharts, andomnia-crds-<version>.tgzschemas/The PromptPack JSON Schema manifest.jsonThe version and every image, chart and schema in the bundle mirror.shThe script for step 3 SHA256SUMSChecksums of everything outside oci/The image list comes from rendering the packaged chart. It covers every image the chart deploys and every image the operator creates at runtime: agent facade and runtime, session-api, memory-api, privacy-api, eval workers, the policy broker, Arena workers, sandbox classes and the sandbox egress proxy. Every Omnia component is switched on for that render, so the bundle serves any combination you enable later.
-
If your values enable an observability subchart (Prometheus, Grafana, Loki, Alloy, Tempo, KEDA or the NFS CSI driver), pass your values file so its images are bundled too:
Terminal window make airgap-bundle VERSION=0.9.0 VALUES=values.yamlAn image that no chart names, such as a custom
spec.framework.imageon an AgentRuntime, goes in a file of one reference per line, passed tohack/airgap-bundle.shwith--extra:Terminal window hack/airgap-bundle.sh 0.9.0 --out dist -f values.yaml --extra my-images.txt -
Carry the tarball across, unpack it, and push the images to your registry:
Terminal window tar -xf omnia-airgap-0.9.0.tarcd omnia-airgap-0.9.0./mirror.sh registry.internal.example.com .Each image keeps its path and loses its source registry host:
ghcr.io/altairalabs/omnia-operator:0.9.0lands atregistry.internal.example.com/altairalabs/omnia-operator:0.9.0, andbusybox:1.36atregistry.internal.example.com/busybox:1.36. A registry value with a path, such asregistry.internal.example.com/omnia, prefixes it.Arguments after
--go to everyskopeo copy. Use them for registry credentials or a private CA:Terminal window ./mirror.sh registry.internal.example.com . -- --dest-authfile auth.jsonAdd
--chartsto also push both charts tooci://<registry>/charts. Add--dry-runto print each source and destination without copying. -
If the registry needs credentials, create a pull secret in the release namespace and in every workspace namespace. Pods the operator creates run in the workspace namespaces, and a pod can only use a Secret in its own namespace:
Terminal window kubectl create secret docker-registry mirror-pull \--namespace omnia-system \--docker-server=registry.internal.example.com \--docker-username=<user> --docker-password=<token> -
Install the CRDs chart from the bundle:
Terminal window helm install omnia-crds charts/omnia-crds-0.9.0.tgz \--namespace omnia-system --create-namespace -
Install the app chart from the bundle with
global.imageRegistry, andglobal.imagePullSecretsif you made a secret:Terminal window helm install omnia charts/omnia-0.9.0.tgz \--namespace omnia-system \--set dashboard.auth.mode=builtin \--set global.imageRegistry=registry.internal.example.com \--set 'global.imagePullSecrets[0].name=mirror-pull' \-f values.yamlThe chart rewrites every image it renders. It also passes the operator and the Arena controller the rewritten image of every pod they create, and passes
global.imagePullSecretson as their--image-pull-secretsflag. An image you set on a custom resource, such asspec.framework.image,spec.facades[].imageor a SandboxClass you write, is used as written. -
Turn off every outbound call, since the cluster has no route to the endpoints: add
--set airGapped=trueto the install. It switches off install telemetry, Enterprise licence activation and its heartbeat, and the community Arena template sync from GitHub, keeps PromptPack schemas on the embedded copy, and fails the render if another value names an outside host. Outbound connections lists every destination and the value that controls it.Licence validation needs no network.
Verify
Section titled “Verify”List every image the release namespace runs:
kubectl get pods -n omnia-system \ -o jsonpath='{range .items[*]}{range .spec.containers[*]}{.image}{"\n"}{end}{end}' | sort -uEvery line starts with your registry. Once you create an AgentRuntime, run the same command against its workspace namespace: the facade and runtime images start with your registry too.
Troubleshooting
Section titled “Troubleshooting”A pod is in ImagePullBackOff with an image under your registry
Section titled “A pod is in ImagePullBackOff with an image under your registry”The image is not in the mirror. Compare the image in kubectl describe pod with images.txt. An image missing from images.txt was not in the render the bundle was built from: rebuild with the values file that enables it, or add it with --extra.
A pod in a workspace namespace fails with unauthorized
Section titled “A pod in a workspace namespace fails with unauthorized”The pull secret named in global.imagePullSecrets does not exist in that namespace. Create it there (step 4). The operator adds the secret’s name to the pod, and the kubelet reads it from the pod’s own namespace.
An observability subchart still pulls from its public registry
Section titled “An observability subchart still pulls from its public registry”Each subchart reads its own registry setting, and only some read global.imageRegistry. The Helm Values Reference lists the key each one reads.