Featured image of post Deploying a Multi-Tier Application with OpenTOFU on Microsoft Azure: A Step-by-Step Guide

Deploying a Multi-Tier Application with OpenTOFU on Microsoft Azure: A Step-by-Step Guide

Learn how to deploy a multi-tier application using OpenTOFU on Microsoft Azure. This step-by-step guide will walk you through the entire process, from setup to validation.

Introduction

Hey everyone! 👋 Ready to dive into the world of Infrastructure as Code with OpenTofu? 🆕 OpenTofu is the new kid on the block, and it’s here to make your life easier. If you’re familiar with Terraform, you’ll feel right at home with OpenTofu. When HashiCorp decided to change Terraform’s license to the Business Source License (BSL), the community rallied together and created OpenTofu. It sticks with the trusty Mozilla Public License 2.0 (MPL 2.0), keeping it open and accessible for everyone.

So, what’s the big deal about OpenTofu? Well, think of it as Terraform with a fresh coat of paint, offering the same powerful functionality you’re used to but with an extra dash of openness and community spirit. Plus, it’s got a fun name that might make you a bit hungry for some tofu every time you use it! 🍣😊

This article is your guide to getting started with OpenTofu and deploying a multi-tier application on Microsoft Azure. Here’s what you’ll learn:

  • Setting up an OpenTofu project for Azure.
  • Defining and deploying resources for a web server, application server, and database server.
  • Configuring networking and dependencies between these components.

By the end of this guide, you’ll see how OpenTofu is just as robust and user-friendly as Terraform, making it a great choice for managing your cloud infrastructure. So, grab a cup of coffee ☕️, and let’s get started! 🚀

Prerequisites

Before we jump in, let’s make sure you’ve got everything you need for a smooth ride 🚲. Here’s what you’ll need on your local machine:

  1. Azure Account
    • Don’t have one? No worries! Sign up for Azure and take advantage of their free tier.
  2. Azure CLI
  3. Text Editor or IDE
    • Pick your favourite text editor or IDE for writing OpenTofu configuration files. Popular choices include Visual Studio Code. ✍️
  4. OpenTofu
    • For macOS using Homebrew:

      1
      2
      
      brew update
      brew install opentofu
      
    • For Linux/macOS/BSD/Unix (POSIX) using the installer script:

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      
      # Download the installer script:
      curl --proto '=https' --tlsv1.2 -fsSL <https://get.opentofu.org/install-opentofu.sh> -o install-opentofu.sh
      # Alternatively: wget --secure-protocol=TLSv1_2 --https-only <https://get.opentofu.org/install-opentofu.sh> -O install-opentofu.sh
      
      # Grant execution permissions:
      chmod +x install-opentofu.sh
      
      # Please inspect the downloaded script at this point.
      
      # Run the installer:
      ./install-opentofu.sh --install-method standalone
      
      # Remove the installer:
      rm install-opentofu.sh
      
    • For Windows (PowerShell):

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      
      # Download the installer script:
      Invoke-WebRequest -outfile "install-opentofu.ps1" -uri "<https://get.opentofu.org/install-opentofu.ps1>"
      
      # Please inspect the downloaded script at this point.
      
      # Run the installer:
      & .\\\\install-opentofu.ps1 -installMethod standalone
      
      # Remove the installer:
      Remove-Item install-opentofu.ps1
      
    • For more detailed instructions, check out the official OpenTofu installation guide. 🍣

With these prerequisites in place, you’re all set to start deploying your multi-tier application with OpenTofu on Azure. Let’s get going! 🚀

Setting Up Your Environment

To get everything ready for deploying your multi-tier application with OpenTofu on Azure, follow these steps:

  1. Log In to Azure
    • Open your terminal and log in to your Azure account using the Azure CLI:

      1
      
      az login
      
    • Follow the instructions to authenticate. 🌐

  2. Verify OpenTofu Installation
    • Ensure that OpenTofu is installed correctly by running:

      1
      
      tofu --version
      
    • This will display the installed version of OpenTofu, confirming that the installation was successful. ✅

  3. Set Up Your Project Directory
    • Create a new directory for your OpenTofu project and navigate into it:

      1
      2
      
      mkdir opentofu-azure-project
      cd opentofu-azure-project
      
    • This will be the workspace where you’ll define and manage your infrastructure. 🗂️

