DEV Community

Cover image for Install and Deploy Docker in Raspberry Pi
Project-42
Project-42

Posted on

Install and Deploy Docker in Raspberry Pi

Im not going to talk too much about benefits of Docker or any Container Engines around, there is already too many good guides you can check to see why is so important to learn about Docker and what you can achieve with it.

In this case, we will start using Docker in our lovely Raspberry Pi, so it is not the fastest system, but is always nice to know what you can achieve with this cheap system available for everybody.

The main mission on this first Docker project will be simulate couple of Ubuntu servers we can later use for small Ansible projects in our Raspberry Pi

Lets start!!

Like I was mentioning earlier, we are using a small Raspberry Pi 2:

Linux raspi-2 4.19.97-v7+ #1294 SMP Thu Jan 30 13:15:58 GMT 2020 armv7l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Feb  7 15:10:01 2020 from 192.168.0.21
    .',;:cc;,'.    .,;::c:,,.    P-42@raspi-2
   ,ooolcloooo:  'oooooccloo:    OS: Raspbian 10 buster
   .looooc;;:ol  :oc;;:ooooo'    Kernel: armv7l Linux 4.19.97-v7+
     ;oooooo:      ,ooooooc.     Uptime: 4d 23h 1m
       .,:;'.       .;:;'.       Packages: 635
       .... ..'''''. ....        Shell: 25900
     .''.   ..'''''.  ..''.      WM: Not Found
     ..  .....    .....  ..      CPU: ARMv7 rev 5 (v7l) @ 4x 900MHz
    .  .'''''''  .''''''.  .     GPU: BCM2708
  .'' .''''''''  .'''''''. ''.   RAM: 193MiB / 926MiB
  '''  '''''''    .''''''  '''
  .'    ........... ...    .'.
    ....    ''''''''.   .''.
    '''''.  ''''''''. .'''''
     '''''.  .'''''. .'''''.
      ..''.     .    .''..
            .'''''''
             ......
P-42@raspi-2:~#
'

Installing Docker

To Install Docker, instead of using your Distro package manager, use the following script from docker.com to make sure you are getting latest version:

P-42@raspi-2:~#curl -sSL https://get.docker.com | sh
# Executing docker install script, commit: f45d7c11389849ff46a6b4d94e0dd1ffebca32c1
+ sudo -E sh -c apt-get update -qq >/dev/null
+ sudo -E sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -qq apt-transport-https ca-certificates curl >/dev/null
+ sudo -E sh -c curl -fsSL "https://download.docker.com/linux/raspbian/gpg" | apt-key add -qq - >/dev/null
Warning: apt-key output should not be parsed (stdout is not a terminal)
+ sudo -E sh -c echo "deb [arch=armhf] https://download.docker.com/linux/raspbian buster stable" > /etc/apt/sources.list.d/docker.list
+ sudo -E sh -c apt-get update -qq >/dev/null
+ [ -n  ]
+ sudo -E sh -c apt-get install -y -qq --no-install-recommends docker-ce >/dev/null
+ sudo -E sh -c docker version
Client: Docker Engine - Community
 Version:           19.03.5
 API version:       1.40
 Go version:        go1.12.12
 Git commit:        633a0ea
 Built:             Wed Nov 13 07:37:22 2019
 OS/Arch:           linux/arm
 Experimental:      false

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:31:17 2019
  OS/Arch:          linux/arm
  Experimental:     false
 containerd:
  Version:          1.2.10
  GitCommit:        b34a5c8af56e510852c35414db4c1f4fa6172339
 runc:
  Version:          1.0.0-rc8+dev
  GitCommit:        3e425f80a8c931f88e6d94a8c831b9d5aa481657
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683
If you would like to use Docker as a non-root user, you should now consider
adding your user to the "docker" group with something like:

  sudo usermod -aG docker P-42

Remember that you will have to log out and back in for this to take effect!

WARNING: Adding a user to the "docker" group will grant the ability to run
         containers which can be used to obtain root privileges on the
         docker host.
         Refer to https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface
         for more information.
P-42@raspi-2:~/Docker#

In order to be able use Docker with our user and no root, lets add our user to the docker group

P-42@raspi-2:~#sudo usermod -aG docker P-42

Make sure you restart your user session so the changes are applied.

To test your installation, is good idea you execute the traditional hello-world build

P-42@raspi-2:~#docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1eda109e4da: Pull complete
Digest: sha256:4df8ca8a7e309c256d60d7971ea14c27672fc0d10c5f303856d7bc48f8cc17ff
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (arm32v7)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

P-42@raspi-2:~#

Docker Configuration

Lets create a folder for our projec where the different containers will be deployed.

P-42@raspi-2:~#mkdir Docker
mkdir: created directory 'Docker'
P-42@raspi-2:~#

Lets create now our first Dockerfile, which will setup our docker image for this first project.

This example, will make sure we create an image that will allow us to create containers based in Ubuntu which will have ssh access, python installed (so we can use Ansible on it) and will also add a new user to it, in case we want to try different things with different users in the future.

P-42@raspi-2:~/Docker#cat Dockerfile
# BUILD VERSION
FROM ubuntu:16.04

# INSTALL SSH AND PYTHON

RUN apt-get update && apt-get install -y openssh-server sshpass python-minimal software-properties-common
RUN apt-get update
RUN mkdir /var/run/sshd


#SET ROOT PASSWORD
RUN echo "root:Welcome1" | chpasswd

# ALLOW SSHLOGIN TO ROOT

RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd

ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile
EXPOSE 22
EXPOSE 80
CMD ["/usr/sbin/sshd", "-D"]

# CREATE USER P-42

RUN groupadd P-42 && useradd -ms /bin/bash -g P-42 P-42

# SET P-42 PASSWORD
RUN echo 'P-42:Welcome1' | chpasswd

# COPY HOST SSH KEY

ARG home=/home/P-42
RUN mkdir $home/.ssh
COPY /id_rsa.pub $home/.ssh/authorized_keys
RUN chown P-42:P-42 $home/.ssh/authorized_keys && \
    chmod 600 $home/.ssh/authorized_keys
P-42@raspi-2:~/Docker#

If you check latest part of the Dockerfile, you will notice we are making a copy of our user public ssh keys so we can connect to the containers using our ssh keys instead the user password.

In order to do that, make sure you have your Docker project directory

P-42@raspi-2:~/Docker#cp -pr $HOME/.ssh/id_rsa.pub .
'/home/P-42/.ssh/id_rsa.pub' -> './id_rsa.pub'
P-42@raspi-2:~/Docker#

Building Docker Image

Lets build our first image called "ansible" so we can later deploy our containers:

P-42@raspi-2:~/Docker#time docker build -t ansible .
Sending build context to Docker daemon  4.096kB
Step 1/18 : FROM ubuntu:16.04
16.04: Pulling from library/ubuntu
e60df59fb597: Downloading [===================>                               ]  14.99MB/38.85MB
99ba0251fafa: Download complete

[......]

Step 16/18 : RUN mkdir $home/.ssh
 ---> Running in df77faedd340
Removing intermediate container df77faedd340
 ---> cb582bdc36f4
Step 17/18 :COPY /id_rsa.pub $home/.ssh/authorized_keys
 ---> 572093ffb71c

real    11m21.811s
user    0m1.019s
sys 0m0.513s
P-42@raspi-2:~/Docker#

As you can see, we took around 10 minutes to get our image created.

Lets create our Docker network called "ANSIBLE"

P-42@raspi-2:~/Docker#docker network create --subnet=172.168.0.0/24 ANSIBLE
1f8498228e9578134ba203346b145ca4c5a4ecea85c932940ce8ffa200ff71ab
P-42@raspi-2:~/Docker#

Now, lets add the IP and hostnames of your container to your /etc/hosts so we get direct access to them

P-42@raspi-2:~/Docker#grep -i Ansible -A20 /etc/hosts
####### ANSIBLE #######

172.168.0.121   server1
172.168.0.122   server2
172.168.0.123   server3
172.168.0.124   server4

Deploying Docker Containers

We are now ready to deploy our container with our recently created "ansible" image

P-42@raspi-2:~/Docker#docker run --net ANSIBLE -h server1 --name server1 --ip 172.168.0.121 -t -d ansible
2f9c42ddd085234c305f1b90d00981ae5109812b654aa9a9bb59fb017ecd0c27
P-42@raspi-2:~/Docker#

and voila! we have our container created that allow us to connect using ssh and have python enabled to use Ansible

P-42@raspi-2:~/Docker#ssh server1
The authenticity of host 'server1 (172.168.0.121)' can't be established.
ECDSA key fingerprint is SHA256:RgpMp25wAJRBNiUTDkfO6MaEX83is1EYP2NaB4dvMpA.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'server1,172.168.0.121' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.19.97-v7+ armv7l)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

P-42@server1:~$

P-42@server1:~$ python3 --version
Python 3.5.2
P-42@server1:~$

Now, we can create our "little servers" with a simple loop as follow

P-42@raspi-2:~/Docker#for i in {1..4}; do docker run --net ANSIBLE -h server$i --name server$i --ip 172.168.0.12$i -t -d ansible; done
91a8331a300269fbb328c553836af187e0c44557c04123bcefb87268eb21b87e
f0ecab6a81e7650c8dcd251bf63da7fe79aac87a0cf463728d16db7765e7a8d0
7d4327d9ed0d7515664dcaf04cb232ded89b002996aab690f05740c0208b0713
3e6b458a42c2d58b1951797ebfa7675cc0da45d748471b78bf634fa40604d837
P-42@raspi-2:~/Docker#


P-42@raspi-2:~/Docker#docker ps
CONTAINER ID        IMAGE               COMMAND               CREATED              STATUS              PORTS               NAMES
3e6b458a42c2        ansible             "/usr/sbin/sshd -D"   58 seconds ago       Up 55 seconds       22/tcp, 80/tcp      server4
7d4327d9ed0d        ansible             "/usr/sbin/sshd -D"   About a minute ago   Up 58 seconds       22/tcp, 80/tcp      server3
f0ecab6a81e7        ansible             "/usr/sbin/sshd -D"   About a minute ago   Up About a minute   22/tcp, 80/tcp      server2
91a8331a3002        ansible             "/usr/sbin/sshd -D"   About a minute ago   Up About a minute   22/tcp, 80/tcp      server1
P-42@raspi-2:~/Docker#

P-42@raspi-2:~/Docker#ssh server4
The authenticity of host 'server4 (172.168.0.124)' can't be established.
ECDSA key fingerprint is SHA256:RgpMp25wAJRBNiUTDkfO6MaEX83is1EYP2NaB4dvMpA.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'server4,172.168.0.124' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.19.97-v7+ armv7l)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

P-42@server4:~$

To stop and delete all the containers, we can use the following:

P-42@raspi-2:~/Docker#docker container stop $(docker container ls -aq)
3e6b458a42c2
7d4327d9ed0d
f0ecab6a81e7
91a8331a3002
P-42@raspi-2:~/Docker#docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
3e6b458a42c2d58b1951797ebfa7675cc0da45d748471b78bf634fa40604d837
7d4327d9ed0d7515664dcaf04cb232ded89b002996aab690f05740c0208b0713
f0ecab6a81e7650c8dcd251bf63da7fe79aac87a0cf463728d16db7765e7a8d0
91a8331a300269fbb328c553836af187e0c44557c04123bcefb87268eb21b87e

Total reclaimed space: 293.6kB
P-42@raspi-2:~/Docker#

If you want to reclaim all the space and delete everything created so far, including Docker Network and Images, you can use the following

P-42@raspi-2:~/Docker#docker system prune -a
WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all images without at least one container associated to them
  - all build cache

Are you sure you want to continue? [y/N] y
Deleted Networks:
ANSIBLE

Deleted Images:
untagged: ubuntu:16.04
untagged: ubuntu@sha256:3f3ee50cb89bc12028bab7d1e187ae57f12b957135b91648702e835c37c6c971
untagged: ansible:latest
deleted: sha256:15d994fd0e7e8568004401b288bacf0d8656f373467acb35cc413157c991b876
deleted: sha256:7019b6089974020846d93a9588093b7dcf88fce59890f8ac2dfb89eade44cac1
[...]

Total reclaimed space: 255.9MB
P-42@raspi-2:~/Docker#

There you go, a simple tutorial about getting Docker working in Rasperry Pi

Top comments (2)

Collapse
 
djstuder profile image
djstuder

First...
Great tutorial! Thanks!!
Second... a quick question...

TL;DR Why is the first character of the username capitalized when it causes an error to be thrown and the username to be rejected?

Please correct me if I'm wrong. The question is purely from curiosity, and asked with great respect. (IE: don't get irritated, I'm just curious.)

In this tutorial, the username is "P-42".
In Raspberry Pi 'buster version 10', this causes an error to be thrown. Interestingly, the error offers not one, but TWO potential solutions if you really want to override the system. It's possible, yet risky, and not advised. Bad things may happen!


pi@Rpi4:~ $ sudo adduser P-42
adduser: Please enter a username matching the regular expression configured
via the NAME_REGEX configuration variable. Use the `--force-badname'

option to relax this check or reconfigure NAME_REGEX.

Even the override option of '--force-badname' indicates that a username with a capital letter as the first character may not be a good idea!

My question... is there any particular reason that a capital letter is/was used for the username "P-42" even though the system throws an error unless you make accommodations for using the preferred username that starts with a capital letter?

Possible reasons that come to mind...

Was it done with the intention of "Always remember this!" teaching opportunity similar to tree command to list files in Linux, which of course returns everything cause EVERYTHING is a file in Linux?

When I was diving deeper on a Linux class project I came across the following...
Try the tree command with the -Q option to show the names of files in double quotes

tree -a -L 4 -R -q -l -F -Q

Coming from a Windows background, I was surprised at the results!
You'll always remember that in Linux, everything is a file. EVERYTHING !!
(I had a great and inspirational Linux class professor! )

Maybe it's a lot of nothing from when Linux was developed, an unneeded and forgotten holdover from Unix?

Maybe it's a default regex expression that was used and never changed? (haven't looked at that possibility or details yet.)

Maybe because it makes for easier reading of the screen? I always wondered why the default Raspberry Pi username is "pi" and not "Pi" .

Maybe it's like overclocking... It may or may not work. Try it and see. If you do try it, we're setting a bit saying you did what we told you not to do, and your warranty will be void. If your system fries, it's your fault and your problem.
( although 2.14 GHz CPU does make my Pi 4 a pretty responsive device ! )

Just trying to understand the intent of making the first letter of the username a capital letter when it seemingly appears to be ill-advised to do so. (That reminds me... I need to get more liquid nitrogen. )

Appreciated any appropriate response or feedback.

Collapse
 
project42 profile image
Project-42

Hi! not sure why I never get comments notifications here :)

I'm not 100% sure about the user.. I have the feeling I just replaced my "real" username for P-42 just for the post :) but really went into a nice rabbit hole there!!, I love it.

So, the only reason to use P-42 was to match the Blog name... nothing else. Now I feel a bit guilty and I'm sure you feel disappointed.. but hey.. the idea was to create a blog and learn things, and I'm sure we both this.. so THANK YOU!!!