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
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
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
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
The services block is where you define the containers that will run; The format is like this; services: servicename: <settings>
The container image that the App Service will pull. It can be any container registry, public or private
Where 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
This 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
Instantiate or use one or more environment variables; App Service configuration fields are set up as key-value pairs inside a container
Depends_on field means that this container will not start unless the depending containers are already running
This 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
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.
What I think is pretty clear that we all know WordPress and have something to love or hate about it. I use for blogging, some friends are using it for small eCommerce, and I’ve seen companies use it for massive operations.
The problem with any website is that it needs to run on a web server for it to be available to the world and that brings up other issues.
When it comes to where to host it, there are a lot of options for hosting/deploying WordPress out there:
1. The possibility of hosting our blog on a shared WHM.
2. The choice of renting a VM and setting up a WHM / Cpanel environment to host it.
3. The option of paying for a “SaaS” like WordPress solution
4. Azure App Services
Today we will apparently talk about Windows / Linux App Services and what you need to know.
When it comes to App Services things might seem pretty clear. I provision an App Service, create a Web Site and deploy my WordPress into it. Simple no? Not really.
You have two flavours of App Services:
2. Linux (I wrote a blog post regarding Linux ones here)
You have to choose one of them because you do not have the possibility of switching between each other without redeploying your solution. The best thing you can do in my opinion is to go with the Linux offering because Apache or Nginx work much better with WordPress than IIS.
You chose an App Service flavour, what now?
Windows App Services run on IIS with PHP / Python / Java extensions. What you need to know.
When you first create the APP Service, you need to modify the application settings, so you have the best of the best performance out there.
Modify PHP version from 5.6 to 7.2 – You will get a significant performance boost just by modifying the PHP version.
Change the Platform to 64-bit – We are in 2017, let’s run everything on 64 bit shall we? 🙂
Set Always On to On – By default, web applications turn off if there’s no traffic on the website and when you initiate an HTTP connection it will have a cold start, and the first viewer will have to wait until the instance boots up. From a cost management standpoint, you’re not saving any money by having this option off so turning it to on it will maintain the website active even though you don’t have any traffic.
Set ARR Affinity to Off – WordPress is not a distributed application, and it’s quite hard to make it one. The option of turning off ARR will disable the feature in IIS and will speed up the loading time.
If you need to modify the PHP configuration of the Web Application, then you need to go into Kudu and add a “.user.ini” to site/wwwroot folder.
The most common settings for WordPress are the following:
<strong>output_buffering=off</strong>=Thisone isby defaultoff but forsome reason inAzure App Services it'sturned toon andit slows down your WordPress instance byalot.
Windows App Services persist local storage by leveraging Azure Files shares over SMB. So be aware of this “limitation” because Azure Files is slow (500 IOPS / 60MB/s)
Linux App Services are based on containers. You have the option of creating an App Service with pre-built binaries, or you can just bring your container from a container registry (Docker Hub / Azure Container Registry)
The prebuilt containers have the following Runtime stacks:
The ones referenced above a starting point. I prefer creating my container because I have more control over the binaries that are inside the container and I like NGINX more than Apache.
The Azure marketplace has a WordPress image allows you to have a “one-click” deployment from which you can just import your current WordPress instance. This works nicely for migrations because you just need to move the content, database and other settings. For this kind of job, there are multiple plugins in the WordPress marketplace which allow you to do these types of migrations. The plugin that works best for me is: All in One WP Migration
If you create the instance using the one-click deployment, then most of the Application Settings are pre-populated, and you don’t quite need to do anything but if you’re like me and like creating your container with your stack then this is what you need to take into consideration.
defaultConnection = mysql connection string
WEBSITES_ENABLE_APP_SERVICE_STORAGE command is crucial for WordPress sites (or any other site that requires persistence) because this tells the App Service to mount the /home directory on Azure Files shares for persistence and scalability. Containers being stateless/immutable means that anything that happens inside it will be lost with the first restart.
WordPress works very nicely in VMs but when you’re deploying an instance in an Azure App Service things change a bit, and you need to do some optimisation for it to work great.
The tool that I use for checking and optimizing my WP blog is Google PageSpeed Insights which is great for desktop and mobile websites. It gives you suggestions on how to improve general performance, increase speed and have a lower time to first byte.
Some extensions I use, and I recommend for improving your WP Instance. (TEST BEFORE YOU USE)
For finding issues with your WP instance, I recommend provisioning an Application Insights instance and install the WP extension. App Insights WordPress
Other more advanced ways of optimizing your instance are to use a CDN and Blob storage. Media files are better served by a CDN and not your App instance, this depends on a case by case scenario, and your mileage may vary. If your WP instance is image heavy then just by offloading those images to blob storage will greatly improve performance. Azure Blob Storage WP Plugin is something I used for clients and it works very well.
If we look at the statistics of Azure, we will see that most of the Virtual Machines that are deployed are running Linux. There’s a good reason as to why to run Linux applications, and I’m not going to cover that in this blog article. Today I will be talking about running Linux Web Applications in Azure’s App Services offering.
You may or may not know that Azure App Services run on IIS so in a nutshell, when you spin up an App Service and deploy a Web Application, you’re deploying that code using the same worker process with one application pool per website. So you’re not provisioning a single virtual machine to host your Web App instead you’re receiving space on an existing VM to host your application.
The main problem with App Services was that you could only host applications on IIS thus limiting your options. You have the possibility of running PHP or Java applications on IIS, but they wouldn’t be as performant as you would expect. Microsoft solved the problem by introducing Containers for Web Apps. You spin up a Linux App Service, and from there you deploy your application on an Apache solution (prebuilt) or a container built by you.
Why containers you might say?
Containers have been around for a long time, and they allow you to consistently run your application in any environment you want without having to say “It works on my machine”. API that was chosen to create, deploy, run containers is Docker. Most people call those containers as Docker Containers, but in reality, Docker is just the API that allows you to create/manage those containers. The main idea is that if you create a container that runs your web application without problems, then you can just take that container and deploy it anywhere because the code and all your dependencies are held in that image.
So how publish/pushh / push my container in a Linux App Service?
Taking your image and pushing it in a Linux App Service is very simple. You first have to have your container image pushed in a public/private repository like Azure Container Registry or Docker Hub then you just create a Web App for Containers and reference your image.
How do I deploy my code in a consistent manner?
Creating images in a centralized consistent manner is quite different than working alone on your laptop. Web App for Container has integration with most of the thing that you would use to deploy your code in a regular Windows App Service.
There are a couple of ways of pushing your code to the Linux App Service:
1. You can create your container image and push it to a repository like Azure Container Registry or Docker Hub.
2. You can use a CI/CD engine like VSTS to create your image and push it to the registry.
3. You just upload your files via FTP and be done with it 🙂
Down below is a demo flow of how you would push an image to the Web App for Containers service
Now if you’re used to App Services running IIS, there are some limitations that you should be aware of.
1. Containers are stateless by nature – If you need persistence you need to leverage blob storage or use another service like Redis Cache or you can leverage a feature to mount the /home directory to an Azure Files share. The latter will downgrade your performance a lot so tread carefully.
2. You only get ports 80/443 so if you need a custom port for your web application then App Services will not allow it.
3. You don’t have Web Jobs
4. You cannot do VNET integration
5. You cannot do Authorization with Azure AD
This is just a number of limitations that you should be aware of. Some features that you get from a regular App Service will eventually pop up in the Linux ones but until then, you need to work with what you have 🙂
That being said, take a look at Web Apps in Containers, play around with them and see what you can come up with.