GitHubで公開されているEMLinux 3.1にDockerをインストールしてみた

# はじめに
- EMLinux 3.1にDockerをインストールし、NGINXのコンテナを動かしてみました。
- 本記事では、GitHubのリポジトリで公開されているEMLinuxを使用しました。
  - [meta-emlinux](https://github.com/miraclelinux/meta-emlinux/tree/bookworm)
    - なお、こちらは製品版ではないので、商用サポートはありません。

# 構成図
```
+--------------------------------+
| +----------------------------+ |
| | +------------------------+ | |
| | | +--------------------+ | | |
| | | | +----------------+ | | | |
| | | | | NGINX          | | | | |
| | | | +----------------+ | | | |
| | | | Docker             | | | |
| | | +--------------------+ | | |
| | |  EMLinux 3.1           | | |
| | +------------------------+ | |
| | QEMU                       | |
| +-+--------------------------+ |
|   |                            |
| +-+----+                       |
| | tap0 |                       |
| +-+----+                       |
|   |                            |
| +-+----------------------+     |
| | virbr0 (192.168.122.1) |     |
| +------------------------+     |
|                                |
| Ubuntu Server                  |
+--------------------------------+
```

# 各ソフトウェアのバージョン
## Ubuntu Server
```
$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.6 LTS"
```

## QEMU
```
$ qemu-system-aarch64 --version 
QEMU emulator version 4.2.1 (Debian 1:4.2-3ubuntu6.28)
Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers
```
# EMLinuxのビルドに必要なパッケージのインストール
1. 以下の記事を参考に、EMLinuxのビルドに必要なパッケージをインストールしてください。
   - [DockerおよびDocker Comoseのインストール](https://qiita.com/fukunagt/items/117bbe20a14584320edc#docker%E3%81%8A%E3%82%88%E3%81%B3docker-comose%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)
   - [qemu-user-staticのインストール](https://qiita.com/fukunagt/items/117bbe20a14584320edc#qemu-user-static%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)

# meta-emlinuxリポジトリのクローン
1. meta-emlinuxのリポジトリのクローン先のディレクトリを作成してください。
   ```sh
   mkdir -p /home/emlinux/github/emlinux/bookworm/docker/repos
   ```
1. 以下のディレクトリに移動してください。
   ```sh
   cd /home/emlinux/github/emlinux/bookworm/docker
   ```
1. 以下の記事を参考に、meta-emlinuxのリポジトリをクローンしてください。
   - [meta-emlinuxリポジトリのクローン](https://qiita.com/fukunagt/items/117bbe20a14584320edc#qemu-user-static%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)

# カスタムレイヤーの作成
1. 以下のディレクトリに移動してください。
   ```sh
   cd /home/emlinux/github/emlinux/bookworm/docker/repos
   ```
1. 以下のディレクトリを作成してください。
   ```
   meta-custom/
   ├── conf
   │   └── layer.conf
   ├── COPYING.MIT
   ├── README
   └── recipes-docker
       ├── configure-docker
       │   ├── configure-docker.bb
       │   └── files
       │       ├── http-proxy.conf
       │       └── postinst
       └── images
           └── emlinux-image-base.bbappend   
   ```
   - layer.conf
     ```
     #
     # layer profile
     #

     BBPATH .= ":${LAYERDIR}"

     BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
             ${LAYERDIR}/recipes-*/*/*.bbappend"

     BBFILE_COLLECTIONS += "custom"
     BBFILE_PATTERN_custom = "^${LAYERDIR}/"
     BBFILE_PRIORITY_custom = "30"

     LAYERSERIES_COMPAT_custom = "next"

     LAYERDIR_custom = "${LAYERDIR}"     
     ```
   - COPYING.MIT
     - 以下のファイルをコピーしてください。
       - https://github.com/miraclelinux/meta-emlinux/blob/warrior/COPYING.MIT
   - README
     ```
     # This directory contains the files to install Docker on EMLinux.
     ```
   - configure-docker.bb
     ```
     FILESEXTRAPATHS:prepend := "${FILE_DIRNAME}/files:"

     DESCRIPTION = "Setup script for Docker"

     DEBIAN_DEPENDS = "docker.io"

     inherit dpkg-raw

     SRC_URI = " \
         file://postinst \
         file://http-proxy.conf \
     "

     do_install() {
         install -v -d ${D}/etc/systemd/system/docker.service.d
         install -v -m 644 ${WORKDIR}/http-proxy.conf ${D}/etc/systemd/system/docker.service.d/
     }
     ```
   - http-proxy.conf
     ```
     [Service]
     Environment="HTTP_PROXY=<proxyサーバのIPアドレス>:<ポート番号>"
     Environment="HTTPS_PROXY=<proxyサーバのIPアドレス>:<ポート番号>"
     ```
   - postinst
     ```
     #!/bin/sh
     systemctl enable docker
     update-alternatives --set iptables /usr/sbin/iptables-legacy
     ```
   - emlinux-image-base.bbappend
     ```
     # Add packages for Docker
     IMAGE_PREINSTALL:append = " \
         ca-certificates \
         connman \
         docker.io \
     "
     ```


# EMLinuxのビルド
1. meta-emlinux/dockerに移動し、run.shを実行してください。
   ```sh
   cd /home/emlinux/github/emlinux/bookworm/docker/repos/meta-emlinux/docker
   ```
   ```sh
   ./run.sh
   ```
1. コンテナにログイン後、環境変数を設定してください。
   ```sh
   source repos/meta-emlinux/scripts/setup-emlinux build 
   ```
1. viコマンドで、conf/bblayers.confの末尾に以下を追記してください。
   ```
   BBLAYERS += "${TOPDIR}/../repos/meta-custom"
   ```
1. meta-customレイヤーが追加されていることを確認してください。
   ```
   $ bitbake-layers show-layers
   NOTE: Starting bitbake server...
   layer                 path                                      priority
   ==========================================================================
   meta                  /home/build/work/build/../repos/isar/meta  5
   meta-emlinux          /home/build/work/build/../repos/meta-emlinux  12
   isar-cip-core         /home/build/work/build/../repos/isar-cip-core  6
   meta-custom           /home/build/work/build/../repos/meta-custom  30
   ```
1. viでconf/local.confを開き、末尾に以下を追記してください。
   ```
   # ARM64
   MACHINE = "qemu-arm64"
   
   # Setup for Docker
   IMAGE_INSTALL:append = " configure-docker"

   # Extra space for rootfs in MB
   ROOTFS_EXTRA = "10240"   
   ```
1. EMLinuxをビルドしてください。
   ```sh
   bitbake emlinux-image-base
   ```
1. ビルド完了後、exitコマンドでコンテナからログアウトしてください。
   ```
   build@82fa043f8378:~/work$ exit 
   exit
   ```

# tap0の作成
1. 以降の作業はsudo権限があるユーザで行ってください。
1. 仮想ブリッジvirbrを有効化するため、libvirt-daemon-systemをインストールしてください。
   ```sh
   sudo apt install libvirt-daemon-system
   ```
1. 以下のコマンドを実行し、tap0を作成してください。
   ```sh
   sudo ip tuntap add tap0 mode tap
   ```
   ```sh
   sudo ip link set tap0 promisc on
   ```
   ```sh
   sudo ip link set dev tap0 master virbr0
   ```
   ```sh
   sudo ip link set dev tap0 up
   ```   

# EMLinuxの起動
1. 以下のディレクトリに移動してください。
   ```sh
   cd /home/emlinux/github/emlinux/bookworm/docker/build
   ```
1. run.shファイルを作成してください。
   ```sh
   touch run.sh
   ```
   ```sh
   chmod +x run.sh
   ```
1. vimでrun.shファイルを以下のように編集してください。
   ```
   qemu-system-aarch64 \
   -net nic \
   -net tap,ifname=tap0,script=no \
   -drive id=disk0,file=./tmp/deploy/images/qemu-arm64/emlinux-image-base-emlinux-bookworm-qemu-arm64.ext4,if=none,format=raw \
   -device virtio-blk-device,drive=disk0 -show-cursor -device VGA,edid=on \
   -device qemu-xhci \
   -device usb-tablet \
   -device usb-kbd \
   -object rng-random,filename=/dev/urandom,id=rng0 \
   -device virtio-rng-pci,rng=rng0 \
   -nographic \
   -machine virt \
   -cpu cortex-a57 \
   -m 2G \
   -serial mon:stdio \
   -serial null \
   -kernel ./tmp/deploy/images/qemu-arm64/emlinux-image-base-emlinux-bookworm-qemu-arm64-vmlinux \
   -initrd ./tmp/deploy/images/qemu-arm64/emlinux-image-base-emlinux-bookworm-qemu-arm64-initrd.img \
   -append 'root=/dev/vda rw highres=off console=ttyS0 mem=2G ip=dhcp console=ttyAMA0'
   ```
1. suコマンドで、sudo権限があるユーザに切り替えてください。
1. run.shを実行してください。
   ```sh
   sudo ./run.sh
   ```
   - パスワードを問われる場合には、sudo権限があるユーザのパスワードを入力してください。
1. rootユーザでログインしてください。既定のパスワードはrootです。
   ```
   EMLinux3 login: root
   Password: 
   ```
1. IPアドレスが割り振られていることを確認してください。
   ```
   root@EMLinux3:~# ip a
   (snip)
   2: enp0s1: <BROADCAST,MULTICAST,DYNAMIC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.77/24 metric 1024 brd 192.168.122.255 scope global dynamic enp0s1
       valid_lft 3523sec preferred_lft 3523sec
   (snip)
   ```
1. コンテナイメージの検索が行えるか確認してください。
   ```
   root@EMLinux3:~# docker search nginx 
   NAME                                              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
   nginx                                             Official build of Nginx.                        19768     [OK]       
   (snip)
   ```
1. 以下のコマンドを実行し、NGINXのコンテナを起動してください。
   ```sh
   docker run -it -d --name nginx-test -p 80:80 nginx:latest
   ```
1. コンテナホストからcurlコマンドで、NGINXにアクセスできることを確認してください。
   ```
   $ curl 192.168.122.77 --noproxy 192.168.122.77
   <!DOCTYPE html>
   <html>
   <head>
   <title>Welcome to nginx!</title>
   (snip)
   ```

# さいごに
EMLinux 3.1のレシピをカスタマイズし、Dockerをインストールしてみました。また、`docker run`でNGINXのコンテナイメージを使い、Webサーバを起動してみました。

ただ、組み込み機器では、わざわざ組み込み機器にログインし、`docker run`などを実行することはないため、Webサーバ経由などで外部から任意のコマンドを実行できるような仕組みが必要と考えていますが、それはまた別の記事で。

# 補足
## Dockerを動作させるために必要なパッケージについて
- Dockerはiptablesに依存しています。また、iptablesを利用するために、`update-alternatives --set iptables /usr/sbin/iptables-legacy`を実行しています。
  - https://gist.github.com/peteristhegreat/4bcbca81ed68605e36cf56bb0fff2960
- `docker pull`など外部との通信を行うために、ca-certificatesをインストールしています。

## ROOTFS_EXTRAについて
- コンテナを保存するために、ディスクサイズを拡張しています。既定では64 MBが指定されています。本記事では、ROOTFS_EXTRA = "10240"をlocal.confに設定しています。
  - https://github.com/ilbers/isar/blob/master/meta/classes/image.bbclass#L85

## カスタムレイヤーの作成について
[上述の手順](#カスタムレイヤーの作成)の場合、ディレクトリやファイルを作成していただく必要があります。

同手順を[GitHub](https://github.com/takaaki-fukunaga/EMLinux/blob/main/doc/jp/Install-Docker-on-EMLinux31_jp.md)にも掲載しております。GitHubの手順はlayerをダウンロードする手順となっています。上述の手順で「ディレクトリやファイルの作成が面倒だなぁ…」と思われた方は、GitHubに記載の手順をご利用ください。