centminmod/upcloud-terraform
Upcloud Terraform Server creation with upctl cli command line tool set
Upcloud Terraform Based Server Installation
Terraform based server install at Upcloud using guide outlined at https://upcloud.com/resources/tutorials/get-started-terraform & https://www.terraform.io/downloads. If you like this guide and want to try out Upcloud, use my referral link here.
- Install Terraform
- Setup Upcloud API Credentials
- Initialize New Terraform Project
- Planning Infrastructure With Terraform
- Using upctl Command Line Tool
- Deleting Terraform Created Server
- Upcloud Region List
- Upcloud Plan List
- OS Template Storage UUID
Install Terraform & upctl
yum install -y yum-utils
yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
yum -y install terraform
terraform -v
Terraform v1.2.9
on linux_amd64
Download upctl command line tool from https://github.com/UpCloudLtd/upcloud-cli/releases
upctl_version=2.1.0
curl -L -o upcloud-cli.tar.gz https://github.com/UpCloudLtd/upcloud-cli/releases/download/v${upctl_version}/upcloud-cli_${upctl_version}_linux_x86_64.tar.gz
tar -C /usr/local/bin -xf upcloud-cli.tar.gz
wget https://github.com/centminmod/upcloud-terraform/raw/master/upctl/bash_completion.d/upctl -O /etc/bash_completion.d/upctl
source /etc/bash_completion.d/upctl
Setup Upcloud API Credentials
Create a new API Access key as outlined at https://upcloud.com/community/tutorials/%20/getting-started-upcloud-api/ and replace the UPCLOUD_USERNAME and UPCLOUD_PASSWORD variable values username and password with your Upcloud API credentials and run the below commands to populate ~/.bashrc. Then apply the new additions.
echo 'export UPCLOUD_USERNAME=username' | tee -a ~/.bashrc
echo 'export UPCLOUD_PASSWORD=password' | tee -a ~/.bashrc
source ~/.bashrc
This will work for both Terraform and upctl command line tool.
Initialize New Terraform Project
Create a new directory for your Terraform project and change into it.
mkdir -p /home/terraform/base
cd /home/terraform/base
Deploying Cloud Servers on UpCloud using Terraform works using the verified provider module.
Create /home/terraform/base/version.tf
touch version.tf
Place in /home/terraform/base/version.tf
terraform {
required_providers {
upcloud = {
source = "UpCloudLtd/upcloud"
}
}
}
provider "upcloud" {
# Your UpCloud credentials are read from the environment variables
# export UPCLOUD_USERNAME="Username for Upcloud API user"
# export UPCLOUD_PASSWORD="Password for Upcloud API user"
# Optional configuration settings can be depclared here
}
terraform init
The initialisation process creates a directory for the plugins in your Terraform folder under .terraform/providers and installs the UpCloud provider module. The Terraform installation for UpCloud is then all set.
ls -lah .terraform/providers/registry.terraform.io/upcloudltd/upcloud/2.5.0/linux_amd64/
total 17M
drwxr-xr-x 2 root root 4.0K Sep 14 09:07 .
drwxr-xr-x 3 root root 4.0K Sep 14 09:07 ..
-rw-rw-rw- 1 root root 9.0K Sep 14 09:07 CHANGELOG.md
-rw-rw-rw- 1 root root 1.1K Sep 14 09:07 LICENSE
-rw-rw-rw- 1 root root 607 Sep 14 09:07 README.md
-rwxr-xr-x 1 root root 17M Sep 14 09:07 terraform-provider-upcloud_v2.5.0
Planning Infrastructure With Terraform
Using values from https://developers.upcloud.com/1.3/ and https://upcloud.com/resources/tutorials/reduce-downtime-terraform-redeployments. Later you can create variables outlined at https://upcloud.com/resources/tutorials/terraform-variables.
Create server1.tf
touch server1.tf
Using:
-
zone =
us-nyc1list of regions -
plan =
4xCPU-8GBlist of plans -
storage template list of OS storage templete UUIDs
- for CentOS 7 UUID =
01000000-0000-4000-8000-000050010300with size =160GB - for AlmaLinux 8 UUID =
01000000-0000-4000-8000-000140010100with size =160GB - for Rocky Linux 8 UUID =
01000000-0000-4000-8000-000150010100with size =160GB - for AlmaLinux 9 UUID =
01000000-0000-4000-8000-000140020100with size =160GB - for Rocky Linux 9 UUID =
01000000-0000-4000-8000-000150020100with size =160GB
- for CentOS 7 UUID =
-
save your desired SSH public key into
~/.ssh/rsa_public_keyand corresponding SSH private key into~/.ssh/rsa_private_key -
The user data scripted section is configured the way it is as in that environment the
$HOMEvariable for root user ends up as/while in a normal SSH terminal session$HOMEis/root. This difference seems to break any scripting which relies of$HOMEvariables. TheRANDFILEis foropensslbinary operations to work properly if you use scripts which runopensslbinary. -
Change the default
remote-execscript path from running at/tmpin case server has noexec set on/tmp. So set inconnectionblockscript_path = "/home/tftmp/terraform_%RAND%.sh"(https://www.terraform.io/language/resources/provisioners/connection)
Notes:
- looks like for AlmaLinux 9 and Rocky Linux 9, they are using
cloud-inittemplates and need to have Upcloud's Metadata enabled otherwise, you'd get an error like:
╷
│ Error: Metadata must be enabled when cloning a cloud-init template (METADATA_DISABLED_ON_CLOUD-INIT)
│
│ with upcloud_server.server1,
│ on server1.tf line 1, in resource "upcloud_server" "server1":
│ 1: resource "upcloud_server" "server1" {
│
╵
- EL9 OSes have SELinux enabled by default and you'd want to disable that before installing Centmin Mod. Centmin Mod can't automatically disable SELinux in EL9 like it can in EL7/EL8 OSes.
grep '^SELINUX=' /etc/selinux/config
SELINUX=enforcing
Contents of server1.tf
resource "upcloud_server" "server1" {
# System hostname
hostname = "terraform.example.com"
# Availability zone
zone = "us-nyc1"
# Number of CPUs and memory in GB
plan = "4xCPU-8GB"
metadata = true
template {
# System storage device size
size = 160
# Template UUID for CentOS 7
storage = "01000000-0000-4000-8000-000050010300"
}
# Network interfaces
network_interface {
type = "public"
}
network_interface {
type = "utility"
}
# Include at least one public SSH key
login {
user = "root"
keys = [
file("~/.ssh/rsa_public_key")
]
create_password = false
password_delivery = "email"
}
# Configuring connection details
connection {
# The server public IP address
host = self.network_interface[0].ip_address
type = "ssh"
user = "root"
private_key = file("~/.ssh/rsa_private_key")
script_path = "/home/terraform_%RAND%.sh"
}
# Remotely executing a command on the server
provisioner "remote-exec" {
inline = [
"echo 'Hello world!'"
]
}
user_data = <<-EOF
export TERM=xterm-256color
mkdir -p /root
export HOME=/root
echo $HOME
touch $HOME/.rnd
export RANDFILE=$HOME/.rnd
chmod 600 $HOME/.rnd
env
yum -y update
EOF
# Remotely executing a command on the server
provisioner "remote-exec" {
inline = [
"echo",
"lscpu",
"echo",
"free -mlt",
"echo",
"df -hT",
"echo",
"cat /etc/redhat-release"
]
}
}
You can optionally enable backups by adding to template{} block
backup_rule {
interval = "daily"
time = "0100"
retention = 8
}
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:
# upcloud_server.server1 will be created
+ resource "upcloud_server" "server1" {
+ cpu = (known after apply)
+ hostname = "terraform.example.com"
+ id = (known after apply)
+ mem = (known after apply)
+ plan = "4xCPU-8GB"
+ user_data = <<-EOT
export TERM=xterm-256color
mkdir -p /home/tftmp
sleep 5
chmod 1777 /home/tftmp
mkdir -p /root
export HOME=/root
echo $HOME
touch $HOME/.rnd
export RANDFILE=$HOME/.rnd
chmod 600 $HOME/.rnd
env
yum -y update
EOT
+ zone = "us-nyc1"
+ login {
+ create_password = false
+ keys = [
+ "ssh-rsa XYZABC",
]
+ password_delivery = "email"
+ user = "root"
}
+ network_interface {
+ bootable = false
+ ip_address = (known after apply)
+ ip_address_family = "IPv4"
+ ip_address_floating = (known after apply)
+ mac_address = (known after apply)
+ network = (known after apply)
+ source_ip_filtering = true
+ type = "public"
}
+ network_interface {
+ bootable = false
+ ip_address = (known after apply)
+ ip_address_family = "IPv4"
+ ip_address_floating = (known after apply)
+ mac_address = (known after apply)
+ network = (known after apply)
+ source_ip_filtering = true
+ type = "utility"
}
+ template {
+ address = (known after apply)
+ delete_autoresize_backup = false
+ filesystem_autoresize = false
+ id = (known after apply)
+ size = 160
+ storage = "01000000-0000-4000-8000-000050010300"
+ tier = (known after apply)
+ title = (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
upcloud_server.server1: Creating...
upcloud_server.server1: Still creating... [10s elapsed]
upcloud_server.server1: Still creating... [20s elapsed]
upcloud_server.server1: Still creating... [30s elapsed]
upcloud_server.server1: Provisioning with 'remote-exec'...
upcloud_server.server1 (remote-exec): Connecting to remote host via SSH...
upcloud_server.server1 (remote-exec): Host: 209.xxx.xxx.xxx
upcloud_server.server1 (remote-exec): User: root
upcloud_server.server1 (remote-exec): Password: false
upcloud_server.server1 (remote-exec): Private key: true
upcloud_server.server1 (remote-exec): Certificate: false
upcloud_server.server1 (remote-exec): SSH Agent: true
upcloud_server.server1 (remote-exec): Checking Host Key: false
upcloud_server.server1 (remote-exec): Target Platform: unix
upcloud_server.server1: Still creating... [40s elapsed]
upcloud_server.server1: Still creating... [50s elapsed]
upcloud_server.server1 (remote-exec): Connecting to remote host via SSH...
upcloud_server.server1 (remote-exec): Host: 209.xxx.xxx.xxx
upcloud_server.server1 (remote-exec): User: root
upcloud_server.server1 (remote-exec): Password: false
upcloud_server.server1 (remote-exec): Private key: true
upcloud_server.server1 (remote-exec): Certificate: false
upcloud_server.server1 (remote-exec): SSH Agent: true
upcloud_server.server1 (remote-exec): Checking Host Key: false
upcloud_server.server1 (remote-exec): Target Platform: unix
upcloud_server.server1 (remote-exec): Connected!
upcloud_server.server1 (remote-exec): Architecture: x86_64
upcloud_server.server1 (remote-exec): CPU op-mode(s): 32-bit, 64-bit
upcloud_server.server1 (remote-exec): Byte Order: Little Endian
upcloud_server.server1 (remote-exec): CPU(s): 4
upcloud_server.server1 (remote-exec): On-line CPU(s) list: 0-3
upcloud_server.server1 (remote-exec): Thread(s) per core: 1
upcloud_server.server1 (remote-exec): Core(s) per socket: 1
upcloud_server.server1 (remote-exec): Socket(s): 4
upcloud_server.server1 (remote-exec): NUMA node(s): 1
upcloud_server.server1 (remote-exec): Vendor ID: AuthenticAMD
upcloud_server.server1 (remote-exec): CPU family: 23
upcloud_server.server1 (remote-exec): Model: 49
upcloud_server.server1 (remote-exec): Model name: AMD EPYC 7542 32-Core Processor
upcloud_server.server1 (remote-exec): Stepping: 0
upcloud_server.server1 (remote-exec): CPU MHz: 2894.558
upcloud_server.server1 (remote-exec): BogoMIPS: 5789.11
upcloud_server.server1 (remote-exec): Hypervisor vendor: KVM
upcloud_server.server1 (remote-exec): Virtualization type: full
upcloud_server.server1 (remote-exec): L1d cache: 64K
upcloud_server.server1 (remote-exec): L1i cache: 64K
upcloud_server.server1 (remote-exec): L2 cache: 512K
upcloud_server.server1 (remote-exec): L3 cache: 16384K
upcloud_server.server1 (remote-exec): NUMA node0 CPU(s): 0-3
upcloud_server.server1 (remote-exec): Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm art rep_good nopl extd_apicid eagerfpu pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw perfctr_core retpoline_amd ssbd ibrs ibpb stibp vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 clzero xsaveerptr arat umip spec_ctrl intel_stibp arch_capabilities
upcloud_server.server1 (remote-exec): total used free shared buff/cache available
upcloud_server.server1 (remote-exec): Mem: 7802 339 7030 17 432 7215
upcloud_server.server1 (remote-exec): Low: 7802 772 7030
upcloud_server.server1 (remote-exec): High: 0 0 0
upcloud_server.server1 (remote-exec): Swap: 0 0 0
upcloud_server.server1 (remote-exec): Total: 7802 339 7030
upcloud_server.server1 (remote-exec): Filesystem Type Size Used Avail Use% Mounted on
upcloud_server.server1 (remote-exec): devtmpfs devtmpfs 3.8G 0 3.8G 0% /dev
upcloud_server.server1 (remote-exec): tmpfs tmpfs 3.9G 0 3.9G 0% /dev/shm
upcloud_server.server1 (remote-exec): tmpfs tmpfs 3.9G 18M 3.8G 1% /run
upcloud_server.server1 (remote-exec): tmpfs tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
upcloud_server.server1 (remote-exec): /dev/vda1 xfs 160G 1.6G 159G 1% /
upcloud_server.server1 (remote-exec): tmpfs tmpfs 781M 0 781M 0% /run/user/0
upcloud_server.server1 (remote-exec): CentOS Linux release 7.9.2009 (Core)
upcloud_server.server1: Creation complete after 52s [id=0006f04a-15e3-4f4d-83xxx-7cc592935xxx]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Variable Template Method
Instead of hardcoding server1.tf settings, you can use variables outlined at https://upcloud.com/resources/tutorials/terraform-variables via a dedicated variables.tf file. Updated with new Upcloud High CPU and High MEM plans.
The variables.tf file
variable "hostname" {
description = "Server hostname"
default = "terraform.example.com"
type = string
}
variable "private_key_path" {
type = string
default = "~/.ssh/rsa_private_key"
}
variable "public_key_path" {
type = string
default = "~/.ssh/rsa_public_key"
sensitive = true
}
variable "zones" {
type = map
default = {
"amsterdam" = "nl-ams1"
"london" = "uk-lon1"
"frankfurt" = "de-fra1"
"helsinki1" = "fi-hel1"
"helsinki2" = "fi-hel2"
"chicago" = "us-chi1"
"sanjose" = "us-sjo1"
"singapore" = "sg-sin1"
"sydney" = "au-syd1"
"warsaw" = "pl-waw1"
"madrid" = "es-mad1"
"newyork" = "us-nyc1"
}
}
variable "plans" {
type = map
default = {
"5USD" = "1xCPU-1GB"
"10USD" = "1xCPU-2GB"
"20USD" = "2xCPU-4GB"
"40USD" = "4xCPU-8GB"
"80USD" = "6xCPU-16GB"
"160USD" = "8xCPU-32GB"
"240USD" = "12xCPU-48GB"
"320USD" = "16xCPU-64GB"
"490USD" = "20xCPU-96GB"
"640USD" = "20xCPU-128GB"
"40USDM" = "HIMEM-2xCPU-8GB"
"65USDM" = "HIMEM-2xCPU-16GB"
"132USDM" = "HIMEM-4xCPU-32GB"
"240USDM" = "HIMEM-4xCPU-64GB"
"480USDM" = "HIMEM-6xCPU-128GB"
"840USDM" = "HIMEM-8xCPU-192GB"
"1080USDM" = "HIMEM-12xCPU-256GB"
"1680USDM" = "HIMEM-16xCPU-384GB"
"130USDC" = "HICPU-8xCPU-12GB"
"160USDC" = "HICPU-8xCPU-16GB"
"260USDC" = "HICPU-16xCPU-24GB"
"310USDC" = "HICPU-16xCPU-32GB"
"530USDC" = "HICPU-32xCPU-48GB"
"620USDC" = "HICPU-32xCPU-64GB"
"1056USDC" = "HICPU-64xCPU-96GB"
"1248USDC" = "HICPU-64xCPU-128GB"
}
}
variable "storage_sizes" {
type = map
default = {
"1xCPU-1GB" = "25"
"1xCPU-2GB" = "50"
"2xCPU-4GB" = "80"
"4xCPU-8GB" = "160"
"6xCPU-16GB" = "320"
"8xCPU-32GB" = "640"
"12xCPU-48GB" = "960"
"16xCPU-64GB" = "1280"
"20xCPU-96GB" = "1920"
"20xCPU-128GB" = "2048"
"HIMEM-2xCPU-8GB" = "100"
"HIMEM-2xCPU-16GB" = "100"
"HIMEM-4xCPU-32GB" = "100"
"HIMEM-4xCPU-64GB" = "200"
"HIMEM-6xCPU-128GB" = "300"
"HIMEM-8xCPU-192GB" = "400"
"HIMEM-12xCPU-256GB" = "500"
"HIMEM-16xCPU-384GB" = "600"
"HICPU-8xCPU-12GB" = "100"
"HICPU-8xCPU-16GB" = "200"
"HICPU-16xCPU-24GB" = "100"
"HICPU-16xCPU-32GB" = "200"
"HICPU-32xCPU-48GB" = "200"
"HICPU-32xCPU-64GB" = "300"
"HICPU-64xCPU-96GB" = "200"
"HICPU-64xCPU-128GB" = "300"
}
}
variable "templates" {
type = map
default = {
"centos7" = "01000000-0000-4000-8000-000050010300"
"almalinux8" = "01000000-0000-4000-8000-000140010100"
"rockylinux8" = "01000000-0000-4000-8000-000150010100"
"almalinux9" = "01000000-0000-4000-8000-000140020100"
"rockylinux9" = "01000000-0000-4000-8000-000150020100"
}
}
variable "set_password" {
type = bool
default = false
}
variable "users" {
type = list
default = ["root", "user1", "user2"]
}
variable "plan" {
type = string
default = "40USD"
}
variable "template" {
type = string
default = "centos7"
}
Which allows you to specify a plan by the pre-defined plan name which in this case is as follows:
"5USD" = "1xCPU-1GB"
"10USD" = "1xCPU-2GB"
"20USD" = "2xCPU-4GB"
"40USD" = "4xCPU-8GB"
"80USD" = "6xCPU-16GB"
"160USD" = "8xCPU-32GB"
"240USD" = "12xCPU-48GB"
"320USD" = "16xCPU-64GB"
"490USD" = "20xCPU-96GB"
"640USD" = "20xCPU-128GB"
"40USDM" = "HIMEM-2xCPU-8GB"
"65USDM" = "HIMEM-2xCPU-16GB"
"132USDM" = "HIMEM-4xCPU-32GB"
"240USDM" = "HIMEM-4xCPU-64GB"
"480USDM" = "HIMEM-6xCPU-128GB"
"840USDM" = "HIMEM-8xCPU-192GB"
"1080USDM" = "HIMEM-12xCPU-256GB"
"1680USDM" = "HIMEM-16xCPU-384GB"
"130USDC" = "HICPU-8xCPU-12GB"
"160USDC" = "HICPU-8xCPU-16GB"
"260USDC" = "HICPU-16xCPU-24GB"
"310USDC" = "HICPU-16xCPU-32GB"
"530USDC" = "HICPU-32xCPU-48GB"
"620USDC" = "HICPU-32xCPU-64GB"
"1056USDC" = "HICPU-64xCPU-96GB"
"1248USDC" = "HICPU-64xCPU-128GB"
Specific Terraform definition files
For CentOS 7 centos.tfvars
template = "centos7"
For AlmaLinux 8 almalinux8.tfvars
template = "almalinux8"
For Rocky Linux 8 rockylinux8.tfvars
template = "rockylinux8"
For AlmaLinux 9 almalinux9.tfvars
template = "almalinux9"
For Rocky Linux 9 rockylinux9.tfvars
template = "rockylinux9"
You can then utilise these definition files on the command line and set the pre-defined plan name from above and desired hostname and --var-file for the OS template name i.e.
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file centos.tfvars
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux8.tfvars
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux8.tfvars
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux9.tfvars
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux9.tfvars
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file centos.tfvars
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux8.tfvars
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux8.tfvars
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux9.tfvars
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux9.tfvars
To apply without prompt at -auto-approve
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file centos.tfvars -auto-approve
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux8.tfvars -auto-approve
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux8.tfvars -auto-approve
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux9.tfvars -auto-approve
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux9.tfvars -auto-approve
plan files
Or save to plan files
# save plan files
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file centos.tfvars -out plan20usd-c7
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux8.tfvars -out plan20usd-al8
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux8.tfvars -out plan20usd-rl8
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux9.tfvars -out plan20usd-al9
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux9.tfvars -out plan20usd-rl9
# inspect plan files
terraform show "plan20usd-c7"
terraform show "plan20usd-al8"
terraform show "plan20usd-rl8"
terraform show "plan20usd-al9"
terraform show "plan20usd-rl9"
# inspect plan files with debug output prefix with TF_LOG=debug
TF_LOG=debug terraform show "plan20usd-c7"
TF_LOG=debug terraform show "plan20usd-al8"
TF_LOG=debug terraform show "plan20usd-rl8"
TF_LOG=debug terraform show "plan20usd-al9"
TF_LOG=debug terraform show "plan20usd-rl9"
# inspect plan files in json output
terraform show -json "plan20usd-c7"
terraform show -json "plan20usd-al8"
terraform show -json "plan20usd-rl8"
terraform show -json "plan20usd-al9"
terraform show -json "plan20usd-rl9"
# apply plan files
terraform apply "plan20usd-c7"
terraform apply "plan20usd-al8"
terraform apply "plan20usd-rl8"
terraform apply "plan20usd-al9"
terraform apply "plan20usd-rl9"
# apply plan files with debug output prefix with TF_LOG=debug
TF_LOG=debug terraform apply "plan20usd-c7"
TF_LOG=debug terraform apply "plan20usd-al8"
TF_LOG=debug terraform apply "plan20usd-rl8"
TF_LOG=debug terraform apply "plan20usd-al9"
TF_LOG=debug terraform apply "plan20usd-rl9"
The server.tf file
resource "upcloud_server" "server1" {
# System hostname
hostname = var.hostname
# Availability zone
zone = var.zones["newyork"]
# Number of CPUs and memory in GB
plan = var.plans[var.plan]
metadata = true
template {
# System storage device size
size = lookup(var.storage_sizes, var.plans[var.plan])
# Template UUID for CentOS 7
storage = var.templates[var.template]
}
# Network interfaces
network_interface {
type = "public"
}
network_interface {
type = "utility"
}
# Include at least one public SSH key
login {
user = var.users[0]
keys = [
chomp(file(var.public_key_path))
]
create_password = var.set_password
password_delivery = "email"
}
# Configuring connection details
connection {
# The server public IP address
host = self.network_interface[0].ip_address
type = "ssh"
user = var.users[0]
private_key = file(var.private_key_path)
script_path = "/home/terraform_%RAND%.sh"
}
# Remotely executing a command on the server
provisioner "remote-exec" {
inline = [
"echo 'Hello world!'"
]
}
user_data = <<-EOF
export TERM=xterm-256color
mkdir -p /root
export HOME=/root
echo $HOME
touch $HOME/.rnd
export RANDFILE=$HOME/.rnd
chmod 600 $HOME/.rnd
env
yum -y update
EOF
# Remotely executing a command on the server
provisioner "remote-exec" {
inline = [
"echo",
"lscpu",
"echo",
"free -mlt",
"echo",
"df -hT",
"echo",
"cat /etc/redhat-release"
]
}
}
You can optionally enable backups by adding to template{} block
backup_rule {
interval = "daily"
time = "0100"
retention = 8
}
Defining Output Variables
Create an output.tf file with your server name defined in server1.tf = server1 as defined by resource "upcloud_server" "server1" {
output "public_ip" {
value = upcloud_server.server1.network_interface[0].ip_address
}
output "utility_ip" {
value = upcloud_server.server1.network_interface[1].ip_address
}
output "hostname" {
value = upcloud_server.server1.hostname
}
output "plan" {
value = upcloud_server.server1.plan
}
output "zone" {
value = upcloud_server.server1.zone
}
output "size" {
value = upcloud_server.server1.template[0].size
}
Then creating a 20USD plan Upcloud server. You can also add -var hostname="host.domain.com" to change the desired hostname.
terraform plan -var plan="20USD"
terraform apply -var plan="20USD"
To apply without prompt at -auto-approve
terraform apply -var plan="20USD" -auto-approve
terraform plan -var plan="20USD"
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:
# upcloud_server.server1 will be created
+ resource "upcloud_server" "server1" {
+ cpu = (known after apply)
+ hostname = "terraform.example.com"
+ id = (known after apply)
+ mem = (known after apply)
+ plan = "2xCPU-4GB"
+ user_data = <<-EOT
export TERM=xterm-256color
mkdir -p /home/tftmp
sleep 5
chmod 1777 /home/tftmp
mkdir -p /root
export HOME=/root
echo $HOME
touch $HOME/.rnd
export RANDFILE=$HOME/.rnd
chmod 600 $HOME/.rnd
env
yum -y update
EOT
+ zone = "us-nyc1"
+ login {
+ create_password = false
+ keys = [
+ "ssh-rsa XYZABC",
]
+ password_delivery = "email"
+ user = "root"
}
+ network_interface {
+ bootable = false
+ ip_address = (known after apply)
+ ip_address_family = "IPv4"
+ ip_address_floating = (known after apply)
+ mac_address = (known after apply)
+ network = (known after apply)
+ source_ip_filtering = true
+ type = "public"
}
+ network_interface {
+ bootable = false
+ ip_address = (known after apply)
+ ip_address_family = "IPv4"
+ ip_address_floating = (known after apply)
+ mac_address = (known after apply)
+ network = (known after apply)
+ source_ip_filtering = true
+ type = "utility"
}
+ template {
+ address = (known after apply)
+ delete_autoresize_backup = false
+ filesystem_autoresize = false
+ id = (known after apply)
+ size = 80
+ storage = "01000000-0000-4000-8000-000050010300"
+ tier = (known after apply)
+ title = (known after apply)
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ hostname = "terraform.example.com"
+ plan = "2xCPU-4GB"
+ public_ip = (known after apply)
+ size = 80
+ utility_ip = (known after apply)
+ zone = "us-nyc1"
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
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.
Viewing User Data Progress
You can check the user data log at /var/log/upcloud_userdata.log on the created Upcloud server
tail -f /var/log/upcloud_userdata.log
Or SSH into the created Upcloud server
ssh root@209.xxx.xxx.xxx tail -f /var/log/upcloud_userdata.log
Using upctl Command Line Tool
Use upctl command line tool https://upcloud.com/resources/tutorials/get-started-upcloud-command-line-interface
List servers
upctl server list
UUID Hostname Plan Zone State
────────────────────────────────────── ─────────────────────── ─────────── ───────── ─────────
0006f04a-15e3-4f4d-83xxx-7cc592935xxx terraform.example.com 4xCPU-8GB us-nyc1 started
Stop server
upctl server stop terraform.example.com
Start server
upctl server start terraform.example.com
Show server info
upctl server show terraform.example.com
upctl server show terraform.example.com
Common
UUID: 0006f04a-15e3-4f4d-83xxx-7cc592935xxx
Hostname: terraform.example.com
Title: terraform.example.com (managed by terraform)
Plan: 4xCPU-8GB
Zone: us-nyc1
State: started
Simple Backup: no
Licence: 0
Metadata: False
Timezone: UTC
Host ID: 746718xxxxx
Tags:
Storage: (Flags: B = bootdisk, P = part of plan)
UUID Title Type Address Size (GiB) Flags
────────────────────────────────────── ────────────────────────────────────── ────── ────────── ──────────── ───────
01a400de-930e-4cac-8114-62408b5xxxxx terraform-terraform.example.com-disk disk virtio:0 160 P
NICs: (Flags: S = source IP filtering, B = bootable)
# Type IP Address MAC Address Network Flags
─── ───────── ────────────────────── ─────────────────── ────────────────────────────────────── ───────
1 public IPv4: 209.xxx.xxx.xxx 52:xx:xx:xx:61:5c 034a97cd-e05c-4785-bf33-7648b64xxxxx S
2 utility IPv4: 10.x.x.xxx 52:xx:xx:xx:be:aa 03243004-e399-49cc-9697-4f5e9fcxxxxx S
Deleting Terraform Created Server
terraform destroy
Upcloud Region List
{
"zones": {
"zone": [
{
"description": "Sydney #1",
"id": "au-syd1",
"public": "yes"
},
{
"description": "Frankfurt #1",
"id": "de-fra1",
"public": "yes"
},
{
"description": "Madrid #1",
"id": "es-mad1",
"public": "yes"
},
{
"description": "Helsinki #1",
"id": "fi-hel1",
"public": "yes"
},
{
"description": "Helsinki #2",
"id": "fi-hel2",
"public": "yes"
},
{
"description": "Amsterdam #1",
"id": "nl-ams1",
"public": "yes"
},
{
"description": "Warsaw #1",
"id": "pl-waw1",
"public": "yes"
},
{
"description": "Singapore #1",
"id": "sg-sin1",
"public": "yes"
},
{
"description": "London #1",
"id": "uk-lon1",
"public": "yes"
},
{
"description": "Chicago #1",
"id": "us-chi1",
"public": "yes"
},
{
"description": "New York #1",
"id": "us-nyc1",
"public": "yes"
},
{
"description": "San Jose #1",
"id": "us-sjo1",
"public": "yes"
}
]
}
}Upcloud Plan List
{
"plans": {
"plan": [
{
"core_number": 1,
"memory_amount": 2048,
"name": "1xCPU-2GB",
"public_traffic_out": 2048,
"storage_size": 50,
"storage_tier": "maxiops"
},
{
"core_number": 1,
"memory_amount": 1024,
"name": "1xCPU-1GB",
"public_traffic_out": 1024,
"storage_size": 25,
"storage_tier": "maxiops"
},
{
"core_number": 2,
"memory_amount": 4096,
"name": "2xCPU-4GB",
"public_traffic_out": 4096,
"storage_size": 80,
"storage_tier": "maxiops"
},
{
"core_number": 2,
"memory_amount": 8192,
"name": "HIMEM-2xCPU-8GB",
"public_traffic_out": 2048,
"storage_size": 100,
"storage_tier": "maxiops"
},
{
"core_number": 2,
"memory_amount": 16384,
"name": "HIMEM-2xCPU-16GB",
"public_traffic_out": 2048,
"storage_size": 100,
"storage_tier": "maxiops"
},
{
"core_number": 4,
"memory_amount": 65536,
"name": "HIMEM-4xCPU-64GB",
"public_traffic_out": 4096,
"storage_size": 200,
"storage_tier": "maxiops"
},
{
"core_number": 4,
"memory_amount": 32768,
"name": "HIMEM-4xCPU-32GB",
"public_traffic_out": 4096,
"storage_size": 100,
"storage_tier": "maxiops"
},
{
"core_number": 4,
"memory_amount": 8192,
"name": "4xCPU-8GB",
"public_traffic_out": 5120,
"storage_size": 160,
"storage_tier": "maxiops"
},
{
"core_number": 6,
"memory_amount": 16384,
"name": "6xCPU-16GB",
"public_traffic_out": 6144,
"storage_size": 320,
"storage_tier": "maxiops"
},
{
"core_number": 6,
"memory_amount": 131072,
"name": "HIMEM-6xCPU-128GB",
"public_traffic_out": 6144,
"storage_size": 300,
"storage_tier": "maxiops"
},
{
"core_number": 8,
"memory_amount": 12288,
"name": "HICPU-8xCPU-12GB",
"public_traffic_out": 4096,
"storage_size": 100,
"storage_tier": "maxiops"
},
{
"core_number": 8,
"memory_amount": 16384,
"name": "HICPU-8xCPU-16GB",
"public_traffic_out": 4096,
"storage_size": 200,
"storage_tier": "maxiops"
},
{
"core_number": 8,
"memory_amount": 196608,
"name": "HIMEM-8xCPU-192GB",
"public_traffic_out": 8192,
"storage_size": 400,
"storage_tier": "maxiops"
},
{
"core_number": 8,
"memory_amount": 32768,
"name": "8xCPU-32GB",
"public_traffic_out": 7168,
"storage_size": 640,
"storage_tier": "maxiops"
},
{
"core_number": 12,
"memory_amount": 262144,
"name": "HIMEM-12xCPU-256GB",
"public_traffic_out": 10240,
"storage_size": 500,
"storage_tier": "maxiops"
},
{
"core_number": 12,
"memory_amount": 49152,
"name": "12xCPU-48GB",
"public_traffic_out": 9216,
"storage_size": 960,
"storage_tier": "maxiops"
},
{
"core_number": 16,
"memory_amount": 24576,
"name": "HICPU-16xCPU-24GB",
"public_traffic_out": 5120,
"storage_size": 100,
"storage_tier": "maxiops"
},
{
"core_number": 16,
"memory_amount": 393216,
"name": "HIMEM-16xCPU-384GB",
"public_traffic_out": 12288,
"storage_size": 600,
"storage_tier": "maxiops"
},
{
"core_number": 16,
"memory_amount": 32768,
"name": "HICPU-16xCPU-32GB",
"public_traffic_out": 5120,
"storage_size": 200,
"storage_tier": "maxiops"
},
{
"core_number": 16,
"memory_amount": 65536,
"name": "16xCPU-64GB",
"public_traffic_out": 10240,
"storage_size": 1280,
"storage_tier": "maxiops"
},
{
"core_number": 20,
"memory_amount": 131072,
"name": "20xCPU-128GB",
"public_traffic_out": 24576,
"storage_size": 2048,
"storage_tier": "maxiops"
},
{
"core_number": 20,
"memory_amount": 98304,
"name": "20xCPU-96GB",
"public_traffic_out": 12288,
"storage_size": 1920,
"storage_tier": "maxiops"
},
{
"core_number": 32,
"memory_amount": 49152,
"name": "HICPU-32xCPU-48GB",
"public_traffic_out": 6144,
"storage_size": 200,
"storage_tier": "maxiops"
},
{
"core_number": 32,
"memory_amount": 65536,
"name": "HICPU-32xCPU-64GB",
"public_traffic_out": 6144,
"storage_size": 300,
"storage_tier": "maxiops"
},
{
"core_number": 64,
"memory_amount": 131072,
"name": "HICPU-64xCPU-128GB",
"public_traffic_out": 7168,
"storage_size": 300,
"storage_tier": "maxiops"
},
{
"core_number": 64,
"memory_amount": 98304,
"name": "HICPU-64xCPU-96GB",
"public_traffic_out": 7168,
"storage_size": 200,
"storage_tier": "maxiops"
}
]
}
}OS Template Storage UUID
{
"storages": {
"storage": [
{
"access": "public",
"license": 3.36,
"size": 28,
"state": "online",
"template_type": "native",
"title": "Windows Server 2016 Datacenter",
"type": "template",
"uuid": "01000000-0000-4000-8000-000010060200"
},
{
"access": "public",
"license": 0.694,
"size": 29,
"state": "online",
"template_type": "native",
"title": "Windows Server 2016 Standard",
"type": "template",
"uuid": "01000000-0000-4000-8000-000010060300"
},
{
"access": "public",
"license": 3.36,
"size": 25,
"state": "online",
"template_type": "native",
"title": "Windows Server 2019 Datacenter",
"type": "template",
"uuid": "01000000-0000-4000-8000-000010070200"
},
{
"access": "public",
"license": 0.694,
"size": 25,
"state": "online",
"template_type": "native",
"title": "Windows Server 2019 Standard",
"type": "template",
"uuid": "01000000-0000-4000-8000-000010070300"
},
{
"access": "public",
"license": 3.36,
"size": 18,
"state": "online",
"template_type": "native",
"title": "Windows Server 2022 Datacenter",
"type": "template",
"uuid": "01000000-0000-4000-8000-000010080200"
},
{
"access": "public",
"license": 0.694,
"size": 18,
"state": "online",
"template_type": "native",
"title": "Windows Server 2022 Standard",
"type": "template",
"uuid": "01000000-0000-4000-8000-000010080300"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "Debian GNU/Linux 9 (Stretch)",
"type": "template",
"uuid": "01000000-0000-4000-8000-000020040100"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "Debian GNU/Linux 10 (Buster)",
"type": "template",
"uuid": "01000000-0000-4000-8000-000020050100"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "Debian GNU/Linux 11 (Bullseye)",
"type": "template",
"uuid": "01000000-0000-4000-8000-000020060100"
},
{
"access": "public",
"license": 0,
"size": 4,
"state": "online",
"template_type": "native",
"title": "Ubuntu Server 18.04 LTS (Bionic Beaver)",
"type": "template",
"uuid": "01000000-0000-4000-8000-000030080200"
},
{
"access": "public",
"license": 0,
"size": 4,
"state": "online",
"template_type": "native",
"title": "Ubuntu Server 20.04 LTS (Focal Fossa)",
"type": "template",
"uuid": "01000000-0000-4000-8000-000030200200"
},
{
"access": "public",
"license": 0,
"size": 4,
"state": "online",
"template_type": "cloud-init",
"title": "Ubuntu Server 22.04 LTS (Jammy Jellyfish)",
"type": "template",
"uuid": "01000000-0000-4000-8000-000030220200"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "CentOS 7",
"type": "template",
"uuid": "01000000-0000-4000-8000-000050010300"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "CentOS 8",
"type": "template",
"uuid": "01000000-0000-4000-8000-000050010400"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "CentOS Stream 8",
"type": "template",
"uuid": "01000000-0000-4000-8000-000050010500"
},
{
"access": "public",
"license": 0,
"size": 5,
"state": "online",
"template_type": "native",
"title": "CentOS Stream 9",
"type": "template",
"uuid": "01000000-0000-4000-8000-000050010600"
},
{
"access": "public",
"license": 0,
"size": 5,
"state": "online",
"template_type": "native",
"title": "Plesk Obsidian",
"type": "template",
"uuid": "01000000-0000-4000-8000-000130010100"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "AlmaLinux 8",
"type": "template",
"uuid": "01000000-0000-4000-8000-000140010100"
},
{
"access": "public",
"license": 0,
"size": 4,
"state": "online",
"template_type": "cloud-init",
"title": "AlmaLinux 9",
"type": "template",
"uuid": "01000000-0000-4000-8000-000140020100"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "Rocky Linux 8",
"type": "template",
"uuid": "01000000-0000-4000-8000-000150010100"
},
{
"access": "public",
"license": 0,
"size": 4,
"state": "online",
"template_type": "cloud-init",
"title": "Rocky Linux 9",
"type": "template",
"uuid": "01000000-0000-4000-8000-000150020100"
},
{
"access": "public",
"license": 0,
"size": 5,
"state": "online",
"template_type": "cloud-init",
"title": "UpCloud K8s",
"type": "template",
"uuid": "01000000-0000-4000-8000-000160010100"
}
]
}
}