Deploying a Docker container on Azure ‘Web App for Containers’ can be done fairly easy. In this blog post, I will provide a step by step guide to get you started. Some basic knowledge of Azure and Docker definitely helps. But why should you care in the first place? You will get:
- a managed runtime (for a single image)
- scaling to multiple instances
- HTTPS
- a simple deployment model
- easy integration with App Insights (Azure’s Monitoring system for Web Apps)
- use any Azure SaaS like CosmosDB, MSSQL, …
Overview
You won’t get a full blown orchestrated container runtime for your microservices architecture. For only a few services the setup can work. If not, migrating to another environment, later on, is straightforward, as we are using Docker. Below is an overview of the infrastructure we will set up.
Prerequisites
- An Azure subscription
- Local Docker installation
Steps
- Create a Docker image
- Create a Docker registry
- Push the Docker image to the registry
- Create a Web App
- Push a new version of the Docker image
Create a docker image for our app
The only requirement for our Docker image is, that it must expose an HTTP service on port 80. For our example, we are going to create a Docker image that contains a tiny NodeJS app. Create a file called index.js and paste the following content:
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello docker!'); }).listen(80);
Those lines create an HTTP server, that returns a plain text response with the content ‘Hello docker!’ for any request. Now we create a Dockerfile. A Dockerfile describes how an image gets composed. Create a file named ‘Dockerfile’ with following the content:
# our base image is the official node image: https://hub.docker.com/r/library/node/ # alpine flavour is the smallest variant you can get FROM node:8-alpine # copy all files from our project dir into the image at location /app COPY * /app/ # sets the current working directory for future commands to /app WORKDIR /app # declare that the container will provide a service on port 80 EXPOSE 80 # this will get executed when container starts ENTRYPOINT node index.js
Now you can test your container:
# create an image tagged (read 'named') azure-docker-blog docker build -t azure-docker-blog . # create a container named azure-docker-blog from our image docker run -d --rm --name azure-docker-blog -p 3000:80 azure-docker-blog # check the service curl http://localhost:3000/ # stop the container docker stop azure-docker-blog
Create a container registry in Azure
Log in to https://portal.azure.com
All Resources > Add > Search ‘Container Registry’ > Create
- Choose a name. In our case ‘azuredockerblogregistry’
- Choose a name for a resource group. In our case ‘azure-docker-blog’
Wait for the success message in the upper right corner. Then click ‘Go to resource’.
Open ‘Access keys’ and activate ‘Admin user’. We need the following info from this page:
- Login server (this is the server name of our image registry)
- username / password (can be used to login into the registry)
Push an image to the registry
# create an image that is tagged for our registry (alternatively, you can tag the existing image)
docker build -t azuredockerblogregistry.azurecr.io/azure-docker-blog .
# login to the registry using the credentials from above
docker login azuredockerblogregistry.azurecr.io
# push the image
docker push azuredockerblogregistry.azurecr.io/azure-docker-blog
Create the Web App for Containers
On the Azure portal:
- All Resources > Add > Search ‘Web App for Containers‘ > Create
- Choose a name. In our case ‘azure-docker-blog-app’
- Configure container
- Image source: Azure Container Registry
- Registry: azuredockerblogregistry
- Image: azure-docker-blog, Tag: latest
- Ok > Create
Wait for the success message in the upper right corner. Then click ‘Go to resource’. On the overview page for the App Service, you can find the public DNS name of the service. Open the address in your browser or use the command line (the first time it takes some seconds until it is ready):
curl https://azure-docker-blog-app.azurewebsites.net/
Make some changes
Now we will enable automatic pull of new images. On the portal site open the settings for your App Service and there enable ‘Continuous Deployment‘ under the section ‘Container settings’. Whenever we push a new version of our image, the App Service will now be notified and replace the existing version.
In order to deploy a new version of your app, you must create a new image. We add two more features to our server. First the output should contain the server start time and second we add a shutdown hook that gets triggered when the path ‘/shutdown’ gets called. Edit index.js
var http = require('http'); const serverStartTime = new Date(); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); if (req.url === '/shutdown') { res.end('Killing the process!'); process.exit(1); } else { res.end('Hello docker! Server started: ' + serverStartTime); } }).listen(80);
Build the image and push it again:
docker build -t azuredockerblogregistry.azurecr.io/azure-docker-blog .
docker push azuredockerblogregistry.azurecr.io/azure-docker-blog
curl https://azure-docker-blog-app.azurewebsites.net/
you should now see “Hello docker! Server started: …”.
With ‘curl https://azure-docker-blog-app.azurewebsites.net/shutdown‘ you can kill the NodeJS process. In this case, it will be restarted automatically.
Conclusion
We now have our app running and can push new versions by simply doing docker build + push. What runs inside the container is up to you. You are not restricted to NodeJS, but you can use anything that runs inside a Linux Docker container. Use your favourite JVM language or go with Haskell, if you like. Just expose your service via HTTP on port 80 and you’re ready to go.
You must be logged in to post a comment.