Back to projects

Engineering case study

Azure · Terraform · Ansible

EpicBook: Dual-Pipeline Deployment with Azure DevOps

A pair of Azure DevOps pipelines that separates infrastructure provisioning from application configuration, handing dynamic VM and database outputs from Terraform to Ansible without committing environment values or secrets.

AzureTerraformAzure PipelinesAnsibleMySQLNginx

2

linked delivery pipelines

2

runtime outputs handed off

3

Ansible roles

7d

database backup retention

The problem

What needed to be solved

The VM address and private database hostname are created at infrastructure runtime, while passwords and SSH keys must remain outside Git. The application deployment needed those values without duplicating infrastructure logic or relying on manual copy-and-paste.

My role

What I owned

I designed and implemented the Terraform infrastructure, Azure DevOps artifact contract, runtime inventory generation, and Ansible roles for host preparation, Nginx configuration, database initialization, and PM2 application management.

Architecture

How the system fits together

The infrastructure pipeline provisions Azure resources and publishes a two-value artifact. A downstream pipeline consumes it, generates an Ansible inventory, configures the VM, and verifies the public endpoint.

Key decisions

Engineering choices and trade-offs

1

Infrastructure and configuration have separate lifecycles

Terraform owns cloud resources; Ansible owns operating-system and application state. Each repository has one clear responsibility.

2

A small artifact is the handoff contract

Stage one publishes only the generated VM public IP and MySQL hostname. Stage two consumes them to create inventory and runtime configuration.

3

Secrets enter only at pipeline runtime

The database password comes from an Azure DevOps variable group, while SSH keys come from Secure Files. Neither is committed to either repository.

4

Database initialization is guarded

Ansible checks whether tables exist before applying the schema and seed data, allowing repeat runs without blindly reseeding the database.

Pipeline snapshot

Terraform outputs become dynamic Ansible inventory

The downstream pipeline downloads the infrastructure artifact, promotes its values to pipeline variables, and builds the deployment inventory at runtime.

Inspect the source file
azure-pipelines.yml
- download: infra
  artifact: infra-outputs

- script: |
    source "$(Pipeline.Workspace)/infra/infra-outputs/infra-outputs.env"
    echo "##vso[task.setvariable variable=vmPublicIp]$vmPublicIp"
    echo "##vso[task.setvariable variable=db_host]$db_host"

- script: |
    ansible-playbook site.yml \
      -e "db_host=$(db_host)" \
      -e "db_password=$(db_password)"
Code excerpt from azure-pipelines.yml

Measurable outcome

What the implementation demonstrates

  • Two independently maintained pipelines are connected through a stable two-value output contract.
  • Three Ansible roles take a fresh VM from base configuration through reverse proxy and application deployment.
  • The Azure MySQL server uses private VNet access and seven-day backup retention, while application database traffic requires TLS.
  • Every deployment concludes with an automated HTTP request against the generated VM address instead of relying on a manual spot check.

Explore another case study