Deploying a multi-container application in Azure App Service is a powerful model for deploying individual services within an application together in a single App Service resource. It stands out as a cheaper alternative for the more sophisticated Azure Kubernetes Service (AKS). Docker Compose is much simpler and easier to set up and use, especially for developers who need to quickly spin up and manage multiple containers. It is the ideal choice for small to medium scale applications where we need to deploy the frontend and the backend servers. By writing a Compose file that defines the application, developers can deploy it quickly in App Service without a significant learning curve.
Multi-container application stands out as an excellent choice for microservice architectures where each service is loosely coupled and can be independently scaled based on its traffic.
Let’s get started now! ⚙️
Before we begin, here we will be deploying an application that comprises a frontend server and a backend server, running in two different ports. Specifically, we will be deploying Nest JS (backend) and Next JS (frontend) servers. The frontend server makes API calls to the backend server’s HTTP endpoints (this is straightforward). We will be deploying our application using Azure’s CLI.
Prerequisites
- A valid Azure account with necessary credits to provision an app service as per your preferred configuration.
- Azure CLI in your local machine logged in with your account.
- Docker installed on your local machine.
- An Azure container registry (ACR) instance created to store the container images.
- Knowledge on docker and docker compose.
- Production build of the frontend and backend server.
Sections
- Create the container images and push them to the ACR instance.
- Defining the Docker Compose file.
- Creating and Configuring the Azure App Service.
Create the container images and push them to the ACR instance
First, to create an image we need to create a Dockerfile, which is a text file containing all the commands to assemble an image. We require two docker files for our two containers - one for the backend and the other for the frontend.
Here are the dockerfiles that are being used in this tutorial:
Backend Dockerfile:
# Use the official Node.js 18 image
FROM node:18-alpine
# Increase Node.js memory limit
ENV NODE_OPTIONS=--max_old_space_size=4096
# Set working directory
WORKDIR /app
# Copy 'package.json' and 'package-lock.json' from the service directory
COPY package.json package-lock.json ./
# Copy the 'contract' folder and any other dependencies
COPY apps/backend apps/backend
# Install dependencies using npm
RUN npm install
WORKDIR /app/apps/backend
# Build the service
RUN npm run build
# Set the command to run your service
CMD ["npm", "start"]
# Expose port 3000 of the container on which the backend service is running
EXPOSE 3000
Frontend Dockerfile:
# Use the official Node.js 18 image
FROM node:18-alpine
# Increase Node.js memory limit
ENV NODE_OPTIONS=--max_old_space_size=4096
# Set working directory
WORKDIR /app
# Copy 'package.json' and 'package-lock.json' from the service directory
COPY package.json package-lock.json ./
# Copy the 'contract' folder and any other dependencies
COPY apps/frontend apps/frontend
# Install dependencies using npm
RUN npm install
WORKDIR /app/apps/frontend
# Build the service
RUN npm run build
# Set the command to run your service
CMD ["npm", "start"]
# Expose port 4000
EXPOSE 4000
Create Dockerfiles for each container that are suitable for building and launching your project's processes, which will be deployed in the multi-container application.
Next, build the Dockerfiles using Docker in your local machine and push it to the Azure Container Registry you had created. To push the images to your ACR you can follow the instructions given in the ‘Quickstart’ blade of the registry resource, which are specific to this container registry. Make sure you tag your image with <registry-name>.azurecr.io/<repository-name>:<tag> before pushing.
Defining a Docker Compose file
A Docker Compose file, docker-compose.yml, defines the services, networks, and volumes for your multi-container application stack. For this application’s docker compose service’s we will be referring to the image repositories we had created in the previous section for each container image in the compose file as a service.
Here is the docker-compose file of our application:
version: "1"
services:
frontend:
image: <registry-name>.azurecr.io/frontend
ports:
- "4000:80"
depends_on:
- backend
backend:
image: <registry-name>.azurecr.io/backend
ports:
- "3000:3000"
There are two services - frontend and backend. We have exposed the frontend in the host machine on port 80 and backend on port 3000. By doing so the frontend is accessible through the deployed link of our application without specifying the port.
Define an appropriate docker-compose file that’s appropriate to your application’s architecture and ensure the image property of every service refers to its respective repository in the container registry.
Next, to check whether the docker-compose is correct, execute the command docker-compose up the file’s directory to spin up the compose application and run it in the background. After that follow it with docker-compose ps to verify whether the services are running. You can also access the services and check them out too. Once everything is working alright, stop the compose application using the docker-compose down command.
Creating and Configuring the Azure App Service
Now we will be creating the App Service using Azure CLI to deploy our multi-container application in this section. Follow this step-by-step guide:
- Open a terminal or command prompt and type the following command to login to azure:
az login --use-device-code
2. After that, next to create the App Service Plan use the following command.
az appservice plan create --name <app-service-plan-name> --resource-group <resource-group-name> --sku <sku> --is-linux
app-service-plan-name: A name you want to assign for the app service plan to which the app service should belong
resource-group-name: Name of the resource group, Preferably this app service should be in the same resource group as the container registry for easier management of resources, especially while tearing down all the related Azure resources when not required anymore
sku: The pricing tier you want to use. F1 for Free Tier, which has been used for this tutorial.
3. Create the app service now under the app service plan in the same resource group:
az webapp create --name <app-service-name> --resource-group <resource-group-name> --plan <app-service-plan-name> --multicontainer-config-type compose --multicontainer-config-file docker-compose.yml
This big command specifies the name, resource group and the app service plan of the app service. After this our deployment model is based on docker compose with the definition that can be found in docker-compose file.
4. Next we need to specify the container settings of the app service with the credentials of the ACR container registry instance, so that it can access the images in that registry.
Since you need to provide credentials for ACR, use the az webapp config container set command for the multi-container setup.
az webapp config appsettings set --name <app-service-name> --resource-group <resource-group-name> --settings DOCKER_REGISTRY_SERVER_URL=<registry-name>.azurecr.io
az webapp config appsettings set --name <app-service-name> --resource-group <resource-group-name> --settings DOCKER_REGISTRY_SERVER_USERNAME=<your-acr-username>
az webapp config appsettings set --name <app-service-name> --resource-group <resource-group-name> --settings DOCKER_REGISTRY_SERVER_PASSWORD=<your-acr-password>
5. You can restart the app service after this configuration.
az webapp restart --name <app-service-name> --resource-group <resource-group-name>
That’s it! 🥳
Once the deployment is complete, navigate to the URL of your App Service (http://<app-service-name>.azurewebsites.net) to verify that your multi-container application is running as expected. It usually takes around 5 minutes after deployment for the application containers to get provisioned and next begin execution.
To sum it up,
Azure App Service allows for the deployment of multi-container applications using the tool Docker compose. We push our container images to the ACR, reference them in our compose file, the definition of our application. We create an app service with multi-container configuration and provide it with this compose file. Finally this Azure App Service boots up a multi-container application defined by this Docker Compose file, comprising all of our web application services.
As an exercise, try deploying your application using the Azure Portal website, which is an alternate route to utilize the Azure services.
So, now you know how to deploy your entire application stack in a single app service now! 🥇
Useful Links
About Harihararam Sriram
Harihararam Sriram is an Intern at CyberMind Works, primarily focusing on backend development. He has also branched out and made significant contributions to full stack projects, showcasing his versatility and dedication to learning.