Kubernetes* 上でコンテナアプリケーションを実行するためにはまずクラスターと呼ばれるものを構築する必要があります。(参考)
今回の記事ではTerasic社製のDE10-Nanoを用いてKubernetes*のディストビューションの1つであるK3s*を用いてFPGAクラスターを構築して最後にFPGAのアップデートを試してみます。
注意事項 本記事では、あくまでクラスター構築に必要な部分のみしか解説しないため、細かい用語等には触れません。
KubernetesとAzure IoT Edge*はコンテナベースの開発という観点のみに着目すると非常に親和性が高いため、
Intel®︎ Developer Zone(IDZ)に公開されているドキュメント(英語版), (日本語(ページ内中央左にあるチュートリアル・モジュール1-4))をよく引用しますので、合わせて読むことを推奨します。
Recap: クラスター構成
著者環境
- Host OS : MacOS Catalina 10.15.7
- Guest OS(Server Node) : Ubuntu 18.04.5
- DE10-Nanos' OS(Agent Node) : Ubuntu 16.04.6
- K3s version : v1.20.4+k3s1 (838a906a)
Agent Node(Kubernetesでは一般的にWorker Nodeとも言います)には今回はTerasic社製のDE10-Nanoを利用します。
OSイメージとしては、同社が公開しているコンテナがすでに使える状態になっている、DE10-Nano-Cloud_native.img
を使います。
Note: 今後コマンドを実行する際は、どこから実行したかをわかりやすくするため前に(devPC=Client),(Guest=Server Node=VM),(de10nano=Agent Node)の三種類を付属します。
本記事はde10nano側に焦点を当てています。前準備が必要になるので、そちらは前編をご覧ください。
Agent Node準備(DE10-Nano)
本章は現在公開されているIDZドキュメント英語版, 日本語版のStep2までとほぼ同様です。
microSDカードについては8GBが付属していますが、これは容量が少ないので非推奨です。可能であれば16/32GBのmicroSDカードを別途ご用意ください。
やらなければならないことは以下の通りです。
- コンテナが使えるOSイメージの準備/microSDカードへの焼き込み
- シリアル通信での接続とrootFS領域の拡張
- IPアドレスの固定 / Hostnameの変更(Optional)
- ディスプレイを使うサービスの停止
コンテナが使えるOSイメージの準備/microSDカードへの焼き込み
Terasicのサイトにアクセスし、SD Card Image for AWS IoT Greengrass
となっているSDイメージをダウンロードしてください。
このイメージはファイル名がDE10-Nano-Cloud-Native.zip
となっており、AWSだけではなく、Azureでも利用可能なLinuxのイメージとなっています。今回の用途においては、Kernelレベルでコンテナが動かせる状態となっているというのが重要です。
Downloadが完了したら、zipを解凍し.imgファイルをお好きなアプリやコマンドで書き込みを行います。私はddや、balenaEtcherを利用しています。
(devPC)$ sudo dd if=DE10-Nano-Cloud-Native.img of=/dev/<your device path> status=progress
シリアル通信での接続とrootFS領域の拡張
書き込んだmicroSDカードをDE10-Nanoに挿入し、シリアル通信でつなぎます。
(pingしていきなりDE10-Nanoにつなぐという方法もありますが、手間なので非推奨です。)
シリアル通信をする際は、screen
や、putty
などのアプリケーションを使うとよいでしょう。
また、FTDIのドライバが入っているか確認しましょう。
(devPC)$ sudo screen /dev/tty.usbserial-A107T0IQ 115200 #Example
Ubuntu 16.04.6 LTS de10nano ttyS0
de10nano login: root
Password:
つながったら、デフォルトのログイン情報を使ってログインします。
Default login credentials:
- Username: root
- Password: de10nano
ログイン後、ディスクの拡張を行います。expand_rootfs.sh
というスクリプトが入っているので、それを実行、書いてあることに従い、再起動、resize2fs_once
を実行します。実行後、df -h
を行うとディスクいっぱいまで領域が拡張されていることが確認できます。
(de10nano)# ls
BT_LED_AP Desktop expand_rootfs.sh hps_gpio opencv
ControlPanel NET_Time gsensor my_first_hps
(de10nano)# ./expand_rootfs.sh
例では、32GBのSDカードを使った場合です。
(de10nano)# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/root 29G 2.2G 25G 8% /
devtmpfs 485M 0 485M 0% /dev
tmpfs 501M 0 501M 0% /dev/shm
tmpfs 501M 13M 489M 3% /run
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 501M 0 501M 0% /sys/fs/cgroup
tmpfs 101M 4.0K 101M 1% /run/user/0
IPアドレスの固定 / Hostnameの変更(Optional)
次は、IPアドレスの固定とHosenameの変更を行います。
この作業をしないと、ボードを再起動するたびIPアドレスが変わってしまい、Development PC(VM)と通信できなくなるのを防ぐためです。IPアドレスはEthernet InterfaceのMAC Addressが毎回変更されるため、DHCP側でほぼ確実に異なるアドレスを振ってくるので必須です。
ネットワーク設定の変更は、nmcli
コマンドを使って行います。
DHCP接続時の設定確認方法:
(de10nano)# nmcli con show Wired\ connection\ 1
設定の確認方法例:
(de10nano)# nmcli con mod Wired\ connection\ 1 connection.interface-name "eth0"
(de10nano)# nmcli con mod Wired\ connection\ 1 802-3-ethernet.mac-address ""
(de10nano)# nmcli con mod Wired\ connection\ 1 ipv4.address 192.168.100.201
(de10nano)# nmcli con mod Wired\ connection\ 1 ipv4.gateway "192.168.100.1"
(de10nano)# nmcli con mod Wired\ connection\ 1 ipv4.dns "8.8.8.8,8.8.4.4"
(de10nano)# nmcli con mod Wired\ connection\ 1 ipv4.method "manual"
(de10nano)# nmcli con down Wired\ connection\ 1 && nmcli con up Wired\ connection\ 1
特に大事なのは、mac-addressを消しておくことです。これをしておくことで、interfaceの名前だけで設定を紐づけてくれるようになります。
Hostnameの変更はServer Nodeと同様Node名を被らないようにするためです。
変更する際は /etc/hosts
と/etc/hostname
を編集します。
Note: 現在はk3s構築時にNode名を自由に指定できるオプションが追加されているため、必ずしも行う必要はありません。
最後に自動化用のスクリプトも作ってあるので、参考までにどうぞ。
少なくとも、ベースとなる(192.168.100.)とgatewayは適宜変更しないと動きませんので、この点はご留意ください。
#!/bin/bash
#for initialization
UUID=$(nmcli -t -f UUID c show --active)
NAME="EthConnection-for-k3s"
#FIXME
ADDR=192.168.100.2XX/24
OLDNODE="de10nano"
NODENAME=k3s-de10-workerXX
if [ $# -ne 1 ]; then
echo "Usage : ./fix-node.sh nodenumber(01/../09/10/.../55)"
exit 1
fi
flag=false
for index in 0{1..9} {10..55};
do
if [ $1 = $index ]; then
NODENAME=${NODENAME/XX/$index}
ADDR=${ADDR/XX/$index}
echo "NODENAME is $NODENAME"
echo "ADDR is $ADDR"
flag=true
break;
fi
done
if ! "${flag}"; then
echo "Error Format : Plz use 01/../09/10/.../55"
exit 1
fi
#Edit Hostname
sudo sh -c "echo $NODENAME > /etc/hostname"
sudo sed -i -e"s/$OLDNODE/$NODENAME/g" /etc/hosts
#Edit Network Connection
sudo nmcli con mod $UUID connection.id $NAME
sudo nmcli con mod $NAME connection.interface-name "eth0"
sudo nmcli con mod $NAME 802-3-ethernet.mac-address ""
sudo nmcli con mod $NAME ipv4.address $ADDR
sudo nmcli con mod $NAME ipv4.gateway "192.168.100.1"
sudo nmcli con mod $NAME ipv4.dns "8.8.8.8,8.8.4.4"
sudo nmcli con mod $NAME ipv4.method "manual"
#Please reboot
今回は例として下記のように実行しました。ここだけはわかりやすくするためにターミナルと同じ表示にしています。
Reboot後はHostnameとipアドレスが指定したものに変わっていることがわかります。
root@de10nano:~# ./fixed-node.sh 10
NODENAME is k3s-de10-worker10
ADDR is 192.168.100.210/24
sudo: unable to resolve host de10nano
sudo: unable to resolve host de10nano
sudo: unable to resolve host de10nano
sudo: unable to resolve host de10nano
sudo: unable to resolve host de10nano
sudo: unable to resolve host de10nano
sudo: unable to resolve host de10nano
root@de10nano:~# reboot
root@k3s-de10-worker10:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether c6:3d:a3:4f:5d:5a brd ff:ff:ff:ff:ff:ff
inet 192.168.100.210/24 brd 192.168.100.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::c63f:f196:b0eb:8344/64 scope link
valid_lft forever preferred_lft forever
Note: "unable to resolve host de10nano"というメッセージは再起動すると出なくなります。
ディスプレイを使うサービスの停止
FPGA をリコンフィグレーションするときにHPSからFPGAへのアクセスがあるとシステムがハングアップする可能性があるので、それを止めておきます。
具体的には、ディスプレイ周りのサービスを止めるよう/overlay/fpgaoverlay.sh
に下記を追加します。
実際に手動で止めてみるとわかりますが、lightdmはGUIの表示、gettyはCLIモードの時にターミナルを表示するサービスです(カーソルがチカチカします)。
(de10nano) vim /overlay/fpgaoverlay.sh
# 下記を追記
systemctl stop lightdm
systemctl stop getty@tty*
echo 0 > /sys/class/graphics/fbcon/cursor_blink
K3sインストール for DE10-Nano
ここからは前編の作業を完了していることを前提とします。
前編ではk3s serverをGuest VMにインストールしましたが、今回はk3s agentをDE10-Nanoにインストールします。
基本的には公式ガイドに従いますが、K3S_URL
とK3S_TOKEN
をインストールオプションに追加して実行しましょう。
k3supというユーティリティーツール現在ではリリースされています。こちらを用いるのもよいでしょう。
K3S_URL
は前編で設定したServerのIPアドレス+ポート番号(Defaultでは6443)を指定します。
K3S_TOKEN
はServer Node内の/var/lib/rancher/k3s/server/tokenの中に格納されています。
(Guest) # cat /var/lib/rancher/k3s/server/token
K107f205d9a138abd18b5f8f4f2ac170398600128fd6c37ab8fd3869a200a66cc02::server:fd287d907c641f05970b1b67a2d4eaf0
また、前章でDE10-Nanoの Node名を変更していない場合は、K3S_NODE_NAME
オプションもつけるとよいでしょう。
#This is a sample
MASTERURL="https://192.168.100.100:6443"
MASTERTOKEN="K107f205d9a138abd18b5f8f4f2ac170398600128fd6c37ab8fd3869a200a66cc02::server:fd287d907c641f05970b1b67a2d4eaf0"
curl -sfL https://get.k3s.io | K3S_URL=$MASTERURL K3S_TOKEN=$MASTERTOKEN sh -
これを実行することで自動的にインストール、k3s-agentが起動します。
しばらくすると、master側にも Nodeが登録されます。
(de10nano) # sudo systemctl status k3s-agent.service
● k3s-agent.service - Lightweight Kubernetes
Loaded: loaded (/etc/systemd/system/k3s-agent.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2021-03-31 06:45:11 UTC; 1min 23s ago
Docs: https://k3s.io
Process: 2100 ExecStartPre=/sbin/modprobe overlay (code=exited, status=0/SUCCESS)
Process: 2090 ExecStartPre=/sbin/modprobe br_netfilter (code=exited, status=0/SUCCESS)
Main PID: 2107 (k3s-agent)
Tasks: 41
Memory: 223.1M
CPU: 50.162s
CGroup: /system.slice/k3s-agent.service
├─2107 /usr/local/bin/k3s agent
├─2146 containerd
└─2517 /var/lib/rancher/k3s/data/912de41a65c99bc4d50bbb78e6106f3acbf3a70b8dead77b4c4ebc6755b4f9d6/bin/containerd-shim-runc-v
(devPC) $ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k3s-de10-worker10 Ready <none> 3m12s v1.20.4+k3s1
k3sserver Ready control-plane,master 10m v1.20.4+k3s1
最後にworkerであることを明示するためにラベルをつけておきましょう。
(devPC) $ kubectl label node k3s-de10-worker10 node-role.kubernetes.io/node=
node/k3s-de10-worker10 labeled
(devPC) $ kubectl label node k3s-de10-worker10 type=worker
node/k3s-de10-worker10 labeled
FPGAのアップデートを試す
ビルドイメージの作成
今回はK3sを使ってFPGAをアップデート(リコンフィグレーション)するというところにフォーカスするため、
FPGAイメージはすでにアップロードされているものを利用します。(FPGAの開発手順については別記事(英語のみ)を参照ください。)
具体的には、IDZ内のデモ(英語版), (日本語版)で利用されているものを利用します。
必要なファイルは以下の通りです。
LHoWa_TPat.rbf # FPGA bitstream GitHubより引用
config_sysid.dtbo # FPGA Reconfigurationを実行するDevice Tree Overlay File GitHubより引用
overlay.sh # DeviceTreeOverlayを実行するスクリプト、上記リンク内のドキュメントに存在するものを引用
Dockerfile #上記3つのファイルをコピーして保存するDockerfile 上記リンク内に存在するものを引用
overlay.sh, Dockerfile
#!/bin/bash
overlay_dir="/sys/kernel/config/device-tree/overlays/socfpga"
overlay_dtbo="config_sysid.dtbo"
overlay_rbf="LHoWa_TPat.rbf"
if [ -d $overlay_dir ];then
echo "Deleting $overlay_dir"
rmdir $overlay_dir
fi
echo "Copy DTBO and RBF"
cp $overlay_dtbo /lib/firmware/
cp $overlay_rbf /lib/firmware/
echo "creating $overlay_dir"
mkdir $overlay_dir
echo "Doing Device Tree Overlay"
echo config_sysid.dtbo > $overlay_dir/path
echo "Successfully Device Tree Overlay Done."
FROM arm32v7/ubuntu:xenial AS base
WORKDIR /app
COPY overlay.sh /app
COPY LHoWa_TPat.rbf /app
COPY config_sysid.dtbo /app
CMD ["./overlay.sh"]
チュートリアルでも触れているように今回はあくまでも、FPGAのReconfigurationを行うのみのイメージとなります。
実用ではソフトウェアなどもイメージにまとめることでホストアプリケーションの実行も可能です。
この手法では、Device Tree OverlayというLinuxの機能を活用しFPGAのリコンフィグレーションを行います。
具体的な手法については、ドキュメント, 日本語版内に解説がありますので、そちらをご参照ください。
すべてのファイルを同一のディレクトリへとコピーが完了したら、Buildxが使える状態でコンテナをビルドします。
(devPC) $ docker build --rm -f Dockerfile -t <AWS account ID>.dkr.ecr.<region>.amazonaws.com/<repository name>:<tag> .
e.g. docker build --rm -f Dockerfile -t 309190452075.dkr.ecr.us-east-2.amazonaws.com/kubernetes-demo-image:testv0 .
問題なくビルドができれば、ECRにプッシュします。ログアウトしてしまっている場合は再度ログインしなおしてください。
#aws ecr get-login-password | docker login --username AWS --password-stdin <AWS account ID>.dkr.ecr.<region>.amazonaws.com
(devPC) $ docker push <AWS account ID>.dkr.ecr.<region>.amazonaws.com/<repository name>:<tag> .
e.g. docker push 309190452075.dkr.ecr.us-east-2.amazonaws.com/kubernetes-demo-image:testv0 .
Kubernetesに載せてみる
スケジューリングからServer Nodeを除外します。
この設定はすでにデフォルトで組み込まれているはず(Issue)ですが、確認するか、念のため実行しておくとよいでしょう。
(devPC) $ kubectl taint nodes k3sserver node-role.kubernetes.io/master=effect:NoSchedule
続いて、下記の内容をファイルにまとめて、kubectl apply -f overlay.yaml
で実行してみます。
FPGAをReconfigurationするためには、/lib/firmware
と/sys/kernel/config
をコンテナにマウントする必要があります。
また、ホスト側のリソースにアクセスするため、Privileged権限も必用です。
FPGAのアップデートすることを主眼においているので、ワークロードリソースに関してはJobを指定しています。
kind: Job
apiVersion: batch/v1
metadata:
name: overlay-test
spec:
completions: 1
parallelism: 1
backoffLimit: 10
template:
metadata:
labels:
app: overlay
env: de10nano
spec:
restartPolicy: Never
containers:
- name: fpga-overlay
image: <AWS account ID>.dkr.ecr.<region>.amazonaws.com/<repository name>:<tag>
#e.g. image: 309190452075.dkr.ecr.us-east-2.amazonaws.com/kubernetes-demo-image:testv0
imagePullPolicy: IfNotPresent
securityContext:
privileged: true
volumeMounts:
- name: fpga-image
mountPath: /lib/firmware
- name: overlay-dir
mountPath: /sys/kernel/config
volumes:
- name: fpga-image
hostPath:
path : /lib/firmware
type : Directory
- name: overlay-dir
hostPath:
path : /sys/kernel/config
type : Directory
imagePullSecrets:
- name: aws
JobがCompleteされ、HDMIをつないでカラーバーが出るか、LEDがぼやぁと変化するようになったら成功です。
(devPC) $ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/overlay-test-csznn 0/1 Completed 0 14s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 398d
NAME COMPLETIONS DURATION AGE
job.batch/overlay-test 1/1 3s 14s
(devPC) $ kubectl logs overlay-test-csznn
Deleting /sys/kernel/config/device-tree/overlays/socfpga
Copy DTBO and RBF
creating /sys/kernel/config/device-tree/overlays/socfpga
Doing Device Tree Overlay
Successfully Device Tree Overlay Done.
Note: Podの最後はハッシュなので、実行するたびに変わります。
今回はFPGA SoCをKubernetesに載せてコンテナからリコンフィグレーションをしてみるというものを行ってみました。細かな技術的話は端折ってしまいましたが、まずはこれを機に始めてもらえたら嬉しいです。
前編へ戻る
References
- Kubernetesのコンポーネント
- Build, Deploy, and Manage your FPGA-Based IoT Edge Applications using Microsoft* Azure
- インテルのエッジセントリック FPGA ソリューション
- Install the Azure* IoT Edge Runtime
- FPGA クラウド・コネクティビティー・キット・チュートリアル・モジュール 1
- Terasic DE10-Nano Resource
- balenaEtcher
- D2XX Drivers - FTDI
- alexellis/k3sup: bootstrap Kubernetes with k3s over SSH
- Rancher Docs: Installation
- Develop and Deploy Container Using DE10-Nano RFS Daughter card sensor
- Reconfigure an FPGA from the Azure* Cloud using a Container Application
- FPGA クラウド・コネクティビティー・キット・チュートリアル・モジュール 4
- terasic-de10-nano-kit repository
- feat: add NoSchedule toleration on key node-role.kubernetes.io/master
Notices & Disclaimers
No product or component can be absolutely secure.
Your costs and results may vary.
Copies of documents which have an order number and are referenced in this document may be obtained by calling 1-800-548-4725 or visiting http://www.intel.com/design/literature.htm.
Intel disclaims all express and implied warranties, including without limitation, the implied warranties of merchantability, fitness for a particular purpose, and non-infringement, as well as any warranty arising from course of performance, course of dealing, or usage in trade.
No license (express or implied, by estoppel or otherwise) to any intellectual property rights is granted by this document.
© 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.