# Building a Flask and MongoDB App with Azure Container Apps

For those who want to focus on creating scalable containerized applications without having to worry about managing any environments, this is the tutorial for you! We are going to be hosting a dockerized version of our previously built Flask and MongoDB Atlas application on Azure Container Apps.

Azure Container Apps truly simplifies not only the deployment but also the management of containerized applications and microservices on a serverless platform. This Microsoft service also offers a huge range of integrations with other Azure platforms, making it easy to scale or improve your application over time. The combination of Flask, Atlas, and Container Apps allows for developers to build applications that are capable of handling large amounts of data and traffic, while being extremely accessible from any machine or environment. 

The specifics of this tutorial are as follows: We will be cloning our previously built Flask application that utilizes CRUD (create, read, update, and delete) functionality applying to a “bookshelf” created in MongoDB Atlas. When properly up and running and connected to Postman or using cURL, we can add in new books, read back all the books in our database, update (exchange) a book, and even delete books. From here, we will dockerize our application and then we will host our dockerized image on Azure Container Apps. Once this is done, anyone anywhere can access our application!

The success of following this tutorial requires a handful of prerequisites:

* Access and clone our Flask and MongoDB application from the GitHub repository if you would like to follow along.
* View the completed repository for this demo.
* MongoDB Atlas
* Docker Desktop
* Microsoft Azure subscription.
* Python 3.9+.
* Postman Desktop (or another way to test our functions).

### Before we dive in...
Before we continue on to containerizing our application, please ensure you have a proper understanding of our program through this article: Scaling for Demand: Deploying Python Applications Using MongoDB Atlas on Azure App Service. It goes into a lot of detail on how to properly build and connect a MongoDB Atlas database to our application along with the intricacies of the app itself. If you are a beginner, please ensure you completely understand the application prior to containerizing it through Docker. 

#### Insight into our database
Before moving on in our demo, if you’ve followed our previous demo linked above, this is how your Atlas database can look. These books were added in at the end of the previous demo using our endpoint. If you’re using your own application, an empty collection will be supported. But if you have existing documents, they need to support our schema or an error message will appear: 

We are starting with four novels with various pages. Once properly connected and hosted in Azure Container Apps, when we connect to our `/books` endpoint, these novels will show up. 

### Creating a Dockerfile

Once you have a cloned version of the application, it’s time to create our Dockerfile. A Dockerfile is important because it contains all of the information and commands to assemble an image. From the commands in a Dockerfile, Docker can actually build the image automatically with just one command from your CLI. 

In your working directory, create a new file called `Dockerfile` and put in these commands:

```
FROM python:3.9-slim-buster
WORKDIR /azurecontainerappsdemo

COPY ./config/requirements.txt /azurecontainerappsdemo/
RUN pip install -r requirements.txt

COPY . /azurecontainerappsdemo/

ENV FLASK_APP=app.py
EXPOSE 5000
CMD "flask", "run", "--host=0.0.0.0"]
```

Please ensure your `requirements.txt` file is placed under a new folder called `/config`. This is so we can be certain our `requirements.txt` file is located and properly copied in with our Dockerfile since it is crucial for our demo.

Our base image `python:3.9-slim-buster` is essential because it provides a starting point for creating a new container image. In Docker, base images contain all the necessary components to successfully build and run an application. The rest of the commands copy over all the files in our working directory, expose Flask’s default port 5000, and specify how to run our application while allowing network access from anywhere. It is crucial to include the `--host=0.0.0.0` because otherwise, when we attempt to host our app on Azure, it will not connect properly.

In our app.py file, please make sure to add the following two lines at the very bottom of the file:
```
if __name__ == '__main__':
   app.run(host='0.0.0.0', debug=True)
```

This once again allows Flask to run the application, ensuring it is accessible from any network. 

###### Optional

You can test and make sure your app is properly dockerized with these commands:

Build: `docker build --tag azurecontainerappsdemo . `

Run: `docker run -d -p 5000:5000 -e "CONNECTION_STRING=" azurecontainerappsdemo`

You should see your app up and running on your local host.

