Skip to main content

Command Palette

Search for a command to run...

Cloud-Native DevOps: Automating Deployment with Terraform, Ansible & Azure DevOps

Published
5 min read
Cloud-Native DevOps: Automating Deployment with Terraform, Ansible & Azure DevOps
V

Hi there! I'm Vineet Singh Negi and I have just started writing blogs. I'm passionate about DevOps and Machine Learning exploring all the different technologies involved in the process. I am constantly seeking new opportunities to expand my skill set and am actively working on various projects to improve my knowledge.

On my Hashnode blogs, you'll find a mix of tutorials and insights as I navigate the world of DevOps and Machine Learning. I will be sharing everything I learn along the way.

Introduction

In today’s DevOps world, automation is the backbone of efficiency and consistency.
In this project, I automated the Book Review Application deployment from end to end — provisioning infrastructure with Terraform, configuring servers with Ansible, and orchestrating the entire workflow using Azure DevOps Pipelines.

By the end of this pipeline, a fully functional Book Review web app runs on Azure, deployed through code, without a single manual click.

Project Overview

We’ll be building two key repositories and two pipelines:

  1. Infra Repository (book-review-infra)

    Contains Terraform code to provision:

    Resource Group

    Virtual Network and Subnet

    Two Ubuntu VMs (frontend & backend)

    MySQL (Flexible Server or VM-based)

  2. App Repository (book-review-app)

    Contains:

    Book Review App source code (Frontend + Backend)

    Ansible playbooks for configuration and deployment

Pipelines Overview

  • Infra Pipeline: Uses Terraform to create Azure resources.

  • App Pipeline: Uses Ansible to configure the servers and deploy the app.

Tools & Technologies

  • Azure DevOps — CI/CD orchestration

  • Terraform — Infrastructure as Code

  • Ansible — Configuration management

  • Azure Service Principal — Secure authentication

  • SSH Keys — Secure VM access

  • Ubuntu — OS for VMs

  • MySQL — Database for the app

Step 1: Setting up Azure and Service Connection

  1. Create an Azure Service Principal

    Run the following command to create a Service Principal:

     az ad sp create-for-rbac --name "devops-terraform-sp" --role Contributor \
     --scopes /subscriptions/<your-subscription-id>
    

    Copy the output — it will include:

    • appId (Client ID)

    • password (Client Secret)

    • tenant

    • subscriptionId

You’ll use these values to connect Azure DevOps to Azure.

  1. Create a Service Connection in Azure DevOps

    1. Go to Project Settings → Service Connections → New Service Connection

    2. Choose Azure Resource Manager → Service Principal (Manual)

    3. Paste the Client ID, Client Secret, Tenant ID, and Subscription ID

    4. Verify and Save as it-azure-connection

Step 2: Setting up Secure Files

  1. In Azure DevOps → Pipelines → Library → Secure Files, upload:
  • Your SSH private key (id_rsa)

  • Your SSH public key (id_rsa.pub)

  1. Authorize them for use in pipelines.

These keys are essential for Ansible to connect to the provisioned VMs.

Step 3: Infrastructure Automation (Terraform)

Repository: book-review-infra

terraform/
 ├── main.tf
 ├── provider.tf
 ├── variables.tf
 ├── outputs.tf
 ├── envs/
 │   └── dev.tfvars
 ├── modules/
     └── compute
     └── network
     └── database

You can clone the repo here: https://github.com/VineetSnegi/book-review-infra

provider.tf

provider "azurerm" {
  features {
    resource_group {
      prevent_deletion_if_contains_resources = false
    }
  }
}

outputs.tf

output "frontend_public_ip" {
  value = azurerm_public_ip.frontend_pip.ip_address
}
output "backend_public_ip" {
  value = azurerm_public_ip.backend_pip.ip_address
}
output "mysql_fqdn" {
  value = azurerm_mysql_flexible_server.db.fqdn
}

Infra Pipeline YAML (azure-pipelines.yml)

trigger:
- main
pool:
  name: 'self-hosted-agent-pool'
