200 lines
8.7 KiB
Markdown
200 lines
8.7 KiB
Markdown
# Wave 1 `rail-kubernetes` Boundary
|
|
|
|
Date: 2026-07-25
|
|
|
|
## Purpose
|
|
|
|
Define the wave-1 extraction boundary between `railiance-cluster` and a future
|
|
`rail-kubernetes` repo.
|
|
|
|
This document exists to make `rail-kubernetes` real rather than rhetorical.
|
|
Today, `railiance-cluster` already contains the practical contract for running
|
|
managed workloads on Kubernetes:
|
|
|
|
- `docs/deployment-lifecycle.md`
|
|
- `docs/app-toml-contract.md`
|
|
- `docs/overlay-repo-pattern.md`
|
|
- `schemas/railiance-app.schema.json`
|
|
- `examples/railiance/app.toml`
|
|
- `bin/railiance`
|
|
- `tools/cmd/railiance-run`
|
|
- `tools/cmd/railiance-stage2`
|
|
- `tools/cmd/railiance-stage3`
|
|
- `tools/create_railiance_overlay_repo.sh`
|
|
|
|
That is already a rail in substance. The problem is that it currently lives
|
|
inside the S2 cluster-runtime repo.
|
|
|
|
## Decision Summary
|
|
|
|
- `rail-kubernetes` is the default base rail for wave 1.
|
|
- `railiance-cluster` remains the S2 owner of the Kubernetes substrate.
|
|
- `rail-kubernetes` owns the generic workload-on-Kubernetes execution contract.
|
|
- Workload-specific helpers currently living in `railiance-cluster` are not
|
|
part of the long-term boundary for either repo. They are migration debt that
|
|
must be rehomed.
|
|
|
|
## What `railiance-cluster` Keeps
|
|
|
|
`railiance-cluster` remains responsible for the Kubernetes substrate itself.
|
|
|
|
It keeps ownership of:
|
|
|
|
- k3s installation, upgrade, and baseline configuration
|
|
- cluster networking, ingress controllers, DNS, and certificate plumbing
|
|
- cluster operators and addons such as cert-manager, CloudNative PG operator,
|
|
ArgoCD, admission controllers, and similar cluster-scoped services
|
|
- kubeconfig management, runtime access patterns, and cluster backup/restore
|
|
posture
|
|
- cluster smoke tests that prove substrate readiness
|
|
- cluster-level runbooks for substrate recovery, upgrade, access, and failure
|
|
handling
|
|
- cluster capability declarations that tell higher layers what the substrate
|
|
actually supports
|
|
|
|
`railiance-cluster` may describe the prerequisites a rail needs from the
|
|
substrate, but it should not own the workload lifecycle semantics that run on
|
|
top of those prerequisites.
|
|
|
|
## What `rail-kubernetes` Must Own
|
|
|
|
`rail-kubernetes` owns the generic contract for Railiance-managed workloads
|
|
that run on Kubernetes.
|
|
|
|
It should own:
|
|
|
|
- the three-stage lifecycle semantics for Kubernetes-backed workloads
|
|
- the canonical `railiance/app.toml` contract for the Kubernetes rail
|
|
- the machine-readable schema and reference example for that contract
|
|
- the generic Stage 1, Stage 2, and Stage 3 CLI/tooling
|
|
- Kubernetes-specific check types, rollout modes, and rollback expectations
|
|
- the generic packaging pattern for Kubernetes-managed `rapp`s
|
|
- the generic repo scaffold for Kubernetes-targeting wrappers
|
|
- compatibility guidance for how a `rapp` declares Kubernetes namespaces,
|
|
releases, probes, ingress, routing, and rollback
|
|
- the documented compatibility path from today's overlay pattern into future
|
|
`rapp-*` repos
|
|
|
|
In short:
|
|
|
|
- `railiance-cluster` answers "is the Kubernetes substrate present and healthy?"
|
|
- `rail-kubernetes` answers "how does a Railiance-managed workload run on that
|
|
substrate?"
|
|
|
|
## What Should Not Stay In Either Boundary
|
|
|
|
Some items currently inside `railiance-cluster` are not good long-term
|
|
residents of either `railiance-cluster` or the future `rail-kubernetes`.
|
|
|
|
Examples include workload-specific helpers such as:
|
|
|
|
- `deploy-triage-robustness`
|
|
- `admin-sync-smoke`
|
|
- workload-specific runtime reconcile flows tied to `activity-core` or similar
|
|
single-workload concerns
|
|
|
|
These belong with the owning workload or ownership repo unless they are
|
|
refactored into clearly generic rail behavior.
|
|
|
|
`rail-kubernetes` must not become a second junk drawer after the split.
|
|
|
|
## File And Artifact Migration Map
|
|
|
|
| Current location in `railiance-cluster` | Target owner | Notes |
|
|
| --- | --- | --- |
|
|
| `docs/deployment-lifecycle.md` | `rail-kubernetes` | Generic workload lifecycle, no longer S2-owned |
|
|
| `docs/app-toml-contract.md` | `rail-kubernetes` | Base rail contract for Kubernetes-managed workloads |
|
|
| `schemas/railiance-app.schema.json` | `rail-kubernetes` | Versioned workload declaration schema |
|
|
| `examples/railiance/app.toml` | `rail-kubernetes` | Reference contract example |
|
|
| `docs/overlay-repo-pattern.md` | `rail-kubernetes` | Keep as compatibility doc, evolve toward `rapp-*` language |
|
|
| `tools/create_railiance_overlay_repo.sh` | `rail-kubernetes` | Keep behavior initially, then retarget toward `rapp-*` scaffolding |
|
|
| `docs/railiance-run-command.md` | `rail-kubernetes` | Stage 1 command reference |
|
|
| `docs/stage2-deploy-observe.md` | `rail-kubernetes` | Stage 2 command reference |
|
|
| `tools/cmd/railiance-run` | `rail-kubernetes` | Generic Stage 1 tooling |
|
|
| `tools/cmd/railiance-stage2` | `rail-kubernetes` | Generic Stage 2 tooling |
|
|
| `tools/cmd/railiance-stage3` | `rail-kubernetes` | Generic Stage 3 tooling |
|
|
| `bin/railiance` generic lifecycle commands | `rail-kubernetes` | `run`, `deploy`, `observe`, `promote`, `rollback`, `create-overlay` |
|
|
| `bin/railiance` substrate/bootstrap commands | `railiance-cluster` | `doctor`, `plan-host`, `cloudinit`, `backup`, `preflight`, similar substrate helpers |
|
|
| `tests/smoke_kube.sh`, cluster bootstrap tests | `railiance-cluster` | Substrate health proof |
|
|
| workload-specific reconcile helpers | rehome later | Move to owner repo or rewrite as generic rail helpers |
|
|
|
|
## The Interface Between The Two Repos
|
|
|
|
The clean split depends on a narrow interface.
|
|
|
|
`railiance-cluster` should publish a Kubernetes substrate profile that
|
|
`rail-kubernetes` can consume. At minimum, that profile should declare:
|
|
|
|
- cluster distro and supported Kubernetes version range
|
|
- ingress controller and ingress classes
|
|
- supported canary modes, such as `isolated` and optional `weighted`
|
|
- certificate management path
|
|
- default storage classes and stateful-workload constraints
|
|
- required or optional operators available to workloads
|
|
- namespace and RBAC expectations for managed workloads
|
|
- observability surfaces available for health, logs, and metrics
|
|
- approved secret-delivery patterns available on this substrate
|
|
|
|
`rail-kubernetes` should not assume a capability the substrate profile does not
|
|
declare.
|
|
|
|
This keeps the substrate owner and the rail owner separate while still letting
|
|
them compose.
|
|
|
|
## Migration-Safe Path
|
|
|
|
The split should happen in six steps.
|
|
|
|
1. Create `rail-kubernetes` with the copied contract docs, schema, examples,
|
|
and generic Stage 1-3 tooling now living in `railiance-cluster`.
|
|
2. Leave compatibility shims in `railiance-cluster` for one migration window.
|
|
The cluster repo may keep a thin `bin/railiance` wrapper that delegates the
|
|
generic lifecycle commands to `rail-kubernetes`.
|
|
3. Update the moved docs in `railiance-cluster` to become short boundary notes
|
|
that point to `rail-kubernetes` as the owning source.
|
|
4. Keep accepting the current `<app>-railiance-overlay` pattern during the
|
|
migration window, even though the long-term direction is toward `rapp-*`.
|
|
5. Rehome or delete workload-specific helpers that do not belong in either the
|
|
substrate repo or the generic Kubernetes rail.
|
|
6. Only after `rail-kubernetes` is stable should Railiance add `rail-knative`.
|
|
|
|
This path avoids breaking current users while making the new boundary real.
|
|
|
|
## Follow-On Path For `rail-knative`
|
|
|
|
`rail-knative` is the first expected follow-on rail, motivated by the need to
|
|
run `qonto-assistent`.
|
|
|
|
That follow-on rail should:
|
|
|
|
- depend on the Kubernetes substrate being described cleanly first
|
|
- reuse the top-level Railiance workload and promotion model where that remains
|
|
sensible
|
|
- own Knative-specific runtime semantics such as revisions, scale-to-zero,
|
|
traffic splitting, activator behavior, and event-driven behavior
|
|
- avoid forcing Knative-specific design choices back into the wave-1
|
|
`rail-kubernetes` boundary
|
|
|
|
The test for wave 1 is not "can Railiance describe all future rails now?"
|
|
|
|
The test is "can Railiance separate the Kubernetes base rail cleanly enough
|
|
that `rail-knative` can be added later without another taxonomy rewrite?"
|
|
|
|
## Risks To Watch
|
|
|
|
- If `railiance-cluster` keeps generic workload lifecycle ownership,
|
|
`rail-kubernetes` will be nominal only.
|
|
- If `rail-kubernetes` absorbs substrate bootstrap and operator ownership, it
|
|
stops being a rail and becomes a second cluster repo.
|
|
- If workload-specific helpers are moved unchanged into `rail-kubernetes`, the
|
|
split will preserve the current ambiguity instead of reducing it.
|
|
- If `rapp-*` migration is delayed too long, the old overlay naming and the new
|
|
workload-package model will drift apart.
|
|
|
|
## Outcome
|
|
|
|
Wave 1 should produce a base Kubernetes rail with a clean contract and a
|
|
backward-compatible migration path.
|
|
|
|
That is enough to start practical repo separation without pretending the rest
|
|
of the rail family already exists.
|