Step by Step: Set up Docker on Azure, Connect to Nginx container from Windows

Level: Easy

Objective of Tutorial:

  1. Set up a Docker Server on an Ubuntu VM running on Azure
  2. Set up a Windows Docker client on your desktop or laptop and connect to the above server - both from command prompt and cygwin
  3. Create a NGINX container in the Docker Server on Azure
  4. Access the container serving static pages from any browser on the internet

 

Prerequisites:

  1. Azure account
  2. Windows desktop/ laptop

 

Step 1: Set up your Docker server on Ubuntu VM on Azure

  1. Go to Azure Marketplace (https://azure.microsoft.com/en-us/marketplace/) and search for "Docker". You should be able to find "Docker on Ubuntu Server". Here is the direct link: https://azure.microsoft.com/en-us/marketplace/partners/canonicalandmsopentech/dockeronubuntuserver1404lts/

  2. Create a VM directly from the Marketplace. Use all defaults - it comes with the Docker VM Extension installed. Choose or create new storage account, resource group, virtual network etc. Give it a nice name, use username and password as authentication (instead of SSH keys). Let it create and start up. You will see the VM being spun up on your Azure portal (https://portal.azure.com)

  3. Once started, we have a Linux VM with Docker daemon installed on it. But this marketplace image, for security reasons, does not come pre-configured for any client to access the docker server over TCP. In order to configure it for client access, we have to log into the machine using Putty or any other SSH client and execute some commands

    If you are unsure how to use PUTTY to SSH into your newly created Linux VM, follow these instruction: https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-linux-how-to-log-on/

  4. Once you are inside (logged into the Azure Linux VM), you have to basically follow the steps documented here, from the beginning: https://docs.docker.com/articles/https/. However, please note the following caveats:

    1. When you log into the Linux VM, you log into your user home (\home\[user id]). The rest of the steps in this tutorial assume that you are running the commands from right here (as opposed to cd-ing to some other directory)

    2. You have to replace "$HOST" (wherever it occurs) with the FULL DNS Name of the VM just created (e.g., "whatevername.cloudapp.net", and you will get this from the portal. Also, remember this FULL DNS Name, as wherever we refer to [DNS Name of Docker Server VM] below in this tutorial, we mean this)

    3. There is a step where you will print (echo) a list of IP addresses to extfile.cnf ("subjectAltName = …"). In that list of IP addresses, include the following: (I) The Virtual IP Address of the docker VM from the portal (Settings --> Properties) - this is the public IP address of the Load Balancer in front of your VM (II) The Private IP Address of the docker VM from the portal (Settings --> Properties) (III) 127.0.0.1 and (IV) 0.0.0.0

    4. STOP at the last chmod command. Before proceeding further, we have to open an endpoint from the portal. Basically, we have to create a public-private port pair for port 2376 (that's where the docker daemon listens to). Go to the portal (https://portal.azure.com), click on the newly created VM, click on Settings/ Properties, click on Endpoints, click on +ADD from the top banner, add a new endpoint by naming it "Docker", leave Protocol as TCP, use 2376 as both public and private ports, leave Floating IP Disabled, leave Access Control as No Rules, and add the endpoint

    5. After doing the above step, go back to the tutorial and run the very next command (that runs the docker server daemon) with a sudo. This will run your docker daemon with the modified keys, ready to be connected from any client which uses the right keys. You can stop here, there is no need to run further commands from the tutorial at this point.

      [Note: This last command runs the Docker server. Here is the command, replace the /path/to part with the correct path. If you wish, you can create a separate directory (e.g., /docker), copy the PEM files there and use that path here:

      sudo docker daemon --tlsverify --tlscacert=/path/to/ca.pem --tlscert=/path/to/server-cert.pem --tlskey=/path/to/server-key.pem -H=0.0.0.0:2376

      This command will make the server hog your terminal. There are ways to run the server in the background as a daemon. Left as exercise.]

  5. After you have completed all the steps listed in #4 above, you should have 8 files in your home directory. Do an ls and verify this

    [user id]@testmpdockerserver:~$ ls -l
    total 32
    -r-------- 1 Azure123 Azure123 3326 Sep 25 20:46 ca-key.pem
    -r--r--r-- 1 Azure123 Azure123 2171 Sep 25 20:49 ca.pem
    -rw-rw-r-- 1 Azure123 Azure123   17 Sep 25 20:55 ca.srl
    -r--r--r-- 1 Azure123 Azure123 1899 Sep 25 20:55 cert.pem
    -rw-rw-r-- 1 Azure123 Azure123   30 Sep 25 20:54 extfile.cnf
    -r-------- 1 Azure123 Azure123 3243 Sep 25 20:54 key.pem
    -r--r--r-- 1 Azure123 Azure123 1944 Sep 25 20:53 server-cert.pem
    -r-------- 1 Azure123 Azure123 3243 Sep 25 20:50 server-key.pem

Step 2: Set up your Docker client on your Windows desktop/ laptop and connect to the server

  1. Now that your server is set up, we will set up the client. We will use our windows desktop or laptop as the docker client. Follow this tutorial (https://docs.docker.com/windows/step_one/) only up to STEP 2 on your Windows desktop/ laptop (do not execute STEP 3 as it is not needed here). While installing the client, make sure you leave the checkbox that adds docker.exe and docker-machine.exe to PATH checked

    [Note: Also, all you need to install is the Docker client. But it may also install the Oracle VirtualBox with it. If it does that, go back to Control Panel --> Uninstall a Program, choose Oracle Virtual Box and uninstall it (if you do not plan to use it)]

  2. Start a command prompt on your windows box and run "docker version" and it should say something meaningful (and also show an error because it cannot connect to any server), and that means the client is successfully installed

  3. Create a directory ".docker" in your users directory (e.g., C:\users\[user id]\.docker). If it is already created, make sure that there are no .pem files in it

  4. Now you have to COPY 3 pem files (the three that are listed in bold in the above list) from the Docker server (the VM you created above) to this directory for this windows machine to act as a client and connect successfully to the server. Use PSCP to copy these 3 files.

    Download PSCP on your Windows box from here: https://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
    Then open a command prompt and cd to the directory with pscp. Then run these three commands. Two caveats here:

    1. The destination file name's directory should be correct, these examples show mine

    2. The source file paths assume that you followed the directions in [Step 1 --> 4 --> a] above - if you have the pem files generated somewhere else, use that path instead

      pscp [user id]@[DNS Name of Docker Server VM]:\home\[user id]\ca.pem C:\Users\[user id]\.docker\ca.pem
      pscp [user id]@[DNS Name of Docker Server VM]:/home/[user id]/cert.pem C:\Users\[user id]\.docker\cert.pem
      pscp [user id]@[DNS Name of Docker Server VM]:/home/[user id]/key.pem C:\Users\[user id]\.docker\key.pem

  5. Once this is done, we are ready to connect to our Azure Docker VM from our client Windows box. Run this command at the command prompt:
     
    docker --tls -H tcp://[DNS Name of Docker Server VM]:2376 info
    or
    docker --tls -H tcp://[DNS Name of Docker Server VM]:2376 version
     
    and see the response from the server. At the server terminal, you will see these requests being logged

    [Note: At this point, you can also install CYGWIN on your Windows Desktop/ Laptop. When you open a CYGWIN terminal, the above commands should work fine. If you are more used to using LINUX commands, Cygwin provides you with a shell where you can fire away Linux commands and it will translate them to corresponding windows commands under the hood]

  6. Play around with your client: 
     
    docker --tls -H tcp://[DNS Name of Docker Server VM]:2376 search ubuntu
     
    docker --tls -H tcp://[DNS Name of Docker Server VM]:2376 run ubuntu:14.04 /bin/echo 'Hello world'
     
    docker --tls -H tcp://[DNS Name of Docker Server VM]:2376 ps
     
    docker --tls -H tcp://[DNS Name of Docker Server VM]:2376 run -t -i ubuntu:14.04 /bin/bash

  7. Getting tired of typing that long command with --tls and -H option every time? You can reduce that red part to just one word: 'docker'. Type in the following command in your Windows command prompt terminal: 
    setx DOCKER_HOST "tcp://[DNS Name of Docker Server VM]:2376"
    setx DOCKER_TLS_VERIFY "1"

    Then exit the command prompt and open a new one. If you are using Cygwin, you could use 'export' command to have the same effect, but it will not be persistent across shell instances, for which you will need to modify the bash rc/ profile file (or /etc/environment). But the setx on windows command prompt is persistent (as long as you close the prompt on which you ran the setx command), and even Cygwin will take it if you set it from the command prompt

    After setting these environment variables, try: docker ps

  8. [Optional step - How to set up docker client on the Ubuntu Azure VM itself (on the server)]: Now that you can connect from your Windows desktop/ laptop client, you may want to connect from the shell on the server itself. Sometime this is useful for troubleshooting the server when connectivity is lost. You can SSH into the server, open a shell, and run the following command (replace /path/to with correct path):

    docker --tls --tlscacert=/path/to/ca.pem --tlscert=/path/tocert.pem --tlskey=/path/to/key.pem -H=127.0.0.1:2376 info

    In order to free yourself up from having to type such long commands, do this:

    mkdir -pv ~/.docker
    cd ~
    cp -v {ca,cert,key}.pem ~/.docker

    Then, edit /etc/environment and append these 2 lines to it:
    DOCKER_HOST="tcp://127.0.0.1:2376" 
    DOCKER_TLS_VERIFY="1"

    Save, exit from the putty session and enter a new putty session. Now these client commands should work on the server host itself:

    docker version
    docker info
    docker ps
    docker images
    ...

Step 3. Set up an Nginx container and consume a static page served by the same

  1. Log into your Azure Docker VM and set up any directory with a static index.html file. I set up /docker/index.html (with at least read permission to all) and I copied the following contents to it:

     <html> <head> <title>Web Page from Nginx Docker container</title> </head> <body> Hello World from Nginx Docker container! </body> </html> 
    

    Whatever directory you use (in this example "/docker") should be used in the next step as the host-dir after -v option

  2. Run this on docker client:

    docker run --name demo2-nginx -p 8080:80 -v /docker:/usr/share/nginx/html:rw --restart=always -d nginx

    (you may choose not to name your container or choose another host port other than 8080 or choose to mount your drive as ro instead of rw)

    Note: One of the things this docker command does is that it mounts the directory /docker outside the container (on the docker host, i.e., your Azure VM) as /usr/share/nginx/html inside the container. That is required because nginx, by default, looks into /usr/share/nginx/html for static HTML pages to serve. In this example, it will find the index.html file that we created above

  3. Open an endpoint 8080:8080 for your docker VM from the portal. Go to the Azure portal, log in, select your Azure Linux VM, select Settings --> Properties, select Endpoints, add an endpoint with public port = private port = 8080. Name it "docker". Click OK. Click on the notification bell on top. Observe the progress bar showing the activity of adding the endpoint

  4. Browse to https://<your_VM_DNS_name>:8080, and you should see that index.html. Make change to the index.html, and the changes will reflect on your browser

    Note: Notice the two levels of port-forwarding at work here. When you hit your browser, it is requesting content from the cloud service's port 8080. The cloud service was created for your VM, and you have opened an endpoint that forwards any request received on port 8080 of the load balancer to port 8080 of your Azure VM. Hence, your HTTP request is routed to port 8080 of the Azure VM. From there, it again gets routed to port 80 of the nginx container because you said " -p 8080:80" on your docker run command line. Nginx being a web server, listens on port 80. Hence it gets your request, respond to it (sends index.html back) and your browser shows the contents of the html file