I need to review Terraform sometimes, so I left a tutorial+terminology so that I can recall it quickly.
https://www.terraform.io/downloads https://learn.hashicorp.com/tutorials/terraform/install-cli
On Ubuntu 21:
sudo apt-get update && sudo apt-get install -y gnupg software-properties-common curl
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
sudo apt-get update && sudo apt-get install terraform
Check:
➜ terraform --version
Terraform v1.1.2
on linux_amd64
terraform -install-autocomplete
Just follow below without thinking the lines at first (I left a brief explanation later):
mkdir learn-terraform-docker-container
cd learn-terraform-docker-container
Create main.tf
:
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 2.13.0"
}
}
}
provider "docker" {}
resource "docker_image" "nginx" {
name = "nginx:latest"
keep_locally = false
}
resource "docker_container" "nginx" {
image = docker_image.nginx.latest
name = "tutorial"
ports {
internal = 80
external = 8000
}
}
Initialize the project (downloading plugins):
terraform init
Here is the result:
➜ tree -a
.
├── main.tf
├── .terraform
│ └── providers
│ └── registry.terraform.io
│ └── kreuzwerker
│ └── docker
│ └── 2.13.0
│ └── linux_amd64
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ └── terraform-provider-docker_v2.13.0
└── .terraform.lock.hcl
Deploy (this is the full log):
➜ terraform apply
Terraform used the selected providers to generate the following execution plan. Resource
actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# docker_container.nginx will be created
+ resource "docker_container" "nginx" {
+ attach = false
+ bridge = (known after apply)
+ command = (known after apply)
+ container_logs = (known after apply)
+ entrypoint = (known after apply)
+ env = (known after apply)
+ exit_code = (known after apply)
+ gateway = (known after apply)
+ hostname = (known after apply)
+ id = (known after apply)
+ image = (known after apply)
+ init = (known after apply)
+ ip_address = (known after apply)
+ ip_prefix_length = (known after apply)
+ ipc_mode = (known after apply)
+ log_driver = "json-file"
+ logs = false
+ must_run = true
+ name = "tutorial"
+ network_data = (known after apply)
+ read_only = false
+ remove_volumes = true
+ restart = "no"
+ rm = false
+ security_opts = (known after apply)
+ shm_size = (known after apply)
+ start = true
+ stdin_open = false
+ tty = false
+ healthcheck {
+ interval = (known after apply)
+ retries = (known after apply)
+ start_period = (known after apply)
+ test = (known after apply)
+ timeout = (known after apply)
}
+ labels {
+ label = (known after apply)
+ value = (known after apply)
}
+ ports {
+ external = 8000
+ internal = 80
+ ip = "0.0.0.0"
+ protocol = "tcp"
}
}
# docker_image.nginx will be created
+ resource "docker_image" "nginx" {
+ id = (known after apply)
+ keep_locally = false
+ latest = (known after apply)
+ name = "nginx:latest"
+ output = (known after apply)
+ repo_digest = (known after apply)
}
Plan: 2 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
docker_image.nginx: Creating...
docker_image.nginx: Still creating... [10s elapsed]
docker_image.nginx: Creation complete after 10s [id=sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85nginx:latest]
docker_container.nginx: Creating...
docker_container.nginx: Creation complete after 1s [id=2d0d9fd949df2b17d14256ce47e8b06d8eef2470cad634234f60bd46fb486f44]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Check:
➜ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2d0d9fd949df 605c77e624dd "/docker-entrypoint.…" 7 minutes ago Up 7 minutes 0.0.0.0:8000->80/tcp tutorial
You can see Nginx Hello world page at http://localhost:8000
.
After the terraform apply
the command created the file terraform.tfstate
.
terraform destroy
(Here is the full log):
➜ terraform destroy
docker_image.nginx: Refreshing state... [id=sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85nginx:latest]
docker_container.nginx: Refreshing state... [id=2d0d9fd949df2b17d14256ce47e8b06d8eef2470cad634234f60bd46fb486f44]
Terraform used the selected providers to generate the following execution plan. Resource
actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
# docker_container.nginx will be destroyed
- resource "docker_container" "nginx" {
- attach = false -> null
- command = [
- "nginx",
- "-g",
- "daemon off;",
] -> null
- cpu_shares = 0 -> null
- dns = [] -> null
- dns_opts = [] -> null
- dns_search = [] -> null
- entrypoint = [
- "/docker-entrypoint.sh",
] -> null
- env = [] -> null
- gateway = "172.17.0.1" -> null
- group_add = [] -> null
- hostname = "2d0d9fd949df" -> null
- id = "2d0d9fd949df2b17d14256ce47e8b06d8eef2470cad634234f60bd46fb486f44" -> null
- image = "sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85" -> null
- init = false -> null
- ip_address = "172.17.0.2" -> null
- ip_prefix_length = 16 -> null
- ipc_mode = "private" -> null
- links = [] -> null
- log_driver = "json-file" -> null
- log_opts = {} -> null
- logs = false -> null
- max_retry_count = 0 -> null
- memory = 0 -> null
- memory_swap = 0 -> null
- must_run = true -> null
- name = "tutorial" -> null
- network_data = [
- {
- gateway = "172.17.0.1"
- global_ipv6_address = ""
- global_ipv6_prefix_length = 0
- ip_address = "172.17.0.2"
- ip_prefix_length = 16
- ipv6_gateway = ""
- network_name = "bridge"
},
] -> null
- network_mode = "default" -> null
- privileged = false -> null
- publish_all_ports = false -> null
- read_only = false -> null
- remove_volumes = true -> null
- restart = "no" -> null
- rm = false -> null
- security_opts = [] -> null
- shm_size = 64 -> null
- start = true -> null
- stdin_open = false -> null
- sysctls = {} -> null
- tmpfs = {} -> null
- tty = false -> null
- ports {
- external = 8000 -> null
- internal = 80 -> null
- ip = "0.0.0.0" -> null
- protocol = "tcp" -> null
}
}
# docker_image.nginx will be destroyed
- resource "docker_image" "nginx" {
- id = "sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85nginx:latest" -> null
- keep_locally = false -> null
- latest = "sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85" -> null
- name = "nginx:latest" -> null
- repo_digest = "nginx@sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31" -> null
}
Plan: 0 to add, 0 to change, 2 to destroy.
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
docker_container.nginx: Destroying... [id=2d0d9fd949df2b17d14256ce47e8b06d8eef2470cad634234f60bd46fb486f44]
docker_container.nginx: Destruction complete after 1s
docker_image.nginx: Destroying... [id=sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85nginx:latest]
docker_image.nginx: Destruction complete after 0s
Destroy complete! Resources: 2 destroyed.
https://www.terraform.io/language
Here is the general format of the Terraform file:
<BLOCK TYPE> "<BLOCK LABEL>" "<BLOCK LABEL>" {
# Block body
<IDENTIFIER> = <EXPRESSION> # Argument
}
Each
terraform
block can contain a number of settings related to Terraform’s behavior. Within a terraform block, only constant values can be used;
Terraform relies on plugins called “providers” to interact with cloud providers, SaaS providers, and other APIs.
Terraform configurations must declare which providers they require so that Terraform can install and use them. Additionally, some providers require configuration (like endpoint URLs or cloud regions) before they can be used.
Resources are the most important element in the Terraform language. Each resource block describes one or more infrastructure objects, such as virtual networks, compute instances, or higher-level components such as DNS records.
resource "{{ type_of_resource }}" "{{ given_local_name }}"
In the example above, we use docker_image
and docker_container
, that are provided by docker provider.
The `{{ given_local_name }} is used when other resource refer to this resource.
Every time you use a new resource type, please refer to the documentation from provider.
An auto-deploy is not Terraform’s responsibility. Instead, CI/CD (GitLab Runner, GitHub Actions, Jenkins) has a role to auto-deploy.