Raspberry PI Zero (W)에 docker 설치
Synology NAS에 실습을 해 본 김에,
Synology NAS(DS216+II)에 docker 설치 후 .NET Core 2.1 응용 프로그램 실행하는 방법
; https://www.sysnet.pe.kr/2/0/11713
어차피 같은 Linux 계열 운영체제이니 이참에 가지고 있던 
Raspberry PI Zero 모델에 docker를 올려봤습니다. 물론, 상세한 문서가 이미 다음과 같이 공개되어 있습니다. ^^
Get Docker CE for Debian
; https://docs.docker.com/install/linux/docker-ce/debian/
중간에 "Install using the repository"에 보면 "Raspbian users cannot use this method!"라고 하면서 "
convenience script"를 사용하라고 합니다. 이름만큼이나... 정말 설치 방법이 간단한데 그냥 다음과 같이 실행해 주면 해당 스크립트 안에서 모든 작업을 알아서 해줍니다.
$ sudo -i
~# curl -sSL https://get.docker.com  | sh
# Executing docker install script, commit: 36b78b2
+ sh -c apt-get update -qq >/dev/null
+ sh -c apt-get install -y -qq apt-transport-https ca-certificates curl >/dev/null
+ 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)
+ sh -c echo "deb [arch=armhf] https://download.docker.com/linux/raspbian stretch edge" > /etc/apt/sou                          docker.list
+ [ raspbian = debian ]
+ sh -c apt-get update -qq >/dev/null
+ sh -c apt-get install -y -qq --no-install-recommends docker-ce >/dev/null
+ sh -c docker version
Client:
 Version:           18.06.1-ce
 API version:       1.38
 Go version:        go1.10.3
 Git commit:        e68fc7a
 Built:             Tue Aug 21 17:30:52 2018
 OS/Arch:           linux/arm
 Experimental:      false
