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

# はじめに
EMLinux 3.1にK3sをインストールし、NGINXのコンテナを動かしてみました。また、K3sをインストールしたEMLinux 3.1を、QEMUで動かしてみました。

# 構成図
## EMLinux 3.1のビルド時
```
+--------------------------------+
| +----------------------------+ |
| | +------------------------+ | |
| | | +--------------------+ | | |
| | | | Build EMLinux 3.1  | | | |
| | | +--------------------+ | | |
| | | Debian                 | | |
| | +------------------------+ | |
| | Docker                     | |
| +----------------------------+ |
| Ubuntu Server                  |
+--------------------------------+
```


## EMLinux 3.1の起動時
```
+--------------------------------+
| +----------------------------+ |
| | +------------------------+ | |
| | | +--------------------+ | | |
| | | | +----------------+ | | | |
| | | | | NGINX          | | | | |
| | | | +----------------+ | | | |
| | | | K3s                | | | |
| | | +--------------------+ | | |
| | |  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
```

## K3s
```
root@EMLinux3:~/k3s# ./k3s --version 
k3s version v1.30.0+k3s1 (14549535)
go version go1.22.2
```

# K3sのダウンロード
1. K3sをダウンロードしてください。本手順では、ARM64版のバイナリファイルを使用します。
   ```sh
   wget -q "https://github.com/k3s-io/k3s/releases/download/v1.30.0+k3s1/k3s-arm64" -O ./k3s
   ```
   - 最新のバージョンは以下で確認してください。
     - https://github.com/k3s-io/k3s/releases
1. ARM64版のバイナリファイルであることを確認してください。
   ```
   $ file k3s
   k3s: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, Go BuildID=sgjlNVCdbgJadT7Nkgnz/1shQ9VtPwZOY17U5jUlP/oi8kFs5uudpYa6XvT6if/if9gZ0XG95E6uODSd-34, stripped
   ```


# 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/k3s/repos
   ```
1. 以下のディレクトリに移動してください。
   ```sh
   cd /home/emlinux/github/emlinux/bookworm/k3s
   ```
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/k3s/repos
   ```
