Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/chart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ jobs:
- name: Setup Helm
uses: azure/setup-helm@v4
with:
version: v3.21.0
version: v3.21.4
- name: Setup Toolbox Cache
uses: actions/cache@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ jobs:
if: steps.ref.outputs.kind != 'development'
uses: azure/setup-helm@v4
with:
version: v3.21.0
version: v3.21.4
- name: Prepare release chart
if: steps.ref.outputs.kind != 'development'
run: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ metadata:
{{- toYaml . | nindent 4 }}
{{- end }}
---
{{- /*
The worker is bound to cluster-admin, so this binding already covers the routing
resources it manages: the service and the legacy endpoints of the system routing,
and the endpoint slices of the discovery.k8s.io group it writes when it runs
outside a nearby cluster. The grant those operations need is get, list, create,
update and delete on endpointslices, and get, create, update and delete on
services and endpoints. The endpoint slice carries the routing service as its
owner and blocks its deletion, so the grant needs update on the finalizers
subresource of services as well. A narrower binding has to keep all of them, or
the worker stops routing.
*/}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
Expand Down
6 changes: 3 additions & 3 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ A skill link names a procedure; the entry's other fields carry shared facts.
- Use for: which version a manifest or call targets. User-facing resources are `worker.gpustack.ai/v1`; `worker.gpustack.ai/v1alpha1` is internal controller storage behind the public API, not a version users switch between. The layers: public types, the handlers that proxy them onto internal storage, code generation, and the RBAC that grants access.
- Aliases: `worker.gpustack.ai/v1`, `v1alpha1`, `CRD`, `aggregated apiserver`
- Guides: the version table in [Development](contribute/development.md); a public surface example with its grants in [Model Artifact API](modules/model-delivery/views.md).
- Code: public types in [api/worker/v1](../api/worker/v1/) and internal storage in [api/worker/v1alpha1](../api/worker/v1alpha1/) · handlers and proxies in [pkg/worker/extensionapis](../pkg/worker/extensionapis/) over the [pkg/extensionapi](../pkg/extensionapi/) plumbing · generators in [gen/api](../gen/api/) · worker RBAC in [deploy/gpustack-operator/chart/templates/worker/serviceaccount.yaml](../deploy/gpustack-operator/chart/templates/worker/serviceaccount.yaml)
- Code: public types in [api/worker/v1](../api/worker/v1/) and internal storage in [api/worker/v1alpha1](../api/worker/v1alpha1/) · handlers and proxies in [pkg/worker/extensionapis](../pkg/worker/extensionapis/) over the [pkg/extensionapi](../pkg/extensionapi/) plumbing · the routing objects the extension API services are fronted by in [pkg/systemkuberess](../pkg/systemkuberess/) · generators in [gen/api](../gen/api/) · worker RBAC in [deploy/gpustack-operator/chart/templates/worker/serviceaccount.yaml](../deploy/gpustack-operator/chart/templates/worker/serviceaccount.yaml)
- Related: [Development](#development) (`make generate` regenerates the API surface) · [GPU Instances](#gpu-instances) (Instance and InstanceType are the main public resources)
- Skills: [gpustack-operator-generate](../.agents/skills/gpustack-operator-generate/SKILL.md) (regenerate after type or webhook edits)

Expand All @@ -151,7 +151,7 @@ A skill link names a procedure; the entry's other fields carry shared facts.
- ID: `development`
- Use for: build, lint, test and codegen commands; commit and PR conventions; contributor invariants; release steps; site publication and translations.
- Aliases: `make`, `lint`, `codegen`, `vendored dependencies`, `staging`, `Hugo`, `GitHub Pages`
- Guides: commands and targets in [Development](contribute/development.md); a local test cluster in [kind Setup](contribute/kind.md); startup invariants in [Internals](contribute/internals.md); orientation in [Architecture](getting-started/architecture.md).
- Guides: commands and targets in [Development](contribute/development.md); a local test cluster in [Local Cluster Setup](contribute/local-cluster-setup.md); startup invariants in [Internals](contribute/internals.md); orientation in [Architecture](getting-started/architecture.md).
- Code: [Makefile](../Makefile) and the scripts behind it in [hack](../hack/) · site publication in [Site workflow](../.github/workflows/site.yml) and [publisher](../hack/site/publish.py) · patched modules in [staging](../staging/) · generators in [gen](../gen/) · upgrade compatibility checks in [upgrade-compat.sh](../hack/check/upgrade-compat.sh) · the chart test's kubeconfig isolation in [helm.sh](../hack/lib/helm.sh) and [helm-chart-test-selftest.sh](../hack/check/helm-chart-test-selftest.sh)
- Related: [API Changes](#api-changes) (what `make generate` owns) · [Installation](#installation) (chart targets and vendoring)
- Skills: [gpustack-operator-overview](../.agents/skills/gpustack-operator-overview/SKILL.md) (codebase tour) · [gpustack-operator-docs](../.agents/skills/gpustack-operator-docs/SKILL.md) (documentation changes) · [gpustack-operator-code-review](../.agents/skills/gpustack-operator-code-review/SKILL.md) (PR review criteria) · [gpustack-operator-issue-pr](../.agents/skills/gpustack-operator-issue-pr/SKILL.md) (issue and PR titles) · [gpustack-operator-release](../.agents/skills/gpustack-operator-release/SKILL.md) (cut a release) · [gpustack-operator-generate](../.agents/skills/gpustack-operator-generate/SKILL.md) (API codegen)
Expand Down Expand Up @@ -291,7 +291,7 @@ A skill link names a procedure; the entry's other fields carry shared facts.
| Page | Description |
|---|---|
| [Development](contribute/development.md) | Build, generate and lint the project. |
| [kind Setup](contribute/kind.md) | Install kind and provide a cluster for development tests. |
| [Local Cluster Setup](contribute/local-cluster-setup.md) | Install kind and provide a cluster for development tests. |
| [Internals](contribute/internals.md) | Review startup and naming constraints. |

## Conventions
Expand Down
2 changes: 1 addition & 1 deletion docs/contribute/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ before changing the operator's behavior.
## Commands

For cluster-backed tests, provide a kind cluster and its kubeconfig/context. Follow
[kind Setup](kind.md) for manual installation and connection checks.
[Local Cluster Setup](local-cluster-setup.md) for manual installation and connection checks.

`make <target> [args]` runs `hack/<target>.sh` and forwards `args` to it. All builds use `CGO_ENABLED=1`,
`GODEBUG=gotypesalias=0` and the build tags `goccy netgo`.
Expand Down
44 changes: 44 additions & 0 deletions docs/contribute/internals.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,50 @@ last resort, not a pattern to copy; reach for it only where idempotence is out o
> **Why** — Helm's release storage is a compare-and-create, not a mutex, and two Helm actions on one
> release can leave it pending where no later attempt gets past.

### System routing resources

A worker outside a nearby cluster has no pod for the chart's `Service` to select, so it installs the
routing objects itself (`pkg/systemkuberess`), in the system namespace:

- a selectorless `Service` with a `https` port;
- legacy `Endpoints` of the same name, holding the address of the system;
- an `EndpointSlice` in `discovery.k8s.io/v1`, holding the same address and port.

Three environment variables configure the routing at worker startup:

| Variable | Default | Purpose |
|---|---|---|
| `KUBERNETES_POD_NAMESPACE` | `gpustack-system` | Namespace of the routing `Service`, `Endpoints`, `EndpointSlice`, and extension `APIService` backends. |
| `KUBERNETES_SERVICE_NAME` | `gpustack-operator-worker` | Name of the routing `Service` and legacy `Endpoints` (`<name>-direct` for the `EndpointSlice`). |
| `KUBERNETES_POD_IP` | primary host interface IP | Reachable worker IP written to the routing `Endpoints` and `EndpointSlice`. |

With its `--enable-aggregator-routing` flag, the kube-apiserver resolves the backend of an extension
API service from the `EndpointSlice`; without it, the backend is the cluster IP of the `Service`.

The slice therefore carries the `kubernetes.io/service-name` label of the `Service`, a port named
after the `Service` port, and a ready endpoint on the address of the system. Its address type
follows the family of that address, and the endpoint slice controller leaves it alone because its
`endpointslice.kubernetes.io/managed-by` label names this operator.

The legacy `Endpoints` stay for the aggregators that read them, which are the ones older than
Kubernetes 1.34. They carry the `endpointslice.kubernetes.io/skip-mirror` label, so the mirroring
controller neither mirrors them nor leaves a second slice behind that the aggregator could pick
instead.

The reconcile replaces the address and the port it owns instead of appending them, and removes the
slices it owns and no longer needs: the mirror of the legacy `Endpoints`, and a slice an earlier
version left under another name. It removes a slice only when the owner reference names the routing
`Service` or the legacy `Endpoints` of this worker, so a slice of another service stays.

The owner is recognized by the name it carries, and not by its uid, because the routing `Service` and
the legacy `Endpoints` are recreated whenever their spec changes. A slice the resource of the past
owned still belongs to the worker, so the worker adopts it and rewrites its owner reference; refusing
it would leave the worker unable to repair the routing it owns.

One worker owns the routing of a cluster at a time. The namespace and the routing service name are the
same in every installation, so two workers pointing at one cluster write the same slice, and the last
write wins. A slice the worker does not own is refused rather than taken over.

## Worker gateway

`pkg/workergateway/service` folds many clusters' `InstanceType`s into one fleet-wide
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# kind Setup
# Local Cluster Setup

Use [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) to provide a local Kubernetes
cluster for development and integration tests. Keep its kubeconfig separate from other clusters.
Expand Down
Loading
Loading