Running a container in the cloud is quite easy these days but how about multi-web app containers?

In this post, we will find out about the multi-container feature in Azure Web Apps and how we can leverage it.

Getting started with a multi-container in Azure Web Apps is quite easy as a matter of fact; The documentation is quite good as a starting point but when we want it to in production is where the real problems start.

Doing everything from the portal is an option but my preferred method is to use the Azure Cloud Shell or Visual Studio Code with the Azure module where you load the Azure Cloud Shell

Upsized photo of my VSCode instance

Let’s start with the basics:

  • Load up the Azure Cloud Shell
    • Go to shell.azure.com, select the tenant where you want to load up the Cloud Shell
  • [Skip this step if not applicable] Select the Azure SubscriptionSelect the Azure Subscription you’re going to use for the multi-container app deployment
    • az account set –subscription “<SubscriptionName>”
  • Git Clone the sample code from the Azure Samples repo
    • git clone https://github.com/Azure-Samples/multicontainerwordpress in the Azure Cloud Shell
  • Create a Resource Group where the App Service and App Service Plan will sit-in
    • az group create –name Multi-Container-App-RG –location “westeurope”
  • Create an App Service Plan
    • az appservice plan create –name MultiContainerServicePlan –resource-group Multi-Container-App-RG –sku S1 –is-linux
  • Create a Docker Compose Web App
    • az webapp create –resource-group Multi-Container-App-RG –plan MultiContainerServicePlan –name –multicontainer-config-type compose –multicontainer-config-file docker-compose-wordpress.yml

Source: https://docs.microsoft.com/en-us/azure/app-service/containers/tutorial-multi-container-app

These are the basic steps you have to take in order to get a multi-container web app up and running. The last step uses the –multicontainer-config-type compose which has the following code inside it

version: '3.3'

services:
   db:
     image: mysql:5.7
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: somewordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     ports:
       - "8000:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
volumes:
    db_data:

The docker-compose file is in YAML (Yet Another Markup Language) and you can see in there that you have two services referenced, DB and WordPress; This means that the docker-compose is telling the App Service to run two containers in parallel. Down below is a small explanation of the docker-compose specific commands

Setting blockExplanation
ServicesThe services block is where you define the containers that will run;
The format is like this;
services:
servicename:
<settings>
Image
The container image that the App Service will pull. It can be any container registry, public or private
VolumesWhere the container will write its files; By default, it’s running the files inside the container but you can specify an external “folder” where to write the files
RestartThis is the container restart policy; If the container crashes then you want docker to restart it. These are the following restart policies available at the time writing this article
restart: no
restart: always
restart: on-failure
restart: unless-stopped
EnvironmentInstantiate or use one or more environment variables; App Service configuration fields are set up as key-value pairs inside a container
Depends_onDepends_on field means that this container will not start unless the depending containers are already running
PortsThis means on which port the container should run and if it should be exposed to the internet
The syntax is as follows:
CONTAINER_PORT:EXPOSED PORT
8000:80 -> Means instantiate the container on port 8000 expose it as port 80 in the internet

The table from above explains the relevant setting blocks we’re going to need when we will be using the multi-container feature in Azure App Services. The most important setting of them all is the ports one. Why you may ask? Well in App Services you cannot override the default 80/443 ports, you only have the possibility of mapping them.

In the example above you’re seeing that port 8000 on the WordPress container is mapped to port 80 on the App Service and that the “db” service is not exposed in any way. By mapping port 8000 to port 80 tells the App Service how to route traffic to that specific container.

How does the WordPress container know where to connect to the database?

If you look closely to the docker-compose file, you’re going to see an environment variable called WORDPRESS_DB_HOST: db:3306

environment:<br>
       WORDPRESS_DB_HOST: db:3306

Docker, Kubernetes, and other container runtimes/orchestrators offer by default a service discovery feature where it simply requires the alias, service name or label and it will automagically make things happen on the backend without having to deal with any networking.

In the example above, having a service named “db” means that container IP (whatever it may be) has a DB value attached to it (like DNS) which allows us to tell the WordPress container that hey the database you’re looking for is this called “DB” and Dockers problem to tell you the IP Address.

Nailed the basics; How should I run this in production?

First. At the time of writing this article -It’s a preview offering with no SLA and any disaster is on you.

Concept, demo, POC environments are easy because you’re not exposing them to the real world. There are multiple problems that can appear with multi-container apps and I have not experienced them all. As long as you know your app well and you know that it can run without any problems wrapped in a single App Service then you should not have any problems.

I personally don’t recommend multi-containers in one service (App Service / Pod) because it goes against the one container -> one service design principle but there are cases where they fit together like a glove. Very rare cases.

My experience of running multi-container applications in App Services and Kubernetes (multi-container pods) is not that positive. If you’re not involved from the start in the dev/modernization process then it’s going to be a very rough ride.

Problems that you might hit when running the multi-container feature in App Services.

  • One of the containers has a memory leak and causes an OOM exception
    • This means that all the containers will get restarted regardless of the restart policy
  • One container crashed because of reasons
    • Everything gets restarted regardless of restart policy
  • The web service container is running but App Service is showing 404
    • Web Service container should be the first one in the Services stack in the docker-compose file
  • The web Service container is running but cannot access the backend container
    • The backend container is not starting or it needs to have its port exposed explicitly
      • Use expose docker-compose command
  • Cannot access anything; Kudu is not working; App Service is not responding;
    • Delete and restore the web app. No, I’m not kidding, it’s dead Jim.
  • Very slow download speed from Container Registry
    • You cannot speed it up, unfortunately.

If you’re not recommending the, then why are you using them?

You might go to the valley of “do as I say and not as I do”. Setting the joke aside, I very carefully analyze the possible issues that might arise with an application and do a cost/benefit analysis as well. In some cases, the benefits outweigh the risks and it’s worth the hassle.

That being said, this feature works quite well with new applications but not with recently modernized applications.

Have a good one!

Pin It on Pinterest