Skip to main content

Licence and images

Swarmd’s container images live in a private ECR registry. Your licence key is what lets your cluster pull them — and the same key is what billing-service checks to establish your subscription tier. Worth understanding before you install, because it is the one part of the chart that reaches outside your cluster, and the one failure mode that stops everything.

The loop

  1. A pre-install Job runs before anything else. It calls POST {licence.serverUrl}/v1/ecr-credentials with your key in an Authorization: Licence <key> header.
  2. The response carries a base64 dockerConfigJson. The Job decodes it and writes a kubernetes.io/dockerconfigjson Secret — swarmd-ecr-pull by default.
  3. That Secret is appended to global.image.pullSecrets automatically. You don’t wire it up; every pod gets it.
  4. A CronJob refreshes it every 8 hours. AWS ECR tokens expire after 12, so this leaves four hours of headroom.
The Job and CronJob run the same script from one ConfigMap, so the bootstrap and rotation paths can never drift apart. The image they run is alpine/k8s — deliberately a public image, because it has to run before the pull secret exists.
Failure is loud by design. If the licence server is unreachable during pre-install, the script exits non-zero, the hook fails, and Helm rolls the install back. You get an error instead of a namespace full of ImagePullBackOff.

Supplying the key

Set exactly one. Both, or neither, fails the install with a named error.

What you can tune

Raising renewIntervalHours past 12 means the token expires before the next refresh, and every pull fails until the CronJob next runs. Existing pods keep running — kubelet only pulls on start — so the symptom is delayed and confusing: everything is fine until a node reboots or you scale up.Leave it at 8 unless you have a specific reason.
verifyIntervalMinutes and cacheTtlMinutes trade licence-server load against how long a revoked licence keeps working. With the defaults, a revocation takes effect within an hour, and at most two.Loosen them for an air-gapped-ish deployment that can only reach the licence server intermittently; tighten them if you need revocation to bite quickly.

Mirroring into your own registry

If your cluster cannot reach ECR — or policy forbids pulling from a vendor registry — mirror the images and point the chart at your mirror:
global.image.registry is prepended to every image reference that doesn’t already carry a registry.
You still need a valid licence key: billing-service verifies it at runtime independently of image pulls. The ECR bootstrap Job will keep trying and failing harmlessly if it can’t reach the licence server — but plan for offline validation with us rather than relying on that.

When it goes wrong

The pull Secret is missing or stale. Look at the bootstrap Job first — it’s the only thing that creates it:
If the Secret doesn’t exist, the Job never succeeded. If it exists but pulls still fail, the token has expired — check the CronJob:
Force a refresh:
The server answered, but without credentials. That means the key was accepted as a header but rejected as a licence — expired, revoked, or not entitled to image pulls. Check the response body in the Job logs, then talk to Swarmd.
No egress. The script allows 30 seconds. Your cluster needs outbound HTTPS to api.dev.swarmd.ai — check egress policy, proxy configuration, and whether your CNI’s NetworkPolicy allows the swarmd namespace out.
Working as intended: the ECR Job is a pre-install hook, so a failure aborts before any service is created. Fix the cause and re-run helm install — there is nothing to clean up.
Image pulls and tier enforcement are separate paths. Pulls only need the key once; billing-service verifies continuously against licence.serverUrl. If that URL is wrong or unreachable, the tier falls back to STARTER.

Next

Databases

Where all this state actually lives.

Configuration

Secrets, app settings, and the optional components.