Dockerでリアルタイム処理(cyclictest)を実行する
Dockerコンテナでリアルタイムタスクは動かせないの?と思ったので試してみました。
docker docs | Runtime options with Memory, CPUs, and GPUsにはConfigure the realtime schedulerという項目があり,リアルタイム処理を実現できそうな感じがします。
以下の手順でDockerコンテナ上でcyclictestを実行するところまでやってみます。
- カーネルのビルド
- リアルタイムスケジューラを使ったコンテナの起動
- cyclictestの実行
CONFIG_RT_GROUP_SCHEDを有効にしたカーネルをビルドする
docker docsを見るとCONFIG_RT_GROUP_SCHEDが有効になっているカーネルでないとコンテナがリアルタイムスケジューラを使用できないようです。RT PREEMPTIONパッチを当てがてら,CONFIG_RT_GROUP_SCHEDを有効にしてカーネルをビルドします。
パッチとカーネルソースのダウンロード
実はPreemption ModelをLowlatency DesktopとしないとCONFIG_RT_GROUP_SCHEDを有効にできないので,RT PREEMTTIONパッチは必要はなさそうですが一応当てておきます。
まずは以下からRT PREEMPTIONパッチを探します。
https://mirrors.edge.kernel.org/pub/linux/kernel/projects/rt/5.4/
5.4.13-rt7が最新版のようなので,以下から5.4.13のソースをダウンロードします。
https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/
以下の.tar.gzファイルをダウンロードしました。 https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.4.13.tar.gz
RT PREEMPTIONパッチの適用
カーネルソースとパッチを同じディレクトリに保存し,以下を実行します。
$ tar xf linux-5.4.13.tar.gz $ cd linux-5.4.13 $ gzip -cd ../patch-5.4.13-rt7.patch.gz | patch -p1 --verbose
Preemption Modelの変更
$ make menuconfig
以下のように
General setup > Preemption Model > Preemptible Kernel(Low-Latency Desktop)を選択します。
以下のようにGeneral setup > Control Group support > CPUControllerのGroup scheduling for SCHED_RR/FIFOにチェックを入れます。
上記のPreemption ModelでFully Preemptible Kernel(Real-Time)を選択するとGroup scheduling for SCHED_RR/FIFOが選択できなくなります。
上記2つを設定したら下部メニューのExitを選択し,menuconfigを終了します。終了時に.configに内容を保存するか聞かれるのでYesを選択します。
カーネルイメージの作成
以下のコマンドを実行し,カーネルイメージとヘッダイメージを作成します。
$ make-kpkg -j 8 --rootcmd fakeroot --initrd kernel_image kernel_headers
ソースが展開されているディレクトリの一つ上の階層に.debファイルが作成されるので以下のコマンドを実行して.debファイルをインストールします。
$ cd .. $ sudo dpkg -i linux-headers-5.4.13-rt7_5.4.13-rt7-10.00.Custom_amd64.deb linux-image-5.4.13-rt7_5.4.13-rt7-10.00.Custom_amd64.deb
GRUBメニューが表示されなくなることの対策
ビルドしたカーネルをインストールして再起動しGRUBメニューでカーネルを選択するわけですが,起動時にGRUBメニューが表示されない場合があります。
そのような場合は,/etc/default/grubファイルを編集してGRUBメニューが表示されるようにします。
$ sudo vi /etc/default/grub 以下のように先頭に#をつけて,2行をコメントアウトする # GRUB_TIMEOUT_STYLE=hidden # GRUB_TIMEOUT=0
編集後はupdate-grub
を実行しておきます。
Invalid Signatureによりカーネルがロードできない場合の対策
ビルドしたカーネルで起動しようとした際にInvalid Signatureエラーによりカーネルがロードできない場合があります。
以下のようにしてSecure Bootを無効にすることで回避できます。
PCをシャットダウンする前に以下のコマンドを実行します。
$ sudo mokutil --disable-validation
再起動後にmokutilを実行するか確認するダイアログが表示されます。mokutilを実行すると上記のmokutilコマンド実行時に設定したパスワード入力を求められます。
入力したパスワードをすべて入力するのではなく,パスワードの何文字目は何かという形式で1文字ずつ入力します。
リアルタイムスケジューラを使うコンテナの起動
起動前の確認
以下のファイルがあることを確認します。
/sys/fs/cgroup/cpu.rt_runtime_us
Dockerデーモンが動作していることを確認します。
$ docker ps
起動していない場合,以下コマンドにより再起動します。
$ sudo service docker restart
Dockerfileの作成とイメージのビルド
以下のようなDockerfileを作成します。ubuntu18.04にRT-Testsをインストールしています。
FROM ubuntu:18.04 RUN apt-get update && apt-get upgrade -y && apt-get install -y build-essential libnuma-dev git python RUN git clone git://git.kernel.org/pub/scm/utils/rt-tests/rt-tests.git && \ cd rt-tests && \ git checkout stable/v1.0 && \ make all && \ make install
Dockerファイルをビルドします。
$ docker build -t rttest:latest .
コンテナの起動
以下のコマンドによりrttestイメージを起動します。
$ docker run -it --cpu-rt-runtime=950000 --ulimit rtprio=99 --cap-add=sys_nice rttest:latest
起動時に以下のようなエラーが出る場合があります。
docker: Error response from daemon: OCI runtime create failed: container_linux.go:345: starting container process caused "process_linux.go:281: applying cgroup configuration for process caused \"failed to write 950000 to cpu.rt_runtime_us: write /sys/fs/cgroup/cpu,cpuacct/docker/e2a68990c554b501acfdee02a2d6be94240edd8860335c6ce5b64f559e82eba3/cpu.rt_runtime_us: invalid argument\"": unknown.
上記のようなエラーが出るのは/sys/fs/cgroup/cpu/docker/cpu.rt_runtime_usに設定されているリアルタイムタスクの実行時間が0になっているためのようなので,以下のコマンドにより0以上の値を設定します。
$ sudo -s # echo 950000 > /sys/fs/cgroup/cpu/docker/cpu.rt_runtime_us
/sys/fs/cgroup/cpu/docker/cpu.rt_period_usには1000000が設定されており,これとの比率で割り当てられたCPU処理時間の何%をリアルタイム処理に回すかを設定できます。上記の場合はcpu.rt_runtime_usが950000なので,95%がリアルタイム処理に回されます。
上記を実行後,再度docker run
コマンドを実行し,rttestコンテナのコンソールに接続します。
cyclictestの実行
起動したコンテナ上でcyclictestを実行します。
# cyclictest --smp --priority=80 --interval=200 --distance=0
以下のように表示され,cyclictestが実行できました。
WARN: stat /dev/cpu_dma_latency failed: No such file or directory policy: fifo: loadavg: 6.18 3.00 1.65 6/1057 23 T: 0 ( 20) P:80 I:200 C: 618500 Min: 2 Act: 7 Avg: 8 Max: 2419 T: 1 ( 21) P:80 I:200 C: 617407 Min: 2 Act: 6 Avg: 8 Max: 2513 T: 2 ( 22) P:80 I:200 C: 618459 Min: 2 Act: 12 Avg: 7 Max: 2540 T: 3 ( 23) P:80 I:200 C: 616966 Min: 2 Act: 6 Avg: 9 Max: 2431
しかし,スレッドの起動周期200us(cyclictestの引数--inteval=200)に対して最大のレイテンシが2540usとなっています。
平均は約10usなので概ね大丈夫そうですが,たまに遅れるようです。
まとめ
Dockerコンテナ上でcyclictestを実行するところまで試しました。
次回はcyclictestの結果をヒストグラム表示してもう少し詳しく見てみます。