variables:
  TF_VERSION: '1.9.2'
steps:
- task: DownloadSecureFile@1
  name: download_ssh_key
  inputs:
    secureFile: 'id_rsa.pub'
- script: |
    sudo apt-get update -y
    sudo apt-get install -y unzip
    curl -LO https://releases.hashicorp.com/terraform/${TF_VERSION}/terraform_${TF_VERSION}_linux_amd64.zip
    unzip terraform_${TF_VERSION}_linux_amd64.zip
    sudo mv terraform /usr/local/bin/
    terraform -version
  displayName: 'Install Terraform'
- script: |
    terraform init
    terraform plan -var-file="envs/dev.tfvars"
    terraform apply -var-file="envs/dev.tfvars" -auto-approve
  displayName: 'Terraform Apply'

Once the pipeline runs successfully, note down the frontend IP, backend IP, and MySQL FQDN from the Terraform outputs.

Confirm the resources creation on azure portal.

Step 4: Configuration Management (Ansible) Outputs)

For configuration of the application and other necessary, Ansible is the deal.

Step 5: Manual Handoff (Passing Infra Outputs)

Copy the Terraform outputs and update your Ansible inventory and variables.

ansible/inventory.ini:

[frontend]
<frontend_public_ip> ansible_user=azureuser

[backend]
<backend_public_ip> ansible_user=azureuser

ansible/group_vars/backend.yml

db_host: "<mysql_fqdn>"

ansible/group_vars/frontend.yml

backend_api_url: "http://<backend_public_ip>:5000"

Commit and push these updates.

Step 6: App Pipeline (Ansible Deployment)

Repository: book-review-app

Your azure-pipelines.yml:

trigger:
- main

pool:
  name: 'self-hosted-agent-pool'
steps:
- task: DownloadSecureFile@1
  name: download_private_key
  inputs:
    secureFile: 'id_rsa'
- script: |
    sudo apt-get update
    sudo apt-get install -y ansible sshpass
    chmod 600 $(download_private_key.secureFilePath)
  displayName: 'Install Ansible and Configure SSH'
- script: |
    ansible-playbook -i ansible/inventory.ini ansible/site.yml \
      --private-key $(download_private_key.secureFilePath)
  displayName: 'Run Ansible Playbook'

This pipeline connects to the VMs provisioned by Terraform and configures:

  • Backend (Flask + MySQL connection)

  • Frontend (Nginx serving UI)

Press enter or click to view image in full size

Step 7: Validate the Deployment

After the app pipeline runs successfully:

  1. Copy the frontend public IP from Terraform output.

  2. Open it in your browser.

  3. You should see the Book Review App running live
    Register a user, add a review, and confirm backend connectivity.

Step 8: Destroy the Infrastructure (Cleanup)

Once you’re done testing:

terraform destroy -var-file="envs/dev.tfvars" -auto-approve

Or via Azure DevOps:

  • Edit the infra pipeline and change apply to destroy.

  • Commit and rerun the pipeline.

Conclusion

This project demonstrated a complete CI/CD workflow combining Terraform, Ansible, and Azure DevOps.
We achieved a fully automated environment, deploying a real-world app from scratch — all via code.
The pipelines are reusable, modular, and production-ready, representing a solid foundation for modern DevOps automation.

This journey deepened my understanding of end-to-end DevOps automation.
I learned how Terraform and Ansible complement each other — Terraform builds the infrastructure, and Ansible brings it to life.
Setting up Azure DevOps pipelines and secure connections provided a hands-on experience with enterprise-level CI/CD governance and best practices.

Future Work

  1. Automate variable sharing: Pass Terraform outputs to Ansible dynamically using Azure variable groups.

  2. Multi-environment setup: Extend pipelines for Dev → Test → Prod with approval gates.

  3. Add post-deploy validation: Implement smoke tests after app deployment.

  4. Integrate monitoring: Add Azure Monitor and Application Insights.

  5. Containerization: Package the Book Review app in Docker and deploy with Kubernetes.