Azure Loves Docker

On Orchestration and Scalability

Using Azure Docker Container Services is a great approach. I mean ultimately you want to orchestrate and scale your container services and leverage DC/OS, Docker Swarm or even Kubernets. For the app I needed to deploy, we did not need high optimization and scalability, such as the one Azure Container Services provides.

So what other option do we have?

Well, I recently spoke to a Microsoft buddy, and it looks like the App Service on Linux is still in Public Preview as of today. I personally want to avoid all the errors and struggles that come with using a service or product that is not ready.

Therefore, I chose to deploy a docker machine using a Linux VM, within an Azure Resource Group and a static ip address, as my app talks to a third party REST API that has whitelisted IP addresses as one layer of security.

Step 1 - Create a Docker Machine in Azure (Cloud Service)

For this scenario, we will deploy a test environment, and the first step is to build out our environment where our container will live.

Only one parameter is really needed to create the docker machine, and that is the Azure subscription Id. However, the optional parameters were helpful in my scenario to set a static ip for example, and to drop my resources within a specific region to keep things organized, as well as specifying the port to access the app.

NOTE: Because I specified the port, the Network Security Group or firewall will have the port rule created for me automatically.

Azure Resources

And here is the command that makes that magic happen.

docker-machine create -d  azure --azure-subscription-id "YOUR_SUBSCRIPTION_ID" \
--azure-resource-group "SPOscarRGroup" --azure-vnet "SPOscarRGroupvNeT" \
--azure-static-public-ip --azure-location "westus" --azure-open-port 1337 sposcarapp

Once you execute this command, you will see an authentication screen via the browser and enter the code that is generated as shown below.

Generated auth code

going to the browser, you see something similar to this

Enter Auth Code

this triggers the creation of all resources as shown below

Creating Resources

You will notice that now we see my Azure docker machine as well as my local one called ‘default’. Whenever I need to interact with either, I will need to set the env on my terminal. For example, if I wanted to interact with the Azure docker machine, I would execute the following on my terminal to ensure it runs my commands against it.

  eval $(docker-machine env sposcarapp)

Once I do that, I can find out what containers are running by executing the command as follows

  docker ps

I can also ssh into the docker machine by executing the following command

  docker-machine ssh sposcarapp

All goes well, you will see a response similar to the one below

SSH to Docker Machine

and of course if I want to destroy the machine, I can execute the following. This destroys all all resources on Azure and local references to it.

  docker-machine rm sposcarapp

all goes well, you will see output similar to the one below destroy Azure Resoruces

Step 2 - Deploying the NodeJS App

So far, we’ve seen how to deploy the docker machine. But we have not deployed any containers.

Building the App using Dockerfile and docker-compose

First of all, as with any app you wish to dockerize, you must create a Dockerfile, I won’t go into details here as there are many other posts that discuss this in-depth.

You also want to use Docker Compose to manage and deploy services which are comprised of multiple components such as a Webserver, Database etc.

The Dockerfile

Here is what the Dockerfile looks like. This file is within the root of the app which itself is under source control on Github. Note that I base my image from a NodeJS version.

# manually build Docker image
# ➔ docker build -t sharepointoscar/mynodejsapp:beta  -f Dockerfile --build-arg NODE_ENV=development .
#
#
# manually run image using port on any ip address on local host.
# using the image ID as last parameter
#
# docker run --rm -it -p 1337:1337 17e7f6e16553
#
#
FROM node:4.1.2

MAINTAINER Oscar Medina <me@sharepointoscar.com>

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Set required environment where app will run
ARG NODE_ENV=production
ENV NODE_ENV ${NODE_ENV}
RUN echo ${NODE_ENV}


RUN npm install -g grunt-cli
RUN npm install -g bower


COPY package.json /usr/src/app/

RUN npm install

COPY . /usr/src/app

#RUN bower install then  grunt build
RUN bower install
RUN grunt build

EXPOSE 1337

CMD [ "npm", "start" ]

The Docker Compose file (test environment)

I use a different docker compose file for test environment. In the test environment, I have an entry for a database service, for production, we use a hosted MongoDB service so we indicate the URI vs spinning up a MongoDB container.

# To run our test environment, execute the following command.
# -p is used for unique project name
# -d is used to run in background
# docker-compose -f docker-compose.test.yml -p LiteratureTestEnvironment up -d
#
version: '3'
services:
  db:
    container_name: MongoDB
    image: mongo:3.2.12
    ports:
        - '27017:27017'
    volumes:
      - /srv/docker/mongodb:/var/lib/mongodb
  web:
    build:
      context: .
      dockerfile: Dockerfile
    image:  literatureapp:test
    container_name: LiteratureNodeJSApp
    environment:
      - NODE_ENV=development
      - MONGODB_HOST=192.168.99.101
      - MONGODB_PORT=27017
    ports:
      - '1337:1337'
    depends_on:
        - db

The following command builds our services specified in the test yaml file. We bring up the services and execute in the background with the -d parameter.

  docker-compose -f docker-compose.test.yml -p LiteratureAppEnvironment up -d

At this point, the Docker container has been deployed to our Docker Machine. Because we have a static IP address, we are able to access the app via the browser on port 1337 based on the docker compose file and the firewall inbound rule that was created when we executed the docker create command.

Azure is slowly becoming a great place to deploy Docker Containers, it can only get better!

Hope this helps, @SharePointOscar