Radxa Cubie A5Eゲートウェイをとして仕立てる
はじめに
Ethernetポートを2つ備えた低価格なSBCとして、Radxa Cubie A5E があります。 今回はこのSBCを用いて、以下のネットワークサービスを提供するシンプルなゲートウェイとして構築しました。
- DHCP
- TFTP
- NFS
技術基準適合証明(技適)に関しては、対象の無線機能を無効化することにより問題ないと判断しました。 具体的には、ドライバを削除することで該当の無線機能を有効化しない構成としています。この方針は文献 [2] を参考にしています。
やったこと
- 利用目的に合わせたカーネルの再構築を行いました
- カスタムカーネルを反映したインストールメディアを作成しました
- dnsmasq による DHCP・TFTPサーバー、および NFS サーバーのセットアップを行いました
ユースケースに合わせたカーネルの再構築
カーネルの再構築にあたっては、[1] を参考に、無線機能を無効化した上でシステムを構成しました。
まず、Radxaが提供しているSDK(t527_tina5.0_aiot_sdk.repo.tar.gz
)を取得し、展開します。このSDKは repo
によって構成されているため、展開後に各リポジトリの同期を行います。
$ tar -zxvf t527_tina5.0_aiot_sdk.repo.tar.gz
$ repo sync -l
続いて、置き換えが必要なリポジトリを指定のブランチでクローンします。
$ cd target
$ rm -rf a527
$ git clone --depth 1 --branch target-a527 git@github.com:radxa/allwinner-target.git a527
$ cd ../device/config/chips
$ rm -rf a527
$ git clone --depth 1 --branch device-a527 git@github.com:radxa/allwinner-device.git a527
$ cd ../../../
$ rm -rf bsp
$ git clone --depth 1 --branch product-t527-linux git@github.com:radxa/allwinner-bsp.git bsp
$ cd kernel
$ rm -rf linux-5.15
$ git clone --depth 1 --branch allwinner-aiot-linux-5.15 git@github.com:radxa/kernel.git linux-5.15
$ cd ../brandy/brandy-2.0
$ rm -rf u-boot-2018
$ git clone --depth 1 --branch allwinner-aiot-v2018.07 git@github.com:radxa/u-boot.git u-boot-2018
提供されている quick.sh
スクリプトには条件式の誤りがあるため、以下のように修正を行います。
$ cat quick.sh.diff
735c735
< if [ ! -f $1 ] && [ $1 = "build_help" ] ; then
---
> if [ ! -f $1 ] && [ $1 == "build_help" ] ; then
これで、ビルドに必要なファイルが揃いました。次に、ビルド環境の初期化と必要なパッケージの導入を行います。Radxaのドキュメントに記載された source build/envsetup.sh
に加えて、32bitアーキテクチャ向けのライブラリ群を導入します。
$ source build/envsetup.sh
NOTE: The SDK(/home/argon/workspace/radxa) was successfully loaded
...
$ sudo dpkg --add-architecture i386
$ sudo apt install libc6-i386 libz1:i386
$ sudo apt-get install libc6:i386 libstdc++6:i386 zlib1g:i386
$ export PATH=$PATH:$(pwd)/brandy/arisc/ar100s/tools/or32-elf-gcc/toolchain/bin
次に、システムの全体構成を設定します。 ./build.sh config
を実行し、ルートファイルシステムとして linaro-bullseye-lite-arm64.tar.gz
を選択します。
$ ./build.sh config
...
You read time left 8 seconds....
I have already read, understood and accepted the above terms? [Y/N]Y
You select Yes, Build continue....
========ACTION List: mk_config ;========
options :
All available platform:
0. android
1. linux
Choice [android]: 1
All available linux_dev:
0. bsp
1. dragonboard
2. buildroot
3. debian
Choice [bsp]: 3
All available kern_name:
0. linux-5.10
1. linux-5.15
Choice [linux-5.10]: 1
All available ic:
0. a523
1. a527
2. t527
Choice [a523]: 1
All available board:
0. cubie_a5e
1. d10_linux_aiot
2. demo_linux_aiot
3. pro2_linux_aiot
Choice [cubie_a5e]: 0
All available flash:
0. default
1. nor
Choice [default]: 0
cat: /home/argon/workspace/radxa_blog/debian/.config: No such file or directory
All available rootfs files:
0. linaro-bullseye-gnome-arm64.tar.gz
1. linaro-bullseye-lite-arm64.tar.gz
2. linaro-bullseye-lxde-arm64.tar.gz
3. linaro-bullseye-xfce-arm64.tar.gz
Choice [linaro-bullseye-gnome-arm64.tar.gz]: 1
...
カーネル設定は ./build.sh menuconfig
から行います。ローカルバージョンの指定、Wi-Fi/Bluetoothの無効化、NFSの有効化、loopデバイスの有効化などを行います。具体的な変更項目は以下の通りです。
- ローカルバージョンの指定
General setup --->
(-cubie-A5E-giteki) Local version - append to kernel release
- Wifiを無効化
Device Drivers --->
Network device support --->
[ ] Wireless LAN --->
- BlueToothを無効化
Networking support --->
< > Bluetooth subsystem support ---
- nfsを有効化
File systems --->
Network File Systems --->
<*> NFS client support
<*> NFS client support for NFS version 2
<*> NFS client support for NFS version 3
<*> NFS server support
-*- NFS server support for NFS version 3
[*] NFS server support for NFS version 4
- loopデバイスのマウントを有効化
Device Drivers --->
Block devices --->
<*> Loopback device support
システム初期化用のファイルは、target/a527/debian/cubie_a5e/overlay
に配置し、ルートファイルシステム内の設定を上書きします。以下の例のように、APTソース、ホスト名、DNS、ユーザー環境、ネットワーク設定などを行います。
$ cat >> /etc/apt/sources.list
deb http://deb.debian.org/debian/ stable main contrib non-free
deb http://deb.debian.org/debian/ stable-updates main contrib non-free
deb http://security.debian.org/debian-security stable-security main contrib non-free
今回はホスト名をmochi
という名前にします。
$ echo mochi > /etc/hostname
$ cat > /etc/resolv.conf
nameserver 8.8.8.8
nameserver 8.8.4.4
これらの環境変数は後述するconfig.sh
で使用します
$ cat > environment
USERNAME=argon
GROUPNAME=nebarinet
USER_ID=501
GROUP_ID=6809
GITHUB_ID=ar90n
$ cat > network/interfaces.d/eth0.conf
auto eth0
iface eth0 inet static
address 10.0.1.1
netmask 255.255.255.0
$ cat > network/interfaces.d/eth1.conf
auto eth1
iface eth1 inet dhcp
$ cat > sysctl.conf
net.ipv4.ip_forward=1
初回起動時にのみ実行される初期化スクリプト config.sh
も同様に配置します。このスクリプトは3段階で構成され、パーティショニング・ユーザー作成・Docker導入などを自動化します。各ステージの詳細を以下に述べます。
ステージ1: ディスクの初期化とマウント設定
NVMeディスク /dev/nvme0n1
を初期化し、以下の構成でパーティションを作成します。
- p1: swap
- p2:
/home
- p3:
/usr
- p4:
/var
各パーティションには対応ディレクトリの内容を rsync
でコピーし、fstab
に登録します。また、無線関連の systemd サービス(wpa_supplicant
、hostapd
、bluetooth
など)を無効化します。
処理完了後、stage2
を記録し再起動します。
ステージ2: パッケージ導入とユーザー作成
zsh
、chrony
、avahi-daemon
などをインストールし、環境変数で定義されたユーザー・グループを作成します。 GITHUB_ID
が指定されていれば、SSH公開鍵を GitHub から取得して登録します。また、タイムゾーンを Asia/Tokyo
に設定し、guest
ユーザーを削除します。
完了後、stage3
に移行して再起動します。
ステージ3: Dockerのインストールと後処理
APTを通じて Docker CE をインストールし、対象ユーザーを docker
グループに追加します。処理完了後、スクリプト自身と /etc/rc.local
からの呼び出しを削除し、初期化を終了します。
以下に実際のconfig.sh
を示します。
#!/bin/bash
# /etc/config.sh - 3-stage init script for direct partitioning and user setup
export DEBIAN_FRONTEND=noninteractive
STAGE_FILE="/etc/config-stage"
ENV="/etc/environment"
[ -f "$ENV" ] && source "$ENV"
DISK="/dev/nvme0n1"
MOUNT_BASE="/mnt/ssd"
# === Stage 1: Partition, format, and copy from SD ===
if [ ! -f "$STAGE_FILE" ]; then
echo "[Stage 1] Partitioning and copying rootfs..."
# Disable services
systemctl mask wpa_supplicant.service
systemctl stop hostapd.service
systemctl disable hostapd.service
systemctl stop bluetooth.target
systemctl disable bluetooth.target
systemctl stop wpa_supplicant-nl80211@.service
systemctl disable wpa_supplicant-nl80211@.service
systemctl stop wpa_supplicant-wired@.service
systemctl disable wpa_supplicant-wired@.service
systemctl stop wpa_supplicant@.service
systemctl disable wpa_supplicant@.service
systemctl stop dbus-fi.w1.wpa_supplicant1.service
systemctl disable dbus-fi.w1.wpa_supplicant1.service
systemctl stop NetworkManager
systemctl disable NetworkManager
# Install packages
ntpdate pool.ntp.org
dpkg --configure -a || true
apt --fix-broken install -y || true
apt-get update
apt-get install -y rsync
# Uninstall packages
apt-get purge -y x11-common hostapd wpasupplicant bluez pulseaudio
# Partition the disk (swap, home, usr, var)
wipefs -a $DISK
parted -s $DISK mklabel gpt
parted -s $DISK mkpart primary linux-swap 1MiB 4097MiB
parted -s $DISK mkpart primary ext4 4097MiB 20481MiB # home
parted -s $DISK mkpart primary ext4 20481MiB 36865MiB # usr
parted -s $DISK mkpart primary ext4 36865MiB 100%
# Wait for partitions to settle
sleep 2
partprobe
sleep 1
mkswap ${DISK}p1
mkfs.ext4 -F ${DISK}p2 # home
mkfs.ext4 -F ${DISK}p3 # usr
mkfs.ext4 -F ${DISK}p4 # var
mkdir -p $MOUNT_BASE/home $MOUNT_BASE/usr $MOUNT_BASE/var
mount ${DISK}p2 $MOUNT_BASE/home
rsync -aAX /home/ $MOUNT_BASE/home/ || exit 0
umount $MOUNT_BASE/home
mount ${DISK}p3 $MOUNT_BASE/usr
rsync -aAX /usr/ $MOUNT_BASE/usr/ || exit 0
umount $MOUNT_BASE/usr
mount ${DISK}p4 $MOUNT_BASE/var
rsync -aAX /var/ $MOUNT_BASE/var/ || exit 0
umount $MOUNT_BASE/var
echo "UUID=$(blkid -s UUID -o value ${DISK}p1) none swap sw 0 0" >> /etc/fstab
echo "UUID=$(blkid -s UUID -o value ${DISK}p2) /home ext4 defaults 0 2" >> /etc/fstab
echo "UUID=$(blkid -s UUID -o value ${DISK}p3) /usr ext4 defaults 0 2" >> /etc/fstab
echo "UUID=$(blkid -s UUID -o value ${DISK}p4) /var ext4 defaults 0 2" >> /etc/fstab
echo "stage2" > "$STAGE_FILE"
sync
reboot
exit 0
fi
# === Stage 2: Install base packages and create user ===
if grep -q "stage2" "$STAGE_FILE"; then
echo "[Stage 2] Installing base packages and creating user..."
apt install -y avahi-daemon avahi-utils zsh chrony curl gnupg ca-certificates lsb-release
systemctl enable avahi-daemon
systemctl disable avahi-daemon.socket
cp /lib/systemd/system/avahi-daemon.service /etc/systemd/system/avahi-daemon.service
if [ -n "$USERNAME" ] && [ -n "$GROUPNAME" ] && [ -n "$USER_ID" ] && [ -n "$GROUP_ID" ]; then
groupadd -g "$GROUP_ID" "$GROUPNAME"
useradd -m -u "$USER_ID" -g "$GROUP_ID" -s /usr/bin/zsh "$USERNAME"
echo "$USERNAME:$USERNAME" | chpasswd
usermod -aG sudo "$USERNAME"
mkdir -p "/home/$USERNAME/.ssh"
if [ -n "$GITHUB_ID" ]; then
curl -sL "https://github.com/$GITHUB_ID.keys" > "/home/$USERNAME/.ssh/authorized_keys"
chown "$USERNAME:$GROUPNAME" "/home/$USERNAME/.ssh/authorized_keys"
chmod 600 "/home/$USERNAME/.ssh/authorized_keys"
fi
chown -R "$USERNAME:$GROUPNAME" "/home/$USERNAME/.ssh"
fi
userdel -r guest
timedatectl set-timezone Asia/Tokyo
echo "stage3" > "$STAGE_FILE"
reboot
exit 0
fi
# === Stage 3: Install Docker CE and finalize user setup ===
if grep -q "stage3" "$STAGE_FILE"; then
echo "[Stage 3] Installing Docker CE..."
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable docker
if [ -n "$USERNAME" ]; then
usermod -aG docker "$USERNAME"
fi
echo "cleanup" > "$STAGE_FILE"
reboot
exit 0
fi
# === Cleanup state: remove self and rc.local entry ===
if grep -q "cleanup" "$STAGE_FILE"; then
echo "[Stage Cleanup] Removing config.sh and rc.local entry"
rm -f /etc/config.sh
sed -i '/\/etc\/config.sh/d' /etc/rc.local
rm -f "$STAGE_FILE"
exit 0
fi
最後に、全体のビルドとパッケージングを行い、SDカードイメージを作成します。
$ ./buils.sh
$ ./buils.sh kernel
$ ./buils.sh pack
DHCP・TFTP・NFSサーバーの構築
このゲートウェイは、他のSBC(シングルボードコンピュータ)に対してネットブート環境を提供することも目的としています。 そのため、DHCP、TFTP、NFS といった基本的なネットワークブート用サービスを構成します。
今回構築したサービス群の設定は、GitHubリポジトリ にまとめてあります。 この構成では、以下の各サービスを docker-compose.yml
によってコンテナとしてホスティングします。
dnsmasqによるDHCP・TFTPサーバーの構築
DHCPとTFTPは、dnsmasq
を利用して構築します。 dnsmasq
は、以下の Dockerfile
に基づいた軽量コンテナで提供します。
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
\
dnsmasq && rm -rf /var/lib/apt/lists/*
CMD ["dnsmasq", "--no-daemon", "--conf-file=/etc/dnsmasq.conf"]
設定ファイル(dnsmasq.conf
)の内容は以下の通りです。
# TFTP
enable-tftp
tftp-root=/var/tftpboot
tftp-no-blocksize
tftp-max=65535
# DHCP
interface=eth0
bind-interfaces
dhcp-range=10.0.1.100,10.0.1.200,12h
# DHCP option
dhcp-option=66,"10.0.1.1" # TFTPサーバIP
dhcp-option=67,"kernel8.img" # ブートファイル名
NFSサーバーの構築
NFSサーバーも同様に、以下の Dockerfile
によって構築します。 公開ディレクトリは /var/nfsroot
とし、/etc/exports
によってエクスポート設定を行います。
FROM debian:stable-slim
RUN apt-get update && \
apt-get install -y --no-install-recommends \
&& \
nfs-kernel-server apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN mkdir -p /var/nfsroot
VOLUME ["/var/nfsroot"]
COPY exports /etc/exports
EXPOSE 2049 111/udp 111/tcp
CMD ["/bin/sh", "-c", "\
mkdir -p /run/rpcbind && \
rpcbind && \
exportfs -rv && \
/usr/sbin/rpc.nfsd && \
/usr/sbin/rpc.mountd -F -N 2 && \
tail -f /dev/null"]
エクスポート設定ファイルは以下の通りです。
/var/nfsroot *(rw,sync,no_subtree_check,no_root_squash,fsid=0)
このように、DHCP・TFTP・NFS の各サービスはコンテナ化されており、docker-compose
を使って一括で管理できる構成としています。 設定の移植性・再現性を高める目的で、ホスト上ではなくコンテナベースで提供しています。