Share the love

There are several ways to deploy multiple environments with the same Terraform files using Azure DevOps, but one common method is to use pipeline variables and environment-specific Terraform state files. Here is an example of how to set up such a pipeline:

  1. In Azure DevOps, create a new pipeline and select “Terraform” as the template.
  2. Add pipeline variables for each environment, such as “env”, “tfstate_storage_account_name”, and “tfstate_container_name”. These variables will be used to specify the environment-specific Terraform state file location.
  3. In the pipeline, add a Terraform task to initialize the Terraform state. Use the pipeline variables to specify the storage account and container name for the environment-specific Terraform state file.
  4. Add another Terraform task to plan and apply the Terraform configuration. Use the pipeline variable “env” to specify the environment-specific Terraform variables file.
  5. Create a pipeline variable group for each environment and link it to the pipeline.
  6. Create a new release pipeline and select the pipeline you created in step 1.
  7. Set the environment variable for each stage in the release pipeline.
  8. In the pipeline, add a task to deploy the Terraform configuration using the Terraform task you created in step 3 and 4.
  9. Add a task to destroy the Terraform configuration using the Terraform task you created in step 3 and 4.

Here is an example pipeline YAML file:

- main

  vmImage: 'ubuntu-latest'

  - name: env
    value: dev
  - name: tfstate_storage_account_name
    value: mystorageaccount
  - name: tfstate_container_name
    value: tfstate

- stage: Terraform_Init
  - job: Init
    - task: TerraformInstaller@0
        terraformVersion: '0.14.7'
    - task: TerraformTaskV1@0
        command: init
        backendServiceArm: $(tfstate_storage_account_name)
        backendAzureRmResourceGroupName: $(tfstate_container_name)
        backendAzureRmStorageAccountName: $(tfstate_container_name)
        backendAzureRmContainerName: $(tfstate_container_name)
        backendAzureRmKey: $(env).tfstate

- stage: Terraform_Plan_Apply
  - job: Plan_Apply
    - task: TerraformTaskV1@0
        command: plan
        workingDirectory: $(System.DefaultWorkingDirectory)/terraform
        environmentServiceNameAzureRM: $(serviceConnection)
        commandOptions: -var-file="$(env).tfvars"
    - task: TerraformTaskV1@0
        command: apply
        workingDirectory: $(System.DefaultWorkingDirectory)/terraform
        environmentServiceNameAzureRM: $(serviceConnection)
        commandOptions: -var-file="$(env).tfvars" -auto-approve

You can use this pipeline as a reference and customize it as per your requirements.

Note: This is just a sample pipeline, it may not be suitable for all use cases, and you may need to modify the pipeline to fit your specific requirements.

Alternate Option

Another option to deploy multiple environments using Terraform and Azure DevOps is to use environment-specific Terraform Workspaces and Terraform variables.

Here are the steps to set it up:

  1. Create separate Terraform Workspaces for each environment (e.g. dev, test, production) in your Terraform code repository.
  2. Define environment-specific variables in Terraform using either .tfvars files or Terraform’s built-in variables system.
  3. In your Azure DevOps pipeline, set up a task that selects the appropriate Terraform Workspace for each environment by passing the desired workspace name as an environment variable to the Terraform CLI.
  4. Pass the appropriate Terraform variables for each environment to the pipeline by either defining them in your pipeline YAML file or by creating environment-specific variable groups in Azure DevOps.
  5. In your Terraform code, use the passed environment variables to conditionally apply the desired configuration for each environment.
  6. Run the pipeline for each environment, making sure to select the appropriate Terraform Workspace and pass the appropriate environment variables.

This approach allows you to keep your Terraform code DRY and to maintain a single version of the truth for each environment’s configuration while also making it easy to deploy to multiple environments in a consistent manner.