With your environment set up, you’re now ready to start building your OpenTofu project and defining your infrastructure. Let’s dive in! 🚀

Multi-Tier Application Overview

In today’s hands-on you will be setting up a trusted and very common multi-tier application architecture with three layers: a web server, an application server, and a database server.

OpenTofu Multi Tier App on Azure

  1. Web Server:
    • The web server is the public-facing component of your application. It handles HTTP requests and serves static content to your users.
  2. Application Server:
    • This is where your application logic resides. The application server processes requests from the web server and interacts with the database server. It’s internal and only accessible via private IP addresses, ensuring it’s not exposed to the internet.
  3. Database Server:
    • The database server stores and manages your application’s data, providing persistence and retrieval capabilities for user information and other data.

This setup mimics a typical interaction flow in a multi-tier architecture, where users interact with the web server, which communicates with the application server, and the application server accesses the database server.

Now, let’s dive into the configuration of each component! Open up your VS Code, create a main.tf file, and save it in the directory we created earlier. Let’s start defining and configuring our application.

Configuring the Multi-Tier Application

We’ll break down the configuration into manageable sections, making it easier to follow along.

1. Variables and Provider Setup

First, we’ll define the variables and the Azure provider configuration.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Define the variables that will be used by the Web VM, App VM, and SQL Server resources.
variable "resource_group_name" {
  description = "The name of the resource group in which to create the resources."
  type        = string
  default     = "iaMachs_rg"
}

variable "location" {
  description = "The location/region where the resources will be created."
  type        = string
  default     = "Australia East"
}

variable "vm_size" {
  description = "The size of the Virtual Machines."
  type        = string
  default     = "Standard_B2s"
}

// Define the Azure Resource Group that will be used by all resources in our configuration.
provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "iaMachs_rg" {
  name     = var.resource_group_name
  location = var.location
}

2. Virtual Network, and Subnets

Next, we’ll set up the virtual network and subnets for our web and application servers.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

// Define the Azure Virtual Network that will be used by the Web VM and App VM.
resource "azurerm_virtual_network" "iaMachs_VNet" {
  name                = "iaMachs-vnet"
  resource_group_name = azurerm_resource_group.iaMachs_rg.name
  location            = azurerm_resource_group.iaMachs_rg.location
  address_space       = ["10.0.0.0/16"]
}

// Define the Azure Subnet for the Web VM.
resource "azurerm_subnet" "iaMachs_Web_Subnet" {
  name                 = "iaMachs-web-subnet"
  resource_group_name  = azurerm_resource_group.iaMachs_rg.name
  virtual_network_name = azurerm_virtual_network.iaMachs_VNet.name
  address_prefixes     = ["10.0.1.0/24"]
}
// Define the Azure Subnet for the App VM.
resource "azurerm_subnet" "iaMachs_App_Subnet" {
  name                 = "iaMachs-app-subnet"
  resource_group_name  = azurerm_resource_group.iaMachs_rg.name
  virtual_network_name = azurerm_virtual_network.iaMachs_VNet.name
  address_prefixes     = ["10.0.2.0/24"]
}

3. Web Server Configuration

We’ll configure the public IP, network interface, and virtual machine for the web server.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
resource "azurerm_public_ip" "iaMachs_Web_PIP" {
  name                = "iaMachs-web-pip"
  location            = azurerm_resource_group.iaMachs_rg.location
  resource_group_name = azurerm_resource_group.iaMachs_rg.name
  allocation_method   = "Dynamic"
}

resource "azurerm_network_interface" "iaMachs_Web_NIC" {
  name                = "iaMachs-web-nic"
  location            = azurerm_resource_group.iaMachs_rg.location
  resource_group_name = azurerm_resource_group.iaMachs_rg.name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.iaMachs_Web_Subnet.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.iaMachs_Web_PIP.id
  }
}