1. 以下のように、ディレクトリおよびファイルを作成してください。
   ```
   meta-custom/
   ├── conf
   │   ├── layer.conf
   │   └── machine
   │       └── qemu-arm64-k3s.conf
   ├── COPYING.MIT
   ├── README
   └── recipes-k3s
       ├── configure-k3s
       │   ├── configure-k3s.bb
       │   └── files
       │       ├── k3s
       │       ├── k3s.service
       │       ├── k3s.service.env
       │       └── postinst
       ├── images
       │   └── emlinux-image-base.bbappend
       └── linux
           ├── files
           │   └── qemu-arm64_k3s_defconfig
           └── linux-cip_%.bbappend
   ```
   - local.conf
     ```
     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}"
     ```
   - qemu-arm64-k3s.conf
     ```
     DISTRO_ARCH = "arm64"

     IMAGE_FSTYPES ?= "ext4"

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

     DESCRIPTION = "Setup script for K3s"

     DEBIAN_DEPENDS = "iptables"

     inherit dpkg-raw

     SRC_URI = " \
         file://k3s \
         file://k3s.service \
         file://k3s.service.env \
         file://postinst \
     "

     do_install() {
         install -v -d ${D}/etc/systemd/system
         install -v -m 755 ${WORKDIR}/k3s.service ${D}/etc/systemd/system/
         install -v -m 755 ${WORKDIR}/k3s.service.env ${D}/etc/systemd/system/
         install -v -d ${D}/root/
         install -v -m 755 ${WORKDIR}/k3s ${D}/root/
     }
     ```
   - k3s
     - [上記の手順](#k3sのダウンロード)でダウンロードしたバイナリファイルを置いてください。
   - k3s.service
     ```
     [Unit]
     Description=Lightweight Kubernetes
     Documentation=https://k3s.io

     [Service]
     Type=notify
     EnvironmentFile=-/etc/default/%N
     EnvironmentFile=-/etc/sysconfig/%N
     EnvironmentFile=-/etc/systemd/system/k3s.service.env
     ExecStart=/root/k3s server
     KillMode=process
     Delegate=yes
     # Having non-zero Limit*s causes performance problems due to accounting overhead
     # in the kernel. We recommend using cgroups to do container-local accounting.
     LimitNOFILE=1048576
     LimitNPROC=infinity
     LimitCORE=infinity
     TasksMax=infinity
     TimeoutStartSec=0
     Restart=always

     [Install]
     WantedBy=multi-user.target
     ```
     - 参考: https://raw.githubusercontent.com/k3s-io/k3s/master/k3s.service
   - k3s.service.env
     ```
     HTTP_PROXY=http://<proxyサーバのIPアドレス>:<ポート番号>
     HTTPS_PROXY=http://<proxyサーバのIPアドレス>:<ポート番号>
     NO_PROXY=localhost,127.0.0.1
     ```
   - postinst
     ```
     #!/bin/sh
     systemctl enable k3s.service
     update-alternatives --set iptables /usr/sbin/iptables-legacy
     update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
     ```
   - resolv.conf
     ```
     nameserver 192.168.122.1
     ```
     - 本記事の環境では、ホストマシンのIPアドレスである192.168.122.1を指定しています。
   - emlinux-image-base.bbappend
     ```
     # Add packages for K3s
     IMAGE_PREINSTALL:append = " \
         ca-certificates \
         connman \
     "
     ```
   - qemu-arm64_k3s_defconfig
     1. flannelを動作させるために、kernelのパラメータを変更します。`repos/meta-emlinux/recipes-kernel/linux/files/qemu-arm64_defconfig`をコピーし、`qemu-arm64_k3s_defconfig`と名前を変更してください。
     1. `qemu-arm64_k3s_defconfig`を以下のように編集してください。
        ```
        CONFIG_CFS_BANDWIDTH=y
        ```
        ```
        CONFIG_BLK_DEV_THROTTLING=y
        ```
        ```
        CONFIG_XFRM=y
        CONFIG_XFRM_USER=m
        CONFIG_XFRM_ALGO=m
        ```
        ```
        CONFIG_INET_ESP=m
        ```
        ```
        CONFIG_IP_SET=m
        ```
        ```
        CONFIG_IP_VS_PROTO_TCP=y
        CONFIG_IP_VS_PROTO_UDP=y
        ```
        ```
        CONFIG_IP_VS_RR=m
        ```
        ```
        CONFIG_IP_VS_NFCT=y
        ```
        ```
        CONFIG_IP_NF_TARGET_REDIRECT=m
        ```
        ```
        CONFIG_NET_CLS_CGROUP=m
        ```
        ```
        CONFIG_CGROUP_NET_PRIO=y
        ```
        ```
        CONFIG_VXLAN=m
        ```
        ```
        CONFIG_EXT4_FS_SECURITY=y
        ```
        ```
        CONFIG_CRYPTO_SEQIV=m
        ```
   - linux-cip_%.bbappend
     ```
     FILESEXTRAPATHS:prepend := "${FILE_DIRNAME}/files:"

     SRC_URI += "file://qemu-arm64_k3s_defconfig"     
     ```

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-k3s"

   # Setup for K3s
   IMAGE_INSTALL:append = " configure-k3s"

   # 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/k3s/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-k3s/emlinux-image-base-emlinux-bookworm-qemu-arm64-k3s.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-k3s/emlinux-image-base-emlinux-bookworm-qemu-arm64-k3s-vmlinux \
   -initrd ./tmp/deploy/images/qemu-arm64-k3s/emlinux-image-base-emlinux-bookworm-qemu-arm64-k3s-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. K3sが起動していることを確認してください。
   ```sh
   cd /root
   ```
   ```
   root@EMLinux3:~# ./k3s kubectl get node 
   
   NAME       STATUS   ROLES                  AGE   VERSION
   emlinux3   Ready    control-plane,master   21m   v1.30.0+k3s1   
   ```
   ```
   # ./k3s kubectl get pod --all-namespaces 

   NAMESPACE     NAME                                      READY   STATUS      RESTARTS   AGE
   kube-system   coredns-576bfc4dc7-wv864                  1/1     Running     0          20m
   kube-system   local-path-provisioner-75bb9ff978-g2mjf   1/1     Running     0          20m
   kube-system   metrics-server-557ff575fb-gt76v           1/1     Running     0          20m
   kube-system   helm-install-traefik-crd-lvm86            0/1     Completed   0          20m
   kube-system   helm-install-traefik-96cf4                0/1     Completed   1          20m
   kube-system   svclb-traefik-53f5042a-qx9xr              2/2     Running     0          18m
   kube-system   traefik-5fb479b77-lvsqc                   1/1     Running     0          18m   
   ```
1. kubeconfigを取得してください。
   ```sh
   ./k3s kubectl config view --raw
   ```
   - 上記コマンドの出力結果を、EMLinuxの他のマシンの任意のファイルに保存してください。本記事では、ホストマシンにあたるUbuntu Server 20.04.6 LTSに保存しました。
1. Ubuntu Server 20.04.6 LTSにて、kubectlコマンドを実行させるためのユーザを作成してください。本記事では、kubeuserを作成しました。
1. kubeuserでログインし、.kubeディレクトリを作成してください。
   ```sh
   cd ~
   ```
   ```sh
   mkdir .kube
   ```
1. vimコマンドなどで、configファイルを作成し、上述の`./k3s kubectl config view --raw`の実行結果を貼り付けてください。また、IPアドレスが、127.0.0.1となっている個所を、EMLinuxのIPアドレス (私の環境では192.168.122.76でした) に変更してください。
   ```sh
   vim .kube/config
   ```
   ```yaml
   apiVersion: v1
   clusters:
   - cluster:
       certificate-authority-data: (snip)
       server: https://192.168.122.76:6443
     name: default
   contexts:
   - context:
       cluster: default
       user: default
     name: default
   current-context: default
   kind: Config
   preferences: {}
   users:
   - name: default
     user:
       client-certificate-data: (snip)
       client-key-data: (snip)   
   ```

# kubectlのダウンロード
1. kubectlを任意の場所にダウンロードしてください。本記事では、Ubuntu Server 20.04.6 LTS上にダウンロードしました。
   ```sh
   curl -LO https://dl.k8s.io/release/v1.30.0/bin/linux/amd64/kubectl
   ```
   - 参考: https://kubernetes.io/ja/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux
1. kubectlがあるディレクトリにて、以下を実行し、k3sの状態を取得できることを確認してください。
   ```sh
   ./kubectl get node
   ```

# NGINXのPodの作成
1. kubectlがあるディレクトリにて、yamlディレクトリを作成してください。
   ```sh
   mkdir yaml
   ```
1. nginx.yamlファイルを作成し、以下のように編集してください。
   ```sh
   vim yaml/nginx.yaml
   ```
   ```yaml
   apiVersion: v1
   kind: Pod
   metadata:
     name: nginx
     labels:
       app: nginx
   spec:
     containers:
       - name: nginx
         image: nginx
         ports:
         - containerPort: 80
   ---
   apiVersion: v1
   kind: Service
   metadata:
     name: nginx
   spec:
     type: NodePort
     ports:
       - name: nginx
         protocol: TCP
         port: 80
         targetPort: 80
         nodePort: 30080
     selector:
       app: nginx
   ```
1. NGINXのPodと、ポートフォワードのためのServiceを作成してください。
   ```sh
   kubectl apply -f nginx.yaml
   ```
1. PodとServiceが動いていることを確認してください。
   ```
   $ ./kubectl get pod,svc
   NAME        READY   STATUS    RESTARTS   AGE
   pod/nginx   1/1     Running   0          84s

   NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
   service/kubernetes   ClusterIP   10.43.0.1     <none>        443/TCP        44m
   service/nginx        NodePort    10.43.22.94   <none>        80:30080/TCP   83s
   ```
1. NGINXにアクセスできることを確認してください。
   ```sh
   curl 192.168.122.76:30080 --noproxy 192.168.122.76
   ```
   - 本記事の環境ではproxyサーバがあるため、`--noproxy`を指定しています。

# さいごに
ちょっと長い記事になってしまいましたが、EMLinuxのレシピをカスタマイズし、K3sを動かすことに成功しました。

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