TemplatesModules
Back to Templates
Docker Containers Icon

Docker Containers

By:
Provision Docker containers as Coder workspaces
Source
README
Resources (3)

Copy and paste the following into main.tf and run coder template push:

1terraform {
2  required_providers {
3    coder = {
4      source = "coder/coder"
5    }
6    docker = {
7      source = "kreuzwerker/docker"
8    }
9  }
10}
11
12locals {
13  username = data.coder_workspace_owner.me.name
14}
15
16data "coder_provisioner" "me" {
17}
18
19provider "docker" {
20}
21
22data "coder_workspace" "me" {
23}
24data "coder_workspace_owner" "me" {}
25
26resource "coder_agent" "main" {
27  arch           = data.coder_provisioner.me.arch
28  os             = "linux"
29  startup_script = <<-EOT
30    set -e
31
32    # Prepare user home with default files on first start.
33    if [ ! -f ~/.init_done ]; then
34      cp -rT /etc/skel ~
35      touch ~/.init_done
36    fi
37
38    # Install the latest code-server.
39    # Append "--version x.x.x" to install a specific version of code-server.
40    curl -fsSL https://code-server.dev/install.sh | sh -s -- --method=standalone --prefix=/tmp/code-server
41
42    # Start code-server in the background.
43    /tmp/code-server/bin/code-server --auth none --port 13337 >/tmp/code-server.log 2>&1 &
44  EOT
45
46  # These environment variables allow you to make Git commits right away after creating a
47  # workspace. Note that they take precedence over configuration defined in ~/.gitconfig!
48  # You can remove this block if you'd prefer to configure Git manually or using
49  # dotfiles. (see docs/dotfiles.md)
50  env = {
51    GIT_AUTHOR_NAME     = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name)
52    GIT_AUTHOR_EMAIL    = "${data.coder_workspace_owner.me.email}"
53    GIT_COMMITTER_NAME  = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name)
54    GIT_COMMITTER_EMAIL = "${data.coder_workspace_owner.me.email}"
55  }
56
57  # The following metadata blocks are optional. They are used to display
58  # information about your workspace in the dashboard. You can remove them
59  # if you don't want to display any information.
60  # For basic resources, you can use the `coder stat` command.
61  # If you need more control, you can write your own script.
62  metadata {
63    display_name = "CPU Usage"
64    key          = "0_cpu_usage"
65    script       = "coder stat cpu"
66    interval     = 10
67    timeout      = 1
68  }
69
70  metadata {
71    display_name = "RAM Usage"
72    key          = "1_ram_usage"
73    script       = "coder stat mem"
74    interval     = 10
75    timeout      = 1
76  }
77
78  metadata {
79    display_name = "Home Disk"
80    key          = "3_home_disk"
81    script       = "coder stat disk --path $${HOME}"
82    interval     = 60
83    timeout      = 1
84  }
85
86  metadata {
87    display_name = "CPU Usage (Host)"
88    key          = "4_cpu_usage_host"
89    script       = "coder stat cpu --host"
90    interval     = 10
91    timeout      = 1
92  }
93
94  metadata {
95    display_name = "Memory Usage (Host)"
96    key          = "5_mem_usage_host"
97    script       = "coder stat mem --host"
98    interval     = 10
99    timeout      = 1
100  }
101
102  metadata {
103    display_name = "Load Average (Host)"
104    key          = "6_load_host"
105    # get load avg scaled by number of cores
106    script   = <<EOT
107      echo "`cat /proc/loadavg | awk '{ print $1 }'` `nproc`" | awk '{ printf "%0.2f", $1/$2 }'
108    EOT
109    interval = 60
110    timeout  = 1
111  }
112
113  metadata {
114    display_name = "Swap Usage (Host)"
115    key          = "7_swap_host"
116    script       = <<EOT
117      free -b | awk '/^Swap/ { printf("%.1f/%.1f", $3/1024.0/1024.0/1024.0, $2/1024.0/1024.0/1024.0) }'
118    EOT
119    interval     = 10
120    timeout      = 1
121  }
122}
123
124resource "coder_app" "code-server" {
125  agent_id     = coder_agent.main.id
126  slug         = "code-server"
127  display_name = "code-server"
128  url          = "http://localhost:13337/?folder=/home/${local.username}"
129  icon         = "/icon/code.svg"
130  subdomain    = false
131  share        = "owner"
132
133  healthcheck {
134    url       = "http://localhost:13337/healthz"
135    interval  = 5
136    threshold = 6
137  }
138}
139
140resource "docker_volume" "home_volume" {
141  name = "coder-${data.coder_workspace.me.id}-home"
142  # Protect the volume from being deleted due to changes in attributes.
143  lifecycle {
144    ignore_changes = all
145  }
146  # Add labels in Docker to keep track of orphan resources.
147  labels {
148    label = "coder.owner"
149    value = data.coder_workspace_owner.me.name
150  }
151  labels {
152    label = "coder.owner_id"
153    value = data.coder_workspace_owner.me.id
154  }
155  labels {
156    label = "coder.workspace_id"
157    value = data.coder_workspace.me.id
158  }
159  # This field becomes outdated if the workspace is renamed but can
160  # be useful for debugging or cleaning out dangling volumes.
161  labels {
162    label = "coder.workspace_name_at_creation"
163    value = data.coder_workspace.me.name
164  }
165}
166
167resource "docker_image" "main" {
168  name = "coder-${data.coder_workspace.me.id}"
169  build {
170    context = "./build"
171    build_args = {
172      USER = local.username
173    }
174  }
175  triggers = {
176    dir_sha1 = sha1(join("", [for f in fileset(path.module, "build/*") : filesha1(f)]))
177  }
178}
179
180resource "docker_container" "workspace" {
181  count = data.coder_workspace.me.start_count
182  image = docker_image.main.name
183  # Uses lower() to avoid Docker restriction on container names.
184  name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
185  # Hostname makes the shell more user friendly: coder@my-workspace:~$
186  hostname = data.coder_workspace.me.name
187  # Use the docker gateway if the access URL is 127.0.0.1
188  entrypoint = ["sh", "-c", replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")]
189  env        = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"]
190  host {
191    host = "host.docker.internal"
192    ip   = "host-gateway"
193  }
194  volumes {
195    container_path = "/home/${local.username}"
196    volume_name    = docker_volume.home_volume.name
197    read_only      = false
198  }
199
200  # Add labels in Docker to keep track of orphan resources.
201  labels {
202    label = "coder.owner"
203    value = data.coder_workspace_owner.me.name
204  }
205  labels {
206    label = "coder.owner_id"
207    value = data.coder_workspace_owner.me.id
208  }
209  labels {
210    label = "coder.workspace_id"
211    value = data.coder_workspace.me.id
212  }
213  labels {
214    label = "coder.workspace_name"
215    value = data.coder_workspace.me.name
216  }
217}
218