Skip to content

Commit e230aa0

Browse files
committed
Merge branch 'main' of https://github.com/coder/coder into bq/replace-mui-icons-2
2 parents c81d99c + 9d7630b commit e230aa0

File tree

33 files changed

+714
-445
lines changed

33 files changed

+714
-445
lines changed

.github/workflows/weekly-docs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
reporter: github-pr-review
3737
config_file: ".github/.linkspector.yml"
3838
fail_on_error: "true"
39-
filter_mode: "nofilter"
39+
filter_mode: "file"
4040

4141
- name: Send Slack notification
4242
if: failure() && github.event_name == 'schedule'
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# Prebuilt workspaces
2+
3+
Prebuilt workspaces allow template administrators to improve the developer experience by reducing workspace
4+
creation time with an automatically maintained pool of ready-to-use workspaces for specific parameter presets.
5+
6+
The template administrator configures a template to provision prebuilt workspaces in the background, and then when a developer creates
7+
a new workspace that matches the preset, Coder assigns them an existing prebuilt instance.
8+
Prebuilt workspaces significantly reduce wait times, especially for templates with complex provisioning or lengthy startup procedures.
9+
10+
Prebuilt workspaces are:
11+
12+
- Created and maintained automatically by Coder to match your specified preset configurations.
13+
- Claimed transparently when developers create workspaces.
14+
- Monitored and replaced automatically to maintain your desired pool size.
15+
16+
## Relationship to workspace presets
17+
18+
Prebuilt workspaces are tightly integrated with [workspace presets](./parameters.md#workspace-presets-beta):
19+
20+
1. Each prebuilt workspace is associated with a specific template preset.
21+
1. The preset must define all required parameters needed to build the workspace.
22+
1. The preset parameters define the base configuration and are immutable once a prebuilt workspace is provisioned.
23+
1. Parameters that are not defined in the preset can still be customized by users when they claim a workspace.
24+
25+
## Prerequisites
26+
27+
- [**Premium license**](../../licensing/index.md)
28+
- **Compatible Terraform provider**: Use `coder/coder` Terraform provider `>= 2.4.0`.
29+
- **Feature flag**: Enable the `workspace-prebuilds` [experiment](../../../reference/cli/server.md#--experiments).
30+
31+
## Enable prebuilt workspaces for template presets
32+
33+
In your template, add a `prebuilds` block within a `coder_workspace_preset` definition to identify the number of prebuilt
34+
instances your Coder deployment should maintain:
35+
36+
```hcl
37+
data "coder_workspace_preset" "goland" {
38+
name = "GoLand: Large"
39+
parameters = {
40+
jetbrains_ide = "GO"
41+
cpus = 8
42+
memory = 16
43+
}
44+
prebuilds {
45+
instances = 3 # Number of prebuilt workspaces to maintain
46+
}
47+
}
48+
```
49+
50+
After you publish a new template version, Coder will automatically provision and maintain prebuilt workspaces through an
51+
internal reconciliation loop (similar to Kubernetes) to ensure the defined `instances` count are running.
52+
53+
## Prebuilt workspace lifecycle
54+
55+
Prebuilt workspaces follow a specific lifecycle from creation through eligibility to claiming.
56+
57+
1. After you configure a preset with prebuilds and publish the template, Coder provisions the prebuilt workspace(s).
58+
59+
1. Coder automatically creates the defined `instances` count of prebuilt workspaces.
60+
1. Each new prebuilt workspace is initially owned by an unprivileged system pseudo-user named `prebuilds`.
61+
- The `prebuilds` user belongs to the `Everyone` group (you can add it to additional groups if needed).
62+
1. Each prebuilt workspace receives a randomly generated name for identification.
63+
1. The workspace is provisioned like a regular workspace; only its ownership distinguishes it as a prebuilt workspace.
64+
65+
1. Prebuilt workspaces start up and become eligible to be claimed by a developer.
66+
67+
Before a prebuilt workspace is available to users:
68+
69+
1. The workspace is provisioned.
70+
1. The agent starts up and connects to coderd.
71+
1. The agent starts its bootstrap procedures and completes its startup scripts.
72+
1. The agent reports `ready` status.
73+
74+
After the agent reports `ready`, the prebuilt workspace considered eligible to be claimed.
75+
76+
Prebuilt workspaces that fail during provisioning are retried with a backoff to prevent transient failures.
77+
78+
1. When a developer requests a new workspace, the claiming process occurs:
79+
80+
1. Developer selects a template and preset that has prebuilt workspaces configured.
81+
1. If an eligible prebuilt workspace exists, ownership transfers from the `prebuilds` user to the requesting user.
82+
1. The workspace name changes to the user's requested name.
83+
1. `terraform apply` is executed using the new ownership details, which may affect the [`coder_workspace`](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/workspace) and
84+
[`coder_workspace_owner`](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/workspace_owner)
85+
datasources (see [Preventing resource replacement](#preventing-resource-replacement) for further considerations).
86+
87+
The developer doesn't see the claiming process — the workspace will just be ready faster than usual.
88+
89+
You can view available prebuilt workspaces in the **Workspaces** view in the Coder dashboard:
90+
91+
![A prebuilt workspace in the dashboard](../../../images/admin/templates/extend-templates/prebuilt/prebuilt-workspaces.png)
92+
_Note the search term `owner:prebuilds`._
93+
94+
### Template updates and the prebuilt workspace lifecycle
95+
96+
Prebuilt workspaces are not updated after they are provisioned.
97+
98+
When a template's active version is updated:
99+
100+
1. Prebuilt workspaces for old versions are automatically deleted.
101+
1. New prebuilt workspaces are created for the active template version.
102+
1. If dependencies change (e.g., an [AMI](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) update) without a template version change:
103+
- You may delete the existing prebuilt workspaces manually.
104+
- Coder will automatically create new prebuilt workspaces with the updated dependencies.
105+
106+
The system always maintains the desired number of prebuilt workspaces for the active template version.
107+
108+
## Administration and troubleshooting
109+
110+
### Managing resource quotas
111+
112+
Prebuilt workspaces can be used in conjunction with [resource quotas](../../users/quotas.md).
113+
Because unclaimed prebuilt workspaces are owned by the `prebuilds` user, you can:
114+
115+
1. Configure quotas for any group that includes this user.
116+
1. Set appropriate limits to balance prebuilt workspace availability with resource constraints.
117+
118+
If a quota is exceeded, the prebuilt workspace will fail provisioning the same way other workspaces do.
119+
120+
### Template configuration best practices
121+
122+
#### Preventing resource replacement
123+
124+
When a prebuilt workspace is claimed, another `terraform apply` run occurs with new values for the workspace owner and name.
125+
126+
This can cause issues in the following scenario:
127+
128+
1. The workspace is initially created with values from the `prebuilds` user and a random name.
129+
1. After claiming, various workspace properties change (ownership, name, and potentially other values), which Terraform sees as configuration drift.
130+
1. If these values are used in immutable fields, Terraform will destroy and recreate the resource, eliminating the benefit of prebuilds.
131+
132+
For example, when these values are used in immutable fields like the AWS instance `user_data`, you'll see resource replacement during claiming:
133+
134+
![Resource replacement notification](../../../images/admin/templates/extend-templates/prebuilt/replacement-notification.png)
135+
136+
To prevent this, add a `lifecycle` block with `ignore_changes`:
137+
138+
```hcl
139+
resource "docker_container" "workspace" {
140+
lifecycle {
141+
ignore_changes = all
142+
}
143+
144+
count = data.coder_workspace.me.start_count
145+
name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
146+
...
147+
}
148+
```
149+
150+
For more targeted control, specify which attributes to ignore:
151+
152+
```hcl
153+
resource "docker_container" "workspace" {
154+
lifecycle {
155+
ignore_changes = [name]
156+
}
157+
158+
count = data.coder_workspace.me.start_count
159+
name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
160+
...
161+
}
162+
```
163+
164+
Learn more about `ignore_changes` in the [Terraform documentation](https://developer.hashicorp.com/terraform/language/meta-arguments/lifecycle#ignore_changes).
165+
166+
### Current limitations
167+
168+
The prebuilt workspaces feature has these current limitations:
169+
170+
- **Organizations**
171+
172+
Prebuilt workspaces can only be used with the default organization.
173+
174+
[coder/internal#364](https://github.com/coder/internal/issues/364)
175+
176+
- **Autoscaling**
177+
178+
Prebuilt workspaces remain running until claimed. There's no automated mechanism to reduce instances during off-hours.
179+
180+
[coder/internal#312](https://github.com/coder/internal/issues/312)
181+
182+
### Monitoring and observability
183+
184+
#### Available metrics
185+
186+
Coder provides several metrics to monitor your prebuilt workspaces:
187+
188+
- `coderd_prebuilt_workspaces_created_total` (counter): Total number of prebuilt workspaces created to meet the desired instance count.
189+
- `coderd_prebuilt_workspaces_failed_total` (counter): Total number of prebuilt workspaces that failed to build.
190+
- `coderd_prebuilt_workspaces_claimed_total` (counter): Total number of prebuilt workspaces claimed by users.
191+
- `coderd_prebuilt_workspaces_desired` (gauge): Target number of prebuilt workspaces that should be available.
192+
- `coderd_prebuilt_workspaces_running` (gauge): Current number of prebuilt workspaces in a `running` state.
193+
- `coderd_prebuilt_workspaces_eligible` (gauge): Current number of prebuilt workspaces eligible to be claimed.
194+
195+
#### Logs
196+
197+
Search for `coderd.prebuilds:` in your logs to track the reconciliation loop's behavior.
198+
199+
These logs provide information about:
200+
201+
1. Creation and deletion attempts for prebuilt workspaces.
202+
1. Backoff events after failed builds.
203+
1. Claiming operations.
40.3 KB
Loading
72.2 KB
Loading

docs/manifest.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,12 @@
437437
"description": "Use parameters to customize workspaces at build",
438438
"path": "./admin/templates/extending-templates/parameters.md"
439439
},
440+
{
441+
"title": "Prebuilt workspaces",
442+
"description": "Pre-provision a ready-to-deploy workspace with a defined set of parameters",
443+
"path": "./admin/templates/extending-templates/prebuilt-workspaces.md",
444+
"state": ["premium", "beta"]
445+
},
440446
{
441447
"title": "Icons",
442448
"description": "Customize your template with built-in icons",

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ require (
9898
github.com/coder/flog v1.1.0
9999
github.com/coder/guts v1.3.1-0.20250428170043-ad369017e95b
100100
github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0
101-
github.com/coder/quartz v0.1.2
101+
github.com/coder/quartz v0.1.3
102102
github.com/coder/retry v1.5.1
103103
github.com/coder/serpent v0.10.0
104104
github.com/coder/terraform-provider-coder/v2 v2.4.0-pre1.0.20250417100258-c86bb5c3ddcd

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -909,8 +909,8 @@ github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0 h1:3A0ES21Ke+FxEM8CXx
909909
github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0/go.mod h1:5UuS2Ts+nTToAMeOjNlnHFkPahrtDkmpydBen/3wgZc=
910910
github.com/coder/preview v0.0.2-0.20250506154333-6f500ca7b245 h1:RGoANNubwwPZF8puiYAk2qbzhVgipBMNu8WIrY1VIbI=
911911
github.com/coder/preview v0.0.2-0.20250506154333-6f500ca7b245/go.mod h1:5VnO9yw7vq19hBgBqqBksE2BH53UTmNYH1QltkYLXJI=
912-
github.com/coder/quartz v0.1.2 h1:PVhc9sJimTdKd3VbygXtS4826EOCpB1fXoRlLnCrE+s=
913-
github.com/coder/quartz v0.1.2/go.mod h1:vsiCc+AHViMKH2CQpGIpFgdHIEQsxwm8yCscqKmzbRA=
912+
github.com/coder/quartz v0.1.3 h1:hA2nI8uUA2fNN9uhXv2I4xZD4aHkA7oH3g2t03v4xf8=
913+
github.com/coder/quartz v0.1.3/go.mod h1:vsiCc+AHViMKH2CQpGIpFgdHIEQsxwm8yCscqKmzbRA=
914914
github.com/coder/retry v1.5.1 h1:iWu8YnD8YqHs3XwqrqsjoBTAVqT9ml6z9ViJ2wlMiqc=
915915
github.com/coder/retry v1.5.1/go.mod h1:blHMk9vs6LkoRT9ZHyuZo360cufXEhrxqvEzeMtRGoY=
916916
github.com/coder/serpent v0.10.0 h1:ofVk9FJXSek+SmL3yVE3GoArP83M+1tX+H7S4t8BSuM=

site/migrate-icons.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Look for all the @mui/icons-material icons below and replace them accordinlying with the Lucide icon:
2+
3+
MUI | Lucide
4+
TaskAlt | CircleCheckBigIcon
5+
InfoOutlined | InfoIcon
6+
ErrorOutline | CircleAlertIcon
7+
8+
You should update the imports and usage.

site/src/components/BuildIcon/BuildIcon.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
1-
import DeleteOutlined from "@mui/icons-material/DeleteOutlined";
2-
import PlayArrowOutlined from "@mui/icons-material/PlayArrowOutlined";
3-
import StopOutlined from "@mui/icons-material/StopOutlined";
41
import type { WorkspaceTransition } from "api/typesGenerated";
2+
import { PlayIcon, SquareIcon, TrashIcon } from "lucide-react";
53
import type { ComponentProps } from "react";
64

7-
type SVGIcon = typeof PlayArrowOutlined;
5+
type SVGIcon = typeof PlayIcon;
86

97
type SVGIconProps = ComponentProps<SVGIcon>;
108

119
const iconByTransition: Record<WorkspaceTransition, SVGIcon> = {
12-
start: PlayArrowOutlined,
13-
stop: StopOutlined,
14-
delete: DeleteOutlined,
10+
start: PlayIcon,
11+
stop: SquareIcon,
12+
delete: TrashIcon,
1513
};
1614

1715
export const BuildIcon = (

site/src/components/InputGroup/InputGroup.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,9 @@ export const InputGroup: FC<HTMLProps<HTMLDivElement>> = (props) => {
2525
zIndex: 2,
2626
},
2727

28-
"& > *:first-child": {
28+
"& > *:first-of-type": {
2929
borderTopRightRadius: 0,
3030
borderBottomRightRadius: 0,
31-
32-
"&.MuiFormControl-root .MuiInputBase-root": {
33-
borderTopRightRadius: 0,
34-
borderBottomRightRadius: 0,
35-
},
3631
},
3732

3833
"& > *:last-child": {
@@ -45,7 +40,7 @@ export const InputGroup: FC<HTMLProps<HTMLDivElement>> = (props) => {
4540
},
4641
},
4742

48-
"& > *:not(:first-child):not(:last-child)": {
43+
"& > *:not(:first-of-type):not(:last-child)": {
4944
borderRadius: 0,
5045

5146
"&.MuiFormControl-root .MuiInputBase-root": {

0 commit comments

Comments
 (0)