TemplatesModules
Back to Templates
DigitalOcean Droplet (Linux) Icon

DigitalOcean Droplet (Linux)

By:
Provision DigitalOcean Droplets as Coder workspaces
Source
README
Resources (3)
Variables (2)

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    digitalocean = {
7      source = "digitalocean/digitalocean"
8    }
9  }
10}
11
12provider "coder" {
13}
14
15variable "step1_do_project_id" {
16  type        = string
17  description = <<-EOF
18    Enter project ID
19
20      $ doctl projects list
21  EOF
22  sensitive   = true
23
24  validation {
25    # make sure length of alphanumeric string is 36
26    condition     = length(var.step1_do_project_id) == 36
27    error_message = "Invalid Digital Ocean Project ID."
28  }
29
30}
31
32variable "step2_do_admin_ssh_key" {
33  type        = number
34  description = <<-EOF
35    Enter admin SSH key ID (some Droplet images require an SSH key to be set):
36
37    Can be set to "0" for no key.
38
39    Note: Setting this to zero will break Fedora images and notify root passwords via email.
40
41      $ doctl compute ssh-key list
42  EOF
43  sensitive   = true
44
45  validation {
46    condition     = var.step2_do_admin_ssh_key >= 0
47    error_message = "Invalid Digital Ocean SSH key ID, a number is required."
48  }
49}
50
51data "coder_parameter" "droplet_image" {
52  name         = "droplet_image"
53  display_name = "Droplet image"
54  description  = "Which Droplet image would you like to use?"
55  default      = "ubuntu-22-04-x64"
56  type         = "string"
57  mutable      = false
58  option {
59    name  = "AlmaLinux 9"
60    value = "almalinux-9-x64"
61    icon  = "/icon/almalinux.svg"
62  }
63  option {
64    name  = "AlmaLinux 8"
65    value = "almalinux-8-x64"
66    icon  = "/icon/almalinux.svg"
67  }
68  option {
69    name  = "Fedora 39"
70    value = "fedora-39-x64"
71    icon  = "/icon/fedora.svg"
72  }
73  option {
74    name  = "Fedora 38"
75    value = "fedora-38-x64"
76    icon  = "/icon/fedora.svg"
77  }
78  option {
79    name  = "CentOS Stream 9"
80    value = "centos-stream-9-x64"
81    icon  = "/icon/centos.svg"
82  }
83  option {
84    name  = "CentOS Stream 8"
85    value = "centos-stream-8-x64"
86    icon  = "/icon/centos.svg"
87  }
88  option {
89    name  = "Debian 12"
90    value = "debian-12-x64"
91    icon  = "/icon/debian.svg"
92  }
93  option {
94    name  = "Debian 11"
95    value = "debian-11-x64"
96    icon  = "/icon/debian.svg"
97  }
98  option {
99    name  = "Debian 10"
100    value = "debian-10-x64"
101    icon  = "/icon/debian.svg"
102  }
103  option {
104    name  = "Rocky Linux 9"
105    value = "rockylinux-9-x64"
106    icon  = "/icon/rockylinux.svg"
107  }
108  option {
109    name  = "Rocky Linux 8"
110    value = "rockylinux-8-x64"
111    icon  = "/icon/rockylinux.svg"
112  }
113  option {
114    name  = "Ubuntu 22.04 (LTS)"
115    value = "ubuntu-22-04-x64"
116    icon  = "/icon/ubuntu.svg"
117  }
118  option {
119    name  = "Ubuntu 20.04 (LTS)"
120    value = "ubuntu-20-04-x64"
121    icon  = "/icon/ubuntu.svg"
122  }
123}
124
125data "coder_parameter" "droplet_size" {
126  name         = "droplet_size"
127  display_name = "Droplet size"
128  description  = "Which Droplet configuration would you like to use?"
129  default      = "s-1vcpu-1gb"
130  type         = "string"
131  icon         = "/icon/memory.svg"
132  mutable      = false
133  # s-1vcpu-512mb-10gb is unsupported in tor1, blr1, lon1, sfo2, and nyc3 regions
134  # s-8vcpu-16gb access requires a support ticket with Digital Ocean
135  option {
136    name  = "1 vCPU, 1 GB RAM"
137    value = "s-1vcpu-1gb"
138  }
139  option {
140    name  = "1 vCPU, 2 GB RAM"
141    value = "s-1vcpu-2gb"
142  }
143  option {
144    name  = "2 vCPU, 2 GB RAM"
145    value = "s-2vcpu-2gb"
146  }
147  option {
148    name  = "2 vCPU, 4 GB RAM"
149    value = "s-2vcpu-4gb"
150  }
151  option {
152    name  = "4 vCPU, 8 GB RAM"
153    value = "s-4vcpu-8gb"
154  }
155}
156
157data "coder_parameter" "home_volume_size" {
158  name         = "home_volume_size"
159  display_name = "Home volume size"
160  description  = "How large would you like your home volume to be (in GB)?"
161  type         = "number"
162  default      = "20"
163  mutable      = false
164  validation {
165    min = 1
166    max = 100 # Sizes larger than 100 GB require a support ticket with Digital Ocean
167  }
168}
169
170data "coder_parameter" "region" {
171  name         = "region"
172  display_name = "Region"
173  description  = "This is the region where your workspace will be created."
174  icon         = "/emojis/1f30e.png"
175  type         = "string"
176  default      = "ams3"
177  mutable      = false
178  # nyc1, sfo1, and ams2 regions were excluded because they do not support volumes, which are used to persist data while decreasing cost
179  option {
180    name  = "Canada (Toronto)"
181    value = "tor1"
182    icon  = "/emojis/1f1e8-1f1e6.png"
183  }
184  option {
185    name  = "Germany (Frankfurt)"
186    value = "fra1"
187    icon  = "/emojis/1f1e9-1f1ea.png"
188  }
189  option {
190    name  = "India (Bangalore)"
191    value = "blr1"
192    icon  = "/emojis/1f1ee-1f1f3.png"
193  }
194  option {
195    name  = "Netherlands (Amsterdam)"
196    value = "ams3"
197    icon  = "/emojis/1f1f3-1f1f1.png"
198  }
199  option {
200    name  = "Singapore"
201    value = "sgp1"
202    icon  = "/emojis/1f1f8-1f1ec.png"
203  }
204  option {
205    name  = "United Kingdom (London)"
206    value = "lon1"
207    icon  = "/emojis/1f1ec-1f1e7.png"
208  }
209  option {
210    name  = "United States (California - 2)"
211    value = "sfo2"
212    icon  = "/emojis/1f1fa-1f1f8.png"
213  }
214  option {
215    name  = "United States (California - 3)"
216    value = "sfo3"
217    icon  = "/emojis/1f1fa-1f1f8.png"
218  }
219  option {
220    name  = "United States (New York - 1)"
221    value = "nyc1"
222    icon  = "/emojis/1f1fa-1f1f8.png"
223  }
224  option {
225    name  = "United States (New York - 3)"
226    value = "nyc3"
227    icon  = "/emojis/1f1fa-1f1f8.png"
228  }
229}
230
231# Configure the DigitalOcean Provider
232provider "digitalocean" {
233  # Recommended: use environment variable DIGITALOCEAN_TOKEN with your personal access token when starting coderd
234  # alternatively, you can pass the token via a variable.
235}
236
237data "coder_workspace" "me" {}
238data "coder_workspace_owner" "me" {}
239
240resource "coder_agent" "main" {
241  os   = "linux"
242  arch = "amd64"
243
244  metadata {
245    key          = "cpu"
246    display_name = "CPU Usage"
247    interval     = 5
248    timeout      = 5
249    script       = "coder stat cpu"
250  }
251  metadata {
252    key          = "memory"
253    display_name = "Memory Usage"
254    interval     = 5
255    timeout      = 5
256    script       = "coder stat mem"
257  }
258  metadata {
259    key          = "home"
260    display_name = "Home Usage"
261    interval     = 600 # every 10 minutes
262    timeout      = 30  # df can take a while on large filesystems
263    script       = "coder stat disk --path /home/${lower(data.coder_workspace_owner.me.name)}"
264  }
265}
266
267resource "digitalocean_volume" "home_volume" {
268  region                   = data.coder_parameter.region.value
269  name                     = "coder-${data.coder_workspace.me.id}-home"
270  size                     = data.coder_parameter.home_volume_size.value
271  initial_filesystem_type  = "ext4"
272  initial_filesystem_label = "coder-home"
273  # Protect the volume from being deleted due to changes in attributes.
274  lifecycle {
275    ignore_changes = all
276  }
277}
278
279resource "digitalocean_droplet" "workspace" {
280  region = data.coder_parameter.region.value
281  count  = data.coder_workspace.me.start_count
282  name   = "coder-${lower(data.coder_workspace_owner.me.name)}-${lower(data.coder_workspace.me.name)}"
283  image  = data.coder_parameter.droplet_image.value
284  size   = data.coder_parameter.droplet_size.value
285
286  volume_ids = [digitalocean_volume.home_volume.id]
287  user_data = templatefile("cloud-config.yaml.tftpl", {
288    username          = lower(data.coder_workspace_owner.me.name)
289    home_volume_label = digitalocean_volume.home_volume.initial_filesystem_label
290    init_script       = base64encode(coder_agent.main.init_script)
291    coder_agent_token = coder_agent.main.token
292  })
293  # Required to provision Fedora.
294  ssh_keys = var.step2_do_admin_ssh_key > 0 ? [var.step2_do_admin_ssh_key] : []
295}
296
297resource "digitalocean_project_resources" "project" {
298  project = var.step1_do_project_id
299  # Workaround for terraform plan when using count.
300  resources = length(digitalocean_droplet.workspace) > 0 ? [
301    digitalocean_volume.home_volume.urn,
302    digitalocean_droplet.workspace[0].urn
303    ] : [
304    digitalocean_volume.home_volume.urn
305  ]
306}
307
308resource "coder_metadata" "workspace-info" {
309  count       = data.coder_workspace.me.start_count
310  resource_id = digitalocean_droplet.workspace[0].id
311
312  item {
313    key   = "region"
314    value = digitalocean_droplet.workspace[0].region
315  }
316  item {
317    key   = "image"
318    value = digitalocean_droplet.workspace[0].image
319  }
320}
321
322resource "coder_metadata" "volume-info" {
323  resource_id = digitalocean_volume.home_volume.id
324
325  item {
326    key   = "size"
327    value = "${digitalocean_volume.home_volume.size} GiB"
328  }
329}
330