Server:
 Engine:
  Version:          18.06.1-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.3
  Git commit:       e68fc7a
  Built:            Tue Aug 21 17:26:37 2018
  OS/Arch:          linux/arm
  Experimental:     false
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 your-user
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.
끝입니다. ^^ 단지, 메시지에 보이는 데로 docker 명령어는 원래 sudo 권한으로 실행해야 하는데 "usermod -aG docker [사용자계정]"으로 추가한 계정에 대해서는 sudo를 붙이지 않아도 docker 명령어를 사용할 수 있으니 원한다면 (편의상) 그렇게 해줍니다.
그런데 라즈베리 파이 제로의 CPU가 armv6l 기반이라서,
$ uname -a
Linux rasp01 4.14.73+ #1148 Mon Oct 1 16:41:23 BST 2018 armv6l GNU/Linux
적절한 docker 이미지를 찾는 것이 쉽지 않습니다. 가령, arm 계열을 위한 hello-world 예제인 듯 보이는 이미지를 실행해도,
$ docker run armhf/hello-world
$
보는 바와 같이 아무런 출력이 없고 container는 그냥 종료된 상태입니다. 검색해 보면 다음의 (답변 없는) 상황과 일치합니다.
Docker run does not display any output
; https://stackoverflow.com/questions/52233182/docker-run-does-not-display-any-output
Rasberry PI Zero도 다음의 명령어 결과로 봐서는 armhf이긴 한 것 같은데,
$ dpkg --print-architecture
armhf
좀 더 찾아 보면,
What is difference between arm64 and armhf?
; https://stackoverflow.com/questions/37790029/what-is-difference-between-arm64-and-armhf
armhf stands for "arm hard float", and is the name given to a debian port for arm processors (armv7+) that have hardware floating point support. 
armv7 이후의 모델에 해당한다고 합니다. Rasberry PI Zero의 경우 armv6l이기 때문에 아마도 armhf 접두사가 붙은 docker 이미지들은 실행을 못하는 것 같습니다. 검색해 보면, resin에서 배포하는 이미지들이 그나마 armv6에 대한 것들이 있는 데요,
C:> docker search "Raspberry"  --limit 100 --no-trunc
NAME                                          DESCRIPTION                                                                                           STARS               OFFICIAL            AUTOMATED
homeassistant/raspberrypi3-homeassistant                                                                                                            81
sdthirlwall/raspberry-pi-cross-compiler       Raspberry Pi cross-compiler and sysroot in a box.                                                     30                                      [OK]
resin/raspberrypi3-python                     The Python buildpack image for Python apps for Raspberry Pi 3. Maintained by Resin.io.                28
resin/raspberrypi3-debian                     The bare bones OS image for Raspberry Pi 3. Maintained by Resin.io.                                   20
sdt4docker/raspberry-pi-cross-compiler        Raspberry Pi cross-compiler in a box.                                                                 19                                      [OK]
resin/raspberrypi3-node                       Node.js is a JavaScript-based platform for server-side and networking apps. Maintained by Resin.io.   15
resin/raspberry-pi-alpine-node                Node.js is a JavaScript-based platform for server-side and networking apps. Maintained by Resin.io.   12
resin/raspberry-pi-python                     The Python buildpack image for Python apps for Raspberry Pi v1 & ZERO. Maintained by Resin.io.        11
resin/raspberry-pi-alpine                     The bare bones Alpine Linux OS image for Raspberry Pi v1 & ZERO. Maintained by Resin.io.              10
resin/raspberrypi2-node                       This repository is obsolete.                                                                          9
homeassistant/raspberrypi2-homeassistant                                                                                                            7
resin/raspberrypi2-python                     This repository is obsolete.                                                                          7
resin/raspberrypi3-alpine-python              The Python buildpack image for Python apps. Maintained by Resin.io.                                   7
resin/raspberrypi3-alpine                     The bare bones Alpine Linux OS image for Raspberry Pi 3. Maintained by Resin.io.                      6
resin/raspberry-pi2-python                    The Python buildpack image for Python apps for Raspberry Pi 2. Maintained by Resin.io.                5
resin/raspberrypi3-alpine-node                Node.js is a JavaScript-based platform for server-side and networking apps. Maintained by Resin.io.   5
resin/raspberrypi2-debian                     This repository is obsolete.                                                                          5
homeassistant/raspberrypi-homeassistant                                                                                                             5
resin/raspberry-pi-node                       Node.js is a JavaScript-based platform for server-side and networking apps. Maintained by Resin.io.   4
microsoft/iot-hub-c-raspberrypi-build         Includes toolchain for building Raspberry Pi C code                                                   4
resin/raspberrypi2-alpine                     This repository is obsolete.                                                                          4
resin/raspberrypi-node                        This repository is obsolete.                                                                          4
demosense/raspberrypi3-opencv                 Based on resin/raspberrypi3-python:3.6 installed opencv                                               4
resin/raspberry-pi-openjdk                    OpenJDK is an open-source implementation of the Java Platform, SE. Maintained by Resin.io.            3
resin/raspberry-pi-debian                     The bare bones OS image for Raspberry Pi v1 & ZERO. Maintained by Resin.io.                           3
homeassistant/raspberrypi3-64-homeassistant                                                                                                         3
resin/raspberrypi-buildpack-deps              This repository is obsolete.                                                                          3
resin/raspberrypi-python                      This repository is obsolete.                                                                          2
resin/raspberry-pi-golang                     Go (golang) is a general purpose, imperative programming language. Maintained by Resin.io.            2
resin/raspberrypi2-buildpack-deps             This repository is obsolete.                                                                          2
resin/raspberrypi2-alpine-node                This repository is obsolete.                                                                          2
resin/raspberry-pi3-python                    This repository is obsolete.                                                                          2
resin/raspberry-pi2-debian                    The bare bones OS image for Raspberry Pi 2. Maintained by Resin.io.                                   2
resin/raspberrypi-golang                      This repository is obsolete.                                                                          2
resin/raspberry-pi3-node                      This repository is obsolete.                                                                          1
resin/raspberrypi2-alpine-python              This repository is obsolete.                                                                          1
resin/raspberrypi2-golang                     This repository is obsolete.                                                                          1
resin/raspberry-pi-alpine-python              The Python buildpack image for Python apps. Maintained by Resin.io.                                   1
resin/raspberry-pi-alpine-golang              Go (golang) is a general purpose, imperative programming language. Maintained by Resin.io.            1
resin/raspberry-pi2-alpine-golang             Go (golang) is a general purpose, imperative programming language. Maintained by Resin.io.            1
resin/raspberrypi3-openjdk                    OpenJDK is an open-source implementation of the Java Platform, SE. Maintained by Resin.io.            1
resin/raspberry-pi2-alpine-node               Node.js is a JavaScript-based platform for server-side and networking apps. Maintained by Resin.io.   1
resin/raspberrypi-alpine-python               This repository is obsolete.                                                                          1
resin/raspberry-pi2-node                      Node.js is a JavaScript-based platform for server-side and networking apps. Maintained by Resin.io.   1
resin/raspberrypi3-alpine-openjdk             OpenJDK is an open-source implementation of the Java Platform, SE. Maintained by Resin.io.            1
resin/raspberry-pi2-openjdk                   OpenJDK is an open-source implementation of the Java Platform, SE. Maintained by Resin.io.            1
resin/raspberry-pi-alpine-openjdk             OpenJDK is an open-source implementation of the Java Platform, SE. Maintained by Resin.io.            1
resin/raspberry-pi2-alpine                    The bare bones Alpine Linux OS image for Raspberry Pi 2. Maintained by Resin.io.                      1
resin/raspberrypi3-buildpack-deps             A collection of common dependencies used for installing various modules. Maintained by Resin.io.      0
habridge/ha-bridge-raspberry-pi2              Docker image of ha-bridge (https://github.com/bwssytems/ha-bridge) specialized for Raspberry Pi 2     0
resin/raspberry-pi2-fedora-node               Node.js is a JavaScript-based platform for server-side and networking apps. Maintained by Resin.io.   0
resin/raspberrypi2-fedora-node                This repository is obsolete.                                                                          0
resin/raspberrypi3-fedora                     Docker builds of Fedora from Resin for Raspberry Pi 3. Maintained by Resin.io.                        0
resin/raspberrypi2-fedora-golang              This repository is obsolete.                                                                          0
resin/raspberrypi3-alpine-buildpack-deps      A collection of common dependencies used for installing various modules. Maintained by Resin.io.      0
resin/raspberry-pi2-fedora-golang             Go (golang) is a general purpose, imperative programming language. Maintained by Resin.io.            0
resin/raspberry-pi2-alpine-python             The Python buildpack image for Python apps. Maintained by Resin.io.                                   0
resin/raspberry-pi3-golang                    This repository is obsolete.                                                                          0
jekotia/resin-raspberrypi3-alpine-node        resin-raspberrypi3-alpine-node                                                                        0                                       [OK]
resin/raspberry-pi2-fedora                    Docker builds of Fedora from Resin for Raspberry Pi 2. Maintained by Resin.io.                        0
resin/raspberrypi3-fedora-python              The Python buildpack image for Python apps. Maintained by Resin.io.                                   0
resin/raspberrypi2-alpine-buildpack-deps      This repository is obsolete.                                                                          0
resin/raspberry-pi2-buildpack-deps            A collection of common dependencies used for installing various modules. Maintained by Resin.io.      0
resin/raspberrypi3-fedora-golang              Go (golang) is a general purpose, imperative programming language. Maintained by Resin.io.            0
resin/raspberrypi-openjdk                     This repository is obsolete.                                                                          0
resin/raspberrypi3-fedora-buildpack-deps      A collection of common dependencies used for installing various modules. Maintained by Resin.io.      0
resin/raspberry-pi-alpine-buildpack-deps      A collection of common dependencies used for installing various modules. Maintained by Resin.io.      0
resin/raspberrypi-alpine-golang               This repository is obsolete.                                                                          0
resin/raspberry-pi2-alpine-openjdk            OpenJDK is an open-source implementation of the Java Platform, SE. Maintained by Resin.io.            0
resin/raspberrypi-alpine-buildpack-deps       This repository is obsolete.                                                                          0
resin/raspberry-pi2-alpine-buildpack-deps     A collection of common dependencies used for installing various modules. Maintained by Resin.io.      0
resin/raspberrypi2-alpine-golang              This repository is obsolete.                                                                          0
resin/raspberry-pi3-alpine-node               This repository is obsolete.                                                                          0
resin/raspberry-pi-buildpack-deps             A collection of common dependencies used for installing various modules. Maintained by Resin.io.      0
resin/raspberrypi3-fedora-node                Node.js is a JavaScript-based platform for server-side and networking apps. Maintained by Resin.io.   0
resin/raspberrypi2-alpine-openjdk             This repository is obsolete.                                                                          0
resin/raspberry-pi2-golang                    Go (golang) is a general purpose, imperative programming language. Maintained by Resin.io.            0
resin/raspberry-pi3-alpine-golang             This repository is obsolete.                                                                          0
resin/raspberrypi3-fedora-openjdk             OpenJDK is an open-source implementation of the Java Platform, SE. Maintained by Resin.io.            0
resin/raspberrypi-alpine-node                 This repository is obsolete.                                                                          0
resin/raspberrypi2-fedora-python              This repository is obsolete.                                                                          0
resin/raspberry-pi2-fedora-buildpack-deps     A collection of common dependencies used for installing various modules. Maintained by Resin.io.      0
resin/raspberrypi-alpine                      This repository is obsolete.                                                                          0
resin/raspberry-pi3-alpine-python             This repository is obsolete.                                                                          0
resin/raspberry-pi2-fedora-python             The Python buildpack image for Python apps. Maintained by Resin.io.                                   0
habridge/ha-bridge-raspberrypi3               Docker image of ha-bridge (https://github.com/bwssytems/ha-bridge) specialized for Raspberry Pi 3     0
resin/raspberrypi2-fedora-buildpack-deps      This repository is obsolete.                                                                          0
eyigitoglu/raspberrypitest                                                                                                                          0
resin/raspberrypi3-alpine-golang              Go (golang) is a general purpose, imperative programming language. Maintained by Resin.io.            0
resin/raspberrypi3-golang                     Go (golang) is a general purpose, imperative programming language. Maintained by Resin.io.            0
resin/raspberrypi2-openjdk                    This repository is obsolete.                                                                          0
resin/raspberrypi2-fedora                     This repository is obsolete.                                                                          0
raspberrypython/noddyws                       A noddy web server serving a blank html page with a random background color                           0                                       [OK]
gbevin/raspberry-ci                           Raspbian Jessie image for running Continuous Integration UI tests with Docker on a Raspberry PI.      0
resin/raspberrypi2-fedora-openjdk             This repository is obsolete.                                                                          0
resin/raspberry-pi2-ubuntu-node                                                                                                                     0
jekotia/resin-raspberrypi3-debian             resin-raspberrypi3-debian                                                                             0                                       [OK]
resin/raspberry-pi2-fedora-openjdk            OpenJDK is an open-source implementation of the Java Platform, SE. Maintained by Resin.io.            0
resin/raspberrypi3-ubuntu-node                                                                                                                      0
resin/raspberry-pi3-alpine-openjdk            This repository is obsolete.                                                                          0
실제로 "The bare bones OS image for Raspberry Pi v1 & ZERO. Maintained by Resin.io."라고 하는 "resin/raspberry-pi-debian" 이미지를,
resin/raspberry-pi-debian
; https://hub.docker.com/r/resin/raspberry-pi-debian/
실행해 보면,
$ docker run --rm resin/raspberry-pi-debian echo Test
Test
$
저렇게 결과가 출력되는 것을 확인할 수 있습니다.
그렇다면 혹시 .NET Core 응용 프로그램을 실행해 볼 수 있을까요? docker는 CPU의 명령어까지 가상화하는 수준은 아니므로 docker image에 포함된 바이너리 역시 docker 환경이 실행되는 CPU의 제약을 받습니다. .NET Core의 경우 ARM 버전에 포팅된 것이,
.NET Core on Raspberry Pi
; https://github.com/dotnet/core/blob/master/samples/RaspberryPiInstructions.md
armv7 CPU의 명령어 셋을 내포하기 때문에 docker를 이용해도 .NET Core 응용 프로그램을 실행할 수 없습니다.
참고로, docker를 라즈베리 파이가 지원하지 않는 CPU 버전으로 설치하는 경우 다음과 같은 식의 오류가 발생합니다.
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"
Traceback (most recent call last):
  File "/usr/bin/add-apt-repository", line 95, in <module>
    sp = SoftwareProperties(options=options)
  File "/usr/lib/python3/dist-packages/softwareproperties/SoftwareProperties.py", line 109, in __init__
    self.reload_sourceslist()
  File "/usr/lib/python3/dist-packages/softwareproperties/SoftwareProperties.py", line 599, in reload_sourceslist
    self.distro.get_sources(self.sourceslist)
  File "/usr/lib/python3/dist-packages/aptsources/distro.py", line 89, in get_sources
    (self.id, self.codename))
aptsources.distro.NoDistroTemplateException: Error: could not find a distribution template for Raspbian/stretch
또한, "
Get Docker CE for Debian" 공식 문서에 나온 "https://get.docker.com"의 script가 아니라 "https://download.docker.com/linux/debian"으로부터 "apt-get install docker-ce" 명령어로 직접 설치하려는 경우 다음과 같은 식의 설치 오류가 발생합니다.
$ sudo apt-get -y install docker-ce
Reading package lists... Done
Building dependency tree
Reading state information... Done
docker-ce is already the newest version (18.06.1~ce~3-0~debian).
0 upgraded, 0 newly installed, 0 to remove and 9 not upgraded.
1 not fully installed or removed.
After this operation, 0 B of additional disk space will be used.
Setting up docker-ce (18.06.1~ce~3-0~debian) ...
Job for docker.service failed because a fatal signal was delivered causing the control process to dump core.
See "systemctl status docker.service" and "journalctl -xe" for details.
invoke-rc.d: initscript docker, action "start" failed.
 docker.service - Docker Application Container Engine
   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
   Active: activating (auto-restart) (Result: core-dump) since Wed 2018-10-03 12:36:15 KST; 191ms ago
     Docs: https://docs.docker.com
  Process: 3636 ExecStart=/usr/bin/dockerd -H fd:// (code=dumped, signal=SEGV)
 Main PID: 3636 (code=dumped, signal=SEGV)
      CPU: 546ms
Oct 03 12:36:15 rasp01 systemd[1]: docker.service: Unit entered failed state.
Oct 03 12:36:15 rasp01 systemd[1]: docker.service: Failed with result 'core-dump'.
Oct 03 12:36:16 rasp01 systemd[1]: docker.service: Service hold-off time over, scheduling restart.
Oct 03 12:36:16 rasp01 systemd[1]: Stopped Docker Application Container Engine.
dpkg: error processing package docker-ce (--configure):
 subprocess installed post-installation script returned error exit status 1
Errors were encountered while processing:
 docker-ce
E: Sub-process /usr/bin/dpkg returned an error code (1)
journalctl 명령어로 보면 다음과 같은 로그만 있을 뿐입니다.
$ journalctl -u docker.service
Oct 03 13:14:35 rasp01 systemd[1]: docker.service: Main process exited, code=dumped, status=11/SEGV
Oct 03 13:14:35 rasp01 systemd[1]: Failed to start Docker Application Container Engine.
Oct 03 13:14:35 rasp01 systemd[1]: docker.service: Unit entered failed state.
Oct 03 13:14:35 rasp01 systemd[1]: docker.service: Failed with result 'core-dump'.
Oct 03 13:14:35 rasp01 systemd[1]: docker.service: Service hold-off time over, scheduling restart.
Oct 03 13:14:35 rasp01 systemd[1]: Stopped Docker Application Container Engine.
Oct 03 13:14:35 rasp01 systemd[1]: docker.service: Start request repeated too quickly.
Oct 03 13:14:35 rasp01 systemd[1]: Failed to start Docker Application Container Engine.
Oct 03 13:14:35 rasp01 systemd[1]: docker.service: Unit entered failed state.
Oct 03 13:14:35 rasp01 systemd[1]: docker.service: Failed with result 'core-dump'.
armhf에 대해 좀 더 찾아 보니,
2.1. 지원하는 하드웨어
; https://www.debian.org/releases/jessie/armhf/ch02s01.html.ko
다음과 같은 설명이 있습니다.
- 데비안/armel은 오래된 32비트 ARM 프로세서로 하드웨어 부동 소수점 기능(FPU)이 없는 프로세서이고,
 
- 데비안/armhf는 최소한 ARMv7 아키텍쳐를 구현하고 ARM vector floating point specification의 버전3를(VFPv3) 구현한 최근의 ARM 프로세서에서만 동작합니다. 이 모델의 프로세서에 들어 있는 확장된 기능을 사용하므로 성능이 높습니다.
 
- 데비안/arm64는 최소한 ARMv8 아키텍쳐를 구현한 64비트 ARM 프로세서입니다.
 
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]