Infrastructure tools · guide
Infrastructure as code with OpenTofu
The course’s labs build their machines in Microsoft Azure with a tool called OpenTofu. This page explains what the tool does and what each of its commands is for. You don’t need to know how to code to follow it.
Infrastructure as code
Section titled “Infrastructure as code”Infrastructure is the set of machines and networks that a system runs on. In the course, most of it is virtual machines: computers that run as software on Microsoft’s hardware in Azure, Microsoft’s cloud service. You rent them by the hour instead of buying and looking after physical computers.
You can build a virtual machine by clicking through the Azure Portal, Azure’s website. That works, but it’s hard to repeat exactly, and nothing records what you clicked.
Infrastructure as code means you describe the machines in text files instead, and a tool builds them from those files. The files say what should exist, not the steps to make it. OpenTofu calls this set of files a configuration. Because it’s plain text, you can read it and build from it again.
OpenTofu is a tool that reads a configuration and builds what it describes. You type its commands in a terminal (see What a terminal is), and every command starts with the word tofu.
Providers and resources
Section titled “Providers and resources”OpenTofu can’t reach Azure by itself. It uses providers: add-on programs that let it manage one platform. The course uses the Azure provider called azurerm, which manages Azure virtual machines, networks and storage.
A resource is one thing the configuration describes, such as one network or one virtual machine. The block below is written in OpenTofu’s own file language. It’s shortened from the course’s Module 3 files and describes an Azure resource group: a named group in Azure that holds related resources. When you delete a resource group, Azure deletes everything in it.
resource "azurerm_resource_group" "lab" { name = var.resource_group_name location = "eastus"}The first line names the kind of resource and gives it a label, lab. The lines inside set the group’s name and its Azure region, the part of the world whose Microsoft data centres hold it: here East US. var.resource_group_name stands for the value of the variable called resource_group_name.
Variables and the .tfvars file
Section titled “Variables and the .tfvars file”A variable is a named setting that the configuration leaves open, so each person can fill in their own value without editing the configuration. The course’s variables include these:
- Your Azure subscription ID: the ID of the Azure account that pays.
- Your SSH public key. SSH is the way you log in to a remote Linux machine from a terminal. It uses a key pair: two matching keys, a private one that stays on your computer and a public one you put on the machine.
- A short name of your choosing that goes into each machine’s web address.
You set the values in a .tfvars file, a short text file of lines in the form name = "value". OpenTofu reads a file called terraform.tfvars in the folder automatically. Each lab folder comes with terraform.tfvars.example, which the first lab step copies to terraform.tfvars for you to fill in.
Your terraform.tfvars is never shared. It holds your settings: your subscription, your key and, in one module, an admin password. The course’s labs repository, its folder of lab files on GitHub, is set up so this file is never saved into its shared history. Don’t post it or send it to anyone.
You can also set one variable for one command with -var. In Module 7, the fleet machines are the course’s Ubuntu Linux client machines. The lab starts with one, then grows the fleet to three with tofu apply -var fleet_count=3.
Four commands: init, plan, apply, destroy
Section titled “Four commands: init, plan, apply, destroy”tofu initprepares the folder and downloads the providers the configuration needs. It’s safe to run more than once.tofu plancompares the configuration with what already exists and lists what it would add, change or destroy. It changes nothing.tofu applycarries out a plan. Run on its own, it makes a fresh plan, shows it, and waits for you to typeyes.tofu destroyremoves everything this configuration built. It’s another way to writetofu apply -destroy, so it also shows the plan and waits foryes. Machines left running cost money, so the labs tear them down between sessions.
Read the plan before you apply it
Section titled “Read the plan before you apply it”A plan ends with a summary line, such as Plan: 21 to add, 0 to change, 0 to destroy. Read it every time. If you expected only additions and it says something will be destroyed, stop and find out why.
In Module 7, fleet_count is 1 unless you say otherwise. If three fleet machines already exist from an earlier tofu apply -var fleet_count=3, a later apply without -var fleet_count=3 plans to destroy two of them.
The course reads every plan first, in one of two ways:
- Modules 3 to 9 use
tofu applyandtofu destroyon their own. Each shows its plan and waits, so read the plan before you typeyes. - From Module 10 on, the labs save the plan to a file first.
tofu plan -out <file>saves the plan and prints it. After you read it,tofu apply <file>carries out exactly the actions in that file. Tearing down works the same way, withtofu plan -destroy -out <file>and thentofu apply <file>.
When you give apply a saved plan, it doesn’t ask again: the saved file counts as your approval. The OpenTofu docs warn that a saved plan file can hold sensitive values in plain text, so the labs delete it right after applying it.
To know what it built, OpenTofu keeps state: a record that links each resource in the configuration to the real object in Azure. By default it’s a file called terraform.tfstate in the same folder.
Keep state private. The docs describe local state as plain-text files that hold every setting of every resource, which can include passwords, and they say to treat state as sensitive. The labs repository never saves state files into its shared history. Keep the file in its folder, too: OpenTofu needs it to match your configuration to what exists in Azure.
Outputs
Section titled “Outputs”An output is a value the configuration reports back after it builds something, such as a machine’s web address. Outputs print at the end of tofu apply, not after tofu plan. tofu output shows them again later.
OpenTofu and Terraform
Section titled “OpenTofu and Terraform”OpenTofu started as a fork (a separately developed copy) of Terraform, HashiCorp’s infrastructure-as-code tool, after HashiCorp changed Terraform’s licence. It aims to stay compatible with Terraform configurations, and in this course the commands are the same with terraform in place of tofu. That’s also why the files are still called terraform.tfvars and terraform.tfstate.
Commands you’ll use in the course
Section titled “Commands you’ll use in the course”| Command | What it does |
|---|---|
Copy-Item terraform.tfvars.example terraform.tfvars |
Makes your own copy of the example settings file to fill in (cp instead of Copy-Item on macOS or Linux). |
tofu init |
Prepares the folder and downloads the providers the configuration needs. |
tofu plan |
Shows what would be added, changed or destroyed, and changes nothing. |
tofu plan -out <file> |
Saves the plan to a file with any name you choose, such as lab.tfplan, so you can read it and then apply exactly that. |
tofu apply <file> |
Carries out a saved plan, without asking again. |
Remove-Item <file> |
Deletes the saved plan file once it’s applied, because it can contain secrets (rm on macOS or Linux). |
tofu apply |
Makes a fresh plan, shows it, and builds only after you type yes. |
tofu apply -var <name>=<value> |
Sets one variable for this run only, such as fleet_count=3. |
tofu apply -replace <address> |
Removes one resource and builds it again. The address is the resource’s name as the plan prints it, such as azurerm_linux_virtual_machine.fleet["02"]. In Module 7 the -var must come along, and in PowerShell the address goes in single quotes with \" inside: tofu apply -var fleet_count=3 -replace 'azurerm_linux_virtual_machine.fleet[\"02\"]'. |
tofu output |
Lists every output value, such as the machines’ web addresses. |
tofu output -raw <name> |
Prints one output value on its own, ready to copy. |
tofu plan -destroy -out <file> |
Saves a plan that removes everything this folder built, so you can read it before you apply it. |
tofu destroy |
Shows a plan to remove everything this folder built, and removes it after you type yes. |
Sources
Facts on this page are explained in our own words. Short quotes are marked and linked.
- What is OpenTofu? (OpenTofu docs)
- The core OpenTofu workflow (OpenTofu docs)
- Providers (OpenTofu docs)
- Resources (OpenTofu docs)
- Input variables (OpenTofu docs)
- Output values (OpenTofu docs)
- State (OpenTofu docs)
- Sensitive data in state (OpenTofu docs)
- Command init (OpenTofu docs)
- Command plan (OpenTofu docs)
- Command apply (OpenTofu docs)
- Command destroy (OpenTofu docs)
- Command output (OpenTofu docs)
- OpenTofu FAQ
- Migrating to OpenTofu (OpenTofu docs)
- Overview of Terraform on Azure (Microsoft Learn)
- Overview of virtual machines in Azure (Microsoft Learn)
- What is Azure Resource Manager? (Microsoft Learn)
- ssh(1), Linux manual page
- ssh-keygen(1), Linux manual page