Swiftorial Logo
Home
Swift Lessons
Matchuup
CodeSnaps
Tutorials
Career
Resources

Docker with Terraform

Terraform allows you to define and provision infrastructure as code, including Docker containers. This guide covers key concepts, steps to use Terraform with Docker, examples, and best practices for deploying Dockerized Express.js applications with Terraform.

Key Concepts of Docker with Terraform

  • Providers: Terraform providers are responsible for managing the lifecycle of resources (e.g., Docker containers).
  • Resources: Resources are the components that Terraform manages, such as Docker containers and images.
  • State: Terraform state is used to map real-world resources to your configuration and keep track of metadata.
  • Modules: Modules are reusable configurations that can be shared and used across projects.
  • Variables: Variables allow you to parameterize your Terraform configurations.

Setting Up the Project

Initialize a new Express.js project and create a Dockerfile:

// Initialize a new project
// npm init -y

// Install Express
// npm install express

// Create the project structure
// mkdir src
// touch src/index.js Dockerfile .dockerignore .gitignore

// .gitignore
node_modules
.env

// .dockerignore
node_modules
npm-debug.log

Creating an Express Application

Create a simple Express application:

Example: index.js

// src/index.js
const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
    res.send('Hello, Docker with Terraform!');
});

app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}/`);
});

Creating a Dockerfile

Create a Dockerfile to containerize your Express application:

Example: Dockerfile

// Dockerfile
FROM node:14

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
COPY package*.json ./
RUN npm install

# Bundle app source
COPY . .

# Expose port 3000 to the outside world
EXPOSE 3000

# Run app when the container launches
CMD ["node", "src/index.js"]

Building and Running the Docker Container

Build and run the Docker container for your Express application:

// Build the Docker image
docker build -t my-express-app .

// Run the Docker container
docker run -d -p 3000:3000 --name my-express-app my-express-app

// Open http://localhost:3000 in your browser to see the application running

Setting Up Terraform

Install Terraform and create a Terraform configuration file:

Install Terraform

// On a Linux or macOS system
// Install Terraform using a package manager or download from the official website
brew install terraform

Create a Terraform Configuration File

// main.tf
provider "docker" {
  host = "unix:///var/run/docker.sock"
}

resource "docker_image" "my_express_app" {
  name         = "my-express-app"
  build {
    context    = "${path.module}"
    dockerfile = "${path.module}/Dockerfile"
  }
}

resource "docker_container" "my_express_app" {
  name  = "my-express-app"
  image = docker_image.my_express_app.latest
  ports {
    internal = 3000
    external = 3000
  }
}

Initializing Terraform

Initialize Terraform in your project directory:

// Initialize Terraform
terraform init

Applying the Terraform Configuration

Apply the Terraform configuration to deploy your Dockerized Express application:

// Apply the Terraform configuration
terraform apply

// Confirm the action
// Type 'yes' when prompted

Using Terraform Variables

Parameterize your Terraform configurations using variables:

Example: Using Variables

// variables.tf
variable "image_name" {
  description = "The name of the Docker image"
  default     = "my-express-app"
}

variable "internal_port" {
  description = "The internal port of the Docker container"
  default     = 3000
}

variable "external_port" {
  description = "The external port of the Docker container"
  default     = 3000
}

// main.tf
provider "docker" {
  host = "unix:///var/run/docker.sock"
}

resource "docker_image" "my_express_app" {
  name         = var.image_name
  build {
    context    = "${path.module}"
    dockerfile = "${path.module}/Dockerfile"
  }
}

resource "docker_container" "my_express_app" {
  name  = var.image_name
  image = docker_image.my_express_app.latest
  ports {
    internal = var.internal_port
    external = var.external_port
  }
}

Using Terraform Modules

Organize your Terraform configurations using modules:

Example: Using Modules

// Create a module directory
// mkdir -p modules/docker_app

// modules/docker_app/main.tf
provider "docker" {
  host = "unix:///var/run/docker.sock"
}

resource "docker_image" "my_express_app" {
  name         = var.image_name
  build {
    context    = "${path.module}"
    dockerfile = "${path.module}/Dockerfile"
  }
}

resource "docker_container" "my_express_app" {
  name  = var.image_name
  image = docker_image.my_express_app.latest
  ports {
    internal = var.internal_port
    external = var.external_port
  }
}

// modules/docker_app/variables.tf
variable "image_name" {
  description = "The name of the Docker image"
  default     = "my-express-app"
}

variable "internal_port" {
  description = "The internal port of the Docker container"
  default     = 3000
}

variable "external_port" {
  description = "The external port of the Docker container"
  default     = 3000
}

// main.tf
module "docker_app" {
  source        = "./modules/docker_app"
  image_name    = "my-express-app"
  internal_port = 3000
  external_port = 3000
}

Best Practices for Docker with Terraform

  • Use Modules: Organize your Terraform configurations using modules to make them reusable and maintainable.
  • Version Control: Store your Terraform configurations in version control systems like Git to track changes and collaborate with others.
  • Remote State: Use remote state storage to share the state file between team members and environments.
  • Parameterize Configurations: Use variables to parameterize your Terraform configurations and make them more flexible.
  • Document Configurations: Document your Terraform configurations to make it easier for others to understand and use them.
  • Testing: Test your Terraform configurations in a staging environment before deploying them to production.

Testing Docker with Terraform

Test your Terraform configurations to ensure they work correctly:

Example: Testing with Terratest

// Install Go and Terratest
// Download and install Go from the official website
// Install Terratest using 'go get' command
go get github.com/gruntwork-io/terratest/modules/terraform

// test/terraform_test.go
package test

import (
    "testing"
    "github.com/gruntwork-io/terratest/modules/terraform"
    "github.com/stretchr/testify/assert"
)

func TestTerraformDockerExample(t *testing.T) {
    terraformOptions := &terraform.Options{
        TerraformDir: "../",
    }

    defer terraform.Destroy(t, terraformOptions)
    terraform.InitAndApply(t, terraformOptions)

    output := terraform.Output(t, terraformOptions, "container_name")
    assert.Equal(t, "my-express-app", output)
}

// Run the tests
go test -v

Key Points

  • Providers: Terraform providers are responsible for managing the lifecycle of resources (e.g., Docker containers).
  • Resources: Resources are the components that Terraform manages, such as Docker containers and images.
  • State: Terraform state is used to map real-world resources to your configuration and keep track of metadata.
  • Modules: Modules are reusable configurations that can be shared and used across projects.
  • Variables: Variables allow you to parameterize your Terraform configurations.
  • Follow best practices for Docker with Terraform, such as using modules, version control, remote state, parameterizing configurations, documenting configurations, and testing in a staging environment before production deployment.

Conclusion

Terraform allows you to define and provision infrastructure as code, including Docker containers. By understanding and implementing the key concepts, steps, examples, and best practices covered in this guide, you can effectively deploy Dockerized Express.js applications with Terraform. Happy coding!