DEV Community

Dhanush Reddy
Dhanush Reddy

Posted on

Using Pulumi to Streamline Deployment of Dockerized Applications on Azure

Infrastructure as Code (IaC) is a method of provisioning and managing infrastructure using code and automation tools, rather than manual configuration. The goal of IaC is to make it easy to provision, update, and manage infrastructure, while also providing a way to version control and audit changes.

With IaC, infrastructure is defined in a code file, such as a YAML or JSON, and then provisioned using a tool such as Terraform. This code file acts as a single source of truth for the infrastructure, and can be version controlled, meaning that the history of changes to the infrastructure can be tracked, and rollback to a previous version can be done easily.

But, for this tutorial, I am going to use Pulumi, an open-source tool that allows you to define your infrastructure as code and automate the deployment of it on Azure. Pulumi enables you to use your preferred programming language to define your infrastructure, making it easy to understand and manage for developers than working with YAMLs. I will be using Python to deploy a simple Dockerized Flask app here.

Prerequisites

Before you begin, you should have the following things set up:

I would recommend everyone to go through the Pulumi Docs to understand the API, on how to communicate with various services.

Writing the Code:

Before going to the code, ensure that you are logged in to Azure and Pulumi.

You can login to Azure by entering the following command in your terminal

az login
Enter fullscreen mode Exit fullscreen mode

Similarly, login to Pulumi by entering:

pulumi login
Enter fullscreen mode Exit fullscreen mode

You can initialize a new Pulumi project in python by entering:

pulumi new python
Enter fullscreen mode Exit fullscreen mode

Follow the prompts in creating a stack.

Now let's go through the __main__.py file. It contains the entire logic that is needed for pulumi to provision infrastructure. Remove the given boilerplate code with the one below. We shall go line by line in writing it.

import pulumi
import pulumi_docker as docker
import pulumi_azure_native.resources as resources
import pulumi_azure_native.web as web
Enter fullscreen mode Exit fullscreen mode

Importing the necessary libraries: The first few lines of the code contains the import statements for the necessary libraries of the script, i.e, pulumi, pulumi_docker, pulumi_azure_native.resources, and pulumi_azure_native.web. These libraries are required for interacting with Azure and Docker using Pulumi.

You need to add pulumi_docker and pulumi_azure_native to your virtual environment which Pulumi has created in the venv folder. Now activate the virtual environment and install those packages:

source venv/bin/activate # For Linux/Mac
# venv\Scripts\activate # For Windows
pip install pulumi_docker pulumi_azure_native
Enter fullscreen mode Exit fullscreen mode
config = pulumi.Config()
dockerHubUserName = config.require("username")
dockerHubPassword = config.require("password")
Enter fullscreen mode Exit fullscreen mode

Configuring the necessary parameters: The config variable is used to read the username and password from the Pulumi configuration, which will be used later to authenticate to the Docker registry.

You can add those secrets to your Pulumi configuration by entering the following lines in your terminal:

pulumi config set --secret username YOUR_DOCKERHUB_USERNAME
pulumi config set --secret password YOUR_DOCKERHUB_ACCESS_TOKEN
Enter fullscreen mode Exit fullscreen mode

You can generate an access token for your Docker Hub account on hub.docker.com/settings/security

imageName = "flask_azure_pulumi"
imageTag = "v1.0.0"  # Change to whatever version you are creating
azureResourceLocation = (
    "UAE North"  # Change to the region that is closest to your end users
)
Enter fullscreen mode Exit fullscreen mode

The imageName variable is set to flask_azure_pulumi and imageTag variable is set to v1.0.0, you can change it to the version you are creating. The azureResourceLocation variable is set to UAE North, but you can change it to the region that is closest to your end users. I have chosen UAE North because it is the closest location to me having an F1 tier.

flaskAzureImage = docker.Image(
    imageName,
    build=docker.DockerBuild(context="app"),
    image_name=f"{dockerHubUserName}/{imageName}:{imageTag}",
    registry=docker.ImageRegistry(
        server="docker.io", username=dockerHubUserName, password=dockerHubPassword
    ),
)
Enter fullscreen mode Exit fullscreen mode

