Firstlume Docs firstlume.io ENPT PT Talk to us

Install with Helm

One chart installs both components: the control plane (API, UI and server) and the agent that creates run Jobs. The commands below use deploy/helm/firstlume, the chart's path in the Firstlume repository.

The container image is not public yet. To request access, write to hello@firstlume.io.

Everything in one cluster

With a managed database:

helm install firstlume deploy/helm/firstlume -n firstlume --create-namespace \
  --set controlPlane.database.url='postgres://user:pass@host:5432/firstlume?sslmode=require'

The URL can also come from an existing Secret, with controlPlane.database.existingSecret.

To test without an external database, use --set postgresql.enabled=true. That is a single instance with no backups, for testing only.

Reach the server

Turn on the ingress and set the public address:

helm upgrade firstlume deploy/helm/firstlume -n firstlume --reuse-values \
  --set controlPlane.ingress.enabled=true \
  --set controlPlane.ingress.host=firstlume.example.com \
  --set controlPlane.publicURL=https://firstlume.example.com

controlPlane.publicURL defaults to the ingress host. Sign-in redirects and the JWTs that Vault checks use this address.

The admin token is in the release's Secret:

kubectl -n firstlume get secret firstlume-control-plane \
  -o jsonpath='{.data.admin-token}' | base64 -d

Open https://firstlume.example.com and sign in with it, or continue with Your first run.

The image

The image is ghcr.io/bsteigleder/firstlume, for amd64 and arm64. Tags are main, sha-<commit> and, for vX.Y.Z releases, X.Y.Z.

Create a pull Secret and pass it to the chart:

--set imagePullSecrets[0].name=<secret>

The server, the agent and the run Jobs (through the executor's ServiceAccount) all use it. On a cluster with an internal registry, prefer a proxy cache pointing at GHCR, so the credential lives in one place.

An additional agent in another cluster

An agent belongs to one organization and only receives that organization's runs. Create a token for it with POST /api/v1/orgs/{org}/agents:

curl -s -H "Authorization: Bearer $FIRSTLUME_ADMIN_TOKEN" \
  https://firstlume.example.com/api/v1/orgs/default/agents -d '{"name": "cluster-b"}'

Then install only the agent in the other cluster:

helm install firstlume-agent deploy/helm/firstlume -n firstlume --create-namespace \
  --set controlPlane.enabled=false \
  --set agent.name=cluster-b \
  --set agent.apiUrl=https://firstlume.example.com \
  --set agent.token=fla_...

The agent only makes outbound requests, so the API never has to reach it.

Where runs run

Run Jobs accept agent.executor.nodeSelector, tolerations and affinity (including anti-affinity), with the same fields as a pod. Use them when only some nodes can reach the machines your code configures.

For code that talks to the API of its own cluster (the kubernetes and helm providers with no kubeconfig), turn on agent.executor.automountServiceAccountToken and grant permissions to the executor's ServiceAccount with agent.executor.serviceAccount.clusterRoles. These apply to every run of that agent. For different permissions, use another agent.

Cloud credentials come from the pod's identity (IRSA, Workload Identity), through annotations in agent.executor.serviceAccount.annotations.

Sign-in with OIDC

Without this, only the admin token works. Gitea is the first supported provider. Other OIDC providers use the same settings.

Register a confidential OAuth app in the provider, with <publicURL>/auth/callback as the redirect address, and keep the client secret in an existing Secret. All values are under controlPlane.:

Value Default
publicURL the ingress host required with OIDC: the server will not start without it or an ingress host
auth.oidc.enabled false
auth.oidc.providerName Gitea the text on the sign-in button
auth.oidc.issuer for example https://gitea.example.com
auth.oidc.clientId
auth.oidc.existingSecret, auth.oidc.clientSecretKey key client-secret the client secret never goes in the values
auth.oidc.scopes openid profile email groups
auth.oidc.groupsClaim groups
auth.oidc.allowedGroups empty when set, only members of these groups can sign in
auth.oidc.adminGroups empty members are installation administrators
auth.adminTokenLogin true offers "Use admin token" on the sign-in screen

Gitea sends organizations (acme) and teams (acme:infra) as groups, and both lists accept either form. If the provider is down when the server starts, the server still comes up with the admin token working and keeps retrying.

Signing in gives access to no organization by itself. See who sees what.

Back up the secret key

Back up the secret-key key of the <release>-control-plane Secret. Without it, the encrypted data can't be recovered: sensitive variables, Git tokens, plans and state versions. The Secret is kept on helm uninstall.

All options

values.yaml in the chart lists every option, with comments. State storage has its own page: Where state lives.