Installing Docker in a mixed Operating System lab environment

I recently had to help a high growth technology business with the installation of Docker across their mixed Operating System estate. I figured that it would be useful to set up a small environment in my lab, to assist with the process, help with the inevitable debugging and potentially, the documentation. This post lists the steps that I took and hopefully, others might benefit from it too.

5/20/20245 min read

So, what is Docker?

To quote Docker.com "In 2013, Docker introduced what would become the industry standard for containers. Containers are a standardised unit of software that allows developers to isolate their app from its environment, solving the 'it works on my machine' headache." This is really important when shipping software between environments. It is all too common to hear "it worked in UAT but it doesn't work in Production". Containers make that scenario much less likely and give a layer of abstraction so that Developers do not need to worry about the underlying IT Infrastructure (and vice versa).

I found the Docker docs to be extremely helpful in gaining a deeper understanding of the architecture and how to implement Docker. Additionally, I found these links helpful too; Docker architecture, a Beginners Guide to Docker and an interview with James Turnball, VP of Services at Docker.

This post is specifically focussed on a mixed Operating System environment, where the clients are Windows based and the servers are running Linux (in this case, Ubuntu).

Installing the Docker client on Windows 10 laptop/desktop

Since I do not have Hyper V on my Windows devices, I am opting for the legacy Docker Toolbox for Windows. This will install the Docker client so that I can control the Docker server/daemons out on my lab network. The Windows boxes are 64 bit (x64) so this is fine as it is a prerequisite.

You can get the .exe at https://docs.docker.com/toolbox/toolbox_install_windows/

It will also install VirtualBox so be careful that it is not already installed.

It creates a local Docker machine on the Windows device.

Installing the Docker server installation on Ubuntu 16.04

Log onto the box and the run the following commands:

sudo apt-get update

sudo apt-get install apt-transport-https ca-certificates curl software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

sudo apt-get update

sudo apt-get install docker-ce (CE stands for Community Edition, as opposed to Enterprise Edition)

Test that it installed ok by doing:

sudo docker run hello-world

docker --version

Start docker as a daemon and get it to start at startup next time:

sudo systemctl start docker

sudo systemctl enable docker

One last test to check all is well:

sudo docker run --rm -ti ubuntu:latest /bin/bash

Connect the Windows Docker client to the Ubuntu Docker server

This requires that you are able to ssh to the remote host (Ubuntu server) and sudo without entering a password:

Run and look at output from:

C:\Windows\System32\OpenSSH\ssh.exe

If it is not set up already then run C:\Windows\System32\OpenSSH\ssh-keygen to generate a public key (id_rsa.pub) which is located in the same directory while the public key is stored in C:\Users\<user>\.ssh

Now add the contents of id_rsa.pub to authorized_keys in .ssh on the Ubuntu server using cat.

Once complete, you should be able to ssh to the Ubuntu server from the Windows client:

ssh pgroom@<IP of Ubuntu server>

and can log in without a password.

As Docker needs to be able to sudo without a password also do on the Ubuntu server:

sudo visudo

and add the below line to the file

{username} ALL=(ALL) NOPASSWD:ALL

To provision a remote Docker host machine

In a cmd window on the Windows 10 box

Go to C:\Program Files\Docker Toolbox

and run

docker-machine create --driver generic --generic-ip-address=<IP address of Ubuntu server> --generic-ssh-user=pgroom <hostname of Ubuntu server> where pgroom is an user on the Ubuntu server

docker-machine env <hostname of Ubuntu server>

Produces:

SET DOCKER_TLS_VERIFY=1

SET DOCKER_HOST=tcp://<IP address of Ubuntu server>:2376

SET DOCKER_CERT_PATH=C:\Users\net_k\.docker\machine\machines\remote-docker-host

SET DOCKER_MACHINE_NAME=<hostname of Ubuntu server>

SET COMPOSE_CONVERT_WINDOWS_PATHS=true

REM Run this command to configure your shell:

REM @FOR /f "tokens=*" %i IN ('docker-machine env remote-docker-host') DO @%i

then run this

@FOR /f "tokens=*" %i IN ('docker-machine env nklserv02') DO @%i

to check which machine connected to:

docker-machine ls

Finally, check all is ok on the Ubuntu server:

docker run ubuntu /bin/echo hello world

Some helpful hints/commands when operating Docker containers

Removing a Docker container

If a Docker container is no longer required then you can remove it by:

docker rmi <image id>

where the <image id> is part of the output from docker images command

or by:

docker-machine rm <hostname of Ubuntu server>

Debugging a Docker container

To debug and get to a shell inside the container do (assuming it was started by something like the below):

docker run -d -t ubuntu /bin/bash

Can look for the container ID by running docker ps and looking for the command /bin/bash - in this case 5b8c64046b71 (or use the name if you gave the container one when you created it)

Then do

docker exec -t -i 5b8c64046b71 /bin/bash

and you get a prompt of

root@5b8c64046b71:/#

you can now debug the Docker container interactively

Creating and starting a Docker container

Below are the steps that I went through to create a Docker container that runs a simple Curl PHP script. It lists all recruitment agencies by UK county and is normally run as per below:

/usr/bin/php /home/pgroom/agencies.php Devon

Option 1 - interactive Bash shell

docker run --name=curl -d -v -i /home/pgroom:/home ubuntu:latest /bin/bash

However the name has to be unique so can't have 2 containers with the same name, even if one is stopped

Option 2 - Using a Dockerfile then run a machine that runs curl and exits

This is the Dockerfile

FROM ubuntu:latest

RUN apt-get update && \

apt-get install -y tzdata

RUN ln -fs /usr/share/zoneinfo/Europe/London /etc/localtime

RUN dpkg-reconfigure --frontend noninteractive tzdata

RUN apt-get install -y php && \

apt-get install -y curl

COPY agencies.php /home/pgroom

Then build the image

docker build -t jrncurl:0.1 "C:\Program Files\Docker Toolbox\dockerfiles"

where C:\Program Files\Docker Toolbox\dockerfiles is the directory that has the Dockerfile listed above and note the lowercase for the tag.

Although php install needs to know which country and city in order to proceed as it used tzdata so need to put 2 extra lines, one for /etc/localtime and the other for dpkg-reconfigure

The last couple of lines look something like this:

Removing intermediate container 4fb2c32171b3

---> 82df8e0dd07d

Successfully built 82df8e0dd07d

Now need to start a container based on the build so:

docker run -it jrncurl:0.1 /bin/bash

Problem: Can't access the file system so can't get to agencies.php

Tried to copy the script but no luck as could not find the file agencies.php

COPY failed: stat /var/lib/docker/tmp/docker-builder658320030/agencies.php: no such file or directory

Found a copy command that worked but this generates an error as it is outside of the Docker context i.e. directory

COPY ../../../../../home/pgroom/agencies.php /home/agencies.php

In the end, had to copy agencies.php to C:\Program Files\Docker Toolbox\dockerfiles

Then run:

docker build -t jrncurl:0.6 "C:\Program Files\Docker Toolbox\dockerfiles"

This now builds the image but need to remember that the file has to be in the same directory as the Dockerfile.

Now need to start a container based on the build so:

docker run -it jrncurl:0.6 /bin/bash

Can now run the below and get the results back

/usr/bin/php /home/pgroom/agencies.php Devon

Hopefully the above will be of use to someone and from one engineer to another, good luck with whatever you are building. I have written similar posts to this on Ansible, Selenium & Python and php & curl that might be helpful, particularly around the use of OpenSSH on Windows devices.

All the best.

Pete