Variables and Outputs

LinuxBeginner
Practice Now

Introduction

Imagine you are ordering a coffee. If the menu only says "Coffee", you might get black coffee every time. But if the menu has options like "Size" or "Milk Type", you can customize your order without the barista needing to learn a new recipe for every single combination.

In Terraform, variables make configurations reusable by allowing input values to change without rewriting the whole file.

Outputs let Terraform report important resulting values, such as IDs, names, or addresses. Together, variables and outputs make Terraform configurations more modular and practical.

By the end of this lab, you will have a flexible Terraform configuration that can create containers with different names on demand.

Variables separate configuration logic from environment-specific data. Outputs do the opposite direction: they publish useful resulting values back to the user or to later automation.

Create Variables File

Good chefs organize their ingredients before they start cooking. In Terraform, it is best practice to keep your customized options (Variables) in a separate file from your main recipe.

The standard name for this file is variables.tf. Creating this file doesn't change how Terraform works—Terraform reads all .tf files in the folder as if they were one big book—but it helps us keep things organized.

That organization principle matters in IaC because real configurations grow quickly. Clear separation of variables, resources, and outputs makes later maintenance much easier.

Let's go to our project folder and create this file.

cd ~/project
touch variables.tf

We now have an empty file ready for our definitions. In the next step, we will add content to it.

Define a Variable

Now, we need to declare what options are available. This is like adding a "Name" field to an order form.

Open variables.tf using nano:

nano variables.tf

Add this block. It tells Terraform: "There is an option called container_name, it accepts text (string), and if the user doesn't say anything, just call it 'ExampleNginxContainer'."

variable "container_name" {
  description = "Value of the name for the Docker container"
  type        = string
  default     = "ExampleNginxContainer"
}

Save and exit nano (Ctrl+O, Enter, Ctrl+X).

Now that the form field exists, we need to use it in our recipe. We will create a main.tf file that uses this variable.

Create main.tf:

nano main.tf

Paste the following code. Pay attention to name = var.container_name. This is how we plug the variable into the configuration.

terraform {
  required_providers {
    docker = {
      source  = "kreuzwerker/docker"
      version = "~> 3.0.1"
    }
  }
}

provider "docker" {}

resource "docker_image" "nginx" {
  name         = "nginx:latest"
  keep_locally = false
}

resource "docker_container" "nginx" {
  image = docker_image.nginx.image_id
  name  = var.container_name
  ports {
    internal = 80
    external = 8000
  }
}

Remember to save and exit nano.

By using var.container_name, we are saying: "Don't hardcode a name; look up whatever value is in the 'container_name' variable and use that."

Define Outputs

When you buy something, you get a receipt. In Terraform, Outputs act like that receipt—they show you important details about what was just built.

This is very useful for getting information that you couldn't know before the resource was created, like a random ID assigned by the system or a public IP address.

Outputs are especially useful when one piece of infrastructure needs to hand information to a human operator, another Terraform module, or a later automation step.

Let's create a file named outputs.tf to organize these return values. Open it with nano:

nano outputs.tf

Add this block. It tells Terraform: "After you are done, print out the ID of the nginx container."

output "container_id" {
  description = "ID of the Docker container"
  value       = docker_container.nginx.id
}

Save and exit nano.

Now, let's run our code!

First, initialize the project (downloading the Docker provider):

terraform init

Next, apply the configuration. We won't specify a container name, so it will use the default (ExampleNginxContainer). We use -auto-approve to skip the "yes" confirmation prompt to save time.

terraform apply -auto-approve

Look at the very bottom of the output. You should see Outputs:, followed by the container_id.

Override Variables

The real power of variables is changing them without rewriting code. Imagine you want to launch a second container with a different name. You don't need to edit main.tf.

You can simply tell Terraform to override the default value using the -var flag. It's like telling the barista, "Actually, make that a Large."

Run this command:

terraform apply -var="container_name=MyDynamicContainer" -auto-approve

Watch the output closely. Terraform says: docker_container.nginx must be replaced.

Why? Because in Docker, you cannot rename a running container easily. To change the name, Terraform decides it must Destroy the old container (-) and Create a new one (+) with the new name. This is a key principle of Immutable Infrastructure—we replace things rather than patching them.

Verify the new container is running:

docker ps --format "{{.Names}}"

You should see MyDynamicContainer.

Summary

Congratulations! You have successfully made your Terraform code dynamic.

In this lab, you learned:

  • Variables: How to use variables.tf to create flexible "form fields" for your code.
  • Reference: How to use var.variable_name to insert those values into your main configuration.
  • Outputs: How to use outputs.tf to display important data (the "receipt") after a run.
  • Overrides: How to key in new values from the command line using -var, allowing you to reuse the same code for different situations.