Run terraform script from docker container

Introduction

Hashicorp provides docker container for terraform. There are two types of containers light and full. Light version contains the binary and full version compiles the binary from source inside the container. For most cases the light version can be the best option.

Preparation

As a example there will be used Azure cloud and storage account as a resource to be created from the container.

Before running terraform docker container there are needed Azure credentials like Subscription, Client ID, Client Secret and Tenant ID. All of these can be obtained from Azure portal.

Export all of them in the shell or add into the shell profile like .bash_profile:

export ARM_SUBSCRIPTION_ID=“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”
export ARM_CLIENT_ID=“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”
export ARM_CLIENT_SECRET=“EyDFM.YYoyoQGXfTHdakYG0+/zP9-I22"
export ARM_TENANT_ID=“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

Next create a folder for terraform files like azure and create the file main.tf. That file may contain one Azure resource like storage account:

terraform {
  required_version = ">=0.12.21"
}

provider "azurerm" {
  features {}
}

resource "azurerm_storage_account" "azure_storage" {
  account_replication_type = "LRS"
  account_tier = "Standard"
  location = "France Central"
  name = "mystorage12345609876543"
  resource_group_name = "StorageRG"
}

This code defines minimum terraform version that can be used, provider and resource definition.

Running docker with terraform

Now go to the previously created folder named azure and run the following command to initialize terraform:

$ docker run -it --rm -v $(pwd):/azure -w /azure \
-e ARM_SUBSCRIPTION_ID -e ARM_CLIENT_ID \
-e ARM_CLIENT_SECRET -e ARM_TENANT_ID \
hashicorp/terraform:light init

Initializing the backend...

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "azurerm" (hashicorp/azurerm) 2.5.0...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.azurerm: version = "~> 2.5"

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.

The options that are used:

-it – that option is optional, it is used mostly when we want to login to the running container after executing the docker command.

-rm – means that the container will be deleted after run.

-v $(pwd):/azure – This will map local folder ~/azure with the folder in the container named /azure. All of the files from folder ~/azure will be copied to the folder in container.

-w /azure – this option sets the WORKDIR for storing files and executing commands in that locations.

-e – this commands passed the system variables to the container. In this example are Azure credentials.

When the command completes it creates the hidden folder .terraform where the Azure plugin has been downloaded.

$ ls -a
.		..		.terraform	main.tf
$ ls .terraform/plugins/linux_amd64/
lock.json				terraform-provider-azurerm_v2.5.0_x5

Next run the command with plan option to verify what resources will be created:

