GeassPlatformConfig
The GeassPlatformConfig holds the settings that belong to the whole platform rather than to one project: the dashboard’s domain and how it is published, the link to the Cloudflare connection, the link to the GitHub App, where to find Prometheus, and the registry that repository builds push to. There is one, named platform, in geass-system. The dashboard creates it the first time you save a domain, a Cloudflare connection or a GitHub App, and edits it from Settings. You can also create and edit it with kubectl.
For the settings as a whole, with the operator flags and environment variables, see Configuration. For the connections it points at, see Cloud connectors.
Summary
Section titled “Summary”| Property | Value |
|---|---|
| API version | geass.geass.dev/v1alpha1 |
| Kind | GeassPlatformConfig |
| Plural | geassplatformconfigs |
| Scope | Namespaced |
| Namespace | geass-system |
| Name | platform. The dashboard and the controllers only read this name. |
| Subresources | status |
| Printer columns | None |
Example
Section titled “Example”A dashboard at geass.example.com, published with a Cloudflare Tunnel, with the Cloudflare and GitHub App credentials already saved in their Secrets.
apiVersion: geass.geass.dev/v1alpha1kind: GeassPlatformConfigmetadata: name: platform namespace: geass-systemspec: rootDomain: example.com dashboardURL: https://geass.example.com dashboardExposure: cloudflare-tunnel cloudflareConnectionRef: name: platform-cloudflare cloudflareZoneID: 0123456789abcdef0123456789abcdef githubAppRef: name: platform-github-app prometheusURL: http://prometheus.example.internal:9090Every field is optional. An empty spec is valid.
Spec fields
Section titled “Spec fields”| Field | Type | Default | Validation | Meaning |
|---|---|---|---|---|
spec.rootDomain |
string | none | Lowercase hostname with at least one dot, such as example.com |
Your apex domain. Geass serves the dashboard at geass.<rootDomain> (or another subdomain, see dashboardURL). If it is empty, Geass takes it from dashboardURL when that host starts with geass.. |
spec.dashboardURL |
string | none | ^https://[a-zA-Z0-9.-]+(?::[0-9]+)?$: HTTPS, host and optional port, no path |
The dashboard’s public address. Used for the GitHub App’s callback and webhook URLs. When it is empty, Geass uses https://geass.<rootDomain>. |
spec.dashboardExposure |
string | ingress |
ingress or cloudflare-tunnel |
How the dashboard is published. ingress creates an Ingress (and, when Cloudflare is connected, a proxied A record). cloudflare-tunnel runs a tunnel instead. |
spec.tunnelCNAMETarget |
string | none | ^[a-z0-9-]+(\.[a-z0-9-]+)+$ |
The tunnel’s hostname, <tunnel id>.cfargotunnel.com. Geass sets it itself when it manages the tunnel. Set it by hand only if you run your own tunnel. |
spec.cloudflareConnectionRef.name |
string | none | none | The Secret with the Cloudflare credentials (apiToken, accountId, and optionally zoneName and zones). Setting it turns the Cloudflare connection on. |
spec.cloudflareZoneID |
string | none | none | The Cloudflare DNS zone for automatic records. When empty, Geass picks the zone whose name equals the root domain, or the only zone the token can see. |
spec.githubAppRef.name |
string | none | none | The Secret with the GitHub App credentials (app_id, client_id, client_secret, slug, private_key, webhook_secret). |
spec.prometheusURL |
string | none | none | Where the dashboard queries metrics. Wins over the GEASS_PROMETHEUS_URL environment variable and the default service address. |
spec.defaultClusterRef.name |
string | none | none | The cluster new projects use when more than one GeassCluster exists. With one cluster it is ignored. |
spec.registry.repository |
string | none | none | The image destination for repository builds when a service sets no build.registry.repository. Used exactly as written. |
spec.registry.credentialRef.name |
string | none | none | A Secret with the key .dockerconfigjson for that registry. Builds push with it, and Geass copies it into a service’s namespace for the nodes to pull the built image with. |
spec.defaultDomain |
string | none | none | In the schema. No code reads it. |
spec.traefikAccessLogs.enabled, .format, .networkLogEndpoint |
boolean, string, string | none | none | In the schema. No code reads them. See GeassNetworkLog. |
Status
Section titled “Status”| Field | Type | Meaning |
|---|---|---|
status.cloudflareTunnelID |
string | The ID of the Cloudflare tunnel Geass manages, when the tunnel is in use. |
status.conditions |
list | DashboardDomainReady and CloudflareReady. |
DashboardDomainReady
Section titled “DashboardDomainReady”This condition says whether the dashboard answers at its public address. It is True only for the generation of the spec it was checked against, so any change to spec makes the controller check again. While it is false, the controller checks every 5 seconds. After 15 minutes without success it reports VerificationTimedOut and checks every 5 minutes, so a late DNS fix still heals.
| Reason | Status | Meaning |
|---|---|---|
Verified |
True |
The dashboard’s HTTPS address answers the Geass probe (/geass-probe), or DNS and the probe agree. |
NoDomain |
False |
There is no root domain. |
PendingDNS |
False |
The host does not resolve to the cluster’s public IP yet, or Geass could not create the Cloudflare record. The message says which. |
PendingHTTPS |
False |
DNS is right, but https://<host>/geass-probe is not reachable yet. The certificate may still be pending. In ingress mode, when a GeassCluster reports ClusterIssuerReady: False, the message ends with its reason in parentheses, for example that no ACME contact email is set. |
PendingTunnel |
False |
Tunnel mode, and no tunnel hostname is known yet. |
ZoneRequired |
False |
Cloudflare is connected, but the token sees several zones and none matches the root domain. Choose a zone in Settings → Domain. |
Error |
False |
The Cloudflare credentials are unavailable or incomplete, the dashboard Service was not found, or the cluster nodes could not be listed. |
VerificationTimedOut |
False |
The check has been pending for 15 minutes. It keeps trying. |
CloudflareReady
Section titled “CloudflareReady”This condition reports the Cloudflare side. It is only set when cloudflareConnectionRef is set.
| Reason | Status | Meaning |
|---|---|---|
Connected |
True |
Ingress mode: Cloudflare is connected and, when there is a root domain, the dashboard’s proxied A record exists. |
Ready |
True |
Tunnel mode: the tunnel exists, cloudflared is deployed and the routes are published. |
CredentialsIncomplete |
False |
The Secret lacks the API token or account ID, or no zone could be chosen. |
CredentialsInvalid |
False |
Cloudflare rejected the token. The message is the reason Cloudflare gave. |
TunnelError |
False |
The tunnel could not be found or created. |
TunnelTokenError |
False |
The tunnel’s connector token could not be fetched. |
TunnelConfigError |
False |
The tunnel’s routes could not be published. |
DNSError |
False |
Ingress mode: the dashboard’s A record could not be created. |
While CloudflareReady is true, services without a host get a default one under the root domain. See Connect Cloudflare.
How the dashboard maps to it
Section titled “How the dashboard maps to it”| Dashboard | Writes |
|---|---|
| Settings → Domain → Save dashboard domain | rootDomain, dashboardURL (from Subdomain, default geass), dashboardExposure (Publish via), tunnelCNAMETarget, cloudflareZoneID. The page’s verify action sets the DashboardDomainReady condition. |
| Settings → Connectors → Cloudflare → Connect | cloudflareConnectionRef (the Secret platform-cloudflare) and cloudflareZoneID. Disconnect clears both. |
| Settings → Connectors → GitHub | githubAppRef (the Secret platform-github-app). Remove GitHub App clears it. |
The dashboard has no screen for prometheusURL, defaultClusterRef or registry. Set the first two with kubectl. An admin can set registry with POST /api/settings/registry/save (see the REST API), which stores the login as the Secret platform-registry, or with kubectl.
Editing by hand
Section titled “Editing by hand”It is safe to edit the spec with kubectl. The controller applies a change within seconds. Do not edit status.
kubectl -n geass-system edit geassplatformconfig platformkubectl -n geass-system get geassplatformconfig platform \ -o jsonpath='{range .status.conditions[*]}{.type}{"\t"}{.status}{"\t"}{.reason}{"\t"}{.message}{"\n"}{end}'If you set cloudflareConnectionRef by hand, create the Secret platform-cloudflare first. If you clear it, delete the Secret yourself.
What happens under the hood
Section titled “What happens under the hood”In ingress mode the controller creates the Ingress geass-dashboard in geass-system for the dashboard host, on the websecure entry point of Traefik, with TLS from cert-manager (the secret geass-dashboard-tls). It then checks DNS and probes the HTTPS address. If Cloudflare is connected it also creates a proxied A record pointing at the cluster’s public IP.
In tunnel mode the controller creates the tunnel geass, the Secret geass-cloudflared-token and the Deployment geass-cloudflared, publishes the routes, and creates CNAME records. Without a Cloudflare connection it deletes the Deployment and Secret.
The routes are the dashboard’s host and the host of every service that has one. The controller works out what it would send first, and compares it with what it last sent in full. When nothing has changed it sends nothing to Cloudflare, and looks again after five minutes, which catches a route or record that someone deleted in Cloudflare. It reacts at once when a service gets, changes or loses a host, because it watches the services for changes to their spec. A CNAME record that cannot be created is only logged, and the controller tries again in five seconds. The route of a service that sleeps when idle points at the add-on’s wake proxy instead of at the service, because the tunnel does not go through Traefik. The platform configuration is also read by the build controller (the registry), the dashboard (metrics address, GitHub readiness) and project creation (the default cluster).
Troubleshooting
Section titled “Troubleshooting”DashboardDomainReady is PendingDNS. The host does not point at the cluster yet. Create an A record for geass.<rootDomain> at the cluster’s public IP, or connect Cloudflare so Geass does it. The message names the address it expects.
PendingHTTPS for a long time. DNS is right but HTTPS does not answer. Check the Ingress and its certificate (kubectl -n geass-system get ingress,certificate), and that the letsencrypt-prod ClusterIssuer exists and is ready (kubectl get clusterissuer letsencrypt-prod). The ClusterIssuerReady condition of the GeassCluster says why it is not, for example ACMEEmailMissing.
ZoneRequired. Choose the zone in Settings → Domain, or set cloudflareZoneID.
CloudflareReady is CredentialsInvalid. Update the token with Update API token. See Connect Cloudflare.
The GitHub App cannot be saved: dashboard URL must be configured first. The GitHub App needs a verified HTTPS dashboard address. Finish the domain first.
I changed an unrelated field and the dashboard briefly says the domain is not verified. A spec change starts a new verification. It returns to Verified at the next check.