Skip to content

Commit 15af3ce

Browse files
committed
chore(examples): update kubernetes devcontainer template with envbuilder provider
1 parent 84fdfd2 commit 15af3ce

File tree

2 files changed

+75
-15
lines changed

2 files changed

+75
-15
lines changed

examples/templates/devcontainer-kubernetes/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Provision Devcontainers as [Coder workspaces](https://coder.com/docs/workspaces)
1919

2020
**Container Image**: This template uses the [envbuilder image](https://github.com/coder/envbuilder) to build a Devcontainer from a `devcontainer.json`.
2121

22+
**(Optional) Cache Registry**: Envbuilder can utilize a Docker registry as a cache to speed up workspace builds. The [envbuilder Terraform provider](https://github.com/coder/terraform-provider-envbuilder) will check the contents of the cache to determine if a prebuilt image exists. In the case of some missing layers in the registry (partial cache miss), Envbuilder can still pull previously built layers directly from the registry.
23+
2224
### Authentication
2325

2426
This template authenticates using a `~/.kube/config`, if present on the server, or via built-in authentication if the Coder provisioner is running on Kubernetes with an authorized ServiceAccount. To use another [authentication method](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs#authentication), edit the template.
@@ -31,6 +33,7 @@ This template provisions the following resources:
3133

3234
- Kubernetes deployment (ephemeral)
3335
- Kubernetes persistent volume claim (persistent on `/workspaces`)
36+
- Envbuilder cached image (optional, persistent).
3437

3538
This template will fetch a Git repo containing a `devcontainer.json` specified by the `repo` parameter, and builds it
3639
with [`envbuilder`](https://github.com/coder/envbuilder).
@@ -47,6 +50,8 @@ Edit the `devcontainer.json` instead!
4750
To speed up your builds, you can use a container registry as a cache.
4851
When creating the template, set the parameter `cache_repo`.
4952

53+
See the [Envbuilder Terraform Provider Examples](https://github.com/coder/terraform-provider-envbuilder/blob/main/examples/resources/envbuilder_cached_image/envbuilder_cached_image_resource.tf/) for a more complete example of how the provider works.
54+
5055
> [!NOTE] We recommend using a registry cache with authentication enabled.
5156
> To allow Envbuilder to authenticate with the registry cache, specify the variable `cache_repo_dockerconfig_secret`
5257
> with the name of a Kubernetes secret in the same namespace as Coder. The secret must contain the key `.dockerconfigjson`.

examples/templates/devcontainer-kubernetes/main.tf

Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ terraform {
77
kubernetes = {
88
source = "hashicorp/kubernetes"
99
}
10+
envbuilder = {
11+
source = "coder/envbuilder"
12+
}
1013
}
1114
}
1215

@@ -15,6 +18,7 @@ provider "kubernetes" {
1518
# Authenticate via ~/.kube/config or a Coder-specific ServiceAccount, depending on admin preferences
1619
config_path = var.use_kubeconfig == true ? "~/.kube/config" : null
1720
}
21+
provider "envbuilder" {}
1822

1923
data "coder_provisioner" "me" {}
2024
data "coder_workspace" "me" {}
@@ -43,7 +47,6 @@ variable "namespace" {
4347
variable "cache_repo" {
4448
default = ""
4549
description = "Use a container registry as a cache to speed up builds."
46-
sensitive = true
4750
type = string
4851
}
4952

@@ -139,20 +142,45 @@ data "kubernetes_secret" "cache_repo_dockerconfig_secret" {
139142
}
140143

141144
locals {
142-
deployment_name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
145+
deployment_name = "coder-${lower(data.coder_workspace.me.id)}"
143146
devcontainer_builder_image = data.coder_parameter.devcontainer_builder.value
144147
git_author_name = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name)
145148
git_author_email = data.coder_workspace_owner.me.email
146149
repo_url = data.coder_parameter.repo.value
150+
# The envbuilder provider requires a key-value map of environment variables.
151+
envbuilder_env = {
152+
"CODER_AGENT_TOKEN" : coder_agent.main.token,
153+
# Use the docker gateway if the access URL is 127.0.0.1
154+
"CODER_AGENT_URL" : replace(data.coder_workspace.me.access_url, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal"),
155+
"ENVBUILDER_GIT_URL" : local.repo_url,
156+
# Use the docker gateway if the access URL is 127.0.0.1
157+
"ENVBUILDER_INIT_SCRIPT" : replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal"),
158+
"ENVBUILDER_FALLBACK_IMAGE" : data.coder_parameter.fallback_image.value,
159+
"ENVBUILDER_CACHE_REPO" : var.cache_repo,
160+
"ENVBUILDER_DOCKER_CONFIG_BASE64" : try(data.kubernetes_secret.cache_repo_dockerconfig_secret[0].data[".dockerconfigjson"], ""),
161+
"ENVBUILDER_PUSH_IMAGE" : var.cache_repo == "" ? "" : "true",
162+
#"ENVBUILDER_INSECURE": "true", # Uncomment if testing with an insecure registry.
163+
}
147164
}
148165

149-
resource "kubernetes_persistent_volume_claim" "home" {
166+
# Check for the presence of a prebuilt image in the cache repo
167+
# that we can use instead.
168+
resource "envbuilder_cached_image" "cached" {
169+
count = var.cache_repo == "" ? 0 : data.coder_workspace.me.start_count
170+
builder_image = local.devcontainer_builder_image
171+
git_url = local.repo_url
172+
cache_repo = var.cache_repo
173+
extra_env = local.envbuilder_env
174+
#insecure = true # Uncomment if testing with an insecure registry.
175+
}
176+
177+
resource "kubernetes_persistent_volume_claim" "workspaces" {
150178
metadata {
151-
name = "coder-${lower(data.coder_workspace_owner.me.name)}-${lower(data.coder_workspace.me.name)}-home"
179+
name = "coder-${lower(data.coder_workspace.me.id)}-workspaces"
152180
namespace = var.namespace
153181
labels = {
154-
"app.kubernetes.io/name" = "coder-pvc"
155-
"app.kubernetes.io/instance" = "coder-pvc-${lower(data.coder_workspace_owner.me.name)}-${lower(data.coder_workspace.me.name)}"
182+
"app.kubernetes.io/name" = "coder-${lower(data.coder_workspace.me.id)}-workspaces"
183+
"app.kubernetes.io/instance" = "coder-${lower(data.coder_workspace.me.id)}-workspaces"
156184
"app.kubernetes.io/part-of" = "coder"
157185
//Coder-specific labels.
158186
"com.coder.resource" = "true"
@@ -173,13 +201,14 @@ resource "kubernetes_persistent_volume_claim" "home" {
173201
storage = "${data.coder_parameter.workspaces_volume_size.value}Gi"
174202
}
175203
}
204+
# storage_class_name = "local-path" # Configure the StorageClass to use here, if required.
176205
}
177206
}
178207

179208
resource "kubernetes_deployment" "main" {
180209
count = data.coder_workspace.me.start_count
181210
depends_on = [
182-
kubernetes_persistent_volume_claim.home
211+
kubernetes_persistent_volume_claim.workspaces
183212
]
184213
wait_for_rollout = false
185214
metadata {
@@ -222,7 +251,7 @@ resource "kubernetes_deployment" "main" {
222251

223252
container {
224253
name = "dev"
225-
image = local.devcontainer_builder_image
254+
image = var.cache_repo == "" ? local.devcontainer_builder_image : envbuilder_cached_image.cached.0.image
226255
image_pull_policy = "Always"
227256
security_context {}
228257
env {
@@ -249,6 +278,15 @@ resource "kubernetes_deployment" "main" {
249278
name = "ENVBUILDER_CACHE_REPO"
250279
value = var.cache_repo
251280
}
281+
env {
282+
name = "ENVBUILDER_PUSH_IMAGE"
283+
value = var.cache_repo == "" ? "" : "true"
284+
}
285+
# Uncomment the below if testing with an insecure registry.
286+
# env {
287+
# name = "ENVBUILDER_INSECURE"
288+
# value = "true"
289+
# }
252290
env {
253291
name = "ENVBUILDER_DOCKER_CONFIG_BASE64"
254292
value = try(data.kubernetes_secret.cache_repo_dockerconfig_secret[0].data[".dockerconfigjson"], "")
@@ -271,16 +309,16 @@ resource "kubernetes_deployment" "main" {
271309
}
272310
}
273311
volume_mount {
274-
mount_path = "/home/coder"
275-
name = "home"
312+
mount_path = "/workspaces"
313+
name = "workspaces"
276314
read_only = false
277315
}
278316
}
279317

280318
volume {
281-
name = "home"
319+
name = "workspaces"
282320
persistent_volume_claim {
283-
claim_name = kubernetes_persistent_volume_claim.home.metadata.0.name
321+
claim_name = kubernetes_persistent_volume_claim.workspaces.metadata.0.name
284322
read_only = false
285323
}
286324
}
@@ -357,9 +395,9 @@ resource "coder_agent" "main" {
357395
}
358396

359397
metadata {
360-
display_name = "Home Disk"
361-
key = "3_home_disk"
362-
script = "coder stat disk --path $HOME"
398+
display_name = "Workspaces Disk"
399+
key = "3_workspaces_disk"
400+
script = "coder stat disk --path /workspaces"
363401
interval = 60
364402
timeout = 1
365403
}
@@ -417,3 +455,20 @@ resource "coder_app" "code-server" {
417455
threshold = 6
418456
}
419457
}
458+
459+
resource "coder_metadata" "container_info" {
460+
count = data.coder_workspace.me.start_count
461+
resource_id = coder_agent.main.id
462+
item {
463+
key = "workspace image"
464+
value = var.cache_repo == "" ? local.devcontainer_builder_image : envbuilder_cached_image.cached.0.image
465+
}
466+
item {
467+
key = "git url"
468+
value = local.repo_url
469+
}
470+
item {
471+
key = "cache repo"
472+
value = var.cache_repo == "" ? "not enabled" : var.cache_repo
473+
}
474+
}

0 commit comments

Comments
 (0)