From 8d48e658609e84b465e35b51df1626de5e53f0f8 Mon Sep 17 00:00:00 2001 From: Thomas Kosiewski Date: Fri, 13 Feb 2026 09:27:02 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20docs:=20refresh=20docs=20accurac?= =?UTF-8?q?y=20and=20structure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: - rewrote architecture, troubleshooting, and docs index pages - improved README structure and app mode coverage - updated tutorial/deploy guides for correctness and actionability - fixed control-plane sample image and made license secret optional --- _Generated with `mux` • Model: `openai:gpt-5.3-codex` • Thinking: `xhigh` • Cost: $2.88_ --- .cspell.json | 7 + README.md | 157 +++++++++--------- .../coder_v1alpha1_codercontrolplane.yaml | 9 +- docs/explanation/architecture.md | 118 ++++++++++--- docs/how-to/deploy-aggregated-apiserver.md | 75 ++++++--- docs/how-to/deploy-controller.md | 51 ++++-- docs/how-to/troubleshooting.md | 108 +++++++----- docs/index.md | 45 +++-- docs/tutorials/getting-started.md | 58 +++++-- 9 files changed, 420 insertions(+), 208 deletions(-) diff --git a/.cspell.json b/.cspell.json index c9b07fc9..d733e5ef 100644 --- a/.cspell.json +++ b/.cspell.json @@ -2,6 +2,7 @@ "version": "0.2", "language": "en", "words": [ + "allapp", "Diátaxis", "GOFLAGS", "Millis", @@ -9,12 +10,14 @@ "apiserverapp", "apiserver", "apiservice", + "apisvc", "clusterrole", "clusterrolebinding", "coder-k8s", "codercontrolplane", "codercontrolplanes", "coderd", + "codersdk", "codertemplate", "codertemplates", "coderworkspace", @@ -28,15 +31,19 @@ "workspaceproxy", "workspaceproxies", "derp", + "crds", "devshell", + "healthz", "gofumpt", "javascripts", "kubeconfig", "kubebuilder", "corev", "metav", + "mcpapp", "mkdocs", "pymdownx", + "readyz", "superfences" ], "ignorePaths": [ diff --git a/README.md b/README.md index 63bbc1f5..e79854ba 100644 --- a/README.md +++ b/README.md @@ -1,133 +1,136 @@ # coder-k8s +[![CI](https://github.com/coder/coder-k8s/actions/workflows/ci.yaml/badge.svg)](https://github.com/coder/coder-k8s/actions/workflows/ci.yaml) +[![Go](https://img.shields.io/badge/go-1.25%2B-00ADD8?logo=go)](./go.mod) +[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](./LICENSE) + > [!WARNING] > **Highly Experimental / Alpha Software** > This repository is a **hackathon contribution** and remains a **highly experimental, alpha-stage** project. > **Do not use this in production or expose it to end users.** -> -## Project description -`coder-k8s` is a Go-based Kubernetes control-plane project with two app modes: +`coder-k8s` is a Kubernetes control-plane project for managing Coder-related resources with native Kubernetes APIs. + +## What this project provides + +- A controller-runtime operator for `coder.com/v1alpha1` resources: + - `CoderControlPlane` + - `CoderProvisioner` + - `CoderWorkspaceProxy` +- An aggregated API server for `aggregation.coder.com/v1alpha1` resources: + - `CoderWorkspace` + - `CoderTemplate` +- An MCP HTTP server for operational tooling. +- A single binary that can run in all-in-one mode or split app modes. -- A `controller-runtime` operator for managing `CoderControlPlane` and - `CoderWorkspaceProxy` resources (`coder.com/v1alpha1`). -- An aggregated API server for `CoderWorkspace` and `CoderTemplate` resources - (`aggregation.coder.com/v1alpha1`). +## Application modes + +| Mode | Description | Typical usage | +| --- | --- | --- | +| `all` (default) | Runs controller + aggregated API + MCP HTTP together | Local dev, demos, simple cluster deployment | +| `controller` | Runs only Kubernetes reconcilers | Controller-focused debugging and e2e smoke flows | +| `aggregated-apiserver` | Runs only aggregated API server | Split deployments with explicit Coder backend flags | +| `mcp-http` | Runs only MCP HTTP server | MCP-focused integrations | ## Prerequisites - Go 1.25+ (`go.mod` currently declares Go 1.25.7) -- A Kubernetes cluster (OrbStack is recommended for local development; any cluster works) -- `kubectl` configured to point at your cluster context +- A Kubernetes cluster (OrbStack, KIND, or any conformant cluster) +- `kubectl` configured for your target cluster -## Quick start / Local development (OrbStack) +## Quick start (local controller run) ```bash -# Generate CRD and RBAC manifests +# Generate and apply CRDs make manifests - -# Apply CRDs to your cluster kubectl apply -f config/crd/bases/ -# Run the controller locally (uses your kubeconfig context) +# Run controller locally against your kubeconfig context GOFLAGS=-mod=vendor go run . --app=controller -# In another terminal: apply the sample CR +# In another terminal, apply a sample control plane kubectl apply -f config/samples/coder_v1alpha1_codercontrolplane.yaml -# Verify +# Verify resource creation kubectl get codercontrolplanes -A ``` -## Examples - -- [`examples/cloudnativepg/`](examples/cloudnativepg/) - Deploy a `CoderControlPlane` with a CloudNativePG-managed PostgreSQL backend. - -## KIND development cluster (for k9s demos) - -Bootstrap a KIND cluster and install CRDs/RBAC (**this also switches your current kubectl context**): +## Documentation -```bash -make kind-dev-up -``` +The project docs follow Diátaxis and live in `docs/`. -> Tip: override defaults when needed: -> -> - Use `CLUSTER_NAME` to run multiple clusters in parallel. -> - Use `KIND_NODE_IMAGE` to pin the node image (default: `kindest/node:v1.34.0`). -> -> ```bash -> CLUSTER_NAME=my-cluster make kind-dev-up -> KIND_NODE_IMAGE=kindest/node:v1.32.0 make kind-dev-up -> ``` +- Home: [`docs/index.md`](docs/index.md) +- Tutorial: [`docs/tutorials/getting-started.md`](docs/tutorials/getting-started.md) +- How-to guides: [`docs/how-to/`](docs/how-to/) +- Architecture: [`docs/explanation/architecture.md`](docs/explanation/architecture.md) +- API reference: [`docs/reference/api/`](docs/reference/api/) -> If the cluster already exists and you change `KIND_NODE_IMAGE`, run `make kind-dev-down` first so the new image can be applied. -> -If you need to switch your kubectl context later: +Serve docs locally: ```bash -make kind-dev-ctx -# or: CLUSTER_NAME=my-cluster make kind-dev-ctx +make docs-serve ``` -Start the controller (pick one): - -- Out-of-cluster (fast iteration): - - ```bash - GOFLAGS=-mod=vendor go run . --app=controller - ``` +## Examples -- In-cluster (closer to CI): +- [`examples/cloudnativepg/`](examples/cloudnativepg/) — Deploy a `CoderControlPlane` with a CloudNativePG-managed PostgreSQL backend. - ```bash - make kind-dev-load-image - kubectl apply -f config/e2e/deployment.yaml - kubectl -n coder-system wait --for=condition=Available deploy/coder-k8s --timeout=120s - ``` +## KIND development cluster (k9s demos) -Demo: +Bootstrap a KIND cluster and install CRDs/RBAC (**this switches current kubectl context**): ```bash -make kind-dev-k9s +make kind-dev-up ``` -Cleanup: +Useful helpers: ```bash +make kind-dev-status +make kind-dev-ctx +make kind-dev-load-image +make kind-dev-k9s make kind-dev-down ``` -Mux users: there is an optional agent skill (`kind-dev`) under `.mux/skills/` with agent-oriented instructions for running per-workspace KIND clusters. - ## Essential commands | Command | Description | | --- | --- | -| `make build` | Build the project | -| `make test` | Run tests | -| `make manifests` | Generate CRD/RBAC manifests | -| `make codegen` | Run deepcopy code generation | -| `make verify-vendor` | Verify vendor consistency | -| `make lint` | Run linter (requires `golangci-lint`) | -| `make vuln` | Run vulnerability check (requires `govulncheck`) | -| `make docs-serve` | Serve the documentation site locally (requires `mkdocs`) | +| `make build` | Build all packages | +| `make test` | Run unit + integration tests | +| `make test-integration` | Run focused controller integration tests | +| `make manifests` | Generate CRD and RBAC manifests | +| `make codegen` | Run deepcopy generation | +| `make docs-reference` | Regenerate API reference docs from Go types | | `make docs-check` | Build docs in strict mode (CI-equivalent) | +| `make verify-vendor` | Verify vendored dependency consistency | +| `make lint` | Run linter + formatting checks | +| `make vuln` | Run vulnerability scan | -## Testing strategy +## Repository layout -- **Unit tests**: `make test` runs all tests, including unit tests in `main_test.go`. -- **Integration tests**: Use `envtest` to exercise reconciliation against a lightweight API server (no real cluster needed). Run them via `make test` (included in the full suite) or `make test-integration` (focused on controller tests only). -- **E2E smoke tests**: Recommended CI smoke coverage uses a Kind-based flow that deploys the controller image and verifies pod health. +- `api/v1alpha1/` — CRD API types (`coder.com/v1alpha1`) +- `api/aggregation/v1alpha1/` — aggregated API types (`aggregation.coder.com/v1alpha1`) +- `internal/app/` — app mode entrypoints (`allapp`, `controllerapp`, `apiserverapp`, `mcpapp`) +- `internal/controller/` — controller reconcilers +- `internal/aggregated/` — aggregated storage + Coder client/provider logic +- `config/` — generated CRDs, RBAC, samples +- `deploy/` — deployable manifests for all-in-one, APIService, and MCP service +- `docs/` — user-facing documentation site content +- `hack/` — code generation and maintenance scripts -## Project structure +## Contributing -- `api/v1alpha1/` — CRD types and generated deepcopy code -- `internal/controller/` — Reconciliation logic -- `config/crd/bases/` — Generated CRD manifests -- `config/rbac/` — RBAC manifests (generated role + deployment bindings) -- `config/samples/` — Sample custom resources -- `hack/` — Code generation and maintenance scripts +Before opening a PR, run at least: + +```bash +make verify-vendor +make test +make build +make lint +make docs-check +``` ## License diff --git a/config/samples/coder_v1alpha1_codercontrolplane.yaml b/config/samples/coder_v1alpha1_codercontrolplane.yaml index c6e62f75..db70cd61 100644 --- a/config/samples/coder_v1alpha1_codercontrolplane.yaml +++ b/config/samples/coder_v1alpha1_codercontrolplane.yaml @@ -4,7 +4,8 @@ metadata: name: codercontrolplane-sample namespace: default spec: - image: "ghcr.io/coder/coder-k8s:main" - licenseSecretRef: - name: coder-license - key: license + image: "ghcr.io/coder/coder:latest" + # Optional Enterprise license upload: + # licenseSecretRef: + # name: coder-license + # key: license diff --git a/docs/explanation/architecture.md b/docs/explanation/architecture.md index a8f4cf00..f9a9c799 100644 --- a/docs/explanation/architecture.md +++ b/docs/explanation/architecture.md @@ -1,38 +1,112 @@ # Architecture -`coder-k8s` builds a single binary (`coder-k8s`) that can run in one of two modes: +`coder-k8s` is a single Go binary that can run different components depending on the `--app` flag. -- `--app=controller` -- `--app=aggregated-apiserver` +## Application modes -The dispatch logic lives in `app_dispatch.go`. The `--app` flag is required, and the code intentionally fails fast with an `assertion failed:` error when it is missing or invalid. +| Mode | Purpose | Default | +| --- | --- | --- | +| `all` | Runs controller + aggregated API server + MCP HTTP server in one process | ✅ | +| `controller` | Runs only the controller-runtime manager and reconcilers | | +| `aggregated-apiserver` | Runs only the aggregated API server (`aggregation.coder.com/v1alpha1`) | | +| `mcp-http` | Runs only the MCP HTTP server | | -## Controller mode +!!! note + `--app` is optional. If omitted, `coder-k8s` defaults to `--app=all`. -In controller mode, the binary runs a `controller-runtime` manager and registers the `CoderControlPlane` API types: +## Default process model (`--app=all`) -- API group: `coder.com/v1alpha1` -- Kind: `CoderControlPlane` +In `all` mode, `internal/app/allapp` creates one shared controller-runtime manager and cache, then: -Key code paths: +1. Registers controller reconcilers. +2. Starts aggregated API server as a non-leader runnable. +3. Starts MCP HTTP server as a non-leader runnable. -- `internal/app/controllerapp/` — scheme construction and manager startup -- `internal/controller/` — reconciliation logic (`CoderControlPlaneReconciler`) +This keeps component startup coordinated and avoids separate cache/process management for local and demo deployments. -## Aggregated API server mode +```mermaid +graph TD + entry["coder-k8s (--app=all)"] --> mgr["controller-runtime manager"] + mgr --> ctrl["Controller reconcilers"] + mgr --> agg["Aggregated API server runnable"] + mgr --> mcp["MCP HTTP runnable"] -In aggregated API server mode, the binary starts an aggregated API server that installs storage for: + ctrl --> crds["coder.com/v1alpha1 CRDs"] + agg --> api["aggregation.coder.com/v1alpha1"] + mcp --> tools["MCP tools over /mcp"] +``` -- API group: `aggregation.coder.com/v1alpha1` -- Resources: `coderworkspaces`, `codertemplates` +## Controller subsystem -Key code paths: +Controller behavior lives in: -- `internal/app/apiserverapp/` — API server bootstrap and API group installation -- `internal/aggregated/storage/` — storage implementations (currently hardcoded in-memory objects) +- `internal/app/controllerapp/` +- `internal/controller/` -## Manifests and generated assets +Key facts: -- `config/` — generated CRDs and RBAC (via `make manifests`) -- `deploy/` — example deployment manifests for controller and aggregated API server -- `vendor/` — vendored dependencies (required by the repo workflow) +- Uses controller-runtime with leader election. +- Exposes health probes on `:8081` (`/healthz`, `/readyz`). +- Reconciles three CRDs in `coder.com/v1alpha1`: + - `CoderControlPlane` + - `CoderProvisioner` + - `CoderWorkspaceProxy` + +For `CoderControlPlane`, the reconciler creates/updates a Deployment + Service in the same namespace, and writes status fields such as `status.url`, `status.phase`, and operator token references. + +## Aggregated API subsystem + +Aggregated API server behavior lives in: + +- `internal/app/apiserverapp/` +- `internal/aggregated/storage/` +- `internal/aggregated/coder/` + +Key facts: + +- Serves HTTPS on port `6443` by default. +- Installs `aggregation.coder.com/v1alpha1` resources: + - `coderworkspaces` + - `codertemplates` +- Storage is **codersdk-backed**, not in-memory: requests are translated to Coder API operations. + +Client provider behavior: + +- In `all` mode, `ControlPlaneClientProvider` discovers eligible `CoderControlPlane` resources and reads operator token secrets dynamically. +- In standalone `--app=aggregated-apiserver` mode, static configuration is expected via: + - `--coder-url` + - `--coder-session-token` + - `--coder-namespace` + +## MCP subsystem + +MCP behavior lives in `internal/app/mcpapp/`. + +Key facts: + +- HTTP listen address: `:8090` +- Endpoints: + - `/mcp` + - `/healthz` + - `/readyz` +- Provides tooling for control planes, templates, workspaces, events, pod logs, and run-state updates. + +## Kubernetes manifests + +- `config/crd/bases/`: generated CRDs for `CoderControlPlane`, `CoderProvisioner`, `CoderWorkspaceProxy` +- `config/rbac/`: ServiceAccount and RBAC bindings (`manager-role`, `coder-k8s`, auth-delegator bindings) +- `deploy/deployment.yaml`: all-in-one deployment (defaults to `--app=all`) +- `deploy/apiserver-service.yaml` + `deploy/apiserver-apiservice.yaml`: aggregated API exposure +- `deploy/mcp-service.yaml`: MCP service on port `8090` + +## High-level request flow (aggregated API) + +```mermaid +graph TD + client["kubectl / API client"] --> kube["Kubernetes API aggregation layer"] + kube --> apisvc["APIService: v1alpha1.aggregation.coder.com"] + apisvc --> agg["coder-k8s aggregated API server"] + agg --> provider["ClientProvider"] + provider --> sdk["Coder SDK client"] + sdk --> coderd["Backing coderd instance"] +``` diff --git a/docs/how-to/deploy-aggregated-apiserver.md b/docs/how-to/deploy-aggregated-apiserver.md index 7c4c6ca7..47f9fe26 100644 --- a/docs/how-to/deploy-aggregated-apiserver.md +++ b/docs/how-to/deploy-aggregated-apiserver.md @@ -1,65 +1,96 @@ # Deploy the aggregated API server (in-cluster) -This guide shows how to deploy the `coder-k8s` **aggregated API server** and register it with the Kubernetes API aggregation layer. - -The aggregated API server serves: +This guide deploys the aggregated API server for: - API group: `aggregation.coder.com` - Version: `v1alpha1` - Resources: `coderworkspaces`, `codertemplates` -## 1. Create the namespace +## 1) Create namespace and RBAC ```bash kubectl create namespace coder-system +kubectl apply -f config/rbac/ ``` -## 2. Apply RBAC - -Apply generated RBAC manifests (including the shared `coder-k8s` ServiceAccount and bindings): +## 2) Apply service and APIService manifests ```bash -kubectl apply -f config/rbac/ +kubectl apply -f deploy/apiserver-service.yaml +kubectl apply -f deploy/apiserver-apiservice.yaml ``` -## 3. Deploy the service and deployment +## 3) Choose a deployment model + +### Option A: all-in-one mode (recommended for most dev/test setups) + +`deploy/deployment.yaml` defaults to `--app=all`, which includes the aggregated API server. ```bash -kubectl apply -f deploy/apiserver-service.yaml kubectl apply -f deploy/deployment.yaml ``` -`deploy/deployment.yaml` defaults to `--app=all`, which runs the controller, aggregated API server, and MCP server in a single pod. +In this mode, backend Coder client configuration is discovered dynamically from eligible `CoderControlPlane` resources. -For split deployments, you can still run individual components by setting `--app=controller`, `--app=aggregated-apiserver`, or `--app=mcp-http` in the Deployment args. +### Option B: standalone aggregated API mode (`--app=aggregated-apiserver`) -## 4. Register the APIService +Use this when you want a split deployment and explicit backend configuration. + +1. Apply deployment manifest: ```bash -kubectl apply -f deploy/apiserver-apiservice.yaml +kubectl apply -f deploy/deployment.yaml ``` -## 5. Verify - -Wait for the deployment: +1. Configure required args: ```bash -kubectl rollout status deployment/coder-k8s -n coder-system +CODER_URL="https://coder.example.com" +CODER_SESSION_TOKEN="replace-me" +CODER_NAMESPACE="coder-system" + +kubectl -n coder-system set args deployment/coder-k8s --containers=coder-k8s -- \ + --app=aggregated-apiserver \ + --coder-url="${CODER_URL}" \ + --coder-session-token="${CODER_SESSION_TOKEN}" \ + --coder-namespace="${CODER_NAMESPACE}" ``` -Check the APIService: +1. Update probes to HTTPS on port `6443` for standalone mode: ```bash -kubectl get apiservice v1alpha1.aggregation.coder.com +kubectl -n coder-system patch deployment coder-k8s --type='merge' -p '{ + "spec": { + "template": { + "spec": { + "containers": [ + { + "name": "coder-k8s", + "livenessProbe": { + "httpGet": {"scheme": "HTTPS", "path": "/healthz", "port": 6443} + }, + "readinessProbe": { + "httpGet": {"scheme": "HTTPS", "path": "/readyz", "port": 6443} + } + } + ] + } + } + } +}' ``` -List resources served by the aggregated API server: +## 4) Verify ```bash +kubectl rollout status deployment/coder-k8s -n coder-system +kubectl get apiservice v1alpha1.aggregation.coder.com kubectl get coderworkspaces.aggregation.coder.com -A kubectl get codertemplates.aggregation.coder.com -A +kubectl logs -n coder-system deploy/coder-k8s ``` ## TLS note -`deploy/apiserver-apiservice.yaml` currently sets `insecureSkipTLSVerify: true`, which is convenient for development but not appropriate for production. +`deploy/apiserver-apiservice.yaml` uses `insecureSkipTLSVerify: true` for development convenience. +Use proper CA-backed TLS wiring for production environments. diff --git a/docs/how-to/deploy-controller.md b/docs/how-to/deploy-controller.md index f396cc6f..e6c6ea86 100644 --- a/docs/how-to/deploy-controller.md +++ b/docs/how-to/deploy-controller.md @@ -1,46 +1,69 @@ # Deploy the controller (in-cluster) -This guide shows how to deploy the `coder-k8s` **controller** to a Kubernetes cluster using manifests from `config/` and `deploy/`. +This guide deploys `coder-k8s` in **controller-only mode** (`--app=controller`). -## 1. Create the namespace +!!! note + `deploy/deployment.yaml` defaults to `--app=all`. In this guide, we explicitly switch it to controller-only mode. -The deployment manifests expect a `coder-system` namespace: +## 1) Create namespace ```bash kubectl create namespace coder-system ``` -## 2. Install the CRDs +## 2) Install CRDs -Install the `CoderControlPlane` CRD: +`config/crd/bases/` includes CRDs for: + +- `CoderControlPlane` +- `CoderProvisioner` +- `CoderWorkspaceProxy` + +Apply them: ```bash kubectl apply -f config/crd/bases/ ``` -## 3. Apply RBAC +## 3) Apply RBAC ```bash kubectl apply -f config/rbac/ ``` -## 4. Deploy `coder-k8s` +## 4) Deploy and force controller-only mode ```bash kubectl apply -f deploy/deployment.yaml +kubectl -n coder-system set args deployment/coder-k8s --containers=coder-k8s -- --app=controller ``` -`deploy/deployment.yaml` defaults to `--app=all`, which runs the controller, aggregated API server, and MCP server in a single pod. - -For split deployments, you can still run individual components by setting `--app=controller`, `--app=aggregated-apiserver`, or `--app=mcp-http` in the Deployment args. - -## 5. Verify +## 5) Verify ```bash kubectl rollout status deployment/coder-k8s -n coder-system kubectl get pods -n coder-system +kubectl logs -n coder-system deploy/coder-k8s ``` -## Customizing the image +Optional smoke check: + +```bash +kubectl apply -f config/samples/coder_v1alpha1_codercontrolplane.yaml +kubectl get codercontrolplanes -A +``` -By default, `deploy/deployment.yaml` uses `ghcr.io/coder/coder-k8s:latest`. For a different image tag, edit the deployment manifest before applying it. +## Customizing image + +By default, `deploy/deployment.yaml` uses `ghcr.io/coder/coder-k8s:latest`. +Edit the image tag before applying if you need a pinned version. + +## If you want all-in-one mode instead + +Skip `kubectl set args ... --app=controller` and keep the default `--app=all`, then also apply: + +```bash +kubectl apply -f deploy/apiserver-service.yaml +kubectl apply -f deploy/apiserver-apiservice.yaml +kubectl apply -f deploy/mcp-service.yaml +``` diff --git a/docs/how-to/troubleshooting.md b/docs/how-to/troubleshooting.md index b26a414b..5b17b8d0 100644 --- a/docs/how-to/troubleshooting.md +++ b/docs/how-to/troubleshooting.md @@ -1,85 +1,103 @@ # Troubleshooting -## The binary exits immediately with "--app flag is required" +## I expected `--app` to be required, but behavior is different -`coder-k8s` requires an explicit application mode. +`coder-k8s` defaults to `--app=all` when you do not pass `--app`. -For the controller: +If you want to isolate components for debugging, set one explicit mode: ```bash GOFLAGS=-mod=vendor go run . --app=controller -``` - -For the aggregated API server: - -```bash GOFLAGS=-mod=vendor go run . --app=aggregated-apiserver +GOFLAGS=-mod=vendor go run . --app=mcp-http ``` -## "no matches for kind" when applying a `CoderControlPlane` +If you pass an unsupported value, startup fails with an `assertion failed: unsupported --app value ...` error. + +## `no matches for kind` when applying `CoderControlPlane` -This usually means the CRD isn't installed in the cluster. +Install (or reinstall) CRDs: ```bash make manifests kubectl apply -f config/crd/bases/ +kubectl get crd | grep coder.com ``` -## The controller is running, but reconciliation doesn't happen +## Controller deployment is running, but reconciliation does not happen -- Check controller logs: +Use the resource names from the shipped manifests: - ```bash - kubectl logs -n coder-system deploy/coder-k8s-controller - ``` +- Deployment: `coder-k8s` +- ClusterRole: `manager-role` +- ClusterRoleBinding: `coder-k8s` -- Confirm RBAC is applied: +Check status and logs: - ```bash - kubectl get clusterrole coder-k8s-controller - kubectl get clusterrolebinding coder-k8s-controller - ``` +```bash +kubectl get deploy -n coder-system coder-k8s +kubectl logs -n coder-system deploy/coder-k8s +kubectl get clusterrole manager-role +kubectl get clusterrolebinding coder-k8s +``` -## Aggregated `codertemplates` / `coderworkspaces` reads are empty or inconsistent +Then inspect a specific control plane object: -If `kubectl get codertemplates.aggregation.coder.com` or `kubectl get coderworkspaces.aggregation.coder.com` returns empty data unexpectedly, check for CRD/APIService conflicts. +```bash +kubectl get codercontrolplane -A +kubectl describe codercontrolplane -n +``` -When both of these exist at once: +## `CoderControlPlane` stays `Pending` -- `APIService` `v1alpha1.aggregation.coder.com` -- CRDs `codertemplates.aggregation.coder.com` and/or `coderworkspaces.aggregation.coder.com` +Typical causes: -Kubernetes may not route reads the way you expect for demos. +1. Control-plane Deployment has no ready pods. +2. Operator bootstrap token is not ready yet. +3. Optional license Secret is missing or invalid when `spec.licenseSecretRef` is set. + +Debug commands: ```bash -kubectl get apiservice v1alpha1.aggregation.coder.com -kubectl get crd codertemplates.aggregation.coder.com coderworkspaces.aggregation.coder.com +kubectl get codercontrolplane -n -o yaml +kubectl get deploy,svc -n +kubectl logs -n coder-system deploy/coder-k8s ``` -For APIService-based demos, remove the conflicting aggregation CRDs: +## Aggregated APIService is `False` / `Unavailable` + +Verify required resources: ```bash -kubectl delete crd codertemplates.aggregation.coder.com coderworkspaces.aggregation.coder.com -kubectl apply -f deploy/apiserver-apiservice.yaml -kubectl wait --for=condition=Available apiservice/v1alpha1.aggregation.coder.com --timeout=120s +kubectl get deploy -n coder-system coder-k8s +kubectl get svc -n coder-system coder-k8s-apiserver +kubectl get apiservice v1alpha1.aggregation.coder.com -o yaml +kubectl logs -n coder-system deploy/coder-k8s ``` -## Aggregated APIService shows `False` / `Unavailable` +If you use APIService aggregation demos, avoid installing conflicting CRDs for the same aggregated resources (`coderworkspaces.aggregation.coder.com`, `codertemplates.aggregation.coder.com`). + +## Aggregated reads return `ServiceUnavailable` + +In `all` mode, this usually means no eligible `CoderControlPlane` exists yet (or operator access is not ready). -- Ensure the deployment and service exist: +In standalone `--app=aggregated-apiserver` mode, ensure all three are configured: - ```bash - kubectl get deploy,svc -n coder-system | grep coder-k8s-apiserver - ``` +- `--coder-url` +- `--coder-session-token` +- `--coder-namespace` + +Check logs for provider configuration messages: + +```bash +kubectl logs -n coder-system deploy/coder-k8s +``` -- Inspect APIService status: +## Aggregated reads return `multiple eligible CoderControlPlane ...` - ```bash - kubectl describe apiservice v1alpha1.aggregation.coder.com - ``` +Current dynamic provider behavior expects a single eligible control plane per request scope. -- Check the aggregated API server logs: +If you have multiple ready control planes, narrow scope: - ```bash - kubectl logs -n coder-system deploy/coder-k8s-apiserver - ``` +- Query a single namespace (`-n `), and/or +- Run a dedicated aggregated API deployment pinned with `--coder-namespace`. diff --git a/docs/index.md b/docs/index.md index 8bb72940..61a26128 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,16 +1,41 @@ # coder-k8s documentation -`coder-k8s` is a Go-based Kubernetes control-plane project with two app modes: +!!! warning + **Highly experimental / alpha software** + This project is an active prototype. Do not use it in production. -- **Controller**: a `controller-runtime` operator for `CoderControlPlane` (`coder.com/v1alpha1`). -- **Aggregated API server**: an aggregated API server for `CoderWorkspace` and `CoderTemplate` - (`aggregation.coder.com/v1alpha1`). +`coder-k8s` is a Kubernetes control-plane project for running and managing Coder through Kubernetes APIs. -This site follows the **Diátaxis** documentation framework: +## What is in this repository? -- **Tutorials**: learning-oriented, step-by-step guides. -- **How-to guides**: task-focused recipes. -- **Reference**: factual documentation (APIs, flags, manifests). -- **Explanation**: concepts and architecture. +`coder-k8s` ships one binary with four app modes: -If you're new to the project, start with **Tutorials → Getting started**. +- **`all` (default)**: controller + aggregated API server + MCP server in one process. +- **`controller`**: reconciles `CoderControlPlane`, `CoderProvisioner`, `CoderWorkspaceProxy` (`coder.com/v1alpha1`). +- **`aggregated-apiserver`**: serves `CoderWorkspace` + `CoderTemplate` (`aggregation.coder.com/v1alpha1`). +- **`mcp-http`**: serves MCP tooling over HTTP. + +## Documentation map (Diátaxis) + +- **Tutorials**: guided learning path + - [Getting started](tutorials/getting-started.md) +- **How-to guides**: task-focused operations + - [Deploy controller](how-to/deploy-controller.md) + - [Deploy aggregated API server](how-to/deploy-aggregated-apiserver.md) + - [Run MCP server](how-to/mcp-server.md) + - [Troubleshooting](how-to/troubleshooting.md) +- **Reference**: generated API reference + - [API reference](reference/api/codercontrolplane.md) +- **Explanation**: conceptual internals + - [Architecture](explanation/architecture.md) + +## Quick commands + +```bash +make manifests +make test +make build +make docs-serve +``` + +New here? Start with the [Getting started tutorial](tutorials/getting-started.md). diff --git a/docs/tutorials/getting-started.md b/docs/tutorials/getting-started.md index 1190d389..02e556bd 100644 --- a/docs/tutorials/getting-started.md +++ b/docs/tutorials/getting-started.md @@ -1,56 +1,86 @@ # Getting started (local development) -This tutorial walks through running the `coder-k8s` **controller** locally against a Kubernetes cluster. +This tutorial walks through running the `coder-k8s` **controller** locally against a Kubernetes cluster, then creating your first `CoderControlPlane` resource. ## Prerequisites - Go 1.25+ (`go.mod` currently declares Go 1.25.7) -- A Kubernetes cluster (OrbStack is recommended for local development; any cluster works) -- `kubectl` configured to point at your cluster context +- A Kubernetes cluster (OrbStack, KIND, or any conformant cluster) +- `kubectl` configured to your target context -If you use the Nix devshell, run: +If you use the Nix devshell: ```bash nix develop ``` -## 1. Generate and install CRDs +Optional: create a disposable KIND cluster with project defaults: -Generate the CRD and RBAC manifests: +```bash +make kind-dev-up +``` + +## 1) Generate and install CRDs + +Generate manifests: ```bash make manifests ``` -Install the CRDs into your cluster: +Install CRDs into your cluster: ```bash kubectl apply -f config/crd/bases/ ``` -## 2. Run the controller locally +## 2) Run the controller locally -Run the controller in **controller** mode (uses your kubeconfig context): +Start controller mode (terminal A): ```bash GOFLAGS=-mod=vendor go run . --app=controller ``` -## 3. Create a sample `CoderControlPlane` +Leave this terminal running so you can watch reconciliation logs. + +## 3) Create a sample `CoderControlPlane` -In another terminal: +In a second terminal (terminal B): ```bash kubectl apply -f config/samples/coder_v1alpha1_codercontrolplane.yaml ``` -## 4. Verify +## 4) Verify reconciliation + +Check resource status: ```bash kubectl get codercontrolplanes -A +kubectl describe codercontrolplane codercontrolplane-sample -n default +``` + +The controller creates a Deployment + Service named after the control plane (`codercontrolplane-sample`) in the same namespace. + +```bash +kubectl get deploy,svc -n default +``` + +## 5) Clean up (optional) + +```bash +kubectl delete codercontrolplane codercontrolplane-sample -n default +``` + +If you used `kind-dev-up`, you can remove the cluster with: + +```bash +make kind-dev-down ``` ## Next steps -- Learn how to deploy the controller in-cluster: **How-to guides → Deploy controller**. -- Learn how the project is structured: **Explanation → Architecture**. +- Deploy in-cluster: [How-to → Deploy controller](../how-to/deploy-controller.md) +- Understand internals: [Explanation → Architecture](../explanation/architecture.md) +- Explore aggregated APIs: [How-to → Deploy aggregated API server](../how-to/deploy-aggregated-apiserver.md)