Installing docker-machine on Raspberry PI

One of the nicest things about docker is reproducibility and containerisation. It is possible to run multiple applications which requires different environment on the same computer and make them live happily altogether. Although Raspberry Pi has ARMv7 instructions set, we still can run docker on it - we just need different images. One would be surprised there are some official images available on docker hub.

The configuration can be very simple - literally two commands in terminal, thanks to widely available devops tools such as docker-machine and ansible. Having this setup there won't be need to login to the RPi and perform any manual configuration per service anymore. Instead, services can be configured and deployed right from your computer.

If you don't have your Rasbperry configured yet refer to previous article for the initial setup.

Copy ssh key

To allow login without password using ssh key we need to transfer it to the RPi. This step can be skipped if it was done before.

Assuming that your pi is running with default login pi and password raspberry run this command and put password:

ssh-copy-id pi@192.168.42.111

Provisioning

There are some prerequiests for your local machine:

Get the playbook I've created:

And simply run

ansible-playbook provision-rpi.yml -i 192.168.42.111, --extra-vars "machine_name=myrpi"

Replacing IP address with your RPi location. Also, note that comma(,) at the end of the address is mandatory! Local name of the docker-machine can be configured via machine_name variable, in the example it set to myrpi

First run can take some time, be patient.

This playbook is updating packages on your RPi, temporary monkey patching name of the OS, installs docker-machine and revert back changes of the name. Since ansible playbook is describing the final state there is no sin of running this playbook again - nothing will break. Be aware that you might want to remove existing docker-machine if it already exists or give it an another name

Sample output:

➜  ansible-playbook provision-rpi.yml -i 192.168.42.111, --extra-vars "machine_name=myrpi"

PLAY [RPi initial provisioner] ************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************
ok: [192.168.42.111]

TASK [Remembering target host information] ************************************************************************************************************************
ok: [192.168.42.111]

TASK [Upgrade packages] *******************************************************************************************************************************************
 [WARNING]: Could not find aptitude. Using apt-get instead

ok: [192.168.42.111]

TASK [Check what the new version is] ******************************************************************************************************************************
changed: [192.168.42.111]

TASK [Temporary monkey-patching os-release] ***********************************************************************************************************************
changed: [192.168.42.111]

TASK [Running docker-machine against 192.168.42.111] ***************************************************************************************************************
changed: [192.168.42.111 -> localhost]

TASK [Reverting OS name back in os-release] ***********************************************************************************************************************
changed: [192.168.42.111]

PLAY RECAP ********************************************************************************************************************************************************
192.168.42.111              : ok=7    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Done!

Let's try to run something against that docker on freshly backed pi

To make our docker client to run against the remote RPi daemon we must setup environment variables. It should be executed only once per session before any docker commands

➜ eval $(docker-machine env myrpi)

Let's see what version of the docker we are running:

➜  docker version
. . . . .
Server: Docker Engine - Community
 Engine:
  Version:          19.03.5
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.12
  Git commit:       633a0ea
  Built:            Wed Nov 13 07:34:13 2019
  OS/Arch:          linux/arm

There are limited number of images available for arm32v7 on the docker hub. For demostration purposes I can run mediawiki:

➜  docker run  -p 9999:80 -d arm32v7/mediawiki
Unable to find image 'arm32v7/mediawiki:latest' locally
latest: Pulling from arm32v7/mediawiki
c4f8e1e649d2: Pull complete 
. . .  . . .
Status: Downloaded newer image for arm32v7/mediawiki:latest
0041a9fbf8d9a3bc85a337eafbbf50e135b77705e4d663c4bfd72771b8935426

➜  docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
22dfef415586        arm32v7/mediawiki   "docker-php-entrypoi…"   26 seconds ago      Up 23 seconds       0.0.0.0:9999->80/tcp   lucid_ramanujan

As expected mediawiki is available via network:

Conclusion

Just 2 commands enable us to deploy our applications in the docker in a snap!