Skip to content
Railgrid Docs
Sections
Open console

Enter a topic to search documentation.

    Self-host Infrastructure

    Deployment prerequisites, verification, and recovery for Infrastructure.

    The infrastructure provider turns templates into running workloads on a runtime cluster through kro , and publishes applications and App Studio previews under a wildcard domain through a Gateway API Gateway. Railgrid runs it in operator mode: the chart installs a small operator and one InfrastructureProvider resource, and the operator installs kro, bootstraps the provider workspace, and manages the serving Deployment.

    Prerequisites

    • A Kubernetes runtime you administer, Helm, and permission to onboard this provider. Use the common provider flow to obtain the workspace kubeconfig.
    • A Gateway API Gateway whose HTTPS listener accepts routes from all namespaces; the provider creates one HTTPRoute per published app in each tenant’s runtime namespace. See Gateway API on GKE or Cloudflare Tunnel .
    • An apps domain with a wildcard DNS record and a wildcard certificate at your edge, for example *.apps.example.com. Each app gets <name>-<tenant hash>.apps.example.com. Below a Cloudflare zone apex, Universal SSL does not cover a second label; use a zone apex or an Advanced Certificate wildcard.
    • hub.portalFrameSources on the hub listing https://*.apps.example.com, or the console blocks preview iframes.
    • A CNI that enforces NetworkPolicy if you enable tenant network isolation.

    Install kro once, as cluster-admin

    The operator installs kro with helm upgrade --install, but kro’s ClusterRole grants */*/*, and Kubernetes lets a subject create a role only with permissions it already holds. The operator’s enumerated role does not hold them, so on a cluster without kro the InfrastructureProvider sticks at KroReleased=False (HelmFailed) ... attempting to grant RBAC permissions not currently held, the serving Deployment is never created, and the provider never appears in the console.

    Install kro once yourself with the operator’s exact arguments; the operator’s later identical upgrades then leave the role untouched and succeed. Prefer this to operator.clusterAdmin: true, which would also bind cluster-admin to the ServiceAccount that handles tenant requests.

    Terminal
    helm upgrade --install kro oci://registry.k8s.io/kro/charts/kro \
      --version 0.9.3 --namespace kro-system --create-namespace --reset-values \
      --set image.repository=registry.k8s.io/kro/kro --wait

    Keep --version equal to operator.kro.version below, and repeat this when a new kro version changes its ClusterRole. If the operator is already retrying, another operation is in progress means you raced it; run the command again.

    Install

    Terminal
    kubectl create namespace railgrid-infrastructure-operator
    kubectl --namespace railgrid-infrastructure-operator create secret generic infrastructure-provider-kubeconfig \
      --from-file=kubeconfig=./infrastructure.kubeconfig

    infrastructure-values.yaml:

    YAML
    hub:
      url: https://railgrid-hub.railgrid-system.svc.cluster.local:9443
      tokenSecretRef:
        name: ""
    operator:
      enabled: true
      providerKubeconfigSecret:
        name: infrastructure-provider-kubeconfig
        key: kubeconfig
      kro:
        version: 0.9.3
        image:
          repository: registry.k8s.io/kro/kro
      application:
        # Zone apps are served under. Required to enable app exposure.
        baseDomain: apps.example.com
        gateway:
          name: railgrid
          namespace: gateway
          # GKE only: a TCP HealthCheckPolicy per route backend. Without it the
          # load balancer's default "GET /" check never passes the access gate.
          backendHealthCheck: gke-tcp
      publishing:
        # Pin the access gate image; it fronts every published app.
        accessProxyImage: ghcr.io/railgrid/railgrid-access-proxy:v0.2.1
        # Browser-reachable hub origin for sign-in redirects.
        hubPublicURL: https://console.example.com
        insecure: true

    Terminal
    helm upgrade --install infrastructure oci://ghcr.io/railgrid/charts/railgrid-infrastructure-provider \
      --version CHART_VERSION --namespace railgrid-infrastructure-operator --values infrastructure-values.yaml

    The operator creates the serving Deployment in its own namespace, railgrid-infrastructure-provider, on the runtime cluster, and reports progress on the InfrastructureProvider resource.

    Provider requirements

    One Gateway, every namespace. Published apps are HTTPRoutes in tenant namespaces. The Gateway’s listener must allow routes from all namespaces, and its wildcard certificate must cover the apps domain.

    The access gate. Every published app’s traffic enters through railgrid-access-proxy, which answers 421 to a request whose Host is not the app’s and redirects private apps to the hub for sign-in. Health checks that expect 200 on / therefore fail; on GKE set backendHealthCheck: gke-tcp (chart 0.2.34 and later). A freshly published app answers 404 for a few minutes while a cloud load balancer programs its route.

    Runtime kubeconfig. In operator mode on the hub’s cluster, the operator uses its own ServiceAccount for the runtime; set operator.runtimeKubeconfigSecret only to target a different cluster. The non-operator chart form takes centralKro.kubeconfigSecretRef instead; prefer a Secret reference over inline kubeconfigs in production.

    Tenant isolation. tenantLimitRange stamps default container resources into every tenant namespace (on by default). tenantNetworkPolicy.enabled adds an ingress NetworkPolicy per tenant namespace; list your Gateway proxies’ namespace and the kube-apiserver source range in allowedNamespaces / allowedCIDRs, or dev-sandbox sync and logs time out.

    Development sandboxes run tenant code. Pin development.agentImage and any development.images.* by digest in production, and set sandbox.runtimeClassName (gvisor or kata) before exposing App Studio to untrusted users.

    Verify

    Terminal
    kubectl -n railgrid-infrastructure-operator get infrastructureprovider \
      -o jsonpath='{range .items[*].status.conditions[*]}{.type}={.status}{"\n"}{end}'   # all True
    kubectl -n railgrid-infrastructure-provider get pods                                 # the serving Deployment
    kubectl -n kro-system get pods

    A fresh provider stays unready until a workspace enables it; see the common flow . Enable Infrastructure in a test workspace, list the Template catalog, and create one disposable Instance using the Infrastructure quickstart . Then publish one app and open its URL: a redirect to the console sign-in is the expected answer for a private app.

    Recover

    SymptomCheckFix
    KroReleased=False, permissions not currently heldkro not pre-installedInstall kro as cluster-admin (above)
    No pods in railgrid-infrastructure-providerInfrastructureProvider conditionsFix the failing condition; the operator retries about every 12 seconds
    Published app: no healthy upstreamLoad-balancer health check vs the access gatebackendHealthCheck: gke-tcp, or an equivalent TCP check
    Published app: 404 with a valid certificateRoute not yet programmed, or the Gateway rejects routes from the tenant namespaceWait a few minutes; check allowedRoutes.namespaces
    Published app: TLS failureNo wildcard certificate for the apps domainAdd the wildcard at the edge
    Preview iframe blocked in the consoleHub portalFrameSourcesAdd https://*.<apps domain>

    For a failed upgrade, preserve both hub control-plane resources and runtime objects. Inspect kro and provider events, restore the provider kubeconfig Secret, then verify the Template catalog and one disposable Instance before resuming user workloads.

    Configuration reference

    Chart values and the chart README are authoritative for the deployed version. Keep the deployed image, chart, kro, and kcp versions recorded together: the provider and kcp move in lockstep .