Using Terraform for managing infrastructure
Tags: devops, docker
Published: 2020-04-29 09:10:00

#What is Terraform?#

It is a tool that is used for building, changing and versioning infrastructure safely and effectively. Using the configuration file you describe to Terraform what components are needed. Terraform then goes and generates an execution plan describing what the desired state should be. And then it goes and executes and builds it. Terraform manages all this through a state file. Now there are two flavors of Terraform:

* An open-source version

* An enterprise version

Terraform supports a wide variety of cloud and infrastructure platforms. This includes AWS, OpenStack, Azure, GCP, Kubernetes and much more. 

#Deploying Infrastructure with Terraform#

The syntax of Terraform configurations is called HashiCorp Configuration Language (HCL). It is meant to strike a balance between being human-readable and editable, and being machine-friendly. For machine-friendliness, Terraform can also read JSON configurations.

The Terraform language uses configuration files that are named with `.tf` file extension. There is also a JSON-based variant of the language that is named with the `.tf.json` file extension.

We will start by creating a very simple Terraform file that will pull down the image from Docker Hub and start the container. In addition, we will use input variables. They serve as parameters for a Terraform file. A variable block configures a single input variable for a Terraform module. Each block declares a single variable. And we will create a map to specify different environment variables based on conditions. This allows us to dynamically deploy infrastructure configurations based on information we pass to the deployment. 

To start with we need to set up the environment:

```
mkdir terraform/
cd terraform/
```

Now, we need to create variable file:

```
vi variables.tf
```

With the following content:

```
# Define variables
variable "environment" {
  description = "env: production or development"
}

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

variable "container_name" {
  type = "map"
  description = "Name of the container"
  default = {
    prod = "container_production"
    dev = "container_development"
  }
}

variable "internal_port" {
  description = "Internal port for container"
  default = "2368"
}

variable "external_port" {
  type = "map"
  description = "External port for container"
  default {
    prod = "80"
    dev = "8081"
  }
}
```

Then we need to create a Terraform script in order to download the latest Ghost image and run container using described variables: 

```
vi main.tf
```

With the following content:

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

# Start the Container
resource "docker_container" "container_id" {
  name  = "${lookup(var.container_name)}"
  image = "${docker_image.image_id.latest}"
  ports {
    internal = "${var.internal_port}"
    external = "${lookup(var.external_port)}"
  }
}
```

Next step would be to initialize new Terraform configuration:

```
terraform init
```

And validate main.tf file:

```
terraform validate
```

Then we need to generate and see `dev` execution plan:

```
terraform plan -out=tfdevelopment_plan -var env=development
```
Here are some useful flags for `plan`:
`-out=path`: Writes a plan file to the given path. This can be used as input to the `apply` command.
`-var foo=bar`: This sets a variable in the Terraform configuration. It can be set mupltiple times.

If everything looks good you can build (or change) `dev` infrastructure according to the plan:

```
terraform apply tfdevelopment_plan
```
Some useful flags for `apply`:
`-auto-approve`: This skips interactive approval of plan before applying.
`-var foo=bar`: This sets a variable in the Terraform configuration. It can be set multiple times.
Confirm your apply by typing `yes`. The `apply` will take a bit to complete.

Now you can list the Docker images or inspect Terraform state or plan by running following commands:

```
docker images ls
```
or
```
terraform show
```

And list Docker containers:

```
docker container ls
```