Building the Docker image: The flaskAzureImage variable is used to create an instance of the docker.Image class. The context for the DockerBuild is set to app, which specifies the path of the folder containing the Dockerfile that will be used to build the image.

The image_name parameter is set dynamically to dockerHubUserName/imageName:imageTag which specifies the name and tag of the image that will be pushed to the Docker registry. The ImageRegistry server is set to docker.io with the corresponding login details.

resource_group = resources.ResourceGroup(
    "pulumi_flask_app", location=azureResourceLocation
)
Enter fullscreen mode Exit fullscreen mode

Creating a Resource Group: The resource_group variable is used to create an instance of the resources.ResourceGroup class. The name is set to pulumi_flask_app and the location parameter is set to azureResourceLocation which is defined earlier. It specifies the Azure region where the resource group will be created.

plan = web.AppServicePlan(
    "pulumi",
    resource_group_name=resource_group.name,
    kind="Linux",
    location=azureResourceLocation,
    reserved=True,
    sku=web.SkuDescriptionArgs(
        name="F1",
        tier="Free",
    ),
)
Enter fullscreen mode Exit fullscreen mode

Creating an App Service Plan: The plan variable is used to create an instance of the web.AppServicePlan class. I have selected a Linux-based Web App using the kind and reserved parameters. The sku parameter is set to web.SkuDescriptionArgs(name="F1", tier="Free") which specifies that the plan will use the "F1" (Free) tier. Change the tier as per your needs.

flask_alpine = web.WebApp(
    "flask-azure-pulumi",
    resource_group_name=resource_group.name,
    server_farm_id=plan.id,
    site_config=web.SiteConfigArgs(
        app_settings=[
            web.NameValuePairArgs(
                name="WEBSITES_ENABLE_APP_SERVICE_STORAGE", value="false"
            )
        ],
        linux_fx_version=f"DOCKER|{dockerHubUserName}/{imageName}:{imageTag}",
    ),
    https_only=True,
)
Enter fullscreen mode Exit fullscreen mode

Creating a Web App: The flask_alpine variable is used to create an instance of the web.WebApp class. The server_farm_id parameter is set to plan.id which specifies the App Service Plan that the Web App will be associated with. The site_config specifies the configuration of the Web App by providing it with the Docker Image link as specified in linux_fx_version. The https_only parameter is set to True which enforces that the Web App can only be accessed via HTTPS.

There are more variables that you can adjust and fine tune as per your app requirements and I have just scratched the surface. So, feel free to refer to the docs while creating.

pulumi.export(
    "websiteURL",
    flask_alpine.default_host_name.apply(
        lambda default_host_name: f"https://{default_host_name}"
    ),
)
Enter fullscreen mode Exit fullscreen mode

Exporting the Website URL: The pulumi.export function is used to export the URL of the website. This exported value can be accessed later using the pulumi stack output command.

Complete code

You can check out my Github Repo for the complete merged code.

Overall, this code uses the Pulumi library to automate the deployment of the infrastructure, using Azure and Docker. The script creates a resource group, an App Service Plan, a Web App and pushes the Docker image to the Docker registry. The script also exports the website URL which can be accessed later. The URL for the app that I have created is flask-azure-pulumic4668d36.azurewebsites.net

Conclusion

In this blog post, we have discussed how to use Pulumi to deploy a simple Dockerized application on Azure. We have explained the benefits of using IaC and how Pulumi simplifies the deployment process. By using Pulumi, we can define our infrastructure as code, automate the deployment process, and version control the changes. Additionally, by using Azure App Service and Web App, we can easily host and scale our application in a secure and reliable environment. Pulumi is a powerful tool that enables developers to manage their infrastructure in a programmatic and automated way, saving time and effort while improving consistency and reproducibility.

I hope this tutorial was helpful in showing you how to use Pulumi in setting up Infrastructure effortlessly. Let me know if you have any questions or suggestions for improvement.

In case if you still have any questions regarding this post or want to discuss something with me feel free to connect on LinkedIn or Twitter.

If you run an organization and want me to write for you, please connect with me on my Socials πŸ™ƒ

Top comments (0)