// Define the Azure Virtual Machine resources for the Web VM.
resource "azurerm_virtual_machine" "iaMachs_Web_VM" {
  name                  = "iaMachs-web-vm"
  location              = azurerm_resource_group.iaMachs_rg.location
  resource_group_name   = azurerm_resource_group.iaMachs_rg.name
  network_interface_ids = [azurerm_network_interface.iaMachs_Web_NIC.id]
  vm_size               = var.vm_size

  storage_os_disk {
    name              = "web-os-disk"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Standard_LRS"
  }

  storage_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "18.04-LTS"
    version   = "latest"
  }

  os_profile {
    computer_name  = "iaMachs-web-vm"
    admin_username = "adminuser"
    admin_password = "P@ssw0rd1234!"
  }

  os_profile_linux_config {
    disable_password_authentication = false
  }

  depends_on = [azurerm_public_ip.iaMachs_Web_PIP]
}

4. Application Server Configuration

Similarly, configure the network interface and virtual machine for the application server.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
resource "azurerm_network_interface" "iaMachs_App_NIC" {
  name                = "iaMachs-app-nic"
  location            = azurerm_resource_group.iaMachs_rg.location
  resource_group_name = azurerm_resource_group.iaMachs_rg.name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.iaMachs_App_Subnet.id
    private_ip_address_allocation = "Dynamic"
  }
}

// Define the App VM resources.
resource "azurerm_virtual_machine" "iaMachs_App_VM" {
  name                  = "iaMachs-app-vm"
  location              = azurerm_resource_group.iaMachs_rg.location
  resource_group_name   = azurerm_resource_group.iaMachs_rg.name
  network_interface_ids = [azurerm_network_interface.iaMachs_App_NIC.id]
  vm_size               = var.vm_size

  storage_os_disk {
    name              = "app-os-disk"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Standard_LRS"
  }

  storage_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "18.04-LTS"
    version   = "latest"
  }

  os_profile {
    computer_name  = "iaMachs-app-vm"
    admin_username = "adminuser"
    admin_password = "P@ssw0rd1234!"
  }

  os_profile_linux_config {
    disable_password_authentication = false
  }
}

5. Database Server Configuration

Finally, configure the SQL server and database.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// Define the SQL Server and SQL Database resources.
resource "azurerm_mssql_server" "iaMachs_SQL_Server" {
  name                         = "iamachs-sql-server"
  resource_group_name          = azurerm_resource_group.iaMachs_rg.name
  location                     = azurerm_resource_group.iaMachs_rg.location
  version                      = "12.0"
  administrator_login          = "sqladmin"
  administrator_login_password = "P@ssw0rd1234!"
}

resource "azurerm_mssql_database" "iaMachs_SQL_DB" {
  name       = "iamachs-sql-db"
  server_id  = azurerm_mssql_server.iaMachs_SQL_Server.id
  sku_name   = "S0"
}

With the infrastructure defined, you’re now ready to deploy it using OpenTofu.

Deploying the Infrastructure

With our infrastructure defined, we are now ready to deploy it using OpenTofu. Follow these steps to deploy your multi-tier application on Microsoft Azure.

1. Initialise the OpenTofu Configuration

Navigate to your project directory and initialise the configuration to download the necessary plugins and modules.

1
tofu init

2. Apply the Configuration

Apply the configuration to deploy the resources defined in your OpenTofu project. This step may take a few minutes as Azure provisions the resources.

1
tofu apply

You will be prompted to confirm the deployment. Type yes to proceed.

1
2
3
4
5
6
7
Plan: 10 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  OpenTOFU will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

Once the deployment is complete, OpenTofu will display a summary of the resources created. 🎉

Testing the Deployment

After the deployment, it’s important to test that all components are functioning correctly. Follow these steps to verify your multi-tier application.

