Using Terraform¶
First Test¶
Creating a simple web server. Most of this is derived from the Linode tutorial.
terraform {
required_providers {
linode = {
source = "linode/linode"
version = "2.34.1"
}
}
}
provider "linode" {
token = "..."
}
resource "linode_instance" "terraform-web" {
image = "linode/ubuntu18.04"
label = "Terraform-Web-Example"
tags = [ "Test" ]
region = "us-east"
type = "g6-standard-1"
authorized_keys = [ "..." ]
root_pass = "..."
}
$ terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
+ create
Terraform will perform the following actions:
# linode_instance.terraform-web will be created
+ resource "linode_instance" "terraform-web" {
+ authorized_keys = [
+ "...",
]
+ backups = (known after apply)
+ backups_enabled = (known after apply)
+ boot_config_label = (known after apply)
+ booted = (known after apply)
+ capabilities = (known after apply)
+ disk_encryption = (known after apply)
+ has_user_data = (known after apply)
+ host_uuid = (known after apply)
+ id = (known after apply)
+ image = "linode/ubuntu18.04"
+ ip_address = (known after apply)
+ ipv4 = (known after apply)
+ ipv6 = (known after apply)
+ label = "Terraform-Web-Example"
+ lke_cluster_id = (known after apply)
+ migration_type = "cold"
+ private_ip_address = (known after apply)
+ region = "us-east"
+ resize_disk = false
+ root_pass = (sensitive value)
+ shared_ipv4 = (known after apply)
+ specs = (known after apply)
+ status = (known after apply)
+ swap_size = (known after apply)
+ tags = [
+ "Test",
]
+ type = "g6-standard-1"
+ watchdog_enabled = true
+ alerts (known after apply)
+ config (known after apply)
+ disk (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if
you run "terraform apply" now.
$ terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
+ create
Terraform will perform the following actions:
# linode_instance.terraform-web will be created
+ resource "linode_instance" "terraform-web" {
+ authorized_keys = [
+ "...",
]
+ backups = (known after apply)
+ backups_enabled = (known after apply)
+ boot_config_label = (known after apply)
+ booted = (known after apply)
+ capabilities = (known after apply)
+ disk_encryption = (known after apply)
+ has_user_data = (known after apply)
+ host_uuid = (known after apply)
+ id = (known after apply)
+ image = "linode/ubuntu18.04"
+ ip_address = (known after apply)
+ ipv4 = (known after apply)
+ ipv6 = (known after apply)
+ label = "Terraform-Web-Example"
+ lke_cluster_id = (known after apply)
+ migration_type = "cold"
+ private_ip_address = (known after apply)
+ region = "us-east"
+ resize_disk = false
+ root_pass = (sensitive value)
+ shared_ipv4 = (known after apply)
+ specs = (known after apply)
+ status = (known after apply)
+ swap_size = (known after apply)
+ tags = [
+ "Test",
]
+ type = "g6-standard-1"
+ watchdog_enabled = true
+ alerts (known after apply)
+ config (known after apply)
+ disk (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
linode_instance.terraform-web: Creating...
linode_instance.terraform-web: Still creating... [10s elapsed]
linode_instance.terraform-web: Still creating... [20s elapsed]
linode_instance.terraform-web: Still creating... [30s elapsed]
linode_instance.terraform-web: Still creating... [40s elapsed]
linode_instance.terraform-web: Still creating... [50s elapsed]
linode_instance.terraform-web: Creation complete after 50s [id=72561064]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
$ terraform destroy
linode_instance.terraform-web: Refreshing state... [id=72561064]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
- destroy
Terraform will perform the following actions:
# linode_instance.terraform-web will be destroyed
- resource "linode_instance" "terraform-web" {
- authorized_keys = [
- "...",
] -> null
- backups = [
- {
- available = false
- enabled = false
- schedule = [
- {
# (2 unchanged attributes hidden)
},
]
},
] -> null
- backups_enabled = false -> null
- boot_config_label = "My Ubuntu 18.04 LTS Disk Profile" -> null
- booted = true -> null
- capabilities = [
- "SMTP Enabled",
] -> null
- disk_encryption = "disabled" -> null
- has_user_data = false -> null
- host_uuid = "438d9d778b8e24e27e8f4ac543801335f3a65dfc" -> null
- id = "72561064" -> null
- image = "linode/ubuntu18.04" -> null
- ip_address = "172.104.5.175" -> null
- ipv4 = [
- "172.104.5.175",
] -> null
- ipv6 = "2600:3c03::f03c:95ff:fe64:78d2/128" -> null
- label = "Terraform-Web-Example" -> null
- lke_cluster_id = 0 -> null
- migration_type = "cold" -> null
- private_ip = false -> null
- region = "us-east" -> null
- resize_disk = false -> null
- root_pass = (sensitive value) -> null
- shared_ipv4 = [] -> null
- specs = [
- {
- accelerated_devices = 0
- disk = 51200
- gpus = 0
- memory = 2048
- transfer = 2000
- vcpus = 1
},
] -> null
- status = "running" -> null
- swap_size = 512 -> null
- tags = [
- "Test",
] -> null
- type = "g6-standard-1" -> null
- watchdog_enabled = true -> null
# (1 unchanged attribute hidden)
- alerts {
- cpu = 90 -> null
- io = 10000 -> null
- network_in = 10 -> null
- network_out = 10 -> null
- transfer_quota = 80 -> null
}
- config {
- id = 75951812 -> null
- kernel = "linode/grub2" -> null
- label = "My Ubuntu 18.04 LTS Disk Profile" -> null
- memory_limit = 0 -> null
- root_device = "/dev/sda" -> null
- run_level = "default" -> null
- virt_mode = "paravirt" -> null
# (1 unchanged attribute hidden)
- devices {
- sda {
- disk_id = 141029448 -> null
- disk_label = "Ubuntu 18.04 LTS Disk" -> null
- volume_id = 0 -> null
}
- sdb {
- disk_id = 141029449 -> null
- disk_label = "512 MB Swap Image" -> null
- volume_id = 0 -> null
}
}
- helpers {
- devtmpfs_automount = true -> null
- distro = true -> null
- modules_dep = true -> null
- network = true -> null
- updatedb_disabled = true -> null
}
}
- disk {
- authorized_keys = [] -> null
- authorized_users = [] -> null
- filesystem = "ext4" -> null
- id = 141029448 -> null
- label = "Ubuntu 18.04 LTS Disk" -> null
- read_only = false -> null
- size = 50688 -> null
- stackscript_data = (sensitive value) -> null
- stackscript_id = 0 -> null
# (2 unchanged attributes hidden)
}
- disk {
- authorized_keys = [] -> null
- authorized_users = [] -> null
- filesystem = "swap" -> null
- id = 141029449 -> null
- label = "512 MB Swap Image" -> null
- read_only = false -> null
- size = 512 -> null
- stackscript_data = (sensitive value) -> null
- stackscript_id = 0 -> null
# (2 unchanged attributes hidden)
}
}
Plan: 0 to add, 0 to change, 1 to destroy.
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
linode_instance.terraform-web: Destroying... [id=72561064]
linode_instance.terraform-web: Still destroying... [id=72561064, 10s elapsed]
linode_instance.terraform-web: Still destroying... [id=72561064, 20s elapsed]
linode_instance.terraform-web: Destruction complete after 28s
Destroy complete! Resources: 1 destroyed.
linode-cli
¶
$ pipx install linode-cli
installed package linode-cli 5.56.2, installed using Python 3.12.3
These apps are now globally available
- lin
- linode
- linode-cli
done! ✨ 🌟 ✨
$ linode-cli configure --token
Welcome to the Linode CLI. This will walk you through some initial setup.
First, we need a Personal Access Token. To get one, please visit
https://cloud.linode.com/profile/tokens and click
"Create a Personal Access Token". The CLI needs access to everything
on your account to work correctly.
Personal Access Token: ...
Configuring luser
Default Region for operations. Choices are:
1 - ap-northeast
2 - ap-south
3 - ap-southeast
4 - ap-west
5 - au-mel
6 - br-gru
7 - ca-central
8 - de-fra-2
9 - es-mad
10 - eu-central
11 - eu-west
12 - fr-par
13 - gb-lon
14 - id-cgk
15 - in-bom-2
16 - in-maa
17 - it-mil
18 - jp-osa
19 - jp-tyo-3
20 - nl-ams
21 - se-sto
22 - sg-sin-2
23 - us-central
24 - us-east
25 - us-iad
26 - us-lax
27 - us-mia
28 - us-ord
29 - us-sea
30 - us-southeast
31 - us-west
Default Region (Optional): 7
Default Type of Linode to deploy. Choices are:
1 - g1-gpu-rtx6000-1
2 - g1-gpu-rtx6000-2
3 - g1-gpu-rtx6000-3
4 - g1-gpu-rtx6000-4
5 - g2-gpu-rtx4000a1-l
6 - g2-gpu-rtx4000a1-m
7 - g2-gpu-rtx4000a1-s
8 - g2-gpu-rtx4000a1-xl
9 - g2-gpu-rtx4000a2-hs
10 - g2-gpu-rtx4000a2-m
11 - g2-gpu-rtx4000a2-s
12 - g2-gpu-rtx4000a4-m
13 - g2-gpu-rtx4000a4-s
14 - g6-dedicated-16
15 - g6-dedicated-2
16 - g6-dedicated-32
17 - g6-dedicated-4
18 - g6-dedicated-48
19 - g6-dedicated-50
20 - g6-dedicated-56
21 - g6-dedicated-8
22 - g6-nanode-1
23 - g6-standard-1
24 - g6-standard-16
25 - g6-standard-2
26 - g6-standard-20
27 - g6-standard-24
28 - g6-standard-32
29 - g6-standard-4
30 - g6-standard-6
31 - g6-standard-8
32 - g7-highmem-1
33 - g7-highmem-16
34 - g7-highmem-2
35 - g7-highmem-4
36 - g7-highmem-8
37 - g7-premium-16
38 - g7-premium-2
39 - g7-premium-32
40 - g7-premium-4
41 - g7-premium-48
42 - g7-premium-50
43 - g7-premium-56
44 - g7-premium-8
Default Type of Linode (Optional): 22
Default Image to deploy to new Linodes. Choices are:
1 - linode/almalinux8
2 - linode/almalinux9
3 - linode/alpine3.17
4 - linode/alpine3.18
5 - linode/alpine3.19
6 - linode/alpine3.20
7 - linode/arch
8 - linode/centos-stream9
9 - linode/debian11
10 - linode/debian12
11 - linode/debian12-kube-v1.29.7
12 - linode/debian12-kube-v1.30.3
13 - linode/debian12-kube-v1.31.0
14 - linode/debian12-kube-v1.32.1
15 - linode/fedora39
16 - linode/fedora40
17 - linode/fedora41
18 - linode/gentoo
19 - linode/kali
20 - linode/opensuse15.5
21 - linode/opensuse15.6
22 - linode/rocky8
23 - linode/rocky9
24 - linode/slackware15.0
25 - linode/ubuntu16.04lts
26 - linode/ubuntu18.04
27 - linode/ubuntu20.04
28 - linode/ubuntu22.04
29 - linode/ubuntu24.04
30 - linode/ubuntu24.10
Default Image (Optional): 10
Select the user that should be given default SSH access to new Linodes. Choices are:
1 - luser
Default Option (Optional): 1
Configure a custom API target? [y/N]:
Suppress API Version Warnings? [y/N]:
Active user is now luser
Custom Images: You can also deploy instances from your own custom images (e.g. ones you built or snapshot). Custom images are identified by an ID prefixed with private/
. For instance, a private image might have an ID like private/123456
. To use a custom image in Terraform, set the image
to that ID. For example, if you have a custom image with ID 17691867, you’d use image = "private/17691867"
in your config. (All custom image IDs begin with "private/"; in this example private/17691867
is the ID output from a Packer-built image.) You can retrieve your custom image IDs via the Linode Cloud Manager or API (the Linode API’s image list will include your private images when called with your API token.
If you need to manage custom images as resources, Terraform’s Linode provider also offers a linode_image
resource and data source, which let you create or look up images (e.g. create an image from a Linode disk, or fetch an image’s details). But in most cases, deploying a custom image simply involves referencing its private/<id>
in the linode_instance
resource.