Architecture¶
coder-k8s is one Go binary. The --app flag selects the components that run. The default value is all.
--app |
Runs |
|---|---|
all (default) |
The controller and the aggregated API server in one process |
controller |
The controller-runtime manager and the reconcilers |
aggregated-apiserver |
The aggregated API server (aggregation.coder.com/v1alpha1) |
mcp-http |
The MCP HTTP server. Only this mode runs it, and it requires --mcp-token-file. |
All-in-one mode¶
In all mode, internal/app/allapp creates one controller-runtime manager with one shared cache. allapp registers the reconcilers with the manager. Then it adds the aggregated API server to the manager as a runnable that does not need leader election. The result is one process, one cache, and one startup sequence.
all mode does not include the MCP server, because the MCP server acts with the authority of the operator. To run it, you must set --app=mcp-http on purpose.
graph TD
entry["coder-k8s (--app=all)"] --> mgr["controller-runtime manager"]
mgr --> ctrl["Controller reconcilers"]
mgr --> agg["Aggregated API server runnable"]
ctrl --> crds["coder.com/v1alpha1 CRDs"]
agg --> api["aggregation.coder.com/v1alpha1"]
Components¶
| Controller | Aggregated API server | MCP server | |
|---|---|---|---|
| Code | internal/app/controllerapp/, internal/controller/ |
internal/app/apiserverapp/, internal/aggregated/storage/, internal/aggregated/coder/ |
internal/app/mcpapp/ |
| Listens on | :8081 (/healthz, /readyz) |
:6443 HTTPS (default) |
127.0.0.1:8090 only. /mcp requires the bearer token. /healthz and /readyz do not. |
| Resources | CoderControlPlane, CoderProvisioner, CoderWorkspaceProxy |
coderworkspaces, codertemplates, codertemplateversions |
Tools for control planes, templates, workspaces, events, pod logs, and run state |
Controller¶
The controller uses controller-runtime with leader election. For each CoderControlPlane, it creates or updates a Deployment and a Service in the same namespace. Then it writes the status, for example status.url, status.phase, and the reference to the operator token.
Aggregated API server¶
The storage of the aggregated API server is the Coder SDK, not memory or etcd. Each request becomes a call to the Coder API. For the effects of this design, see Aggregated API behavior.
The calls to Coder use the operator credentials of the control plane. Thus the server checks each Kubernetes caller first:
- It uses delegated authentication. It accepts the front-proxy client certificate of kube-apiserver, and it uses TokenReview for bearer tokens.
- It uses delegated authorization (SubjectAccessReview).
- If these checks are not available, the server does not allow the request (it fails closed).
- Only the exact paths
/healthz,/livez, and/readyzanswer callers that are not authenticated.
For the full rules, see How callers are checked.
The server does not map Kubernetes users to Coder users. Thus Kubernetes RBAC on aggregation.coder.com in a namespace gives owner-equivalent access in the Coder deployment of the control plane that serves that namespace.
The coderworkspaces/log subresource uses the same operator token. Its own RBAC grant is the only check before the server reads a build log.
The codertemplates/promote subresource also uses the operator token. Its own RBAC grant (create, optionally limited with resourceNames to some templates) is the only check before the server activates a template version.
The server finds its Coder backend in one of two ways:
allmode:ControlPlaneClientProviderfinds the eligibleCoderControlPlaneresources. For each request, it reads the operator token Secret of the matching control plane.- Standalone mode: you set the static flags
--coder-url,--coder-session-token, and--coder-namespace.
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"]
Manifests¶
| Path | Contents |
|---|---|
config/crd/bases/ |
The generated CRDs for CoderControlPlane, CoderProvisioner, and CoderWorkspaceProxy |
config/rbac/ |
The coder-k8s ServiceAccount, the manager-role ClusterRole, and the bindings (including auth-delegator) |
config/apiserver-standalone/ |
For standalone --app=aggregated-apiserver: the coder-k8s-apiserver ServiceAccount, its RBAC, and the placeholder Secret for the serving CA |
deploy/deployment.yaml |
The coder-k8s Deployment (default --app=all) |
deploy/apiserver-service.yaml, deploy/apiserver-apiservice.yaml |
The Service and APIService that make the aggregated API available |