![app hosted on local host

Now, we can use Azure Container Apps to run our containerized application without worrying about infrastructure on a serverless platform. Let’s go over how to do this. 

### Creating an Azure Container Registry

We are going to be building and pushing our image to our Azure Container Registry in order to successfully host our application. To do this, please make sure that you are logged into Azure. There are multiple ways to create an Azure Container Registry: through the user interface, the command line, or even through the VSCode extension. For simplicity, this tutorial will show how to do it through the user interface. 

Our first step is to log into Azure and access the Container Registry service. Click to create a new registry and you will be taken to this page:

Choose which Resource Group you want to use, along with a Registry Name (this will serve as your login URL) and Location. Make a note of these because when we start our Container App, all these need to be the same. After these are in place, press the Review and Create button. Once configured, your registry will look like this:

Now that you have your container registry in place, let’s access it in VSCode. Make sure that you have the Docker extension installed. Go to registries, log into your Azure account, and connect your registry. Mine is called “anaiyaregistry” and when set up, looks like this:

Now, log into your ACR using this command: 
`docker login `

As an example, mine is: 
`docker login anaiyaregistry.azurecr.io`

You will have to go to Access Keys inside of your Container Registry and click on Admin Access. Then, use that username and password to log into your terminal when prompted. If you are on a Windows machine, please make sure to right-click to paste. Otherwise, an error will appear:

When you’ve successfully logged in to your Azure subscription and Azure Registry, we can move on to building and pushing our image. 

### Building and pushing our image to Azure Container Registry

We need to now build our image and push it to our Azure Container Registry. 

If you are using an M1 Mac, we need to reconfigure our image so that it is using `amd64` instead of the configured `arm64`. This is because at the moment, Azure Container Apps only supports `linux/amd64` container images, and with an M1 machine, your image will automatically be built as `arm`. To get around this, we will be utilizing Buildx, a Docker plugin that allows you to build and push images for various platforms and architectures. 

If you are not using an M1 Mac, please skip to our “Non-M1 Machines” section.

#### Install Buildx
To install `buildx` on your machine, please put in the following commands:

`docker buildx install`

To enable `buildx` to use the Docker CLI, please type in:

`docker buildx create –use`

Once this runs and a randomized container name appears in your terminal, you’ll know `buildx` has been properly installed.

#### Building and pushing our image

The command to build our image is as follows:
`docker buildx build --platform linux/amd64 --t /: --output type=docker .`

As an example, my build command is: 
`docker buildx build --platform linux/amd64 --t anaiyaregistry.azurecr.io/azurecontainerappsdemo:latest --output type=docker .`

Specifying the platform you want your image to run on is the most important part. Otherwise, when we attempt to host it on Azure, we are going to get an error. 

Once this has succeeded, we need to push our image to our registry. We can do this with the command:

`docker push /:`

As an example, my push command is:

`docker push anaiyaregistry.azurecr.io/azurecontainerappsdemo:latest`

#### Non-M1 Mac machines
If you have a non-M1 machine, please follow the above steps but feel free to ignore installing `buildx`. For example, your build command will be:

`docker build --t /: --output type=docker .`

Your push command will be:

`docker push /:`

#### Windows machines
For Windows machines, please use the following build command:

`docker build --t /: .`

And use the following push command:

`docker push :`

Once your push has been successful, let’s ensure we can properly see it in our Azure user interface. Access your Container Registries service and click on your registry. Then, click on Repositories. 

Click again on your repository and there will be an image named `latest` since that is what we tagged our image with when we pushed it. This is the image we are going to host on our Container App service.

### Creating our Azure container app

We are going to be creating our container app through the Azure user interface. 

Access your Container Apps service and click Create. 

Now access your Container Apps in the UI. Click Create and fill in the “Basics” like this:

**If this is the first time creating an Azure Container App, please ensure an environment is created when the App is created. A Container Apps environment is crucial as it creates a secure boundary around various container apps that exist on the same virtual network. To check on your Container Apps environments, they can be accessed under “Container Apps Environments” in your Azure portal. 

As we can see, the environment we chose from above is available under our Container Apps Environments tab. 

Please ensure your Region and Resource Group are identical to the options picked while creating your Registry in a previous step. Once you’re finished putting in the “Basics,” click App Settings and uncheck “Use quickstart image.” Under “Image Source,” click on Azure Container Registry and put in your image information.

At the bottom, enter your Environment Variable (your connection string. It’s located in both Atlas and your .env file, if copying over from the previous demo):

Under that, hit “Enabled” for ingress and fill in the rest like this:

When done, hit Review and Create at the very bottom of the screen.

You’ll see this page when your deployment is successful. Hit Go to Resource.

Click on the “Application URL” on the right-hand side. 

You’ll be taken to your app.

If we change the URL to incorporate our ‘/books’ route, we will see all the books from our Atlas database! 

### Conclusion
Our Flask and MongoDB Atlas application has been successfully containerized and hosted on Azure Container Apps! Throughout this article, we’ve gone over how to create a Dockerfile and an Azure Container Registry, along with how to create and host our application on Azure Container Apps. 

Grab more details on MongoDB Atlas or Azure Container Apps.

  [1]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt8640927974b6af94/6491be06c32681403e55e181/containerapps1.png
  [2]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blta91a08c67a4a22c5/6491bea250d8ed2c592f2c2b/containerapps2.png
  [3]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt04705caa092b7b97/6491da12359ef03a0860ef58/containerapps3.png
  [4]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/bltc9e46e8cf38d937b/6491da9c83c7fb0f375f56e2/containerapps4.png
  [5]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/bltd959e0e4e09566fb/6491db1d2429af7455f493d4/containerapps5.png
  [6]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/bltfa57e9ac66da7827/6491db9e595392cc54a060bb/containerapps6.png
  [7]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/bltf60949e01ec5cba1/6491dc67359ef00b4960ef66/containerapps7.png
  [8]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blted59e4c31f184cc4/6491dcd40f2d9b48bbed67a6/containerapps8.png
  [9]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/bltb71c98cdf43724e3/6491dd19ea50bc8939bea30e/containerapps9.png
  [10]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt38985f7d3ddeaa6a/6491dd718b23a55598054728/containerapps10.png
  [11]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt7a9d4d12404bd90b/6491deb474d501e28e016236/containerapps11.png
  [12]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt7b2b6dd5b0b8d228/6491def9ee654933dccceb84/containerapps12.png
  [13]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt6593fb8e678ddfcd/6491dfc0ea50bc4a92bea31f/containerapps13.png
  [14]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt5c03d1267f75bd58/6491e006f7411b5c2137dd1a/containerapps14.png
  [15]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt471796e40d6385b5/6491e04b0f2d9b22fded67c1/containerapps15.png
  [16]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt1fb382a03652147d/6491e074b9a076289492814a/containerapps16.png