1. Get IP Addresses
  • Public IP Address of the Web Server: Obtain the public IP address of the web server from the Azure portal or using the Azure CLI:

    1
    
    az vm list-ip-addresses --name iaMachs-web-vm --resource-group iaMachs_rg --output table
    
  • Private IP Address of the Application Server: Obtain the private IP address of the application server from the Azure portal or using the Azure CLI:

    1
    
    az vm list-ip-addresses --name iaMachs-app-vm --resource-group iaMachs_rg --output table
    
2. Install Nginx on the Web Server
  • SSH into the web server using its public IP address:

    1
    
    ssh adminuser@<web-vm-public-ip>
    
  • Once connected, install Nginx by running the following commands:

    1
    2
    3
    4
    
    sudo apt-get update
    sudo apt-get install -y nginx
    sudo systemctl enable nginx
    sudo systemctl start nginx
    
3. Test the Web Server
  • Open a web browser and navigate to the web server’s public IP address. You should see a default “Welcome to nginx!” page or similar, indicating that the web server is running.
4. Test the Application Server
  • From the web server, SSH into the application server using its private IP address to verify internal communication:

    1
    
    ssh adminuser@<app-vm-private-ip>
    
5. Verify the Database Server Connectivity

To ensure the application server can communicate with the SQL Server, we will use telnet to check the connectivity on port 1433:

  1. Install Telnet on the Application Server

    • Install telnet if it is not already installed:
    1
    
    sudo apt-get install telnet
    
  2. Test Connectivity to SQL Server

    • Use the telnet command to ensure the application server can reach the SQL Server on port 1433:
    1
    
    telnet iamachs-sql-server.database.windows.net 1433
    
    • If the telnet command connects successfully, it will display a message like this:
    1
    2
    3
    4
    
    Trying 20.53.46.128...
    Connected to cr12.australiaeast1-a.control.database.windows.net.
    Escape character is '^]'.
    Connection closed by foreign host.
    
    • Even though it says “Connection closed,” this output verifies that the connection is correct. The “Connection closed” message simply means that the server accepted the connection but did not continue with any further communication, which is expected behavior for this test. If it fails, on the other hand, it will display an error message.

With that we’ve successfully deployed and tested our setup, and now we’re all set to conclude the process.🚀

Cleaning Up Resources 🧹

Alright, folks, the show’s over, and it’s time to clean up the resources created by OpenTofu. Cleaning up unused resources is a good practice to avoid unnecessary Azure costs. Let’s walk through how to do this using the tofu destroy command.

  1. Make sure you are in the same directory where you ran the tofu apply command.

  2. Run the following command to destroy all the resources created by OpenTofu:

    1
    
    tofu destroy
    
  3. OpenTofu will ask you to confirm that you want to destroy the resources. Type yes and hit enter to proceed.

All the resources we created have been successfully deleted from your Azure account, leaving you with a clean slate for your next Azure adventure. 😄

Additional Cleanup for OS Disks

After running tofu destroy, you might notice that the OS disks are not automatically deleted. This is intentional to prevent accidental data loss. To ensure all resources are cleaned up, including OS disks, follow these steps:

  1. List the managed disks in your resource group:

    1
    
    az disk list --resource-group iaMachs_rg --output table
    
  2. Identify the disks you want to delete. Note their names.

  3. Delete each disk using the following command:

    1
    
    az disk delete --name <disk-name> --resource-group iaMachs_rg --yes
    

Replace <disk-name> with the name of the disk you want to delete. Repeat this command for each disk you need to remove.

This ensures that we avoid any unnecessary charges on your Azure account 💰

Conclusion

Et voilà! As you can see, OpenTofu is basically Terraform. OpenTofu has recently gone GA (Generally Available), which means it’s production-ready. The community around OpenTofu is growing, and more and more integrations with existing Terraform tools are being added to ensure compatibility. OpenTofu supports everything that was compatible with Terraform 1.7, making it a robust and reliable choice for your infrastructure management needs.

Ready to embrace this new open-source IaC tool? Dive in and experience the power and flexibility of OpenTofu in your next project! 🌟

Stay tuned for future articles where we’ll explore more advanced concepts and features of OpenTofu. If you have any feedback or questions, feel free to share them. Happy coding! 🚀