Skip to main content

Using Terraform Maps and Workspaces to Deploy Multiple Environments

Hands-On Lab

 

Photo of Travis Thomsen

Travis Thomsen

Course Development Director in Content

Length

01:00:00

Difficulty

Beginner

We have a set of preexisting Terraform files, used for deploying our Ghost blog that is in production. Now we want to use these files for deploying out both a production and development version of the blog. To do this, we need to add a new variable called env, convert our existing variables over to maps, and then use a lookup to reference the variables. Afterward, we'll set up two workspaces, dev and prod, where we will deploy our infrastructure.

What are Hands-On Labs?

Hands-On Labs are scenario-based learning environments where learners can practice without consequences. Don't compromise a system or waste money on expensive downloads. Practice real-world skills without the real-world risk, no assembly required.

Using Terraform Maps and Workspaces to Deploy Multiple Environments

The Scenario

We have a set of preexisting Terraform files, used for deploying our Ghost blog that is in production. Now we want to use these files for deploying out both a production and development version of the blog. To do this, we need to add a new variable called env, convert our existing variables over to maps, and then use a lookup to reference the variables. Afterward, we'll set up two workspaces, dev and prod, where we will deploy our infrastructure.

Logging In

Use the IP address and credentials provided on the hands-on lab overview page, and log in with SSH to the server.

Complete the Terraform Files

Get into the directory where our configuration files are located (cd lab) and edit variables.tf with whatever text editor we like. Add the env variable, then convert image_name, container_name and ext_port to map types. The file should look like this when we're done:

#Define variables

variable "env" {
  description = "env: dev or prod"
}

variable "image_name" {
  type         = "map"
  description = "Image for container."
  default     = {
    dev  = "ghost:latest"
    prod = "ghost:alpine"
  }
}

variable "container_name" {
  type        = "map"
  description = "Name of the container."
  default     = {
    dev  = "blog_dev"
    prod = "blog_prod"
  }
}

variable "ext_port" {
  type        = "map"
  description = "External port for container."
  default     = {
    dev  = "8080"
    prod = "80"
  }
}

In that same directory, edit main.tf, so that it looks like this when we're finished:

# Download the latest Ghost Image
resource "docker_image" "image_id" {
  name = "${lookup(var.image_name, var.env)}"
}

# Start the Container
resource "docker_container" "container_id" {
  name  = "${lookup(var.container_name, var.env)}"
  image = "${docker_image.image_id.latest}"
  ports {
    internal = "2368"
    external = "${lookup(var.ext_port, var.env)}"
  }
}

Initialize Terraform:

[cloud_user@host]$ terraform init

Set up the dev Workspace and Deploy the Environment

Create a dev workspace:

[cloud_user@host]$ terraform workspace new dev

Create a plan for the dev deploy:

[cloud_user@host]$ terraform plan -out=tfdev_plan -var 'env=dev'

Apply the dev plan:

[cloud_user@host]$ terraform apply tfdev_plan

Set up the prod Workspace and Deploy the Environment

Create a prod workspace:

[cloud_user@host]$ terraform workspace new prod

Create a plan for the prod deploy:

[cloud_user@host]$ terraform plan -out=tfprod_plan -var 'env=prod'

Apply the prod plan:

[cloud_user@host]$ terraform apply tfprod_plan

Test

The best way to test this is in a web browser. Let's crank one up and browser to our server's public IP. We'll land in the production environment. If we browser to that same address on port 8080, we'll be looking at the development environment.

Conclusion

This means that we've finished. We have a production and development version of our blog, which is exactly what we wanted. Congratulations!