Terraform with Docker

Sunday, Mar 23, 2025| Tags: Terraform, Docker

DISCLAIMER: Image is generated using FREE version of ChatGPT.




Terraform with Docker


1. Introduction

2. Objectives

3. What is Terraform?

4. Why Terraform?

5. Terraform Configuration File

6. Terraform Workflow

7. Setup

8. Action

9. Cleanup


Introduction


A few days ago, I shared my story about creating a Docker image for The Weekly Challenge website in this blog post.

It was a great learning experience for me, I had never done it before.

Recently at work, I got the opportunity to work with Terraform.

Once again, it was my first time using it.

I decided to learn the basics of Terraform so that at least I understand what I’m doing.


Objectives


The plan is to familiarise myself with Terraform and then use the tool to build the Docker image for The Weekly Challenge website.

Sounds easy, right?

Not for me, at least not yet, but we will see.


What is Terraform?


Terraform is an open-source Infrastructure as Code (IaC) tool developed by HashiCorp.

It allows you to define, provision and manage infrastructure using a declarative configuration language.

Not bad so far.


Why Terraform?


It automates infrastructure, eliminating manual steps.

It supports various cloud providers e.g. AWS, Azure.

It follows a declarative approach i.e. we define what we want and it figures out how to do it.

It also keeps track of the infrastructure state.

Last but not least, it automatically handles dependencies.

That’s enough reason for me to give Terraform a try.

How about you?


Terraform Configuration File


Terraform uses HCL (HashiCorp Configuration Language) to define infrastructure.

The most commonly used configuration file: main.tf


Terraform Workflow


1. Initialise             : terraform init
2. Preview Changes        : terraform plan
3. Apply Configuration    : terraform apply
4. Destroy Infrastructure : terraform destroy

Terraform tracks infrastructure using a state file: terraform.tfstate


Setup


Since, I’m doing this for the first time, I had to setup my environment.

On my personal laptop, running Ubuntu 24.04.1 LTS under WSL2, here is what I did.


$ wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg

$ echo "deb [arch=$(dpkg \
  --print-architecture) \
  --signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
  https://apt.releases.hashicorp.com \
  $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list

$ sudo apt update && sudo apt install terraform

Test the installation:


$ terraform --version
Terraform v1.11.2
on linux_amd64

I already have Docker on my machine, so I skipped that bit.

But in case you need it, please find the instructions below:


$ sudo apt update
$ sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
$ sudo usermod -aG docker $USER
$ docker --version

Action


Time for some real action.

I am going to create my Terraform configuration file: main.tf in the GItHub repository where I already have the Dockerfile saved.

Here is my basic configuration file:

# Configure the Docker provider
terraform {
  required_providers {
    docker = {
      source = "kreuzwerker/docker"
      version = "3.0.2"
    }
  }
}

# Define the Docker image to be built
resource "docker_image" "theweeklychallenge" {
  name = "theweeklychallenge:latest"
  build {
    context = "."
    tag     = ["theweeklychallenge:latest"]
  }
}

# Output the image ID after creation
output "image_id" {
  value = docker_image.theweeklychallenge.image_id
}

Let’s start the process.

As soon as I fired the first command: terraform init, I encountered the following error:


Error loading shared library libstdc++.so.6: No such file or directory (needed by /theweeklychallenge/bin/hugo)
Error loading shared library libgcc_s.so.1: No such file or directory (needed by /theweeklychallenge/bin/hugo)

It turned out that my Dockerfile was missing some libraries: libstdc++, libgcc

So I updated the Dockerfile and now it looks like below:


FROM alpine:latest
LABEL maintainer="mohammad.anwar@yahoo.com"

RUN apk add --no-cache libc6-compat
RUN apk add --no-cache libstdc++ libgcc

WORKDIR /theweeklychallenge
COPY . /theweeklychallenge

EXPOSE 1414
CMD ["bin/hugo", "server", "-p", "1414", "-D", "--bind", "0.0.0.0"]

Let’s re-run the command:


$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding kreuzwerker/docker versions matching "3.0.2"...
- Installing kreuzwerker/docker v3.0.2...
- Installed kreuzwerker/docker v3.0.2 (self-signed, key ID BD080C4571C6104C)
Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

So far so good, passed the init stage.

Now move to next stage:


$ terraform apply
...
...
...
docker_image.theweeklychallenge: Creating...
...
...
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:
image_id = "sha256:055c55d698c6455c108ead190cbd06773066c3d50dc9eceb673a006a785a4a75"

Cool, the Docker image has been created.

Let’s verify that:


$ docker images
REPOSITORY                      TAG       IMAGE ID       CREATED         SIZE
theweeklychallenge              latest    055c55d698c6   5 seconds ago   1.09GB

Indeed, we now have a Docker image.

Let’s run the container now:


$ docker run\
--name theweeklychallenge \
-p 1414:1414 \
-d theweeklychallenge:latest
06a5f07b26dcc1909ffa837ab507483892cf7daf2b2bd673ba50c0793e0d86de


We will check the status of container:


$ dps
Container ID: 06a5f07b26dc
Image: theweeklychallenge:latest
Command: "bin/hugo server -p …"
Created: 2025-03-23 05:09:04 +0000 GMT
Status: Up 6 seconds
Ports: 0.0.0.0:1414->1414/tcp, [::]:1414->1414/tcp

dps is the alias. I created earlier for nice formatted output of the command: docker ps.


alias dps='docker ps --format "Container ID: {{.ID}}\nImage: {{.Image}}\nCommand: {{.Command}}\nCreated: {{.CreatedAt}}\nStatus: {{.Status}}\nPorts: {{.Ports}}\nNames: {{.Names}}\n"'

Time to access the weekly challenge site running inside the container using the image built by Terraform:

http://localhost:1414

I got lucky, everything works fine.


Cleanup


Let’s do the cleaning.

We need to stop the container and then remove it too first.


$ docker stop theweeklychallenge
theweeklychallenge
$ docker rm theweeklychallenge
theweeklychallenge

Now we will ask, Terraform to do the destruction for me.


$ terraform destroy
...
...
docker_image.theweeklychallenge: Destruction complete after 0s
Destroy complete! Resources: 1 destroyed.

However I still see some leftovers.

So I did the manually cleaning:


$ rm -rf .terraform/ terraform.tfstate* .terraform.lock.hcl

Everything back to original state. I hope you had fun with me in this journey.


Keep Hacking !!

SO WHAT DO YOU THINK ?

If you have any suggestions or ideas then please do share with us.

Contact with me