Azure Weather Web App AZ-204 Project 1
Tags: azure, python, docker, webdev
Published: 2023-08-29 18:04:00

**Introduction**

In today's digital age, cloud services are the backbone of many applications. Azure, Microsoft's cloud platform, offers a plethora of services to get applications up and running in no time. In this post, I’ll share my journey in creating a weather application using Azure's array of services.

The Github repository for this project is [Github](https://github.com/Kenseventy/weatherapp)
The actual web app page is http://weather.kmcloud.tech

This is the first part of four related to MadeByGPS’s AZ-204 related projects found in this [video](https://www.youtube.com/watch?v=Ny5SZcV7mbE).
I’ll be making some small adjustments along the way but I want to present what I’ve learned related to the following items:

Azure App Service Web App 
Azure Container Registry
Azure Container Instance
Azure Container Apps 
Azure Functions



**Create an Azure App Service Web App**

Azure App Service is like a toolbox from Microsoft that makes it easy to put web apps on the internet without worrying about all the technical stuff in the background. At the start of this project, I used this toolbox to set up the web app. I like to think of this as setting up my own little space on the internet where the weather app can live and be visited by people.

Creating and setting up a Flask application with Python would be straightforward and with some configuration of the Azure App Service, I would be able to get this application up and accessible to the internet.

**Developing the basic Weather Application**

Before I started using Azure's many tools, I first needed the heart of the project: a simple web application that could talk to weather APIs. I used Python and Flask to create a simple web page with a text field that accepts input, along with a route that would search when the button is pressed. Functionality was needed when the button was pressed, the site would call a weather API and be able to display the relevant information. 

The weather API I picked was the OpenWeatherMap API for this. It's straightforward and accessible, making it easy for us to get basic weather details. This choice was important because it meant the main app would work well, even as I added more features with Azure.

```
def get_weather_data(city_name):
    if not city_name:
        return None

    # OpenWeather API details
    API_URL = "http://api.openweathermap.org/data/2.5/weather"
    API_KEY = os.environ.get("WEATHER_API_KEY")
    
    # Full URL Adding units=metric to get temperature in Celsius.
    full_url = f"{API_URL}?q={city_name}&appid={API_KEY}&units=metric"

    try:
        response = requests.get(full_url)
        data = response.json()
        
        # Check for valid response from OpenWeather API
        if data.get("cod") != 200:
            return None
        
        # Process and return the data
        return {
            "city": data["name"],
            "temperature": data["main"]["temp"],
            "description": data["weather"][0]["description"]
        }

    except Exception as e:
        # Handle any exception that arises when making the API call
        print(e)
        return None

```

**Containerization**

To ensure the web application was isolated and portable, I containerized it. Using Docker, I  was able to package the application with all its dependencies, ensuring that it could run consistently across different environments. 

This step is vital, especially when working with cloud platforms like Azure, because it eliminates the "it works on my machine" problem. By containerizing the application, I made it easier to manage, deploy, and scale. After containerizing the app, I pushed the Docker image to Azure Container Registry, ensuring a secure and private storage for the container image(s). 

This approach streamlined the deployment process, particularly when I decided to test the application using Azure Container Instance and, later on, deploy it to Azure Container Apps. This ensured that the application, from development to deployment, was efficient, consistent, and cloud-ready.

```
FROM python:3.8-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

CMD ["flask", "run", "--host=0.0.0.0", "--port=80"]
```



**Azure Container Registry**

As mentioned in the last section, the ACR was where I would store the Docker Image. The registry streamlines the process of storing and managing those images, ensuring that they're kept in a secure environment. The added benefit of ACR is its seamless integration with other Azure services. 

With the image in the set-up Azure Container Registry I was able to test the application using Azure Container Instance first for testing before deploying it to Azure Container Apps. Not only did it make deployments and testing quicker, but it also ensured that I had a centralized and consistent version of the app ready for deployment when needed.

**Azure Container Instance**

After containerizing the web application and storing it in Azure Container Registry (ACR), it was essential to test it before a full-scale deployment. For this, I used Azure Container Instance (ACI). Unlike traditional container orchestrators which might require complex setup and configuration, ACI presents a simpler approach. It's designed to run containers without the complexity of managing underlying infrastructure or orchestrating multiple container instances. 

This made ACI an excellent choice for my use case; it allowed me to quickly spin up the container and see the application in action in a real-world Azure environment. By testing with ACI, I ensured that the application was ready for the challenges of a live environment, along with ensuring its stability and performance. This step was critical as it provided insights and highlighted any potential issues, ensuring a smoother transition when I decided to deploy the app on Azure Container Apps.


**Azure Function**

Delving deeper into Azure's capabilities, I decided to give the application an expanded feature by using an Azure Function. This serverless solution allowed us to build an alerting mechanism that triggered whenever specific weather conditions were met, Specifically the web page would show if the temperature was under 20° celsius triggering a ‘Sweater Alert’. 

The beauty of Azure Functions lies in its event-driven nature, making the application not just informative based on the search but also proactive in providing insight into weather conditions and proactively alerting..

**Integration of the Azure Function**

Using Flask, I was able to enhance the basic web application to introduce the dynamic ‘Sweater Alert’ mechanism. With just a few tweaks in Flask routes and templates, I seamlessly integrated the alert into the web page.

**Azure Container Apps**

To get the Container Apps up and running, I started by leveraging the Azure CLI. After logging into Azure using az login, I navigated to the specifics of the project with az containerapp create. Following the initial setup, I pointed the application to the image in Azure Container Registry using the --image parameter. 

Compared to Container Instances, Container Apps have more granular control with the use of environments. For example you can adjust Network settings or have applications share a log analytics workspace in the same environment. Having the environment setup was a necessity for having the Container App set up and running.  

From there I was provided a URL that was where the Container App was up and running but I wanted to include the site into my ‘kmcloud.tech’ ecosystem. From the Azure portal, I created a ‘custom domain’ entry and validated the DNS with my DNS provider.


**Push to GitHub**

To implement version control and make the CI/CD processes make more sense I put the codebase up to Github. This also opens up opportunities for collaboration with other developers and engineers to look at my code, potentially give advice or even contribute to this project.

```

Git add .
Git commit -m “First commit”
Git push 

```

**CI/CD Implementation**

To streamline the deployment process, I implemented CI/CD pipelines, automating the process from the codebase to the live application. Using GitHub Actions, I developed a two-pronged approach to address both Docker and Azure Functions.

Before this could be completed with best practices, I needed to create a service principal account that would interact with the Azure services. This would allow a programmatic way to use services in the Subscription without providing user/admin credentials.

The Docker process .yml file was structured to build a Docker image from the included Dockerfile in the repo.. This .yml file facilitates the setting up the environment and installs dependencies. It then pushes the fresh container image to Azure Container Registry. To facilitate this, I stored credentials (including the service principal) as secrets within the GitHub repository. This ensures security while allowing GitHub Actions to authenticate with Azure services programmatically.

For the Azure Function, I developed a separate .yml pipeline. This .yml file starts with setting up the environment then using the stored secrets (along with the service principal) in the GitHub repository, the Github Actions logs into Azure, allowing the pipeline to deploy the Azure Function programmatically. Finally, the GitHub action cleans up by logging out of Azure.

By integrating these CI/CD pipelines, reinforced with the stored secrets, I’m able to optimize the deployment workflow. This ensured that the Web App, Container Image and Azure Function stayed synchronized with the latest changes.


**Documentation**

Last but not least, I wrote out this blog post to document what I had done to get everything up and running. This should make it easier for others to replicate this process, understand design choices, and contribute to the project.


**Conclusion**

Spinning up this project and associated Azure resources was a fantastic learning experience. I was able to learn a ton about Azure Containers including the Registry, Instances and Apps along with a deeper knowledge of Azure Functions. I was also able to learn more about the az cli tool where I could deploy services with a single command instead of clicking around in the Azure portal.

In the near future, I will be returning to this project and implementing IaC with Terraform to allow even more granular control of cloud resources. One other thing I could implement is the CI/CD splitting of the Test and Prod environments. I know there's a way to differentiate when a test image is uploaded and when a prod image is uploaded but that would take some research.

I hoped you learned something through my journey, This was a lot of trial and error before getting everything up and running properly. Using the skills and resources from this project I will be moving onto "Azure Document Vault with Expiry & CDN Integration (Develop for Azure storage)"

Stay tuned for that blog post.
Thanks for reading,
-Kenton