Copy and paste the following into main.tf
and run coder template push
:
1terraform {
2 required_providers {
3 coder = {
4 source = "coder/coder"
5 version = "~> 1.0.0"
6 }
7 docker = {
8 source = "kreuzwerker/docker"
9 }
10 }
11}
12
13provider "coder" {}
14provider "docker" {}
15data "coder_provisioner" "me" {}
16data "coder_workspace" "me" {}
17data "coder_workspace_owner" "me" {}
18
19data "coder_parameter" "repo" {
20 description = "Select a repository to automatically clone and start working with a devcontainer."
21 display_name = "Repository (auto)"
22 mutable = true
23 name = "repo"
24 option {
25 name = "vercel/next.js"
26 description = "The React Framework"
27 value = "https://github.com/vercel/next.js"
28 }
29 option {
30 name = "home-assistant/core"
31 description = "🏡 Open source home automation that puts local control and privacy first."
32 value = "https://github.com/home-assistant/core"
33 }
34 option {
35 name = "discourse/discourse"
36 description = "A platform for community discussion. Free, open, simple."
37 value = "https://github.com/discourse/discourse"
38 }
39 option {
40 name = "denoland/deno"
41 description = "A modern runtime for JavaScript and TypeScript."
42 value = "https://github.com/denoland/deno"
43 }
44 option {
45 name = "microsoft/vscode"
46 icon = "/icon/code.svg"
47 description = "Code editing. Redefined."
48 value = "https://github.com/microsoft/vscode"
49 }
50 option {
51 name = "Custom"
52 icon = "/emojis/1f5c3.png"
53 description = "Specify a custom repo URL below"
54 value = "custom"
55 }
56 order = 1
57}
58
59data "coder_parameter" "custom_repo_url" {
60 default = ""
61 description = "Optionally enter a custom repository URL, see [awesome-devcontainers](https://github.com/manekinekko/awesome-devcontainers)."
62 display_name = "Repository URL (custom)"
63 name = "custom_repo_url"
64 mutable = true
65 order = 2
66}
67
68data "coder_parameter" "fallback_image" {
69 default = "codercom/enterprise-base:ubuntu"
70 description = "This image runs if the devcontainer fails to build."
71 display_name = "Fallback Image"
72 mutable = true
73 name = "fallback_image"
74 order = 3
75}
76
77data "coder_parameter" "devcontainer_builder" {
78 description = <<-EOF
79Image that will build the devcontainer.
80We highly recommend using a specific release as the `:latest` tag will change.
81Find the latest version of Envbuilder here: https://github.com/coder/envbuilder/pkgs/container/envbuilder
82EOF
83 display_name = "Devcontainer Builder"
84 mutable = true
85 name = "devcontainer_builder"
86 default = "ghcr.io/coder/envbuilder:latest"
87 order = 4
88}
89
90variable "cache_repo" {
91 default = ""
92 description = "Use a container registry as a cache to speed up builds."
93 sensitive = true
94 type = string
95}
96
97variable "cache_repo_docker_config_path" {
98 default = ""
99 description = "Path to a docker config.json containing credentials to the provided cache repo, if required."
100 sensitive = true
101 type = string
102}
103
104locals {
105 container_name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
106 devcontainer_builder_image = data.coder_parameter.devcontainer_builder.value
107 git_author_name = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name)
108 git_author_email = data.coder_workspace_owner.me.email
109 repo_url = data.coder_parameter.repo.value == "custom" ? data.coder_parameter.custom_repo_url.value : data.coder_parameter.repo.value
110}
111
112data "local_sensitive_file" "cache_repo_dockerconfigjson" {
113 count = var.cache_repo_docker_config_path == "" ? 0 : 1
114 filename = var.cache_repo_docker_config_path
115}
116
117resource "docker_image" "devcontainer_builder_image" {
118 name = local.devcontainer_builder_image
119}
120
121resource "docker_volume" "workspaces" {
122 name = "coder-${data.coder_workspace.me.id}"
123 # Protect the volume from being deleted due to changes in attributes.
124 lifecycle {
125 ignore_changes = all
126 }
127 # Add labels in Docker to keep track of orphan resources.
128 labels {
129 label = "coder.owner"
130 value = data.coder_workspace_owner.me.name
131 }
132 labels {
133 label = "coder.owner_id"
134 value = data.coder_workspace_owner.me.id
135 }
136 labels {
137 label = "coder.workspace_id"
138 value = data.coder_workspace.me.id
139 }
140 # This field becomes outdated if the workspace is renamed but can
141 # be useful for debugging or cleaning out dangling volumes.
142 labels {
143 label = "coder.workspace_name_at_creation"
144 value = data.coder_workspace.me.name
145 }
146}
147
148resource "docker_container" "workspace" {
149 count = data.coder_workspace.me.start_count
150 image = local.devcontainer_builder_image
151 # Uses lower() to avoid Docker restriction on container names.
152 name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
153 # Hostname makes the shell more user friendly: coder@my-workspace:~$
154 hostname = data.coder_workspace.me.name
155 # Use the docker gateway if the access URL is 127.0.0.1
156 env = [
157 "CODER_AGENT_TOKEN=${coder_agent.main.token}",
158 "CODER_AGENT_URL=${replace(data.coder_workspace.me.access_url, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")}",
159 "ENVBUILDER_GIT_URL=${local.repo_url}",
160 "ENVBUILDER_INIT_SCRIPT=${replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")}",
161 "ENVBUILDER_FALLBACK_IMAGE=${data.coder_parameter.fallback_image.value}",
162 "ENVBUILDER_CACHE_REPO=${var.cache_repo}",
163 "ENVBUILDER_DOCKER_CONFIG_BASE64=${try(data.local_sensitive_file.cache_repo_dockerconfigjson[0].content_base64, "")}",
164 ]
165 host {
166 host = "host.docker.internal"
167 ip = "host-gateway"
168 }
169 volumes {
170 container_path = "/workspaces"
171 volume_name = docker_volume.workspaces.name
172 read_only = false
173 }
174 # Add labels in Docker to keep track of orphan resources.
175 labels {
176 label = "coder.owner"
177 value = data.coder_workspace_owner.me.name
178 }
179 labels {
180 label = "coder.owner_id"
181 value = data.coder_workspace_owner.me.id
182 }
183 labels {
184 label = "coder.workspace_id"
185 value = data.coder_workspace.me.id
186 }
187 labels {
188 label = "coder.workspace_name"
189 value = data.coder_workspace.me.name
190 }
191}
192
193resource "coder_agent" "main" {
194 arch = data.coder_provisioner.me.arch
195 os = "linux"
196 startup_script = <<-EOT
197 set -e
198
199 # install and start code-server
200 curl -fsSL https://code-server.dev/install.sh | sh -s -- --method=standalone --prefix=/tmp/code-server --version 4.11.0
201 /tmp/code-server/bin/code-server --auth none --port 13337 >/tmp/code-server.log 2>&1 &
202 EOT
203 dir = "/workspaces"
204
205 # These environment variables allow you to make Git commits right away after creating a
206 # workspace. Note that they take precedence over configuration defined in ~/.gitconfig!
207 # You can remove this block if you'd prefer to configure Git manually or using
208 # dotfiles. (see docs/dotfiles.md)
209 env = {
210 GIT_AUTHOR_NAME = local.git_author_name
211 GIT_AUTHOR_EMAIL = local.git_author_email
212 GIT_COMMITTER_NAME = local.git_author_name
213 GIT_COMMITTER_EMAIL = local.git_author_email
214 }
215
216 # The following metadata blocks are optional. They are used to display
217 # information about your workspace in the dashboard. You can remove them
218 # if you don't want to display any information.
219 # For basic resources, you can use the `coder stat` command.
220 # If you need more control, you can write your own script.
221 metadata {
222 display_name = "CPU Usage"
223 key = "0_cpu_usage"
224 script = "coder stat cpu"
225 interval = 10
226 timeout = 1
227 }
228
229 metadata {
230 display_name = "RAM Usage"
231 key = "1_ram_usage"
232 script = "coder stat mem"
233 interval = 10
234 timeout = 1
235 }
236
237 metadata {
238 display_name = "Home Disk"
239 key = "3_home_disk"
240 script = "coder stat disk --path $HOME"
241 interval = 60
242 timeout = 1
243 }
244
245 metadata {
246 display_name = "CPU Usage (Host)"
247 key = "4_cpu_usage_host"
248 script = "coder stat cpu --host"
249 interval = 10
250 timeout = 1
251 }
252
253 metadata {
254 display_name = "Memory Usage (Host)"
255 key = "5_mem_usage_host"
256 script = "coder stat mem --host"
257 interval = 10
258 timeout = 1
259 }
260
261 metadata {
262 display_name = "Load Average (Host)"
263 key = "6_load_host"
264 # get load avg scaled by number of cores
265 script = <<EOT
266 echo "`cat /proc/loadavg | awk '{ print $1 }'` `nproc`" | awk '{ printf "%0.2f", $1/$2 }'
267 EOT
268 interval = 60
269 timeout = 1
270 }
271
272 metadata {
273 display_name = "Swap Usage (Host)"
274 key = "7_swap_host"
275 script = <<EOT
276 free -b | awk '/^Swap/ { printf("%.1f/%.1f", $3/1024.0/1024.0/1024.0, $2/1024.0/1024.0/1024.0) }'
277 EOT
278 interval = 10
279 timeout = 1
280 }
281}
282
283resource "coder_app" "code-server" {
284 agent_id = coder_agent.main.id
285 slug = "code-server"
286 display_name = "code-server"
287 url = "http://localhost:13337/?folder=/workspaces"
288 icon = "/icon/code.svg"
289 subdomain = false
290 share = "owner"
291
292 healthcheck {
293 url = "http://localhost:13337/healthz"
294 interval = 5
295 threshold = 6
296 }
297}
298