diff --git a/cli/testdata/coder_templates_init_--help.golden b/cli/testdata/coder_templates_init_--help.golden
index 4d3cd1c2a1228..d44db24aee27b 100644
--- a/cli/testdata/coder_templates_init_--help.golden
+++ b/cli/testdata/coder_templates_init_--help.golden
@@ -6,7 +6,7 @@ USAGE:
Get started with a templated template.
OPTIONS:
- --id aws-devcontainer|aws-linux|aws-windows|azure-linux|digitalocean-linux|docker|docker-devcontainer|gcp-devcontainer|gcp-linux|gcp-vm-container|gcp-windows|kubernetes|kubernetes-devcontainer|nomad-docker|scratch
+ --id aws-devcontainer|aws-linux|aws-windows|azure-linux|digitalocean-linux|docker|docker-devcontainer|docker-envbuilder|gcp-devcontainer|gcp-linux|gcp-vm-container|gcp-windows|kubernetes|kubernetes-devcontainer|nomad-docker|scratch
Specify a given example template by ID.
———
diff --git a/docs/reference/cli/templates_init.md b/docs/reference/cli/templates_init.md
index 30df7bb9c0ad3..7613144e66018 100644
--- a/docs/reference/cli/templates_init.md
+++ b/docs/reference/cli/templates_init.md
@@ -13,8 +13,8 @@ coder templates init [flags] [directory]
### --id
-| | |
-|------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| Type | aws-devcontainer\|aws-linux\|aws-windows\|azure-linux\|digitalocean-linux\|docker\|docker-devcontainer\|gcp-devcontainer\|gcp-linux\|gcp-vm-container\|gcp-windows\|kubernetes\|kubernetes-devcontainer\|nomad-docker\|scratch
|
+| | |
+|------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Type | aws-devcontainer\|aws-linux\|aws-windows\|azure-linux\|digitalocean-linux\|docker\|docker-devcontainer\|docker-envbuilder\|gcp-devcontainer\|gcp-linux\|gcp-vm-container\|gcp-windows\|kubernetes\|kubernetes-devcontainer\|nomad-docker\|scratch
|
Specify a given example template by ID.
diff --git a/examples/examples.gen.json b/examples/examples.gen.json
index 8939c0efd30b1..c891389568a55 100644
--- a/examples/examples.gen.json
+++ b/examples/examples.gen.json
@@ -83,15 +83,29 @@
{
"id": "docker-devcontainer",
"url": "",
- "name": "Docker (Devcontainer)",
+ "name": "Docker-in-Docker Dev Containers",
+ "description": "Provision Docker containers as Coder workspaces running Dev Containers via Docker-in-Docker.",
+ "icon": "/icon/docker.png",
+ "tags": [
+ "docker",
+ "container",
+ "devcontainer"
+ ],
+ "markdown": "\n# Remote Development on Dev Containers\n\nProvision Docker containers as [Coder workspaces](https://coder.com/docs/workspaces) running [Dev Containers](https://code.visualstudio.com/docs/devcontainers/containers) via Docker-in-Docker.\n\n\u003c!-- TODO: Add screenshot --\u003e\n\n## Prerequisites\n\n### Infrastructure\n\nThe VM you run Coder on must have a running Docker socket and the `coder` user must be added to the Docker group:\n\n```sh\n# Add coder user to Docker group\nsudo adduser coder docker\n\n# Restart Coder server\nsudo systemctl restart coder\n\n# Test Docker\nsudo -u coder docker ps\n```\n\n## Architecture\n\nThis example uses the `codercom/enterprise-node:ubuntu` Docker image as a base image for the workspace. It includes necessary tools like Docker and Node.js, which are required for running Dev Containers via the `@devcontainers/cli` tool.\n\nThis template provisions the following resources:\n\n- Docker image (built by Docker socket and kept locally)\n- Docker container (ephemeral)\n- Docker volume (persistent on `/home/coder`)\n- Docker volume (persistent on `/var/lib/docker`)\n\nThis means, when the workspace restarts, any tools or files outside of the home directory or docker library are not persisted.\n\nFor devcontainers running inside the workspace, data persistence is dependent on each projects `devcontainer.json` configuration.\n\n\u003e **Note**\n\u003e This template is designed to be a starting point! Edit the Terraform to extend the template to support your use case.\n"
+ },
+ {
+ "id": "docker-envbuilder",
+ "url": "",
+ "name": "Docker (Envbuilder)",
"description": "Provision envbuilder containers as Coder workspaces",
"icon": "/icon/docker.png",
"tags": [
"container",
"docker",
- "devcontainer"
+ "devcontainer",
+ "envbuilder"
],
- "markdown": "\n# Remote Development on Docker Containers (with Devcontainers)\n\nProvision Devcontainers as [Coder workspaces](https://coder.com/docs/workspaces) in Docker with this example template.\n\n## Prerequisites\n\n### Infrastructure\n\nCoder must have access to a running Docker socket, and the `coder` user must be a member of the `docker` group:\n\n```shell\n# Add coder user to Docker group\nsudo usermod -aG docker coder\n\n# Restart Coder server\nsudo systemctl restart coder\n\n# Test Docker\nsudo -u coder docker ps\n```\n\n## Architecture\n\nCoder supports Devcontainers via [envbuilder](https://github.com/coder/envbuilder), an open source project. Read more about this in [Coder's documentation](https://coder.com/docs/templates/dev-containers).\n\nThis template provisions the following resources:\n\n- Envbuilder cached image (conditional, persistent) using [`terraform-provider-envbuilder`](https://github.com/coder/terraform-provider-envbuilder)\n- Docker image (persistent) using [`envbuilder`](https://github.com/coder/envbuilder)\n- Docker container (ephemeral)\n- Docker volume (persistent on `/workspaces`)\n\nThe Git repository is cloned inside the `/workspaces` volume if not present.\nAny local changes to the Devcontainer files inside the volume will be applied when you restart the workspace.\nKeep in mind that any tools or files outside of `/workspaces` or not added as part of the Devcontainer specification are not persisted.\nEdit the `devcontainer.json` instead!\n\n\u003e **Note**\n\u003e This template is designed to be a starting point! Edit the Terraform to extend the template to support your use case.\n\n## Docker-in-Docker\n\nSee the [Envbuilder documentation](https://github.com/coder/envbuilder/blob/main/docs/docker.md) for information on running Docker containers inside a devcontainer built by Envbuilder.\n\n## Caching\n\nTo speed up your builds, you can use a container registry as a cache.\nWhen creating the template, set the parameter `cache_repo` to a valid Docker repository.\n\nFor example, you can run a local registry:\n\n```shell\ndocker run --detach \\\n --volume registry-cache:/var/lib/registry \\\n --publish 5000:5000 \\\n --name registry-cache \\\n --net=host \\\n registry:2\n```\n\nThen, when creating the template, enter `localhost:5000/devcontainer-cache` for the parameter `cache_repo`.\n\nSee 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.\n\n\u003e [!NOTE]\n\u003e We recommend using a registry cache with authentication enabled.\n\u003e To allow Envbuilder to authenticate with the registry cache, specify the variable `cache_repo_docker_config_path`\n\u003e with the path to a Docker config `.json` on disk containing valid credentials for the registry.\n"
+ "markdown": "\n# Remote Development on Docker Containers (with Envbuilder)\n\nProvision Envbuilder containers based on `devcontainer.json` as [Coder workspaces](https://coder.com/docs/workspaces) in Docker with this example template.\n\n## Prerequisites\n\n### Infrastructure\n\nCoder must have access to a running Docker socket, and the `coder` user must be a member of the `docker` group:\n\n```shell\n# Add coder user to Docker group\nsudo usermod -aG docker coder\n\n# Restart Coder server\nsudo systemctl restart coder\n\n# Test Docker\nsudo -u coder docker ps\n```\n\n## Architecture\n\nCoder supports Envbuilder containers based on `devcontainer.json` via [envbuilder](https://github.com/coder/envbuilder), an open source project. Read more about this in [Coder's documentation](https://coder.com/docs/templates/dev-containers).\n\nThis template provisions the following resources:\n\n- Envbuilder cached image (conditional, persistent) using [`terraform-provider-envbuilder`](https://github.com/coder/terraform-provider-envbuilder)\n- Docker image (persistent) using [`envbuilder`](https://github.com/coder/envbuilder)\n- Docker container (ephemeral)\n- Docker volume (persistent on `/workspaces`)\n\nThe Git repository is cloned inside the `/workspaces` volume if not present.\nAny local changes to the Devcontainer files inside the volume will be applied when you restart the workspace.\nKeep in mind that any tools or files outside of `/workspaces` or not added as part of the Devcontainer specification are not persisted.\nEdit the `devcontainer.json` instead!\n\n\u003e **Note**\n\u003e This template is designed to be a starting point! Edit the Terraform to extend the template to support your use case.\n\n## Docker-in-Docker\n\nSee the [Envbuilder documentation](https://github.com/coder/envbuilder/blob/main/docs/docker.md) for information on running Docker containers inside an Envbuilder container.\n\n## Caching\n\nTo speed up your builds, you can use a container registry as a cache.\nWhen creating the template, set the parameter `cache_repo` to a valid Docker repository.\n\nFor example, you can run a local registry:\n\n```shell\ndocker run --detach \\\n --volume registry-cache:/var/lib/registry \\\n --publish 5000:5000 \\\n --name registry-cache \\\n --net=host \\\n registry:2\n```\n\nThen, when creating the template, enter `localhost:5000/envbuilder-cache` for the parameter `cache_repo`.\n\nSee 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.\n\n\u003e [!NOTE]\n\u003e We recommend using a registry cache with authentication enabled.\n\u003e To allow Envbuilder to authenticate with the registry cache, specify the variable `cache_repo_docker_config_path`\n\u003e with the path to a Docker config `.json` on disk containing valid credentials for the registry.\n"
},
{
"id": "gcp-devcontainer",
diff --git a/examples/examples.go b/examples/examples.go
index 929d6d2bcce04..7deff18f5f9ad 100644
--- a/examples/examples.go
+++ b/examples/examples.go
@@ -31,6 +31,7 @@ var (
//go:embed templates/digitalocean-linux
//go:embed templates/docker
//go:embed templates/docker-devcontainer
+ //go:embed templates/docker-envbuilder
//go:embed templates/gcp-devcontainer
//go:embed templates/gcp-linux
//go:embed templates/gcp-vm-container
diff --git a/examples/templates/docker-devcontainer/README.md b/examples/templates/docker-devcontainer/README.md
index 3026a21fc8657..2b4ac19cc668e 100644
--- a/examples/templates/docker-devcontainer/README.md
+++ b/examples/templates/docker-devcontainer/README.md
@@ -1,25 +1,27 @@
---
-display_name: Docker (Devcontainer)
-description: Provision envbuilder containers as Coder workspaces
+display_name: Docker-in-Docker Dev Containers
+description: Provision Docker containers as Coder workspaces running Dev Containers via Docker-in-Docker.
icon: ../../../site/static/icon/docker.png
maintainer_github: coder
verified: true
-tags: [container, docker, devcontainer]
+tags: [docker, container, devcontainer]
---
-# Remote Development on Docker Containers (with Devcontainers)
+# Remote Development on Dev Containers
-Provision Devcontainers as [Coder workspaces](https://coder.com/docs/workspaces) in Docker with this example template.
+Provision Docker containers as [Coder workspaces](https://coder.com/docs/workspaces) running [Dev Containers](https://code.visualstudio.com/docs/devcontainers/containers) via Docker-in-Docker.
+
+
## Prerequisites
### Infrastructure
-Coder must have access to a running Docker socket, and the `coder` user must be a member of the `docker` group:
+The VM you run Coder on must have a running Docker socket and the `coder` user must be added to the Docker group:
-```shell
+```sh
# Add coder user to Docker group
-sudo usermod -aG docker coder
+sudo adduser coder docker
# Restart Coder server
sudo systemctl restart coder
@@ -30,48 +32,18 @@ sudo -u coder docker ps
## Architecture
-Coder supports Devcontainers via [envbuilder](https://github.com/coder/envbuilder), an open source project. Read more about this in [Coder's documentation](https://coder.com/docs/templates/dev-containers).
+This example uses the `codercom/enterprise-node:ubuntu` Docker image as a base image for the workspace. It includes necessary tools like Docker and Node.js, which are required for running Dev Containers via the `@devcontainers/cli` tool.
This template provisions the following resources:
-- Envbuilder cached image (conditional, persistent) using [`terraform-provider-envbuilder`](https://github.com/coder/terraform-provider-envbuilder)
-- Docker image (persistent) using [`envbuilder`](https://github.com/coder/envbuilder)
+- Docker image (built by Docker socket and kept locally)
- Docker container (ephemeral)
-- Docker volume (persistent on `/workspaces`)
+- Docker volume (persistent on `/home/coder`)
+- Docker volume (persistent on `/var/lib/docker`)
+
+This means, when the workspace restarts, any tools or files outside of the home directory or docker library are not persisted.
-The Git repository is cloned inside the `/workspaces` volume if not present.
-Any local changes to the Devcontainer files inside the volume will be applied when you restart the workspace.
-Keep in mind that any tools or files outside of `/workspaces` or not added as part of the Devcontainer specification are not persisted.
-Edit the `devcontainer.json` instead!
+For devcontainers running inside the workspace, data persistence is dependent on each projects `devcontainer.json` configuration.
> **Note**
> This template is designed to be a starting point! Edit the Terraform to extend the template to support your use case.
-
-## Docker-in-Docker
-
-See the [Envbuilder documentation](https://github.com/coder/envbuilder/blob/main/docs/docker.md) for information on running Docker containers inside a devcontainer built by Envbuilder.
-
-## Caching
-
-To speed up your builds, you can use a container registry as a cache.
-When creating the template, set the parameter `cache_repo` to a valid Docker repository.
-
-For example, you can run a local registry:
-
-```shell
-docker run --detach \
- --volume registry-cache:/var/lib/registry \
- --publish 5000:5000 \
- --name registry-cache \
- --net=host \
- registry:2
-```
-
-Then, when creating the template, enter `localhost:5000/devcontainer-cache` for the parameter `cache_repo`.
-
-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.
-
-> [!NOTE]
-> We recommend using a registry cache with authentication enabled.
-> To allow Envbuilder to authenticate with the registry cache, specify the variable `cache_repo_docker_config_path`
-> with the path to a Docker config `.json` on disk containing valid credentials for the registry.
diff --git a/examples/templates/docker-devcontainer/main.tf b/examples/templates/docker-devcontainer/main.tf
index 2765874f80181..a0275067a57e7 100644
--- a/examples/templates/docker-devcontainer/main.tf
+++ b/examples/templates/docker-devcontainer/main.tf
@@ -1,258 +1,87 @@
terraform {
required_providers {
coder = {
- source = "coder/coder"
- version = "~> 2.0"
+ source = "coder/coder"
}
docker = {
source = "kreuzwerker/docker"
}
- envbuilder = {
- source = "coder/envbuilder"
- }
}
}
+locals {
+ username = data.coder_workspace_owner.me.name
+
+ # Use a workspace image that supports rootless Docker
+ # (Docker-in-Docker) and Node.js.
+ workspace_image = "codercom/enterprise-node:ubuntu"
+}
+
variable "docker_socket" {
default = ""
description = "(Optional) Docker socket URI"
type = string
}
-provider "coder" {}
+data "coder_parameter" "repo_url" {
+ type = "string"
+ name = "repo_url"
+ display_name = "Git Repository"
+ description = "Enter the URL of the Git repository to clone into your workspace. This repository should contain a devcontainer.json file to configure your development environment."
+ default = "https://github.com/coder/coder"
+ mutable = true
+}
+
provider "docker" {
# Defaulting to null if the variable is an empty string lets us have an optional variable without having to set our own default
host = var.docker_socket != "" ? var.docker_socket : null
}
-provider "envbuilder" {}
data "coder_provisioner" "me" {}
data "coder_workspace" "me" {}
data "coder_workspace_owner" "me" {}
-data "coder_parameter" "repo" {
- description = "Select a repository to automatically clone and start working with a devcontainer."
- display_name = "Repository (auto)"
- mutable = true
- name = "repo"
- option {
- name = "vercel/next.js"
- description = "The React Framework"
- value = "https://github.com/vercel/next.js"
- }
- option {
- name = "home-assistant/core"
- description = "🏡 Open source home automation that puts local control and privacy first."
- value = "https://github.com/home-assistant/core"
- }
- option {
- name = "discourse/discourse"
- description = "A platform for community discussion. Free, open, simple."
- value = "https://github.com/discourse/discourse"
- }
- option {
- name = "denoland/deno"
- description = "A modern runtime for JavaScript and TypeScript."
- value = "https://github.com/denoland/deno"
- }
- option {
- name = "microsoft/vscode"
- icon = "/icon/code.svg"
- description = "Code editing. Redefined."
- value = "https://github.com/microsoft/vscode"
- }
- option {
- name = "Custom"
- icon = "/emojis/1f5c3.png"
- description = "Specify a custom repo URL below"
- value = "custom"
- }
- order = 1
-}
-
-data "coder_parameter" "custom_repo_url" {
- default = ""
- description = "Optionally enter a custom repository URL, see [awesome-devcontainers](https://github.com/manekinekko/awesome-devcontainers)."
- display_name = "Repository URL (custom)"
- name = "custom_repo_url"
- mutable = true
- order = 2
-}
-
-data "coder_parameter" "fallback_image" {
- default = "codercom/enterprise-base:ubuntu"
- description = "This image runs if the devcontainer fails to build."
- display_name = "Fallback Image"
- mutable = true
- name = "fallback_image"
- order = 3
-}
-
-data "coder_parameter" "devcontainer_builder" {
- description = <<-EOF
-Image that will build the devcontainer.
-We highly recommend using a specific release as the `:latest` tag will change.
-Find the latest version of Envbuilder here: https://github.com/coder/envbuilder/pkgs/container/envbuilder
-EOF
- display_name = "Devcontainer Builder"
- mutable = true
- name = "devcontainer_builder"
- default = "ghcr.io/coder/envbuilder:latest"
- order = 4
-}
-
-variable "cache_repo" {
- default = ""
- description = "(Optional) Use a container registry as a cache to speed up builds."
- type = string
-}
-
-variable "insecure_cache_repo" {
- default = false
- description = "Enable this option if your cache registry does not serve HTTPS."
- type = bool
-}
-
-variable "cache_repo_docker_config_path" {
- default = ""
- description = "(Optional) Path to a docker config.json containing credentials to the provided cache repo, if required."
- sensitive = true
- type = string
-}
-
-locals {
- container_name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
- devcontainer_builder_image = data.coder_parameter.devcontainer_builder.value
- git_author_name = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name)
- git_author_email = data.coder_workspace_owner.me.email
- repo_url = data.coder_parameter.repo.value == "custom" ? data.coder_parameter.custom_repo_url.value : data.coder_parameter.repo.value
- # The envbuilder provider requires a key-value map of environment variables.
- envbuilder_env = {
- # ENVBUILDER_GIT_URL and ENVBUILDER_CACHE_REPO will be overridden by the provider
- # if the cache repo is enabled.
- "ENVBUILDER_GIT_URL" : local.repo_url,
- "ENVBUILDER_CACHE_REPO" : var.cache_repo,
- "CODER_AGENT_TOKEN" : coder_agent.main.token,
- # Use the docker gateway if the access URL is 127.0.0.1
- "CODER_AGENT_URL" : replace(data.coder_workspace.me.access_url, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal"),
- # Use the docker gateway if the access URL is 127.0.0.1
- "ENVBUILDER_INIT_SCRIPT" : replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal"),
- "ENVBUILDER_FALLBACK_IMAGE" : data.coder_parameter.fallback_image.value,
- "ENVBUILDER_DOCKER_CONFIG_BASE64" : try(data.local_sensitive_file.cache_repo_dockerconfigjson[0].content_base64, ""),
- "ENVBUILDER_PUSH_IMAGE" : var.cache_repo == "" ? "" : "true",
- "ENVBUILDER_INSECURE" : "${var.insecure_cache_repo}",
- }
- # Convert the above map to the format expected by the docker provider.
- docker_env = [
- for k, v in local.envbuilder_env : "${k}=${v}"
- ]
-}
-
-data "local_sensitive_file" "cache_repo_dockerconfigjson" {
- count = var.cache_repo_docker_config_path == "" ? 0 : 1
- filename = var.cache_repo_docker_config_path
-}
-
-resource "docker_image" "devcontainer_builder_image" {
- name = local.devcontainer_builder_image
- keep_locally = true
-}
-
-resource "docker_volume" "workspaces" {
- name = "coder-${data.coder_workspace.me.id}"
- # Protect the volume from being deleted due to changes in attributes.
- lifecycle {
- ignore_changes = all
- }
- # Add labels in Docker to keep track of orphan resources.
- labels {
- label = "coder.owner"
- value = data.coder_workspace_owner.me.name
- }
- labels {
- label = "coder.owner_id"
- value = data.coder_workspace_owner.me.id
- }
- labels {
- label = "coder.workspace_id"
- value = data.coder_workspace.me.id
- }
- # This field becomes outdated if the workspace is renamed but can
- # be useful for debugging or cleaning out dangling volumes.
- labels {
- label = "coder.workspace_name_at_creation"
- value = data.coder_workspace.me.name
- }
-}
+resource "coder_agent" "main" {
+ arch = data.coder_provisioner.me.arch
+ os = "linux"
+ startup_script = <<-EOT
+ set -e
-# Check for the presence of a prebuilt image in the cache repo
-# that we can use instead.
-resource "envbuilder_cached_image" "cached" {
- count = var.cache_repo == "" ? 0 : data.coder_workspace.me.start_count
- builder_image = local.devcontainer_builder_image
- git_url = local.repo_url
- cache_repo = var.cache_repo
- extra_env = local.envbuilder_env
- insecure = var.insecure_cache_repo
-}
+ # Prepare user home with default files on first start.
+ if [ ! -f ~/.init_done ]; then
+ cp -rT /etc/skel ~
+ touch ~/.init_done
+ fi
-resource "docker_container" "workspace" {
- count = data.coder_workspace.me.start_count
- image = var.cache_repo == "" ? local.devcontainer_builder_image : envbuilder_cached_image.cached.0.image
- # Uses lower() to avoid Docker restriction on container names.
- name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
- # Hostname makes the shell more user friendly: coder@my-workspace:~$
- hostname = data.coder_workspace.me.name
- # Use the environment specified by the envbuilder provider, if available.
- env = var.cache_repo == "" ? local.docker_env : envbuilder_cached_image.cached.0.env
- # network_mode = "host" # Uncomment if testing with a registry running on `localhost`.
- host {
- host = "host.docker.internal"
- ip = "host-gateway"
- }
- volumes {
- container_path = "/workspaces"
- volume_name = docker_volume.workspaces.name
- read_only = false
- }
- # Add labels in Docker to keep track of orphan resources.
- labels {
- label = "coder.owner"
- value = data.coder_workspace_owner.me.name
- }
- labels {
- label = "coder.owner_id"
- value = data.coder_workspace_owner.me.id
- }
- labels {
- label = "coder.workspace_id"
- value = data.coder_workspace.me.id
- }
- labels {
- label = "coder.workspace_name"
- value = data.coder_workspace.me.name
- }
-}
-
-resource "coder_agent" "main" {
- arch = data.coder_provisioner.me.arch
- os = "linux"
- startup_script = <<-EOT
+ # Add any commands that should be executed at workspace startup
+ # (e.g. install requirements, start a program, etc) here.
+ EOT
+ shutdown_script = <<-EOT
set -e
- # Add any commands that should be executed at workspace startup (e.g install requirements, start a program, etc) here
+ # Clean up the docker volume from unused resources to keep storage
+ # usage low.
+ #
+ # WARNING! This will remove:
+ # - all stopped containers
+ # - all networks not used by at least one container
+ # - all images without at least one container associated to them
+ # - all build cache
+ docker system prune -a -f
+
+ # Stop the Docker service.
+ sudo service docker stop
EOT
- dir = "/workspaces"
# These environment variables allow you to make Git commits right away after creating a
# workspace. Note that they take precedence over configuration defined in ~/.gitconfig!
# You can remove this block if you'd prefer to configure Git manually or using
# dotfiles. (see docs/dotfiles.md)
env = {
- GIT_AUTHOR_NAME = local.git_author_name
- GIT_AUTHOR_EMAIL = local.git_author_email
- GIT_COMMITTER_NAME = local.git_author_name
- GIT_COMMITTER_EMAIL = local.git_author_email
+ GIT_AUTHOR_NAME = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name)
+ GIT_AUTHOR_EMAIL = "${data.coder_workspace_owner.me.email}"
+ GIT_COMMITTER_NAME = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name)
+ GIT_COMMITTER_EMAIL = "${data.coder_workspace_owner.me.email}"
}
# The following metadata blocks are optional. They are used to display
@@ -279,7 +108,7 @@ resource "coder_agent" "main" {
metadata {
display_name = "Home Disk"
key = "3_home_disk"
- script = "coder stat disk --path $HOME"
+ script = "coder stat disk --path $${HOME}"
interval = 60
timeout = 1
}
@@ -322,51 +151,159 @@ resource "coder_agent" "main" {
}
}
-# See https://registry.coder.com/modules/coder/code-server
-module "code-server" {
- count = data.coder_workspace.me.start_count
- source = "registry.coder.com/coder/code-server/coder"
+resource "coder_script" "init_docker_in_docker" {
+ count = data.coder_workspace.me.start_count
+ agent_id = coder_agent.main.id
+ display_name = "Initialize Docker-in-Docker"
+ run_on_start = true
+ icon = "/icon/docker.svg"
+ script = file("${path.module}/scripts/init-docker-in-docker.sh")
+}
+
+# See https://registry.coder.com/modules/coder/devcontainers-cli
+module "devcontainers-cli" {
+ count = data.coder_workspace.me.start_count
+ source = "registry.coder.com/coder/devcontainers-cli/coder"
+ agent_id = coder_agent.main.id
- # This ensures that the latest non-breaking version of the module gets downloaded, you can also pin the module version to prevent breaking changes in production.
+ # This ensures that the latest non-breaking version of the module gets
+ # downloaded, you can also pin the module version to prevent breaking
+ # changes in production.
version = "~> 1.0"
+}
+# See https://registry.coder.com/modules/coder/git-clone
+module "git-clone" {
+ count = data.coder_workspace.me.start_count
+ source = "registry.coder.com/coder/git-clone/coder"
agent_id = coder_agent.main.id
- order = 1
+ url = data.coder_parameter.repo_url.value
+ base_dir = "~"
+ # This ensures that the latest non-breaking version of the module gets
+ # downloaded, you can also pin the module version to prevent breaking
+ # changes in production.
+ version = "~> 1.0"
}
-# See https://registry.coder.com/modules/coder/jetbrains-gateway
-module "jetbrains_gateway" {
- count = data.coder_workspace.me.start_count
- source = "registry.coder.com/coder/jetbrains-gateway/coder"
+# Automatically start the devcontainer for the workspace.
+resource "coder_devcontainer" "repo" {
+ count = data.coder_workspace.me.start_count
+ agent_id = coder_agent.main.id
+ workspace_folder = "~/${module.git-clone[0].folder_name}"
+}
- # JetBrains IDEs to make available for the user to select
- jetbrains_ides = ["IU", "PS", "WS", "PY", "CL", "GO", "RM", "RD", "RR"]
- default = "IU"
+resource "docker_volume" "home_volume" {
+ name = "coder-${data.coder_workspace.me.id}-home"
+ # Protect the volume from being deleted due to changes in attributes.
+ lifecycle {
+ ignore_changes = all
+ }
+ # Add labels in Docker to keep track of orphan resources.
+ labels {
+ label = "coder.owner"
+ value = data.coder_workspace_owner.me.name
+ }
+ labels {
+ label = "coder.owner_id"
+ value = data.coder_workspace_owner.me.id
+ }
+ labels {
+ label = "coder.workspace_id"
+ value = data.coder_workspace.me.id
+ }
+ # This field becomes outdated if the workspace is renamed but can
+ # be useful for debugging or cleaning out dangling volumes.
+ labels {
+ label = "coder.workspace_name_at_creation"
+ value = data.coder_workspace.me.name
+ }
+}
- # Default folder to open when starting a JetBrains IDE
- folder = "/workspaces"
+resource "docker_volume" "docker_volume" {
+ name = "coder-${data.coder_workspace.me.id}-docker"
+ # Protect the volume from being deleted due to changes in attributes.
+ lifecycle {
+ ignore_changes = all
+ }
+ # Add labels in Docker to keep track of orphan resources.
+ labels {
+ label = "coder.owner"
+ value = data.coder_workspace_owner.me.name
+ }
+ labels {
+ label = "coder.owner_id"
+ value = data.coder_workspace_owner.me.id
+ }
+ labels {
+ label = "coder.workspace_id"
+ value = data.coder_workspace.me.id
+ }
+ # This field becomes outdated if the workspace is renamed but can
+ # be useful for debugging or cleaning out dangling volumes.
+ labels {
+ label = "coder.workspace_name_at_creation"
+ value = data.coder_workspace.me.name
+ }
+}
- # This ensures that the latest non-breaking version of the module gets downloaded, you can also pin the module version to prevent breaking changes in production.
- version = "~> 1.0"
+resource "docker_container" "workspace" {
+ count = data.coder_workspace.me.start_count
+ image = local.workspace_image
+
+ # NOTE: The `privileged` mode is one way to run Docker-in-Docker,
+ # which is required for the devcontainer to work. If this is not
+ # desired, you can remove this line. However, you will need to ensure
+ # that the devcontainer can run Docker commands in some other way.
+ # Mounting the host Docker socket is strongly discouraged because
+ # workspaces will then compete for control of the devcontainers.
+ # For more information, see:
+ # https://coder.com/docs/admin/templates/extending-templates/docker-in-workspaces
+ privileged = true
- agent_id = coder_agent.main.id
- agent_name = "main"
- order = 2
-}
+ # Uses lower() to avoid Docker restriction on container names.
+ name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
+ # Hostname makes the shell more user friendly: coder@my-workspace:~$
+ hostname = data.coder_workspace.me.name
+ # Use the docker gateway if the access URL is 127.0.0.1
+ command = ["sh", "-c", replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")]
+ env = [
+ "CODER_AGENT_TOKEN=${coder_agent.main.token}"
+ ]
+ host {
+ host = "host.docker.internal"
+ ip = "host-gateway"
+ }
+
+ # Workspace home volume persists user data across workspace restarts.
+ volumes {
+ container_path = "/home/coder"
+ volume_name = docker_volume.home_volume.name
+ read_only = false
+ }
-resource "coder_metadata" "container_info" {
- count = data.coder_workspace.me.start_count
- resource_id = coder_agent.main.id
- item {
- key = "workspace image"
- value = var.cache_repo == "" ? local.devcontainer_builder_image : envbuilder_cached_image.cached.0.image
+ # Workspace docker volume persists Docker data across workspace
+ # restarts, allowing the devcontainer cache to be reused.
+ volumes {
+ container_path = "/var/lib/docker"
+ volume_name = docker_volume.docker_volume.name
+ read_only = false
+ }
+
+ # Add labels in Docker to keep track of orphan resources.
+ labels {
+ label = "coder.owner"
+ value = data.coder_workspace_owner.me.name
+ }
+ labels {
+ label = "coder.owner_id"
+ value = data.coder_workspace_owner.me.id
}
- item {
- key = "git url"
- value = local.repo_url
+ labels {
+ label = "coder.workspace_id"
+ value = data.coder_workspace.me.id
}
- item {
- key = "cache repo"
- value = var.cache_repo == "" ? "not enabled" : var.cache_repo
+ labels {
+ label = "coder.workspace_name"
+ value = data.coder_workspace.me.name
}
}
diff --git a/examples/templates/docker-devcontainer/scripts/init-docker-in-docker.sh b/examples/templates/docker-devcontainer/scripts/init-docker-in-docker.sh
new file mode 100755
index 0000000000000..57022d22a47b4
--- /dev/null
+++ b/examples/templates/docker-devcontainer/scripts/init-docker-in-docker.sh
@@ -0,0 +1,101 @@
+#!/bin/sh
+set -e
+
+# Docker-in-Docker setup for Coder dev containers using host.docker.internal
+# URLs. When Docker runs inside a container, the "docker0" bridge interface
+# can interfere with host.docker.internal DNS resolution, breaking
+# connectivity to the Coder server.
+
+if [ "${CODER_AGENT_URL#*host.docker.internal}" = "$CODER_AGENT_URL" ]; then
+ # External access URL detected, no networking workarounds needed.
+ sudo service docker start
+ exit 0
+fi
+
+# host.docker.internal URL detected. Docker's default bridge network creates
+# a "docker0" interface that can shadow the host.docker.internal hostname
+# resolution. This typically happens when Docker starts inside a devcontainer,
+# as the inner Docker daemon creates its own bridge network that conflicts
+# with the outer one.
+
+# Enable IP forwarding to allow packets to route between the host network and
+# the devcontainer networks. Without this, traffic cannot flow properly
+# between the different Docker bridge networks.
+echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
+sudo iptables -t nat -A POSTROUTING -j MASQUERADE
+
+# Set up port forwarding to the host Docker gateway (typically 172.17.0.1).
+# We resolve host.docker.internal to get the actual IP and create NAT rules
+# to forward traffic from this workspace to the host.
+host_ip=$(getent hosts host.docker.internal | awk '{print $1}')
+
+echo "Host IP for host.docker.internal: $host_ip"
+
+# Extract the port from CODER_AGENT_URL. The URL format is typically
+# http://host.docker.internal:port/.
+port="${CODER_AGENT_URL##*:}"
+port="${port%%/*}"
+case "$port" in
+[0-9]*)
+ # Specific port found, forward it to the host gateway.
+ sudo iptables -t nat -A PREROUTING -p tcp --dport "$port" -j DNAT --to-destination "$host_ip:$port"
+ echo "Forwarded port $port to $host_ip"
+ ;;
+*)
+ # No specific port or non-numeric port, forward standard web ports.
+ sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination "$host_ip:80"
+ sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination "$host_ip:443"
+ echo "Forwarded default ports 80/443 to $host_ip"
+ ;;
+esac
+
+# Start Docker service, which creates the "docker0" interface if it doesn't
+# exist. We need the interface to extract the second IP address for DNS
+# resolution.
+sudo service docker start
+
+# Configure DNS resolution to avoid requiring devcontainer project modifications.
+# While devcontainers can use the "--add-host" flag, it requires explicit
+# definition in devcontainer.json. Using a DNS server instead means every
+# devcontainer project doesn't need to accommodate this.
+
+# Wait for the workspace to acquire its Docker bridge IP address. The
+# "hostname -I" command returns multiple IPs: the first is typically the host
+# Docker bridge (172.17.0.0/16 range) and the second is the workspace Docker
+# bridge (172.18.0.0/16). We need the second IP because that's where
+# devcontainers will be able to reach us.
+dns_ip=
+while [ -z "$dns_ip" ]; do
+ dns_ip=$(hostname -I | awk '{print $2}')
+ if [ -z "$dns_ip" ]; then
+ echo "Waiting for hostname -I to return a valid second IP address..."
+ sleep 1
+ fi
+done
+
+echo "Using DNS IP: $dns_ip"
+
+# Install dnsmasq to provide custom DNS resolution. This lightweight DNS
+# server allows us to override specific hostname lookups without affecting
+# other DNS queries.
+sudo apt-get update -y
+sudo apt-get install -y dnsmasq
+
+# Configure dnsmasq to resolve host.docker.internal to this workspace's IP.
+# This ensures devcontainers can find the Coder server even when the "docker0"
+# interface would normally shadow the hostname resolution.
+echo "no-hosts" | sudo tee /etc/dnsmasq.conf
+echo "address=/host.docker.internal/$dns_ip" | sudo tee -a /etc/dnsmasq.conf
+echo "resolv-file=/etc/resolv.conf" | sudo tee -a /etc/dnsmasq.conf
+echo "no-dhcp-interface=" | sudo tee -a /etc/dnsmasq.conf
+echo "bind-interfaces" | sudo tee -a /etc/dnsmasq.conf
+echo "listen-address=127.0.0.1,$dns_ip" | sudo tee -a /etc/dnsmasq.conf
+
+sudo service dnsmasq restart
+
+# Configure Docker daemon to use our custom DNS server. This is the critical
+# piece that ensures all containers (including devcontainers) use our dnsmasq
+# server for hostname resolution, allowing them to properly resolve
+# host.docker.internal.
+echo "{\"dns\": [\"$dns_ip\"]}" | sudo tee /etc/docker/daemon.json
+sudo service docker restart
diff --git a/examples/templates/docker-envbuilder/README.md b/examples/templates/docker-envbuilder/README.md
new file mode 100644
index 0000000000000..828442d621684
--- /dev/null
+++ b/examples/templates/docker-envbuilder/README.md
@@ -0,0 +1,77 @@
+---
+display_name: Docker (Envbuilder)
+description: Provision envbuilder containers as Coder workspaces
+icon: ../../../site/static/icon/docker.png
+maintainer_github: coder
+verified: true
+tags: [container, docker, devcontainer, envbuilder]
+---
+
+# Remote Development on Docker Containers (with Envbuilder)
+
+Provision Envbuilder containers based on `devcontainer.json` as [Coder workspaces](https://coder.com/docs/workspaces) in Docker with this example template.
+
+## Prerequisites
+
+### Infrastructure
+
+Coder must have access to a running Docker socket, and the `coder` user must be a member of the `docker` group:
+
+```shell
+# Add coder user to Docker group
+sudo usermod -aG docker coder
+
+# Restart Coder server
+sudo systemctl restart coder
+
+# Test Docker
+sudo -u coder docker ps
+```
+
+## Architecture
+
+Coder supports Envbuilder containers based on `devcontainer.json` via [envbuilder](https://github.com/coder/envbuilder), an open source project. Read more about this in [Coder's documentation](https://coder.com/docs/templates/dev-containers).
+
+This template provisions the following resources:
+
+- Envbuilder cached image (conditional, persistent) using [`terraform-provider-envbuilder`](https://github.com/coder/terraform-provider-envbuilder)
+- Docker image (persistent) using [`envbuilder`](https://github.com/coder/envbuilder)
+- Docker container (ephemeral)
+- Docker volume (persistent on `/workspaces`)
+
+The Git repository is cloned inside the `/workspaces` volume if not present.
+Any local changes to the Devcontainer files inside the volume will be applied when you restart the workspace.
+Keep in mind that any tools or files outside of `/workspaces` or not added as part of the Devcontainer specification are not persisted.
+Edit the `devcontainer.json` instead!
+
+> **Note**
+> This template is designed to be a starting point! Edit the Terraform to extend the template to support your use case.
+
+## Docker-in-Docker
+
+See the [Envbuilder documentation](https://github.com/coder/envbuilder/blob/main/docs/docker.md) for information on running Docker containers inside an Envbuilder container.
+
+## Caching
+
+To speed up your builds, you can use a container registry as a cache.
+When creating the template, set the parameter `cache_repo` to a valid Docker repository.
+
+For example, you can run a local registry:
+
+```shell
+docker run --detach \
+ --volume registry-cache:/var/lib/registry \
+ --publish 5000:5000 \
+ --name registry-cache \
+ --net=host \
+ registry:2
+```
+
+Then, when creating the template, enter `localhost:5000/envbuilder-cache` for the parameter `cache_repo`.
+
+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.
+
+> [!NOTE]
+> We recommend using a registry cache with authentication enabled.
+> To allow Envbuilder to authenticate with the registry cache, specify the variable `cache_repo_docker_config_path`
+> with the path to a Docker config `.json` on disk containing valid credentials for the registry.
diff --git a/examples/templates/docker-envbuilder/main.tf b/examples/templates/docker-envbuilder/main.tf
new file mode 100644
index 0000000000000..2765874f80181
--- /dev/null
+++ b/examples/templates/docker-envbuilder/main.tf
@@ -0,0 +1,372 @@
+terraform {
+ required_providers {
+ coder = {
+ source = "coder/coder"
+ version = "~> 2.0"
+ }
+ docker = {
+ source = "kreuzwerker/docker"
+ }
+ envbuilder = {
+ source = "coder/envbuilder"
+ }
+ }
+}
+
+variable "docker_socket" {
+ default = ""
+ description = "(Optional) Docker socket URI"
+ type = string
+}
+
+provider "coder" {}
+provider "docker" {
+ # Defaulting to null if the variable is an empty string lets us have an optional variable without having to set our own default
+ host = var.docker_socket != "" ? var.docker_socket : null
+}
+provider "envbuilder" {}
+
+data "coder_provisioner" "me" {}
+data "coder_workspace" "me" {}
+data "coder_workspace_owner" "me" {}
+
+data "coder_parameter" "repo" {
+ description = "Select a repository to automatically clone and start working with a devcontainer."
+ display_name = "Repository (auto)"
+ mutable = true
+ name = "repo"
+ option {
+ name = "vercel/next.js"
+ description = "The React Framework"
+ value = "https://github.com/vercel/next.js"
+ }
+ option {
+ name = "home-assistant/core"
+ description = "🏡 Open source home automation that puts local control and privacy first."
+ value = "https://github.com/home-assistant/core"
+ }
+ option {
+ name = "discourse/discourse"
+ description = "A platform for community discussion. Free, open, simple."
+ value = "https://github.com/discourse/discourse"
+ }
+ option {
+ name = "denoland/deno"
+ description = "A modern runtime for JavaScript and TypeScript."
+ value = "https://github.com/denoland/deno"
+ }
+ option {
+ name = "microsoft/vscode"
+ icon = "/icon/code.svg"
+ description = "Code editing. Redefined."
+ value = "https://github.com/microsoft/vscode"
+ }
+ option {
+ name = "Custom"
+ icon = "/emojis/1f5c3.png"
+ description = "Specify a custom repo URL below"
+ value = "custom"
+ }
+ order = 1
+}
+
+data "coder_parameter" "custom_repo_url" {
+ default = ""
+ description = "Optionally enter a custom repository URL, see [awesome-devcontainers](https://github.com/manekinekko/awesome-devcontainers)."
+ display_name = "Repository URL (custom)"
+ name = "custom_repo_url"
+ mutable = true
+ order = 2
+}
+
+data "coder_parameter" "fallback_image" {
+ default = "codercom/enterprise-base:ubuntu"
+ description = "This image runs if the devcontainer fails to build."
+ display_name = "Fallback Image"
+ mutable = true
+ name = "fallback_image"
+ order = 3
+}
+
+data "coder_parameter" "devcontainer_builder" {
+ description = <<-EOF
+Image that will build the devcontainer.
+We highly recommend using a specific release as the `:latest` tag will change.
+Find the latest version of Envbuilder here: https://github.com/coder/envbuilder/pkgs/container/envbuilder
+EOF
+ display_name = "Devcontainer Builder"
+ mutable = true
+ name = "devcontainer_builder"
+ default = "ghcr.io/coder/envbuilder:latest"
+ order = 4
+}
+
+variable "cache_repo" {
+ default = ""
+ description = "(Optional) Use a container registry as a cache to speed up builds."
+ type = string
+}
+
+variable "insecure_cache_repo" {
+ default = false
+ description = "Enable this option if your cache registry does not serve HTTPS."
+ type = bool
+}
+
+variable "cache_repo_docker_config_path" {
+ default = ""
+ description = "(Optional) Path to a docker config.json containing credentials to the provided cache repo, if required."
+ sensitive = true
+ type = string
+}
+
+locals {
+ container_name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
+ devcontainer_builder_image = data.coder_parameter.devcontainer_builder.value
+ git_author_name = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name)
+ git_author_email = data.coder_workspace_owner.me.email
+ repo_url = data.coder_parameter.repo.value == "custom" ? data.coder_parameter.custom_repo_url.value : data.coder_parameter.repo.value
+ # The envbuilder provider requires a key-value map of environment variables.
+ envbuilder_env = {
+ # ENVBUILDER_GIT_URL and ENVBUILDER_CACHE_REPO will be overridden by the provider
+ # if the cache repo is enabled.
+ "ENVBUILDER_GIT_URL" : local.repo_url,
+ "ENVBUILDER_CACHE_REPO" : var.cache_repo,
+ "CODER_AGENT_TOKEN" : coder_agent.main.token,
+ # Use the docker gateway if the access URL is 127.0.0.1
+ "CODER_AGENT_URL" : replace(data.coder_workspace.me.access_url, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal"),
+ # Use the docker gateway if the access URL is 127.0.0.1
+ "ENVBUILDER_INIT_SCRIPT" : replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal"),
+ "ENVBUILDER_FALLBACK_IMAGE" : data.coder_parameter.fallback_image.value,
+ "ENVBUILDER_DOCKER_CONFIG_BASE64" : try(data.local_sensitive_file.cache_repo_dockerconfigjson[0].content_base64, ""),
+ "ENVBUILDER_PUSH_IMAGE" : var.cache_repo == "" ? "" : "true",
+ "ENVBUILDER_INSECURE" : "${var.insecure_cache_repo}",
+ }
+ # Convert the above map to the format expected by the docker provider.
+ docker_env = [
+ for k, v in local.envbuilder_env : "${k}=${v}"
+ ]
+}
+
+data "local_sensitive_file" "cache_repo_dockerconfigjson" {
+ count = var.cache_repo_docker_config_path == "" ? 0 : 1
+ filename = var.cache_repo_docker_config_path
+}
+
+resource "docker_image" "devcontainer_builder_image" {
+ name = local.devcontainer_builder_image
+ keep_locally = true
+}
+
+resource "docker_volume" "workspaces" {
+ name = "coder-${data.coder_workspace.me.id}"
+ # Protect the volume from being deleted due to changes in attributes.
+ lifecycle {
+ ignore_changes = all
+ }
+ # Add labels in Docker to keep track of orphan resources.
+ labels {
+ label = "coder.owner"
+ value = data.coder_workspace_owner.me.name
+ }
+ labels {
+ label = "coder.owner_id"
+ value = data.coder_workspace_owner.me.id
+ }
+ labels {
+ label = "coder.workspace_id"
+ value = data.coder_workspace.me.id
+ }
+ # This field becomes outdated if the workspace is renamed but can
+ # be useful for debugging or cleaning out dangling volumes.
+ labels {
+ label = "coder.workspace_name_at_creation"
+ value = data.coder_workspace.me.name
+ }
+}
+
+# Check for the presence of a prebuilt image in the cache repo
+# that we can use instead.
+resource "envbuilder_cached_image" "cached" {
+ count = var.cache_repo == "" ? 0 : data.coder_workspace.me.start_count
+ builder_image = local.devcontainer_builder_image
+ git_url = local.repo_url
+ cache_repo = var.cache_repo
+ extra_env = local.envbuilder_env
+ insecure = var.insecure_cache_repo
+}
+
+resource "docker_container" "workspace" {
+ count = data.coder_workspace.me.start_count
+ image = var.cache_repo == "" ? local.devcontainer_builder_image : envbuilder_cached_image.cached.0.image
+ # Uses lower() to avoid Docker restriction on container names.
+ name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
+ # Hostname makes the shell more user friendly: coder@my-workspace:~$
+ hostname = data.coder_workspace.me.name
+ # Use the environment specified by the envbuilder provider, if available.
+ env = var.cache_repo == "" ? local.docker_env : envbuilder_cached_image.cached.0.env
+ # network_mode = "host" # Uncomment if testing with a registry running on `localhost`.
+ host {
+ host = "host.docker.internal"
+ ip = "host-gateway"
+ }
+ volumes {
+ container_path = "/workspaces"
+ volume_name = docker_volume.workspaces.name
+ read_only = false
+ }
+ # Add labels in Docker to keep track of orphan resources.
+ labels {
+ label = "coder.owner"
+ value = data.coder_workspace_owner.me.name
+ }
+ labels {
+ label = "coder.owner_id"
+ value = data.coder_workspace_owner.me.id
+ }
+ labels {
+ label = "coder.workspace_id"
+ value = data.coder_workspace.me.id
+ }
+ labels {
+ label = "coder.workspace_name"
+ value = data.coder_workspace.me.name
+ }
+}
+
+resource "coder_agent" "main" {
+ arch = data.coder_provisioner.me.arch
+ os = "linux"
+ startup_script = <<-EOT
+ set -e
+
+ # Add any commands that should be executed at workspace startup (e.g install requirements, start a program, etc) here
+ EOT
+ dir = "/workspaces"
+
+ # These environment variables allow you to make Git commits right away after creating a
+ # workspace. Note that they take precedence over configuration defined in ~/.gitconfig!
+ # You can remove this block if you'd prefer to configure Git manually or using
+ # dotfiles. (see docs/dotfiles.md)
+ env = {
+ GIT_AUTHOR_NAME = local.git_author_name
+ GIT_AUTHOR_EMAIL = local.git_author_email
+ GIT_COMMITTER_NAME = local.git_author_name
+ GIT_COMMITTER_EMAIL = local.git_author_email
+ }
+
+ # The following metadata blocks are optional. They are used to display
+ # information about your workspace in the dashboard. You can remove them
+ # if you don't want to display any information.
+ # For basic resources, you can use the `coder stat` command.
+ # If you need more control, you can write your own script.
+ metadata {
+ display_name = "CPU Usage"
+ key = "0_cpu_usage"
+ script = "coder stat cpu"
+ interval = 10
+ timeout = 1
+ }
+
+ metadata {
+ display_name = "RAM Usage"
+ key = "1_ram_usage"
+ script = "coder stat mem"
+ interval = 10
+ timeout = 1
+ }
+
+ metadata {
+ display_name = "Home Disk"
+ key = "3_home_disk"
+ script = "coder stat disk --path $HOME"
+ interval = 60
+ timeout = 1
+ }
+
+ metadata {
+ display_name = "CPU Usage (Host)"
+ key = "4_cpu_usage_host"
+ script = "coder stat cpu --host"
+ interval = 10
+ timeout = 1
+ }
+
+ metadata {
+ display_name = "Memory Usage (Host)"
+ key = "5_mem_usage_host"
+ script = "coder stat mem --host"
+ interval = 10
+ timeout = 1
+ }
+
+ metadata {
+ display_name = "Load Average (Host)"
+ key = "6_load_host"
+ # get load avg scaled by number of cores
+ script = <