コンテナ Ready SDカードイメージ作成 for Intel® Agilex™ SoC

[前回][LINK_Part1]はIntel® Agilex™️ SoCのSDカードイメージの作り方について解説しました。
[最後のセクション](https://qiita.com/hikawai/items/14c0c97e7852f113b368#boot%E3%81%A8%E6%AE%8B%E5%BF%B5%E3%81%AA%E3%81%8A%E7%9F%A5%E3%82%89%E3%81%9B)で説明したようにこのままだとコンテナを利用することができず、Azure IoT Edge\*やKubernetes\*などのプラットフォームを活用できません。
そこで今回はSDカードのカスタムの仕方について解説しようと思います。

## おさらい

Intel® Agilex™️ SoCの中のSDカードイメージの中身を復習してみます。

SDカード外(QSPI Flashに格納)
+ Phase 1 FPGA Image(.jic)
  + Phase 1 FPGA Image(.sof)
  + U-Boot SPL Hex/Binary

SDカード:パーティション1
+ `Linux Kernel Image(Image)`
+ Phase 2 FPGA Image(ghrd.core.rbf)
+ Device Tree Blob(socfpga_agilex_socdk.dtb)
+ u-boot.itb
  + U-Boot Image
  + Trusted Firmware-A
  + Device Tree File

SDカード:パーティション2
+ Rootfs Image

今回の場合、コンテナReadyのイメージにするのに必要なことはLinux Kernel Imageの変更だけをすれば十分です。コンテナ内からFPGAイメージを更新する手法として用いていたDevice Tree Overlayについてはまた別の機会に検証してみようと思います。

## Linux Kernel Imageのカスタム方法

[前半][LINK_Part1]ではこのLinux Kernelビルドについてはさらっと流しました。
改めて確認してみます。細かいところは大元のドキュメント
[Building Bootloader for Stratix 10 and Agilex️:Appendix - Building Linux Binaries][LINK_BBSA_BLINUX]  
を参照してください。

```bash
rm -rf linux && mkdir linux
export set LINUX_TOP=`pwd`/linux
cd $LINUX_TOP
export ARCH=arm64
export CROSS_COMPILE=aarch64-none-linux-gnu-
cd $LINUX_TOP
git clone https://github.com/altera-opensource/linux-socfpga linux-socfpga.a53
cd linux-socfpga.a53
# comment out next line to use the latest Linux kernel branch
git checkout -b test-kernel -t origin/socfpga-5.15.50-lts
make clean && make mrproper
# enable JFFS2 and disable 4K sectors for booting from QSPI
echo "CONFIG_JFFS2_FS=y" >> arch/arm64/configs/defconfig
echo "CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=n" >> arch/arm64/configs/defconfig
# reduce QSPI clock to work on early boards. This only aplies to S10 boards hence all Agilex™️ boards works at 100Mhz.
# sed -i 's/spi-max-frequency = <100000000>;/spi-max-frequency = <50000000>;/g' arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts 
make defconfig
```
`make defcofig`というコマンドで`arch/arm64/configs/defconfig`のファイルから`.config`へのコピーが行われます。そしてその後の`make`はこの.configを元にビルドが行われます。

上記のコマンドでは`defconfig`を直接編集していますが、いきなりこれを編集するのは少し勇気がいるので、このコピーされた`.config`をカスタムするのがよいと思います。
(gitで元に戻れはしますが、それはそれで面倒なので・・・)

コンテナ利用可能なカーネルオプションになったかどうかを判定するには、
概念的には、この`.config`と[DE10-Nano/FPGA Cloud Connectivity Kit using Microsoft* Azure][LINK_FCCKMSEdgeDoc]のチュートリアルで使われていた[SDカードイメージ][LINK_FCCKSDCI](!SDカードイメージへの直接URLなのでご注意)の中にある
(!Need to check path)
configファイルを見比べるのがよいのですが、カーネルのバージョンが異なるため全く同一のオプションがない場合があります。

そこで、Azure IoT Edge\*で使われているContainer Engineである[moby][LINK_moby]のカーネルコンフィグをチェックする[スクリプト][LINK_mobyScript]を利用します。([Ref][LINK_IoTEdgeInstallCE])

```bash
curl -ssl https://raw.githubusercontent.com/moby/moby/master/contrib/check-config.sh -o check-config.sh
chmod +x check-config.sh
./check-config.sh
```

<details><summary> オリジナルのSDカードの起動後に、check-config.shを実行</summary><div>

```log
agilex@localhost:~$ bash check-config.sh
info: reading kernel config from /proc/config.gz ...

Generally Necessary:
- cgroup hierarchy: properly mounted [/sys/fs/cgroup]
- CONFIG_NAMESPACES: enabled
- CONFIG_NET_NS: enabled
- CONFIG_PID_NS: enabled
- CONFIG_IPC_NS: enabled
- CONFIG_UTS_NS: enabled
- CONFIG_CGROUPS: enabled
- CONFIG_CGROUP_CPUACCT: enabled
- CONFIG_CGROUP_DEVICE: enabled
- CONFIG_CGROUP_FREEZER: missing
- CONFIG_CGROUP_SCHED: enabled
- CONFIG_CPUSETS: enabled
- CONFIG_MEMCG: enabled
- CONFIG_KEYS: enabled
- CONFIG_VETH: enabled (as module)
- CONFIG_BRIDGE: enabled (as module)
- CONFIG_BRIDGE_NETFILTER: missing
- CONFIG_IP_NF_FILTER: enabled (as module)
- CONFIG_IP_NF_TARGET_MASQUERADE: enabled (as module)
- CONFIG_NETFILTER_XT_MATCH_ADDRTYPE: enabled (as module)
- CONFIG_NETFILTER_XT_MATCH_CONNTRACK: enabled (as module)
- CONFIG_NETFILTER_XT_MATCH_IPVS: missing
- CONFIG_NETFILTER_XT_MARK: missing
- CONFIG_IP_NF_NAT: enabled (as module)
- CONFIG_NF_NAT: enabled (as module)
- CONFIG_POSIX_MQUEUE: enabled
- CONFIG_CGROUP_BPF: missing

Optional Features:
- CONFIG_USER_NS: enabled
- CONFIG_SECCOMP: enabled
- CONFIG_SECCOMP_FILTER: enabled
- CONFIG_CGROUP_PIDS: enabled
- CONFIG_MEMCG_SWAP: enabled
    (cgroup swap accounting is currently enabled)
- CONFIG_BLK_CGROUP: enabled
- CONFIG_BLK_DEV_THROTTLING: missing
- CONFIG_CGROUP_PERF: enabled
- CONFIG_CGROUP_HUGETLB: enabled
- CONFIG_NET_CLS_CGROUP: missing
- CONFIG_CGROUP_NET_PRIO: missing
- CONFIG_CFS_BANDWIDTH: missing
- CONFIG_FAIR_GROUP_SCHED: enabled
- CONFIG_RT_GROUP_SCHED: missing
- CONFIG_IP_NF_TARGET_REDIRECT: missing
- CONFIG_IP_VS: missing
- CONFIG_IP_VS_NFCT: missing
- CONFIG_IP_VS_PROTO_TCP: missing
- CONFIG_IP_VS_PROTO_UDP: missing
- CONFIG_IP_VS_RR: missing
- CONFIG_SECURITY_SELINUX: missing
- CONFIG_SECURITY_APPARMOR: missing
- CONFIG_EXT3_FS: enabled
- CONFIG_EXT3_FS_XATTR: missing
- CONFIG_EXT3_FS_POSIX_ACL: missing
- CONFIG_EXT3_FS_SECURITY: missing
    (enable these ext3 configs if you are using ext3 as backing filesystem)
- CONFIG_EXT4_FS: enabled
- CONFIG_EXT4_FS_POSIX_ACL: enabled
- CONFIG_EXT4_FS_SECURITY: missing
    enable these ext4 configs if you are using ext4 as backing filesystem
- Network Drivers:
  - "overlay":
    - CONFIG_VXLAN: missing
    - CONFIG_BRIDGE_VLAN_FILTERING: enabled
      Optional (for encrypted networks):
      - CONFIG_CRYPTO: enabled
      - CONFIG_CRYPTO_AEAD: enabled
      - CONFIG_CRYPTO_GCM: enabled (as module)
      - CONFIG_CRYPTO_SEQIV: missing
      - CONFIG_CRYPTO_GHASH: enabled (as module)
      - CONFIG_XFRM: missing
      - CONFIG_XFRM_USER: missing
      - CONFIG_XFRM_ALGO: missing
      - CONFIG_INET_ESP: missing
  - "ipvlan":
    - CONFIG_IPVLAN: missing
  - "macvlan":
    - CONFIG_MACVLAN: enabled (as module)
    - CONFIG_DUMMY: missing
  - "ftp,tftp client in container":
    - CONFIG_NF_NAT_FTP: missing
    - CONFIG_NF_CONNTRACK_FTP: missing
    - CONFIG_NF_NAT_TFTP: missing
    - CONFIG_NF_CONNTRACK_TFTP: missing
- Storage Drivers:
  - "aufs":
    - CONFIG_AUFS_FS: missing
  - "btrfs":
    - CONFIG_BTRFS_FS: enabled (as module)
    - CONFIG_BTRFS_FS_POSIX_ACL: enabled
  - "devicemapper":
    - CONFIG_BLK_DEV_DM: enabled (as module)
    - CONFIG_DM_THIN_PROVISIONING: missing
  - "overlay":
    - CONFIG_OVERLAY_FS: enabled (as module)
  - "zfs":
    - /dev/zfs: missing
    - zfs command: missing
    - zpool command: missing

Limits:
- /proc/sys/kernel/keys/root_maxkeys: 1000000

```

</div></details>

> [!Note] コンパイルマシンで.configに対して実行した場合の結果と、実際にSDカード内での結果が微妙に異なる場合があります。そのためカスタムした後は、実機で念の為確認しておくと安心です。

これらに対して足りないオプションを補っていきます。
基本的にはGenerally Necessaryは全てEnabledにしましょう。Optionalについては今回はFCCKのconfigファイルと見比べながら(後述)Enabledにしましたが、使わない機能に関しては不要かもしれません。

筆者の手元では、`make menuconfig`を使ってそれぞれのオプションを検索することで修正していきました。

![menuconfig.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698105/82d6d925-dbc0-234d-399c-d2b08520063e.png)


menuconfigを開いたら、右上が`.config`と`Linux/arm64`であることを必ず確認してください。確認できたら`/`を入力すると検索画面が出てきます。検索画面で先ほどの`CONFIG_XXXX`を入力すると該当の項目が出てきます。ものによっては直接ではなく複数の項目をEnabledすることによって等価のものもあります。
その他の操作としては、`Enter`で下の項目に進む、`Esc`で上の項目に戻る、`Y`でEnabled、`N`でDisabledに変更することができます。

注意点としては、`Depends on`を全て`=y`にしていないとオプションが出てこないパターンがかなりあります。例えば下記の例ではBPF_SYSCALLを先にEnabledにする必要があり、BPF_SYSCALLを検索してどこにあるかを調べる必要があります。

```log
 .config - Linux/arm64 5.15.50 Kernel Configuration
  ┌────────────────────Search Results ──────────────────────┐
  │ Symbol: CGROUP_BPF [=n]                                 │  
  │ Type  : bool                                            │  
  │ Defined at init/Kconfig:1140                            │  
  │   Prompt: Support for eBPF programs attached to cgroups │  
  │   Depends on: CGROUPS [=y] && BPF_SYSCALL [=n]          │  
  │   Location:                                             │  
  │     -> General setup                                    │  
  │ (1)   -> Control Group support (CGROUPS [=y])           │  
  │ Selects: SOCK_CGROUP_DATA [=n]                          |
```

この変更はそこそこ大変ですが、頑張ってやりましょう。
> どなたかもっとスマートなやり方をご存じでしたら是非教えてください。

実際に筆者が修正したconfigに対して実行し直したものがこちらです。

<details><summary> カスタムした.configに対して、check-config.shを実行</summary><div>

```log
agilex@localhost:~$ bash check-config.sh .config
info: reading kernel config from .config ...

Generally Necessary:
- cgroup hierarchy: properly mounted [/sys/fs/cgroup]
- CONFIG_NAMESPACES: enabled
- CONFIG_NET_NS: enabled
- CONFIG_PID_NS: enabled
- CONFIG_IPC_NS: enabled
- CONFIG_UTS_NS: enabled
- CONFIG_CGROUPS: enabled
- CONFIG_CGROUP_CPUACCT: enabled
- CONFIG_CGROUP_DEVICE: enabled
- CONFIG_CGROUP_FREEZER: enabled
- CONFIG_CGROUP_SCHED: enabled
- CONFIG_CPUSETS: enabled
- CONFIG_MEMCG: enabled
- CONFIG_KEYS: enabled
- CONFIG_VETH: enabled (as module)
- CONFIG_BRIDGE: enabled (as module)
- CONFIG_BRIDGE_NETFILTER: enabled (as module)
- CONFIG_IP_NF_FILTER: enabled (as module)
- CONFIG_IP_NF_TARGET_MASQUERADE: enabled (as module)
- CONFIG_NETFILTER_XT_MATCH_ADDRTYPE: enabled (as module)
- CONFIG_NETFILTER_XT_MATCH_CONNTRACK: enabled (as module)
- CONFIG_NETFILTER_XT_MATCH_IPVS: enabled (as module)
- CONFIG_NETFILTER_XT_MARK: enabled (as module)
- CONFIG_IP_NF_NAT: enabled (as module)
- CONFIG_NF_NAT: enabled (as module)
- CONFIG_POSIX_MQUEUE: enabled
- CONFIG_CGROUP_BPF: enabled

Optional Features:
- CONFIG_USER_NS: enabled
- CONFIG_SECCOMP: enabled
- CONFIG_SECCOMP_FILTER: enabled
- CONFIG_CGROUP_PIDS: enabled
- CONFIG_MEMCG_SWAP: enabled
    (cgroup swap accounting is currently enabled)
- CONFIG_BLK_CGROUP: enabled
- CONFIG_BLK_DEV_THROTTLING: missing
- CONFIG_CGROUP_PERF: enabled
- CONFIG_CGROUP_HUGETLB: enabled
- CONFIG_NET_CLS_CGROUP: enabled
- CONFIG_CGROUP_NET_PRIO: enabled
- CONFIG_CFS_BANDWIDTH: enabled
- CONFIG_FAIR_GROUP_SCHED: enabled
- CONFIG_RT_GROUP_SCHED: enabled
- CONFIG_IP_NF_TARGET_REDIRECT: enabled (as module)
- CONFIG_IP_VS: enabled (as module)
- CONFIG_IP_VS_NFCT: enabled
- CONFIG_IP_VS_PROTO_TCP: enabled
- CONFIG_IP_VS_PROTO_UDP: enabled
- CONFIG_IP_VS_RR: enabled (as module)
- CONFIG_SECURITY_SELINUX: missing
- CONFIG_SECURITY_APPARMOR: missing
- CONFIG_EXT3_FS: enabled
- CONFIG_EXT3_FS_XATTR: missing
- CONFIG_EXT3_FS_POSIX_ACL: missing
- CONFIG_EXT3_FS_SECURITY: missing
    (enable these ext3 configs if you are using ext3 as backing filesystem)
- CONFIG_EXT4_FS: enabled
- CONFIG_EXT4_FS_POSIX_ACL: enabled
- CONFIG_EXT4_FS_SECURITY: enabled
- Network Drivers:
  - "overlay":
    - CONFIG_VXLAN: enabled
    - CONFIG_BRIDGE_VLAN_FILTERING: enabled
      Optional (for encrypted networks):
      - CONFIG_CRYPTO: enabled
      - CONFIG_CRYPTO_AEAD: enabled
      - CONFIG_CRYPTO_GCM: enabled
      - CONFIG_CRYPTO_SEQIV: enabled
      - CONFIG_CRYPTO_GHASH: enabled
      - CONFIG_XFRM: enabled
      - CONFIG_XFRM_USER: enabled
      - CONFIG_XFRM_ALGO: enabled
      - CONFIG_INET_ESP: enabled
  - "ipvlan":
    - CONFIG_IPVLAN: enabled (as module)
  - "macvlan":
    - CONFIG_MACVLAN: enabled (as module)
    - CONFIG_DUMMY: enabled
  - "ftp,tftp client in container":
    - CONFIG_NF_NAT_FTP: enabled (as module)
    - CONFIG_NF_CONNTRACK_FTP: enabled (as module)
    - CONFIG_NF_NAT_TFTP: enabled (as module)
    - CONFIG_NF_CONNTRACK_TFTP: enabled (as module)
- Storage Drivers:
  - "aufs":
    - CONFIG_AUFS_FS: missing
  - "btrfs":
    - CONFIG_BTRFS_FS: enabled (as module)
    - CONFIG_BTRFS_FS_POSIX_ACL: enabled
  - "devicemapper":
    - CONFIG_BLK_DEV_DM: enabled (as module)
    - CONFIG_DM_THIN_PROVISIONING: enabled (as module)
  - "overlay":
    - CONFIG_OVERLAY_FS: enabled (as module)
  - "zfs":
    - /dev/zfs: missing
    - zfs command: missing
    - zpool command: missing

Limits:
- /proc/sys/kernel/keys/root_maxkeys: 1000000

```

</div></details>

適切が変更できたら、前回同様カーネルコンパイルを行います。
dtb(Device Tree Blob)については特に変更を行っていないので実行しなくても構いませんが、dtbのコンパイルはそこまでオーバーヘッドがないので、実行してしまっても良いと思います。

```bash
make -j 48 Image dtbs modules
make -j 48 modules_install INSTALL_MOD_PATH=modules_install
```

これで`Image`およびそこに含まれるカーネルモジュールのカスタムが完了しました。

### 補足:FPGA Cloud Connectivity Kitに入っているコンフィグオプション
FCCKの中に入っているconfigに対して、実行した結果も載せておきます。
参考資料として使ってみてください。

<details><summary> FCCKのconfigファイルに対して、check-config.shを実行</summary><div>

```log
root@de10nano:~# bash check-config.sh
info: reading kernel config from /proc/config.gz ...

Generally Necessary:
- cgroup hierarchy: properly mounted [/sys/fs/cgroup]
- CONFIG_NAMESPACES: enabled
- CONFIG_NET_NS: enabled
- CONFIG_PID_NS: enabled
- CONFIG_IPC_NS: enabled
- CONFIG_UTS_NS: enabled
- CONFIG_CGROUPS: enabled
- CONFIG_CGROUP_CPUACCT: enabled
- CONFIG_CGROUP_DEVICE: enabled
- CONFIG_CGROUP_FREEZER: enabled
- CONFIG_CGROUP_SCHED: enabled
- CONFIG_CPUSETS: enabled
- CONFIG_MEMCG: enabled
- CONFIG_KEYS: enabled
- CONFIG_VETH: enabled (as module)
- CONFIG_BRIDGE: enabled (as module)
- CONFIG_BRIDGE_NETFILTER: enabled (as module)
- CONFIG_IP_NF_FILTER: enabled (as module)
- CONFIG_IP_NF_TARGET_MASQUERADE: enabled (as module)
- CONFIG_NETFILTER_XT_MATCH_ADDRTYPE: enabled (as module)
- CONFIG_NETFILTER_XT_MATCH_CONNTRACK: enabled (as module)
- CONFIG_NETFILTER_XT_MATCH_IPVS: enabled (as module)
- CONFIG_NETFILTER_XT_MARK: enabled (as module)
- CONFIG_IP_NF_NAT: enabled (as module)
- CONFIG_NF_NAT: enabled (as module)
- CONFIG_POSIX_MQUEUE: enabled
- CONFIG_NF_NAT_IPV4: enabled (as module)
- CONFIG_NF_NAT_NEEDED: enabled

Optional Features:
- CONFIG_USER_NS: enabled
- CONFIG_SECCOMP: enabled
- CONFIG_SECCOMP_FILTER: enabled
- CONFIG_CGROUP_PIDS: enabled
- CONFIG_MEMCG_SWAP: enabled
- CONFIG_MEMCG_SWAP_ENABLED: enabled
    (cgroup swap accounting is currently enabled)
- CONFIG_IOSCHED_CFQ: enabled
- CONFIG_CFQ_GROUP_IOSCHED: enabled
- CONFIG_BLK_CGROUP: enabled
- CONFIG_BLK_DEV_THROTTLING: enabled
- CONFIG_CGROUP_PERF: enabled
- CONFIG_CGROUP_HUGETLB: missing
- CONFIG_NET_CLS_CGROUP: enabled (as module)
- CONFIG_CGROUP_NET_PRIO: enabled
- CONFIG_CFS_BANDWIDTH: enabled
- CONFIG_FAIR_GROUP_SCHED: enabled
- CONFIG_RT_GROUP_SCHED: enabled
- CONFIG_IP_NF_TARGET_REDIRECT: enabled (as module)
- CONFIG_IP_VS: enabled (as module)
- CONFIG_IP_VS_NFCT: enabled
- CONFIG_IP_VS_PROTO_TCP: enabled
- CONFIG_IP_VS_PROTO_UDP: enabled
- CONFIG_IP_VS_RR: enabled (as module)
- CONFIG_SECURITY_SELINUX: missing
- CONFIG_SECURITY_APPARMOR: missing
- CONFIG_EXT3_FS: enabled
- CONFIG_EXT3_FS_XATTR: missing
- CONFIG_EXT3_FS_POSIX_ACL: missing
- CONFIG_EXT3_FS_SECURITY: missing
    (enable these ext3 configs if you are using ext3 as backing filesystem)
- CONFIG_EXT4_FS: enabled
- CONFIG_EXT4_FS_POSIX_ACL: enabled
- CONFIG_EXT4_FS_SECURITY: enabled
- Network Drivers:
  - "overlay":
    - CONFIG_VXLAN: enabled (as module)
    - CONFIG_BRIDGE_VLAN_FILTERING: enabled
      Optional (for encrypted networks):
      - CONFIG_CRYPTO: enabled
      - CONFIG_CRYPTO_AEAD: enabled
      - CONFIG_CRYPTO_GCM: enabled
      - CONFIG_CRYPTO_SEQIV: enabled
      - CONFIG_CRYPTO_GHASH: enabled
      - CONFIG_XFRM: enabled
      - CONFIG_XFRM_USER: enabled
      - CONFIG_XFRM_ALGO: enabled
      - CONFIG_INET_ESP: enabled (as module)
      - CONFIG_INET_XFRM_MODE_TRANSPORT: enabled (as module)
  - "ipvlan":
    - CONFIG_IPVLAN: enabled (as module)
  - "macvlan":
    - CONFIG_MACVLAN: enabled (as module)
    - CONFIG_DUMMY: enabled (as module)
  - "ftp,tftp client in container":
    - CONFIG_NF_NAT_FTP: enabled (as module)
    - CONFIG_NF_CONNTRACK_FTP: enabled (as module)
    - CONFIG_NF_NAT_TFTP: enabled (as module)
    - CONFIG_NF_CONNTRACK_TFTP: enabled (as module)
- Storage Drivers:
  - "aufs":
    - CONFIG_AUFS_FS: missing
  - "btrfs":
    - CONFIG_BTRFS_FS: enabled (as module)
    - CONFIG_BTRFS_FS_POSIX_ACL: enabled
  - "devicemapper":
    - CONFIG_BLK_DEV_DM: enabled (as module)
    - CONFIG_DM_THIN_PROVISIONING: enabled (as module)
  - "overlay":
    - CONFIG_OVERLAY_FS: enabled (as module)
  - "zfs":
    - /dev/zfs: missing
    - zfs command: missing
    - zpool command: missing

Limits:
- /proc/sys/kernel/keys/root_maxkeys: 1000000


```

</div></details>

## SDカードのアップデート
これが終わったら後はファイルを置き換えてSDカードを作り直すだけです。

```bash
cp $LINUX_BIN/a53/Image .
cd ..

cd rootfs-ubuntu 
sudo rm -rf lib/modules/*
sudo cp -r $LINUX_BIN/a53/modules/* lib/modules/
cd ..

sudo python3 make_sdimage_p3.py -f \
-P sdfs/*,num=1,format=fat32,size=56M \
-P rootfs/*,num=2,format=ext3,size=2500M \
-s 2556M \
-n container-ready-sdcard.img
cd ..
```

注意点としてはカーネルモジュールのサイズがかなり大きくなっているので、サイズを適切に変更してください。サイズが足りないとpython実行時にエラーを出力します。

作成が終わった後は[前半同様](https://qiita.com/hikawai/items/14c0c97e7852f113b368#sd%E3%82%AB%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%81%BF)、書き込みおよびカスタマイズを行なってください。

## コンテナテスト

今回は念には念を入れてAzure IoT Edge\*に加えて、別のLinux Container Runtimeである`lxc`も試してみる。基本的には公式のガイドに従って実行してみて起動するところまで確認します。

### LXC Test
基本的に下記のガイドに従ってテストをするだけです。
[Linux Containers - LXC - Getting started][LINK_LXCGS]
Ubuntuではaptのパッケージにまとまっているので、サクッとテストできるところが魅力的です。

```
sudo apt install -y lxc
```

今回はコンテナが起動するかどうかのテストをするだけなので、Privilegedコンテナを作ってテストしました。テストログに関しては、後に載せているのでご興味があるかたは確認してみてください。

<details><summary> LXC テストログ</summary><div>

```bash
agilex@localhost:~$ lxc-checkconfig
LXC version 4.0.12
--- Namespaces ---
Namespaces: enabled
Utsname namespace: enabled
Ipc namespace: enabled
Pid namespace: enabled
User namespace: enabled
Network namespace: enabled

--- Control groups ---
Cgroups: enabled
Cgroup namespace: enabled

Cgroup v1 mount points:
/sys/fs/cgroup/systemd
/sys/fs/cgroup/net_cls,net_prio
/sys/fs/cgroup/cpuset
/sys/fs/cgroup/devices
/sys/fs/cgroup/freezer
/sys/fs/cgroup/blkio
/sys/fs/cgroup/cpu,cpuacct
/sys/fs/cgroup/perf_event
/sys/fs/cgroup/hugetlb
/sys/fs/cgroup/pids
/sys/fs/cgroup/memory

Cgroup v2 mount points:
/sys/fs/cgroup/unified

Cgroup v1 clone_children flag: enabled
Cgroup device: enabled
Cgroup sched: enabled
Cgroup cpu account: enabled
Cgroup memory controller: enabled
Cgroup cpuset: enabled

--- Misc ---
Veth pair device: enabled, not loaded
Macvlan: enabled, not loaded
Vlan: enabled, not loaded
Bridges: enabled, loaded
Advanced netfilter: enabled, not loaded
CONFIG_IP_NF_TARGET_MASQUERADE: enabled, not loaded
CONFIG_IP6_NF_TARGET_MASQUERADE: enabled, not loaded
CONFIG_NETFILTER_XT_TARGET_CHECKSUM: enabled, loaded
CONFIG_NETFILTER_XT_MATCH_COMMENT: missing
FUSE (for use with lxcfs): enabled, loaded

--- Checkpoint/Restore ---
checkpoint restore: missing
CONFIG_FHANDLE: enabled
CONFIG_EVENTFD: enabled
CONFIG_EPOLL: enabled
CONFIG_UNIX_DIAG: missing
CONFIG_INET_DIAG: enabled
CONFIG_PACKET_DIAG: missing
CONFIG_NETLINK_DIAG: missing
File capabilities:

Note : Before booting a new kernel, you can check its configuration
usage : CONFIG=/path/to/config /usr/bin/lxc-checkconfig

root@localhost:/home/agilex# lxc-create -t download -n privileged-container
Downloading the image index

---
DIST    RELEASE ARCH    VARIANT BUILD
---
almalinux       8       amd64   default 20221206_23:08
almalinux       8       arm64   default 20221206_23:09
almalinux       8       ppc64el default 20221206_23:08
almalinux       9       amd64   default 20221206_23:08
almalinux       9       arm64   default 20221206_23:11
almalinux       9       ppc64el default 20221206_23:09
alpine  3.14    amd64   default 20221206_13:00
alpine  3.14    arm64   default 20221206_13:02
alpine  3.14    armhf   default 20221206_13:31
alpine  3.14    i386    default 20221206_13:00
alpine  3.14    ppc64el default 20221206_13:00
alpine  3.14    s390x   default 20221205_14:14
alpine  3.15    amd64   default 20221206_13:02
alpine  3.15    arm64   default 20221206_13:31
alpine  3.15    armhf   default 20221206_13:03
alpine  3.15    i386    default 20221206_13:02
alpine  3.15    ppc64el default 20221205_14:46
alpine  3.15    s390x   default 20221205_14:36
alpine  3.16    amd64   default 20221206_13:00
alpine  3.16    arm64   default 20221206_13:52
alpine  3.16    armhf   default 20221206_13:02
alpine  3.16    i386    default 20221206_13:00
alpine  3.16    ppc64el default 20221205_14:53
alpine  3.16    s390x   default 20221205_14:14
alpine  3.17    amd64   default 20221206_13:00
alpine  3.17    arm64   default 20221206_13:03
alpine  3.17    armhf   default 20221206_13:03
alpine  3.17    i386    default 20221206_13:02
alpine  3.17    ppc64el default 20221205_14:52
alpine  3.17    s390x   default 20221205_14:38
alpine  edge    amd64   default 20221206_13:00
alpine  edge    arm64   default 20221206_13:31
alpine  edge    armhf   default 20221206_13:31
alpine  edge    i386    default 20221206_13:04
alpine  edge    ppc64el default 20221205_14:47
alpine  edge    s390x   default 20221205_14:38
alt     Sisyphus        amd64   default 20221207_01:18
alt     Sisyphus        arm64   default 20221207_01:18
alt     Sisyphus        armhf   default 20221207_01:18
alt     Sisyphus        ppc64el default 20221207_01:17
alt     p10     amd64   default 20221207_01:17
alt     p10     arm64   default 20221207_01:28
alt     p10     armhf   default 20221207_01:18
alt     p10     ppc64el default 20221207_01:17
alt     p9      amd64   default 20221207_01:17
alt     p9      arm64   default 20221207_01:18
alt     p9      armhf   default 20221207_01:18
alt     p9      ppc64el default 20221207_01:17
amazonlinux     current amd64   default 20221207_05:09
amazonlinux     current arm64   default 20221207_05:09
apertis v2020   amd64   default 20221206_10:54
apertis v2020   arm64   default 20221206_10:54
apertis v2020   armhf   default 20221206_10:54
apertis v2021   amd64   default 20221206_10:53
apertis v2021   arm64   default 20221206_10:54
apertis v2021   armhf   default 20221206_10:54
archlinux       current amd64   default 20221207_04:18
archlinux       current arm64   default 20221207_04:18
archlinux       current armhf   default 20221207_04:18
busybox 1.34.1  amd64   default 20221207_06:00
busybox 1.34.1  arm64   default 20221207_06:01
centos  7       amd64   default 20221206_07:11
centos  7       arm64   default 20221206_07:11
centos  7       armhf   default 20221206_08:48
centos  7       i386    default 20221206_07:08
centos  7       ppc64el default 20221206_07:08
centos  8-Stream        amd64   default 20221206_07:09
centos  8-Stream        arm64   default 20221206_07:11
centos  8-Stream        ppc64el default 20221206_07:08
centos  9-Stream        amd64   default 20221206_07:09
centos  9-Stream        arm64   default 20221206_08:48
centos  9-Stream        ppc64el default 20221206_07:08
debian  bookworm        amd64   default 20221207_05:26
debian  bookworm        arm64   default 20221207_05:25
debian  bookworm        armel   default 20221207_05:25
debian  bookworm        armhf   default 20221207_05:25
debian  bookworm        i386    default 20221207_05:24
debian  bookworm        ppc64el default 20221207_05:24
debian  bookworm        s390x   default 20221207_05:24
debian  bullseye        amd64   default 20221207_05:24
debian  bullseye        arm64   default 20221206_06:35
debian  bullseye        armel   default 20221207_05:25
debian  bullseye        armhf   default 20221207_05:25
debian  bullseye        i386    default 20221207_05:24
debian  bullseye        ppc64el default 20221207_05:24
debian  bullseye        s390x   default 20221207_05:24
debian  buster  amd64   default 20221207_05:24
debian  buster  arm64   default 20221206_06:35
debian  buster  armel   default 20221207_05:25
debian  buster  armhf   default 20221207_05:25
debian  buster  i386    default 20221207_05:24
debian  buster  ppc64el default 20221207_05:24
debian  buster  s390x   default 20221207_05:24
debian  sid     amd64   default 20221207_05:24
debian  sid     arm64   default 20221207_05:25
debian  sid     armel   default 20221207_05:25
debian  sid     armhf   default 20221207_05:25
debian  sid     i386    default 20221207_05:25
debian  sid     ppc64el default 20221207_05:24
debian  sid     s390x   default 20221207_05:24
devuan  ascii   amd64   default 20221206_11:51
devuan  ascii   arm64   default 20221206_12:50
devuan  ascii   armel   default 20221205_18:20
devuan  ascii   armhf   default 20221206_13:52
devuan  ascii   i386    default 20221206_11:50
devuan  beowulf amd64   default 20221206_11:50
devuan  beowulf arm64   default 20221206_11:51
devuan  beowulf armel   default 20221204_11:51
devuan  beowulf armhf   default 20221206_13:52
devuan  beowulf i386    default 20221206_11:50
devuan  beowulf ppc64el default 20221206_11:50
devuan  chimaera        amd64   default 20221206_11:50
devuan  chimaera        arm64   default 20221206_11:51
devuan  chimaera        armel   default 20221206_13:52
devuan  chimaera        armhf   default 20221205_16:51
devuan  chimaera        i386    default 20221206_11:50
devuan  chimaera        ppc64el default 20221206_11:50
fedora  35      amd64   default 20221206_20:33
fedora  35      arm64   default 20221206_20:34
fedora  35      ppc64el default 20221206_20:33
fedora  35      s390x   default 20221206_20:33
fedora  36      amd64   default 20221206_22:02
fedora  36      arm64   default 20221206_20:34
fedora  36      armhf   default 20221206_20:34
fedora  36      ppc64el default 20221206_20:33
fedora  36      s390x   default 20221206_20:47
fedora  37      amd64   default 20221206_20:34
fedora  37      arm64   default 20221206_20:34
fedora  37      ppc64el default 20221206_20:48
fedora  37      s390x   default 20221206_20:33
funtoo  1.4     amd64   default 20221206_16:45
funtoo  1.4     armhf   default 20221206_19:54
kali    current amd64   default 20221206_17:14
kali    current arm64   default 20221206_17:15
kali    current armel   default 20221206_17:58
kali    current armhf   default 20221206_17:17
mint    tara    amd64   default 20221206_08:51
mint    tessa   amd64   default 20221206_08:51
mint    tina    amd64   default 20221206_08:51
mint    tricia  amd64   default 20221206_08:51
mint    ulyana  amd64   default 20221206_08:51
mint    ulyssa  amd64   default 20221206_08:51
mint    uma     amd64   default 20221206_08:53
mint    una     amd64   default 20221206_08:54
mint    vanessa amd64   default 20221206_08:51
openeuler       20.03   amd64   default 20221206_15:48
openeuler       22.03   amd64   default 20221204_16:58
opensuse        15.3    amd64   default 20221207_04:20
opensuse        15.3    arm64   default 20221205_04:21
opensuse        15.3    ppc64el default 20221207_04:20
opensuse        15.3    s390x   default 20221207_04:20
opensuse        15.4    amd64   default 20221207_04:20
opensuse        15.4    arm64   default 20221207_04:21
opensuse        15.4    ppc64el default 20221207_04:20
opensuse        15.4    s390x   default 20221207_04:20
opensuse        tumbleweed      amd64   default 20221207_04:20
opensuse        tumbleweed      arm64   default 20221207_04:20
opensuse        tumbleweed      ppc64el default 20221207_04:20
opensuse        tumbleweed      s390x   default 20221207_04:20
openwrt 21.02   amd64   default 20221206_11:57
openwrt 21.02   arm64   default 20221206_12:34
openwrt 21.02   armhf   default 20221206_11:59
openwrt 22.03   amd64   default 20221206_11:57
openwrt 22.03   arm64   default 20221206_12:13
openwrt 22.03   armhf   default 20221204_11:59
openwrt snapshot        amd64   default 20221206_11:57
openwrt snapshot        arm64   default 20221206_12:11
openwrt snapshot        armhf   default 20221206_11:58
oracle  7       amd64   default 20221206_07:46
oracle  7       arm64   default 20221206_07:50
oracle  8       amd64   default 20221206_07:46
oracle  8       arm64   default 20221206_07:49
oracle  9       amd64   default 20221206_07:46
oracle  9       arm64   default 20221206_09:30
plamo   6.x     amd64   default 20221207_01:33
plamo   7.x     amd64   default 20221207_01:34
pld     current amd64   default 20221206_20:46
rockylinux      8       amd64   default 20221207_02:06
rockylinux      8       arm64   default 20221207_02:06
rockylinux      9       amd64   default 20221207_02:06
rockylinux      9       arm64   default 20221207_02:06
rockylinux      9       ppc64el default 20221207_02:06
springdalelinux 7       amd64   default 20221206_06:38
springdalelinux 7       i386    default 20221206_06:38
springdalelinux 8       amd64   default 20221206_06:38
springdalelinux 9       amd64   default 20221206_06:38
ubuntu  bionic  amd64   default 20221204_08:51
ubuntu  bionic  arm64   default 20221206_11:17
ubuntu  bionic  armhf   default 20221205_19:06
ubuntu  bionic  i386    default 20221204_07:43
ubuntu  bionic  ppc64el default 20221204_07:42
ubuntu  bionic  s390x   default 20221204_07:42
ubuntu  focal   amd64   default 20221204_07:43
ubuntu  focal   arm64   default 20221206_11:17
ubuntu  focal   armhf   default 20221206_11:19
ubuntu  focal   ppc64el default 20221204_07:42
ubuntu  focal   s390x   default 20221204_07:42
ubuntu  jammy   amd64   default 20221205_16:52
ubuntu  jammy   arm64   default 20221205_19:05
ubuntu  jammy   armhf   default 20221206_11:22
ubuntu  jammy   ppc64el default 20221204_07:42
ubuntu  jammy   s390x   default 20221204_07:54
ubuntu  kinetic amd64   default 20221204_07:43
ubuntu  kinetic arm64   default 20221206_12:38
ubuntu  kinetic armhf   default 20221205_19:05
ubuntu  kinetic ppc64el default 20221204_07:42
ubuntu  kinetic s390x   default 20221204_07:42
ubuntu  xenial  amd64   default 20221204_07:42
ubuntu  xenial  arm64   default 20221205_19:05
ubuntu  xenial  armhf   default 20221205_19:05
ubuntu  xenial  i386    default 20221204_07:43
ubuntu  xenial  ppc64el default 20221204_07:42
ubuntu  xenial  s390x   default 20221204_07:42
voidlinux       current amd64   default 20221206_17:10
voidlinux       current arm64   default 20221206_17:11
voidlinux       current armhf   default 20221206_18:07
---

Distribution:
ubuntu
Release:
xenial
Architecture:
arm64

Using image from local cache
Unpacking the rootfs

---
You just created an Ubuntu xenial arm64 (20221205_19:05) container.

To enable SSH, run: apt install openssh-server
No default root or user password are set by LXC.
root@localhost:/home/agilex# lxc-start -n privileged-container
root@localhost:/home/agilex# lxc-attach -n privileged-container
root@privileged-container:/# cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.7 LTS"
root@privileged-container:/# exit
exit
root@localhost:/home/agilex# lxc-stop -n privileged-container
root@localhost:/home/agilex# lxc-destroy -n privileged-container
```

</div></details>


### Azure IoT Edge\* Test

公式のガイド通りにインストールします。コマンドはコピーしておきますが最新版に関しては公式のドキュメントを参照してください。
[Create and provision an IoT Edge device on Linux using symmetric keys][LINK_IoTEdgeInstall]

```bash
#Setup the package
wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb

#Install Container Runtime
sudo apt-get update; \
  sudo apt-get install moby-engine
sudo cat << EOF > /etc/docker/daemon.json
{
      "log-driver": "local"
}
EOF
sudo systemctl restart docker 

#Install Azure IoT Edge
sudo apt-get update; \
  sudo apt-get install aziot-edge defender-iot-micro-agent-edge
sudo iotedge config mp --connection-string 'PASTE_DEVICE_CONNECTION_STRING_HERE'
sudo iotedge config apply

#Check Configurations
sudo iotedge system status
sudo iotedge system logs
sudo iotedge check
```

最後に確認した際のログです。

<details><summary> Azure IoT Edge* テストログ</summary><div>

```bash
root@localhost:/home/agilex# sudo iotedge check

Configuration checks (aziot-identity-service)
---------------------------------------------
√ keyd configuration is well-formed - OK
√ certd configuration is well-formed - OK
√ tpmd configuration is well-formed - OK
√ identityd configuration is well-formed - OK
√ daemon configurations up-to-date with config.toml - OK
√ identityd config toml file specifies a valid hostname - OK
√ aziot-identity-service package is up-to-date - OK
√ host time is close to reference time - OK
√ preloaded certificates are valid - OK
√ keyd is running - OK
√ certd is running - OK
√ identityd is running - OK
√ read all preloaded certificates from the Certificates Service - OK
√ read all preloaded key pairs from the Keys Service - OK
√ check all EST server URLs utilize HTTPS - OK
√ ensure all preloaded certificates match preloaded private keys with the same ID - OK

Connectivity checks (aziot-identity-service)
--------------------------------------------
√ host can connect to and perform TLS handshake with iothub AMQP port - OK
√ host can connect to and perform TLS handshake with iothub HTTPS / WebSockets port - OK
√ host can connect to and perform TLS handshake with iothub MQTT port - OK

Configuration checks
--------------------
√ aziot-edged configuration is well-formed - OK
√ configuration up-to-date with config.toml - OK
√ container engine is installed and functional - OK
√ configuration has correct URIs for daemon mgmt endpoint - OK
√ aziot-edge package is up-to-date - OK
√ container time is close to host time - OK
‼ DNS server - Warning
    Container engine is not configured with DNS server setting, which may impact connectivity to IoT Hub.
    Please see https://aka.ms/iotedge-prod-checklist-dns for best practices.
    You can ignore this warning if you are setting DNS server per module in the Edge deployment.
‼ production readiness: logs policy - Warning
    Container engine is not configured to rotate module logs which may cause it run out of disk space.
    Please see https://aka.ms/iotedge-prod-checklist-logs for best practices.
    You can ignore this warning if you are setting log policy per module in the Edge deployment.
‼ production readiness: Edge Agent's storage directory is persisted on the host filesystem - Warning
    The edgeAgent module is not configured to persist its /tmp/edgeAgent directory on the host filesystem.
    Data might be lost if the module is deleted or updated.
    Please see https://aka.ms/iotedge-storage-host for best practices.
× production readiness: Edge Hub's storage directory is persisted on the host filesystem - Error
    Could not check current state of edgeHub container
√ Agent image is valid and can be pulled from upstream - OK
√ proxy settings are consistent in aziot-edged, aziot-identityd, moby daemon and config.toml - OK

Connectivity checks
-------------------
√ container on the default network can connect to upstream AMQP port - OK
√ container on the default network can connect to upstream HTTPS / WebSockets port - OK
√ container on the IoT Edge module network can connect to upstream AMQP port - OK
√ container on the IoT Edge module network can connect to upstream HTTPS / WebSockets port - OK
31 check(s) succeeded.
3 check(s) raised warnings. Re-run with --verbose for more details.
1 check(s) raised errors. Re-run with --verbose for more details.
2 check(s) were skipped due to errors from other checks. Re-run with --verbose for more details.


root@localhost:/home/agilex# sudo iotedge system status
System services:
    aziot-edged             Running
    aziot-identityd         Running
    aziot-keyd              Running
    aziot-certd             Running
    aziot-tpmd              Ready

Use 'iotedge system logs' to check for non-fatal errors.
Use 'iotedge check' to diagnose connectivity and configuration issues.
```

</div></details>


以上でIntel® Agilex™️ SoC向けコンテナ利用可能なSDカードを作成することができました。
次は、Device Treeを変更しDevice Tree Overlayを利用したFPGAイメージの変更を行いたいと思います。


## References
+ [SDカードイメージ作り for Agilex™ SoC ~Cyclone®︎ V SoCとの比較を添えて~][LINK_Part1]
+ [Building Bootloader for Stratix 10 and Agilex️][LINK_BBSA]
+ [Moby Project - a collaborative project for the container ecosystem to assemble container-based systems][LINK_moby]
+ [Create and provision an IoT Edge device on Linux using symmetric keys][LINK_IoTEdgeInstall]
+ [DE10-Nano/FPGA Cloud Connectivity Kit using Microsoft* Azure][LINK_FCCKMSEdgeDoc]
+ [FCCK SD Card Image][LINK_FCCKSDCI]
+ [Linux Containers - LXC - Getting started][LINK_LXCGS]

[LINK_Part1]:https://qiita.com/hikawai/items/14c0c97e7852f113b368
[LINK_BBSA]: https://www.rocketboards.org/foswiki/Documentation/BuildingBootloader
[LINK_moby]:https://github.com/moby/moby
[LINK_IoTEdgeInstall]:https://learn.microsoft.com/en-us/azure/iot-edge/how-to-provision-single-device-linux-symmetric
[LINK_FCCKMSEdgeDoc]: https://github.com/intel-iot-devkit/terasic-de10-nano-kit/tree/master/azure-de10nano-document
[LINK_FCCKSDCI]: http://download.terasic.com/downloads/cd-rom/de10-nano/DE10-Nano-Cloud-Native.zip
[LINK_LXCGS]:https://linuxcontainers.org/lxc/getting-started/

<!--Hidden only used in the body-->
[LINK_BBSA_BLINUX]: https://www.rocketboards.org/foswiki/Documentation/BuildingBootloader#Appendix_45_Building_Linux_Binaries
[LINK_mobyScript]:https://github.com/moby/moby/blob/master/contrib/check-config.sh
[LINK_IoTEdgeInstallCE]:https://learn.microsoft.com/en-us/azure/iot-edge/how-to-provision-single-device-linux-symmetric?view=iotedge-1.4&tabs=azure-portal%2Cubuntu#install-a-container-engine

## Notices & Disclaimers

Code names are used by Intel to identify products, technologies, or services that are in development and not publicly available. These a​​re not "commercial" names and not intended to function as trademarks.​​​​​​
© Intel Corporation.  Intel, the Intel logo, and other Intel marks are trademarks of Intel Corporation or its subsidiaries.  Other names and brands may be claimed as the property of others​.​


​


​





​
​