Terraform and Docker

Table of contents
- Blocks and Resources in Terraform:
- Terraform Block:
- Task-01
- Provider Block:
- Task-02
- Create a resource Block for an nginx docker image
- Hint:
- Create a resource Block for running a docker container for nginx
- Note: In case Docker is not installed
- sudo apt-get install docker.io sudo docker ps sudo chown $USER /var/run/docker.sock
- Terraform Script (main.tf)
- Explanation of Resource Blocks:
- Steps to Execute the Terraform Script
- Terraform Variables
- Types of Variables in Terraform
- Benefits of Using Variables
- Task-03
- Data Types in Terraform:
- 1. Primitive Data Types
- 2. Complex Data Types
- 3. Structural Data Types
- Why Use Data Types in Terraform?
- Map:
- Task-04
- Step 1: Create the Terraform Configuration (main.tf)
- Step 2: Execute the Terraform Script
- Step 3: Refresh the Terraform State
- Step 4: Verify the Output File (output.txt)
In Terraform, specifying the provider is essential to determine which infrastructure platform will be managed. A provider acts as a plugin that allows Terraform to interact with a specific service, such as Docker, AWS, or Kubernetes. To use a provider in Terraform, we need to declare it explicitly along with its source and version. This ensures that Terraform downloads the correct provider plugin and maintains compatibility with our configurations. For Docker, we define the provider in the main.tf
file using the required_providers
block. Here, we specify kreuzwerker/docker
as the source and define the version to ensure stability. Additionally, we configure the provider by specifying the Docker host, which allows Terraform to interact with the Docker daemon. This setup ensures that Terraform can efficiently manage Docker containers and images as part of the automation process.
Blocks and Resources in Terraform:
Terraform configurations are built using blocks, which define the desired infrastructure. Each block serves a specific purpose and consists of arguments and parameters to configure resources.
1. Blocks in Terraform
A block in Terraform is a fundamental unit of configuration that defines settings and infrastructure components. Each block starts with a block type followed by configuration parameters enclosed in {}
. Common block types include:
Provider Block: Specifies the provider (e.g., AWS, Docker) that Terraform will use.
Resource Block: Defines the infrastructure components, such as virtual machines, networks, or storage.
Variable Block: Declares input variables that allow configuration customization.
Output Block: Displays the results of a Terraform execution.
Module Block: Groups multiple resources together for reuse.
2. Resources in Terraform
A resource is the most important block in Terraform, representing an actual infrastructure component. It defines what Terraform will create, modify, or delete. The syntax follows:
resource "<provider>_<type>" "<name>" {
# Configuration settings
}
For example, to create an AWS EC2 instance:
resource "aws_instance" "example" {
ami = "ami-12345678"
instance_type = "t2.micro"
}
Here:
aws_instance
is the resource type.example
is the resource name.ami
andinstance_type
are arguments specifying the instance details.
Terraform Block:
The Terraform block is the most fundamental in a Terraform configuration. It is used to define the required Terraform version and specify the providers needed for the infrastructure. This block ensures that Terraform works with a compatible version and installs the correct provider plugins.
Syntax of a Terraform Block
The Terraform block is written at the beginning of the main.tf
file and follows this structure:
terraform {
required_version = ">= 1.3.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
Key Components:
required_version
– Ensures Terraform uses a specific version or a compatible range.required_providers
– Defines the providers needed for the configuration, specifying the source and version to maintain compatibility.
Task-01
Create a Terraform script with Blocks and Resources
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 2.21.0"
}
}
}
In this task, we will create a Terraform script that defines the necessary blocks and resources to manage Docker containers. This script includes:
A Terraform block to specify the required provider.
A Provider block to configure Docker.
A Resource block to create a Docker container.
Terraform Script (main.tf
)
# Terraform Block - Specifies provider requirements
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 2.21.0"
}
}
}
# Provider Block - Configures the Docker provider
provider "docker" {
host = "unix:///var/run/docker.sock"
}
# Resource Block - Defines a Docker container
resource "docker_container" "nginx" {
name = "nginx_container"
image = docker_image.nginx.latest
ports {
internal = 80
external = 8080
}
}
# Resource Block - Pulls the latest Nginx image
resource "docker_image" "nginx" {
name = "nginx:latest"
}
Explanation of Blocks and Resources:
Terraform Block:
- Defines the required Docker provider (
kreuzwerker/docker
) and specifies the version.
- Defines the required Docker provider (
Provider Block:
- Configures Docker to communicate using the Docker daemon socket.
Resource Blocks:
docker_image
: Pulls the latest Nginx image from Docker Hub.docker_container
: Creates a Docker container from the Nginx image and maps port 8080 on the host to port 80 in the container.
Execution Steps:
Initialize Terraform
terraform init
Validate the Configuration
terraform validate
Apply the Configuration
terraform apply -auto-approve
Check the Running Container
docker ps
Destroy Resources (If Needed)
terraform destroy -auto-approve
This script ensures Terraform automates the deployment of a Docker container, making infrastructure management more efficient.
Provider Block:
The Provider block in Terraform is used to configure the provider that Terraform will interact with to manage infrastructure. A provider is a plugin that allows Terraform to communicate with different services like AWS, Azure, GCP, Docker, and many others.
Syntax of a Provider Block
provider "<provider_name>" {
# Configuration settings
}
Each provider has its required configuration settings, such as authentication details or API endpoints.
Example: Docker Provider Block
provider "docker" {
host = "unix:///var/run/docker.sock"
}
Explanation:
provider "docker"
→ Specifies that Terraform will use the Docker provider.host
→ Defines the Docker daemon socket to connect to (used for local Docker installations).
Example: AWS Provider Block
provider "aws" {
region = "us-east-1"
}
Explanation:
provider "aws"
→ Specifies the AWS provider.region
→ Sets the AWS region where resources will be deployed.
Why is the Provider Block Important?
Tell Terraform which provider to use.
Configures provider-specific settings.
Ensures Terraform can authenticate and communicate with the provider's API.
Task-02
Create a resource Block for an nginx docker image
Hint:
resource "docker_image" "nginx" {
name = "nginx:latest"
keep_locally = false
}
Create a resource Block for running a docker container for nginx
resource "docker_container" "nginx" {
image = docker_image.nginx.latest
name = "tutorial"
ports {
internal = 80
external = 80
}
}
Note: In case Docker is not installed
sudo apt-get install
docker.io
sudo docker ps
sudo chown $USER /var/run/docker.sock
In this task, we will define resource blocks in Terraform to:
Pull the latest Nginx image from Docker Hub.
Create and run a Docker container using the pulled Nginx image.
Terraform Script (main.tf
)
# Terraform Block - Defines the required provider
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 2.21.0"
}
}
}
# Provider Block - Configures Docker provider
provider "docker" {
host = "unix:///var/run/docker.sock"
}
# Resource Block - Pulls the latest Nginx image
resource "docker_image" "nginx" {
name = "nginx:latest"
keep_locally = false
}
# Resource Block - Creates and runs an Nginx container
resource "docker_container" "nginx" {
image = docker_image.nginx.latest
name = "tutorial"
ports {
internal = 80
external = 80
}
}
Explanation of Resource Blocks:
1. docker_image
Block:
name = "nginx:latest"
→ Pulls the latest Nginx image.keep_locally = false
→ Removes the image if not used to free up space.
2. docker_container
Block:
image = docker_image.nginx.latest
→ Uses the previously pulled Nginx image.name = "tutorial"
→ Assign the container a name.ports
Mapping:internal = 80
→ The Nginx server listens on port 80 inside the container.external = 80
→ The container exposes port 80 on the host system, making Nginx accessible viahttp://localhost:80
.
Steps to Execute the Terraform Script
1. Install Docker (If Not Installed)
Run the following commands to install and configure Docker:
sudo apt-get install docker.io
sudo chown $USER /var/run/docker.sock
sudo docker ps
2. Initialize Terraform
terraform init
3. Validate the Configuration
terraform validate
4. Apply the Configuration
terraform apply -auto-approve
5. Verify the Running Container
docker ps
6. Access Nginx in Browser
Open http://localhost:80 in your web browser. You should see the default Nginx welcome page.
7. Destroy the Resources (If Needed)
terraform destroy -auto-approve
This Terraform script automates the deployment of an Nginx container using Docker, making infrastructure provisioning efficient and repeatable.
Terraform Variables
In Terraform, variables are used to make configurations more flexible and reusable. Instead of hardcoding values, variables allow you to pass dynamic inputs into your Terraform scripts.
Types of Variables in Terraform
1. Input Variables (var
)
These variables allow you to parameterize configurations, making them more dynamic and reusable.
Defining an Input Variable
You can define a variable using the variable
block in a separate file (variables.tf
) or directly in main.tf
.
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t2.micro"
}
Using an Input Variable in Resources
resource "aws_instance" "example" {
ami = "ami-12345678"
instance_type = var.instance_type
}
2. Environment Variables
Terraform also allows setting variables using environment variables, following the TF_VAR_<variable_name>
format.
Example:
export TF_VAR_instance_type="t3.medium"
3. Variable Assignment Methods
Variables can be assigned values in multiple ways:
Using
terraform.tfvars
Fileinstance_type = "t3.small"
Command-line Flags
terraform apply -var="instance_type=t3.large"
4. Output Variables (output
)
These are used to display values after execution.
Example:
output "instance_ip" {
value = aws_instance.example.public_ip
}
Benefits of Using Variables
Increases reusability of Terraform configurations.
Enhances flexibility by allowing different values without modifying the code.
Improves security by avoiding hardcoded sensitive information.
Task-03
Create a local file using Terraform Hint:
resource "local_file" "devops" {
filename = var.filename
content = var.content
}
In this task, we will use Terraform to create a local file dynamically by defining variables for the filename and content.
Terraform Script (main.tf
)
# Terraform Block - Defines required providers
terraform {
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.0"
}
}
}
# Provider Block - Uses the local provider
provider "local" {}
# Resource Block - Creates a local file
resource "local_file" "devops" {
filename = var.filename
content = var.content
}
Defining Variables (variables.tf
)
variable "filename" {
description = "Name of the file to be created"
type = string
default = "devops.txt"
}
variable "content" {
description = "Content to be written inside the file"
type = string
default = "Welcome to DevOps with Terraform!"
}
Execution Steps
1. Initialize Terraform
terraform init
2. Validate the Configuration
terraform validate
3. Apply the Configuration
terraform apply -auto-approve
4. Verify the File Creation
cat devops.txt
You should see:
Welcome to DevOps with Terraform!
5. Destroy the Resources (If Needed)
terraform destroy -auto-approve
Explanation of the Terraform Script
Terraform Block
- Specifies that the
local
provider is required to create local files.
- Specifies that the
Provider Block
- Uses the
local
provider, which enables Terraform to interact with local system resources.
- Uses the
Resource Block (
local_file
)filename = var.filename
→ Uses a variable for the filename.content = var.content
→ Uses a variable for the file content.
Variables (
variables.tf
)- Allows customization of the filename and content without modifying the script.
This Terraform configuration helps automate file creation dynamically using variables.
Data Types in Terraform:
Terraform supports various data types for defining variables. These data types ensure that inputs are structured correctly and help in writing robust and error-free infrastructure code.
1. Primitive Data Types
These are the basic data types supported in Terraform.
a. String
A sequence of characters enclosed in quotes (""
).
variable "instance_type" {
type = string
default = "t2.micro"
}
b. Number
Can be an integer or a floating-point value.
variable "instance_count" {
type = number
default = 2
}
c. Boolean
Represents true
or false
values.
variable "enable_monitoring" {
type = bool
default = true
}
2. Complex Data Types
Terraform also supports collections and structural types.
a. List (Ordered Collection of Elements)
A list contains multiple values of the same type.
variable "availability_zones" {
type = list(string)
default = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
Accessing List Elements:
availability_zones[0] # Output: "us-east-1a"
b. Map (Key-Value Pairs)
A map stores key-value pairs for easy retrieval.
variable "instance_tags" {
type = map(string)
default = {
Name = "Terraform-Instance"
Environment = "Dev"
}
}
Accessing Map Elements:
instance_tags["Name"] # Output: "Terraform-Instance"
c. Set (Unique Unordered Collection)
A set contains unique values but does not maintain order.
variable "allowed_ports" {
type = set(number)
default = [22, 80, 443]
}
3. Structural Data Types
Terraform allows defining nested objects and tuples for more complex configurations.
a. Object (Structured Collection of Key-Value Pairs)
Objects can contain multiple types within them.
variable "server_config" {
type = object({
name = string
cpu = number
is_linux = bool
})
default = {
name = "web-server"
cpu = 4
is_linux = true
}
}
b. Tuple (Fixed-Length Collection of Elements)
A tuple allows different types but must follow a fixed structure.
variable "db_config" {
type = tuple([string, number, bool])
default = ["db-server", 8, true]
}
Accessing Tuple Elements:
db_config[0] # Output: "db-server"
Why Use Data Types in Terraform?
Ensures data consistency and prevents incorrect inputs.
Improves reusability by defining structured configurations.
Reduces errors by validating inputs before execution.
Map:
In Terraform, a map is a key-value pair structure that allows storing multiple values under different keys. This makes configurations more organized, flexible, and reusable.
Example: Defining a Map Variable
variable "file_contents" {
type = map(string)
default = {
"statement1" = "this is cool"
"statement2" = "this is cooler"
}
}
Explanation:
type = map(string)
→ Specifies that the variable is a map where both keys and values are strings.Keys →
"statement1"
,"statement2"
Values →
"this is cool"
,"this is cooler"
Using the Map Variable in a Resource
We can use this map variable to create a local file with multiple lines:
resource "local_file" "example" {
filename = "example.txt"
content = "${var.file_contents["statement1"]}\n${var.file_contents["statement2"]}"
}
Accessing Map Values
To retrieve values from a map, use var.map
_name["key"]
:
output "statement1" {
value = var.file_contents["statement1"]
}
output "statement2" {
value = var.file_contents["statement2"]
}
Expected Output:
statement1 = "this is cool"
statement2 = "this is cooler"
Why Use Maps in Terraform?
Organizes data efficiently
Improves reusability of variables
Enables dynamic configurations
Task-04
Use terraform to demonstrate usage of List, Set, and Object datatypes
In this task, we will use Terraform to define and use List, Set, and Object data types, apply the configuration, refresh the state, and capture the outputs.
Step 1: Create the Terraform Configuration (main.tf
)
# Terraform Block - Defines required providers
terraform {
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.0"
}
}
}
# Provider Block
provider "local" {}
# Variable - List Example
variable "fruits" {
type = list(string)
default = ["Apple", "Banana", "Cherry"]
}
# Variable - Set Example (Ensures Unique Values)
variable "unique_numbers" {
type = set(number)
default = [10, 20, 30, 40, 40] # Terraform automatically removes duplicates
}
# Variable - Object Example (Complex Data Structure)
variable "server_config" {
type = object({
name = string
cpu = number
is_linux = bool
})
default = {
name = "web-server"
cpu = 4
is_linux = true
}
}
# Resource - Creating a Local File using Variables
resource "local_file" "example" {
filename = "output.txt"
content = <<EOT
List Example:
Fruit 1: ${var.fruits[0]}
Fruit 2: ${var.fruits[1]}
Fruit 3: ${var.fruits[2]}
Set Example:
Numbers: ${join(", ", tostring(var.unique_numbers))}
Object Example:
Server Name: ${var.server_config.name}
CPU Cores: ${var.server_config.cpu}
Is Linux: ${var.server_config.is_linux}
EOT
}
# Output Blocks
output "list_example" {
value = var.fruits
}
output "set_example" {
value = var.unique_numbers
}
output "object_example" {
value = var.server_config
}
Step 2: Execute the Terraform Script
1. Initialize Terraform
terraform init
2. Apply the Configuration
terraform apply -auto-approve
Expected Output:
list_example = [
"Apple",
"Banana",
"Cherry"
]
set_example = [
10,
20,
30,
40
]
object_example = {
"name" = "web-server"
"cpu" = 4
"is_linux" = true
}
Step 3: Refresh the Terraform State
To update the Terraform state based on changes in the configuration file, run:
terraform refresh
This ensures that Terraform reloads the latest values of variables from the configuration.
Step 4: Verify the Output File (output.txt
)
Check the contents of the generated file:
cat output.txt
Expected Content:
List Example:
Fruit 1: Apple
Fruit 2: Banana
Fruit 3: Cherry
Set Example:
Numbers: 10, 20, 30, 40
Object Example:
Server Name: web-server
CPU Cores: 4
Is Linux: true
This Terraform setup demonstrates how to work with List, Set, and Object types effectively while managing infrastructure as code.
Subscribe to my newsletter
Read articles from Vanshika Sharma directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Vanshika Sharma
Vanshika Sharma
I am currently a B.Tech student pursuing Computer Science with a specialization in Data Science at I.T.S Engineering College. I am always excited to learn and explore new things to increase my knowledge. I have good knowledge of programming languages such as C, Python, Java, and web development.