$ docker run -it --rm -v $(pwd):/azure -w /azure 
-e ARM_SUBSCRIPTION_ID -e ARM_CLIENT_ID \
-e ARM_CLIENT_SECRET -e ARM_TENANT_ID \
hashicorp/terraform:light plan

Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_storage_account.azure_storage will be created
  + resource "azurerm_storage_account" "azure_storage" {
      + access_tier                      = (known after apply)
      + account_kind                     = "StorageV2"
      + account_replication_type         = "LRS"
      + account_tier                     = "Standard"
      + enable_https_traffic_only        = true
      + id                               = (known after apply)
      + is_hns_enabled                   = false
      + location                         = "francecentral"
      + name                             = "mystorage12345609876543"
      + primary_access_key               = (sensitive value)
      + primary_blob_connection_string   = (sensitive value)
      + primary_blob_endpoint            = (known after apply)
      + primary_blob_host                = (known after apply)
      + primary_connection_string        = (sensitive value)
      + primary_dfs_endpoint             = (known after apply)
      + primary_dfs_host                 = (known after apply)
      + primary_file_endpoint            = (known after apply)
      + primary_file_host                = (known after apply)
      + primary_location                 = (known after apply)
      + primary_queue_endpoint           = (known after apply)
      + primary_queue_host               = (known after apply)
      + primary_table_endpoint           = (known after apply)
      + primary_table_host               = (known after apply)
      + primary_web_endpoint             = (known after apply)
      + primary_web_host                 = (known after apply)
      + resource_group_name              = "StorageRG"
      + secondary_access_key             = (sensitive value)
      + secondary_blob_connection_string = (sensitive value)
      + secondary_blob_endpoint          = (known after apply)
      + secondary_blob_host              = (known after apply)
      + secondary_connection_string      = (sensitive value)
      + secondary_dfs_endpoint           = (known after apply)
      + secondary_dfs_host               = (known after apply)
      + secondary_file_endpoint          = (known after apply)
      + secondary_file_host              = (known after apply)
      + secondary_location               = (known after apply)
      + secondary_queue_endpoint         = (known after apply)
      + secondary_queue_host             = (known after apply)
      + secondary_table_endpoint         = (known after apply)
      + secondary_table_host             = (known after apply)
      + secondary_web_endpoint           = (known after apply)
      + secondary_web_host               = (known after apply)

      + blob_properties {
          + cors_rule {
              + allowed_headers    = (known after apply)
              + allowed_methods    = (known after apply)
              + allowed_origins    = (known after apply)
              + exposed_headers    = (known after apply)
              + max_age_in_seconds = (known after apply)
            }

          + delete_retention_policy {
              + days = (known after apply)
            }
        }

      + identity {
          + principal_id = (known after apply)
          + tenant_id    = (known after apply)
          + type         = (known after apply)
        }

      + network_rules {
          + bypass                     = (known after apply)
          + default_action             = (known after apply)
          + ip_rules                   = (known after apply)
          + virtual_network_subnet_ids = (known after apply)
        }

      + queue_properties {
          + cors_rule {
              + allowed_headers    = (known after apply)
              + allowed_methods    = (known after apply)
              + allowed_origins    = (known after apply)
              + exposed_headers    = (known after apply)
              + max_age_in_seconds = (known after apply)
            }

          + hour_metrics {
              + enabled               = (known after apply)
              + include_apis          = (known after apply)
              + retention_policy_days = (known after apply)
              + version               = (known after apply)
            }

          + logging {
              + delete                = (known after apply)
              + read                  = (known after apply)
              + retention_policy_days = (known after apply)
              + version               = (known after apply)
              + write                 = (known after apply)
            }

          + minute_metrics {
              + enabled               = (known after apply)
              + include_apis          = (known after apply)
              + retention_policy_days = (known after apply)
              + version               = (known after apply)
            }
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

Apply the changes by the option apply and all defined resources will be created:

$ docker run -it --rm -v $(pwd):/azure -w /azure \
-e ARM_SUBSCRIPTION_ID -e ARM_CLIENT_ID \
-e ARM_CLIENT_SECRET -e ARM_TENANT_ID \
hashicorp/terraform:light apply -auto-approve

azurerm_storage_account.azure_storage: Creating...
azurerm_storage_account.azure_storage: Still creating... [10s elapsed]
azurerm_storage_account.azure_storage: Still creating... [20s elapsed]
azurerm_storage_account.azure_storage: Creation complete after 29s [id=
/subscriptions/6637196f-8983-4cba-9b5b-0466aef39ca7
/resourceGroups/StorageRG/providers/Microsoft.Storage/
storageAccounts/mystorage12345609876543]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Go to the Azure portal and verify that the Storage Account has been created in the defined Resource Group.

Cleanup

To delete all items previously created run terraform container with option destroy:

$ docker run -it --rm -v $(pwd):/azure -w /azure \
-e ARM_SUBSCRIPTION_ID -e ARM_CLIENT_ID \
-e ARM_CLIENT_SECRET -e ARM_TENANT_ID\
 hashicorp/terraform:light destroy -auto-approve

azurerm_storage_account.azure_storage: Refreshing state... [id=
/subscriptions/6637196f-8983-4cba-9b5b-0466aef39ca7/resourceGroups/
StorageRG/providers/Microsoft.Storage/
storageAccounts/mystorage12345609876543]
azurerm_storage_account.azure_storage: Destroying... [id=
/subscriptions/6637196f-8983-4cba-9b5b-0466aef39ca7/resourceGroups/
StorageRG/providers/Microsoft.Storage/
storageAccounts/mystorage12345609876543]
azurerm_storage_account.azure_storage: Destruction complete after 6s

Destroy complete! Resources: 1 destroyed.

1 Comment

  1. Thank you!!1

    Reply

Leave a Reply