mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
Closes [DOCS-351](https://linear.app/codercom/issue/DOCS-351). > [!WARNING] > **DO NOT MERGE** until [DOCS-349](https://linear.app/codercom/issue/DOCS-349) ([coder.com#877](https://github.com/coder/coder.com/pull/877)) has shipped to production and baked for at least one Vercel cycle. > > Without DOCS-349, the relative links in this PR resolve to broken docs-route URLs (`/docs/helm/coder/values.yaml` -> 404) instead of GitHub URLs tagged with the displayed docs version. DOCS-349 fixes the rewriter to classify these as GitHub blob/tree URLs with the page's resolved ref. ## TL;DR Converts 121 absolute `https://github.com/coder/coder/(blob|tree)/main/<path>` links across 39 docs markdown files to relative paths. After this lands AND DOCS-349 deploys, every one of these links will follow the displayed docs version (mainline tag on bare URLs, explicit tag on `/@vX.Y.Z/`, `main` on `/@main/`) instead of always pointing to `main`. ## Why Today a reader on `/docs/@v2.30.0/install/docker` follows a `compose.yaml` link and arrives at `main`'s `compose.yaml`, which doesn't necessarily match what the docs page describes. Helm values, Terraform templates, and source-code references in particular drift across versions. The fix is to let the coder.com rewriter substitute the page's resolved ref into the URL; that only works on relative links. ## Example payoff (post-DOCS-349) | URL | Today (absolute, always `main`) | After (relative + rewriter) | |---|---|---| | `/docs/install/docker` | `https://github.com/coder/coder/blob/main/compose.yaml` | `https://github.com/coder/coder/blob/v2.34.1/compose.yaml` (today's mainline) | | `/docs/@v2.30.0/install/docker` | same as above | `https://github.com/coder/coder/blob/v2.30.0/compose.yaml` | | `/docs/@main/install/docker` | same as above | `https://github.com/coder/coder/blob/main/compose.yaml` | ## Scope - **121 conversions** across **39 files**. - Verb breakdown: `tree/main` (directories) and `blob/main` (files), both flipped to relative paths. - Line anchors (`#L23-L24`) and query strings preserved verbatim. - Conversion is mechanical: relative path computed from the doc file's directory to the target via `os.path.relpath`. Any path starting at the same directory or below gets a `./` prefix; otherwise `../` chains. ## Rebased on main The branch was rebased onto `main` after the DOCS-350 hotfix ([#26339](https://github.com/coder/coder/pull/26339)) merged. The hotfix repointed 3 `docs-backend-contrib-guide` refs in `backend.md` to `main`, which then needed the same `main` -> relative conversion this PR is doing for the other 121 links. The conflict was resolved by reapplying the mechanical conversion to `backend.md` after taking the hotfix's content. Net result: those 3 links land here as relative, same as everything else. New HEAD `3f501cb622`. ## Inline fix folded in: dead `nix` link - `docs/about/contributing/CONTRIBUTING.md:7` -> `../../../nix` The original absolute URL `https://github.com/coder/coder/tree/main/nix` already returned 404 today. Repointed to `flake.nix` (modern Nix entrypoint, what the prose "Nix environment" semantically refers to). Closes [DOCS-357](https://linear.app/codercom/issue/DOCS-357) here since the `check-docs` Linkspector job surfaced it during rebase; cheaper to fix inline than in a separate single-line PR. ## Out of scope (filed separately) - [DOCS-350](https://linear.app/codercom/issue/DOCS-350): 3 dead `docs-backend-contrib-guide` branch refs in `backend.md` ([#26339](https://github.com/coder/coder/pull/26339), merged). - [DOCS-352](https://linear.app/codercom/issue/DOCS-352): 10 SHA-pinned `(blob|tree)/<sha>` links pending intent review. - [DOCS-355](https://linear.app/codercom/issue/DOCS-355): code-server analog (4 absolute `(blob|tree)/main` links in `coder/code-server`). - [DOCS-356](https://linear.app/codercom/issue/DOCS-356): 2 upstream content bugs in `coder/code-server/docs/CONTRIBUTING.md` (independent of this PR). ## Not triggering `/coder-agents-review` Docs-only edit; per `AGENTS.md` the bot review is reserved for product/CI changes. ## Pre-mortem | Concern | Mitigation | |---|---| | Merging before DOCS-349 deploys regresses ~120 currently-working links into 404s on coder.com | Clear DO-NOT-MERGE banner; tracked as blocker in Linear. | | Relative path computed incorrectly (off-by-one `..`) | Verified all 114 newly-relative non-md/non-image paths resolve to existing files in the repo (only exception is the pre-existing dead `nix` link above). | | Line anchors stripped during conversion | Preserved by the substitution regex; verified `#L<n>-L<m>` cases in `airgap.md` and `speed-up-templates.md`. | | Future code reorgs change file locations | Relative links will start pointing to nothing. Same failure mode as absolute links pointing to renamed files; can be caught with a future link-checker job. | ## Validation ``` $ grep -rE 'github\.com/coder/coder/(blob|tree)/main' docs --include="*.md" | wc -l 0 $ git diff --stat origin/main | tail -1 39 files changed, 118 insertions(+), 118 deletions(-) ``` 114 newly-relative paths verified to resolve to existing repo files (Python `os.path.exists` check on each computed target). <details> <summary>Decision log + planning context</summary> **Why relative over `(blob|tree)/{{currentDocsVersion}}/...` templating**: relative paths require zero markdown-system support and zero upstream churn beyond this one PR. Templating would require a preprocessor on `coder.com` side AND a convention upstream authors have to remember; relative paths just work in a plain editor and `github.com`'s own renderer too. **Why `./` prefix on same-directory targets**: makes the conversion grep-able later (`grep -E '\((\.\./|\./)'`). **Why preserve `#L<n>-L<m>` anchors verbatim**: the anchor is meaningful to the linked file's content, not to the URL form; keeping it as-is preserves authorial intent. If the file later changes such that the line range drifts, that's a different problem the SHA-pin audit ([DOCS-352](https://linear.app/codercom/issue/DOCS-352)) will surface. </details> --- *Generated by Coder Agents on @nickvigilante's behalf.* ## Drive-by external link fix folded in `docs/about/contributing/CONTRIBUTING.md:296` cited `https://reflectoring.io/meaningful-commit-messages/` which is returning HTTP 503 (the host appears to be down site-wide right now). `check-docs` Linkspector flagged it after the rebase. Replaced with `https://cbea.ms/git-commit/` (Chris Beams' canonical "If applied, this commit will..." article, confirmed 200), which is the original source of the rule the prose recites anyway.
271 lines
12 KiB
Markdown
271 lines
12 KiB
Markdown
# Scale Tests and Utilities
|
||
|
||
We scale-test Coder with a built-in utility that can
|
||
be used in your environment for insights into how Coder scales with your
|
||
infrastructure. For scale-testing Kubernetes clusters we recommend that you install
|
||
and use the dedicated Coder template,
|
||
[scaletest-runner](../../../scaletest/templates/scaletest-runner).
|
||
|
||
Learn more about [Coder’s architecture](./architecture.md) and our
|
||
[scale-testing methodology](./scale-testing.md).
|
||
|
||
For more information about scaling, see our [Coder scaling best practices](../../tutorials/best-practices/scale-coder.md).
|
||
|
||
## Recent scale tests
|
||
|
||
The information in this doc is for reference purposes only, and is not intended
|
||
to be used as guidelines for infrastructure sizing.
|
||
|
||
Review the [Reference Architectures](./validated-architectures/index.md#node-sizing) for
|
||
hardware sizing recommendations.
|
||
|
||
| Environment | Coder CPU | Coder RAM | Coder Replicas | Database | Users | Concurrent builds | Concurrent connections (Terminal/SSH) | Coder Version | Last tested |
|
||
|------------------|-----------|-----------|----------------|-------------------|-------|-------------------|---------------------------------------|---------------|--------------|
|
||
| Kubernetes (GKE) | 3 cores | 12 GB | 1 | db-f1-micro | 200 | 3 | 200 simulated | `v0.24.1` | Jun 26, 2023 |
|
||
| Kubernetes (GKE) | 4 cores | 8 GB | 1 | db-custom-1-3840 | 1500 | 20 | 1,500 simulated | `v0.24.1` | Jun 27, 2023 |
|
||
| Kubernetes (GKE) | 2 cores | 4 GB | 1 | db-custom-1-3840 | 500 | 20 | 500 simulated | `v0.27.2` | Jul 27, 2023 |
|
||
| Kubernetes (GKE) | 2 cores | 8 GB | 2 | db-custom-2-7680 | 1000 | 20 | 1000 simulated | `v2.2.1` | Oct 9, 2023 |
|
||
| Kubernetes (GKE) | 4 cores | 16 GB | 2 | db-custom-8-30720 | 2000 | 50 | 2000 simulated | `v2.8.4` | Feb 28, 2024 |
|
||
| Kubernetes (GKE) | 2 cores | 4 GB | 2 | db-custom-2-7680 | 1000 | 50 | 1000 simulated | `v2.10.2` | Apr 26, 2024 |
|
||
|
||
> [!NOTE]
|
||
> A simulated connection reads and writes random data at 40KB/s per connection.
|
||
|
||
## Scale testing utility
|
||
|
||
Since Coder's performance is highly dependent on the templates and workflows you
|
||
support, you may wish to use our internal scale testing utility against your own
|
||
environments.
|
||
|
||
> [!IMPORTANT]
|
||
> This utility is experimental.
|
||
>
|
||
> It is not subject to any compatibility guarantees and may cause interruptions
|
||
> for your users.
|
||
> To avoid potential outages and orphaned resources, we recommend that you run
|
||
> scale tests on a secondary "staging" environment or a dedicated
|
||
> Kubernetes playground cluster.
|
||
>
|
||
> Run it against a production environment at your own risk.
|
||
|
||
### Create workspaces
|
||
|
||
The following command will provision a number of Coder workspaces using the
|
||
specified template and extra parameters:
|
||
|
||
```shell
|
||
coder exp scaletest create-workspaces \
|
||
--retry 5 \
|
||
--count "${SCALETEST_PARAM_NUM_WORKSPACES}" \
|
||
--template "${SCALETEST_PARAM_TEMPLATE}" \
|
||
--concurrency "${SCALETEST_PARAM_CREATE_CONCURRENCY}" \
|
||
--timeout 5h \
|
||
--job-timeout 5h \
|
||
--no-cleanup \
|
||
--output json:"${SCALETEST_RESULTS_DIR}/create-workspaces.json"
|
||
```
|
||
|
||
The command does the following:
|
||
|
||
1. Create `${SCALETEST_PARAM_NUM_WORKSPACES}` workspaces concurrently
|
||
(concurrency level: `${SCALETEST_PARAM_CREATE_CONCURRENCY}`) using the
|
||
template `${SCALETEST_PARAM_TEMPLATE}`.
|
||
1. Leave workspaces running to use in next steps (`--no-cleanup` option).
|
||
1. Store provisioning results in JSON format.
|
||
1. If you don't want the creation process to be interrupted by any errors, use
|
||
the `--retry 5` flag.
|
||
|
||
For more built-in `scaletest` options, use the `--help` flag:
|
||
|
||
```shell
|
||
coder exp scaletest create-workspaces --help
|
||
```
|
||
|
||
### Traffic Generation
|
||
|
||
Given an existing set of workspaces created previously with `create-workspaces`,
|
||
the following command will generate traffic similar to that of Coder's Web
|
||
Terminal against those workspaces.
|
||
|
||
```shell
|
||
# Produce load at about 1000MB/s (25MB/40ms).
|
||
coder exp scaletest workspace-traffic \
|
||
--template "${SCALETEST_PARAM_GREEDY_AGENT_TEMPLATE}" \
|
||
--bytes-per-tick $((1024 * 1024 * 25)) \
|
||
--tick-interval 40ms \
|
||
--timeout "$((delay))s" \
|
||
--job-timeout "$((delay))s" \
|
||
--scaletest-prometheus-address 0.0.0.0:21113 \
|
||
--target-workspaces "0:100" \
|
||
--trace=false \
|
||
--output json:"${SCALETEST_RESULTS_DIR}/traffic-${type}-greedy-agent.json"
|
||
```
|
||
|
||
Traffic generation can be parametrized:
|
||
|
||
1. Send `bytes-per-tick` every `tick-interval`.
|
||
1. Enable tracing for performance debugging.
|
||
1. Target a range of workspaces with `--target-workspaces 0:100`.
|
||
1. For dashboard traffic: Target a range of users with `--target-users 0:100`.
|
||
1. Store provisioning results in JSON format.
|
||
1. Expose a dedicated Prometheus address (`--scaletest-prometheus-address`) for
|
||
scaletest-specific metrics.
|
||
|
||
The `workspace-traffic` supports also other modes - SSH traffic, workspace app:
|
||
|
||
1. For SSH traffic: Use `--ssh` flag to generate SSH traffic instead of Web
|
||
Terminal.
|
||
1. For workspace app traffic: Use `--app [wsdi|wsec|wsra]` flag to select app
|
||
behavior.
|
||
|
||
- `wsdi`: WebSocket discard
|
||
- `wsec`: WebSocket echo
|
||
- `wsra`: WebSocket read
|
||
|
||
### Cleanup
|
||
|
||
The scaletest utility will attempt to clean up all workspaces it creates. If you
|
||
wish to clean up all workspaces, you can run the following command:
|
||
|
||
```shell
|
||
coder exp scaletest cleanup \
|
||
--cleanup-job-timeout 2h \
|
||
--cleanup-timeout 15min
|
||
```
|
||
|
||
This will delete all workspaces and users with the prefix `scaletest-`.
|
||
|
||
## Scale testing template
|
||
|
||
Consider using a dedicated
|
||
[scaletest-runner](../../../scaletest/templates/scaletest-runner)
|
||
template alongside the CLI utility for testing large-scale Kubernetes clusters.
|
||
|
||
The template deploys a main workspace with scripts used to orchestrate Coder,
|
||
creating workspaces, generating workspace traffic, or load-testing workspace
|
||
apps.
|
||
|
||
### Parameters
|
||
|
||
The _scaletest-runner_ offers the following configuration options:
|
||
|
||
- Workspace size selection: minimal/small/medium/large (_default_: minimal,
|
||
which contains just enough resources for a Coder agent to run without
|
||
additional workloads)
|
||
- Number of workspaces
|
||
- Wait duration between scenarios or staggered approach
|
||
|
||
The template exposes parameters to control the traffic dimensions for SSH
|
||
connections, workspace apps, and dashboard tests:
|
||
|
||
- Traffic duration of the load test scenario
|
||
- Traffic percentage of targeted workspaces
|
||
- Bytes per tick and tick interval
|
||
- _For workspace apps_: modes (echo, read random data, or write and discard)
|
||
|
||
Scale testing concurrency can be controlled with the following parameters:
|
||
|
||
- Enable parallel scenarios - interleave different traffic patterns (SSH,
|
||
workspace apps, dashboard traffic, etc.)
|
||
- Workspace creation concurrency level (_default_: 10)
|
||
- Job concurrency level - generate workspace traffic using multiple jobs
|
||
(_default_: 0)
|
||
- Cleanup concurrency level
|
||
|
||
### Kubernetes cluster
|
||
|
||
It is recommended to learn how to operate the _scaletest-runner_ before running
|
||
it against the staging cluster (or production at your own risk). Coder provides
|
||
different
|
||
[workspace configurations](../../../scaletest/templates)
|
||
that operators can deploy depending on the traffic projections.
|
||
|
||
There are a few cluster options available:
|
||
|
||
| Workspace size | vCPU | Memory | Persisted storage | Details |
|
||
|----------------|------|--------|-------------------|-------------------------------------------------------|
|
||
| minimal | 1 | 2 Gi | None | |
|
||
| small | 1 | 1 Gi | None | |
|
||
| medium | 2 | 2 Gi | None | Medium-sized cluster offers the greedy agent variant. |
|
||
| large | 4 | 4 Gi | None | |
|
||
|
||
Note: Review the selected cluster template and edit the node affinity to match
|
||
your setup.
|
||
|
||
#### Greedy agent
|
||
|
||
The greedy agent variant is a template modification that makes the Coder agent
|
||
transmit large metadata (size: 4K) while reporting stats. The transmission of
|
||
large chunks puts extra overhead on coderd instances and agents when handling
|
||
and storing the data.
|
||
|
||
Use this template variant to verify limits of the cluster performance.
|
||
|
||
### Observability
|
||
|
||
During scale tests, operators can monitor progress using a Grafana dashboard.
|
||
Coder offers a comprehensive overview
|
||
[dashboard](../../../scaletest/scaletest_dashboard.json)
|
||
that can seamlessly integrate into the internal Grafana deployment.
|
||
|
||
This dashboard provides insights into various aspects, including:
|
||
|
||
- Utilization of resources within the Coder control plane (CPU, memory, pods)
|
||
- Database performance metrics (CPU, memory, I/O, connections, queries)
|
||
- Coderd API performance (requests, latency, error rate)
|
||
- Resource consumption within Coder workspaces (CPU, memory, network usage)
|
||
- Internal metrics related to provisioner jobs
|
||
|
||
Note: Database metrics are disabled by default and can be enabled by setting the
|
||
environment variable `CODER_PROMETHEUS_COLLECT_DB_METRICS` to `true`.
|
||
|
||
It is highly recommended to deploy a solution for centralized log collection and
|
||
aggregation. The presence of error logs may indicate an underscaled deployment
|
||
of Coder, necessitating action from operators.
|
||
|
||
## Autoscaling
|
||
|
||
We generally do not recommend using an autoscaler that modifies the number of
|
||
coderd replicas. In particular, scale down events can cause interruptions for a
|
||
large number of users.
|
||
|
||
Coderd is different from a simple request-response HTTP service in that it
|
||
services long-lived connections whenever it proxies HTTP applications like IDEs
|
||
or terminals that rely on websockets, or when it relays tunneled connections to
|
||
workspaces. Loss of a coderd replica will drop these long-lived connections and
|
||
interrupt users. For example, if you have 4 coderd replicas behind a load
|
||
balancer, and an autoscaler decides to reduce it to 3, roughly 25% of the
|
||
connections will drop. An even larger proportion of users could be affected if
|
||
they use applications that use more than one websocket.
|
||
|
||
The severity of the interruption varies by application. Coder's web terminal,
|
||
for example, will reconnect to the same session and continue. So, this should
|
||
not be interpreted as saying coderd replicas should never be taken down for any
|
||
reason.
|
||
|
||
We recommend you plan to run enough coderd replicas to comfortably meet your
|
||
weekly high-water-mark load, and monitor coderd peak CPU & memory utilization
|
||
over the long term, reevaluating periodically. When scaling down (or performing
|
||
upgrades), schedule these outside normal working hours to minimize user
|
||
interruptions.
|
||
|
||
### A note for Kubernetes users
|
||
|
||
When running on Kubernetes on cloud infrastructure (i.e. not bare metal), many
|
||
operators choose to employ a _cluster_ autoscaler that adds and removes
|
||
Kubernetes _nodes_ according to load. Coder can coexist with such cluster
|
||
autoscalers, but we recommend you take steps to prevent the autoscaler from
|
||
evicting coderd pods, as an eviction will cause the same interruptions as
|
||
described above. For example, if you are using the
|
||
[Kubernetes cluster autoscaler](https://kubernetes.io/docs/reference/labels-annotations-taints/#cluster-autoscaler-kubernetes-io-safe-to-evict),
|
||
you may wish to set `cluster-autoscaler.kubernetes.io/safe-to-evict: "false"` as
|
||
an annotation on the coderd deployment.
|
||
|
||
## Troubleshooting
|
||
|
||
If a load test fails or if you are experiencing performance issues during
|
||
day-to-day use, you can leverage Coder's
|
||
[Prometheus metrics](../integrations/prometheus.md) to identify bottlenecks
|
||
during scale tests. Additionally, you can use your existing cloud monitoring
|
||
stack to measure load, view server logs, etc.
|