DockerによるDPDKアプリケーションのビルド(前編)
以前書いたDocker開発環境シリーズのゆるい続編です。今回はDPDKを題材にクロスコンパイルについて考えてみます。
DPDKのビルド
ひとまず実際にDPDKのビルドをしてみましょう。準備として手元の環境にDockerをインストールした上で、dinという簡単なスクリプトをPATHの通った場所にインストールしてください。
$ curl -o ~/.local/bin/din \
https://raw.githubusercontent.com/anyakichi/docker-buildenv/main/din.sh
以下のコマンドでDPDKのmainブランチのビルドができます。
$ mkdir dpdk-main && cd $_
$ din ghcr.io/anyakichi/dpdk-builder:main
builder@dpdk-main:/build$ extract -y
builder@dpdk-main:/build$ setup
builder@dpdk-main:/build/dpdk$ build -y
次に、ARM64用のバイナリを作りましょう。ARM64のDockerコンテナを起動する以外は手順はほとんど変わりません。
$ mkdir dpdk-main-aarch64 && cd $_
$ din --platform arm64 ghcr.io/anyakichi/dpdk-builder:main
builder@dpdk-main-aarch64:/build$ extract -y
builder@dpdk-main-aarch64:/build$ setup
builder@dpdk-main-aarch64:/build/dpdk$ build -y
ARM64の方はコンテナが起動できなかった人もいるかもしれません。x86_64環境でaarch64コンテナを動かすためには、binfmtとqemu-user(-static)が正しくセットアップされている必要があります。筆者のArch Linux環境では以下が必要になります。
$ sudo pacman -S qemu-user-static-binfmt
(試していませんが)Ubuntuだと以下のようになるでしょうか。
$ sudo apt install binfmt-support qemu-user-static
ということで、qemuで別のプラットフォームのDockerコンテナを直接動かしてしまうことで、クロスコンパイル(厳密に言えば仮想環境でのネイティブコンパイルですが)も簡単にできてしまいます。なお、エミュレーションのため実行速度は遅めですが、DPDKの規模のビルドであれば我慢できないほどではないと思います。
DPDKのコンテナへのインストール
次にアプリケーションのビルドの話題に移るのですが、DPDKアプリケーションのビルド、特にDPDKのexamplesディレクトリに入っているものではなく、外部アプリケーションとして作成したもののビルドは、pkg-config
の都合上一度DPDKをシステムにインストールしてからでないとやりづらいです。そのため一度コンテナ内の環境にビルドしたDPDKをインストールしてみます。
Dockerのビルド環境では、install
を実行するとコンテナ内にDPDKをインストールできます。
builder@dpdk-main:/build/dpdk$ install -y
さて、ここでもaarch64環境だと以下のようなエラーで失敗する人がいるかもしれません。
sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?
これはbinfmtのCフラグが設定されていないからなのですが、Arch Linuxの場合は以下のようにするとエラーを回避することができます(試していませんが、Ubuntu 22.04では設定ファイルだけ見たところおそらく何もしなくても動くのではないかと思います)。
$ sudo cp /usr/lib/binfmt.d/qemu-aarch64-static.conf /etc/binfmt.d
$ sudo vi /etc/binfmt.d/qemu-aarch64-static.conf
:qemu-aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-aarch64-static:OCF
$ sudo systemctl restart systemd-binfmt.service
ファイルについては、末尾のFP
をOCF
に書き換えただけです。
DPDKアプリケーションのビルド
さて、それでは本題のDPDKアプリケーションのビルドをしてみます。アプリケーションとしては、DPDKのexamples/helloworld
にあるhelloworldプログラムをビルドしてみます。このディレクトリ内には
- アプリケーション本体の
main.c
- dpdkと同時にビルドするための
meson.build
- システムにインストールされたDPDKを前提に、単体ビルド可能な
Makefile
という微妙なサンプルが入っているのですが、今回は
- システムにインストールされたDPDKを前提に、単体ビルド可能な
meson.build
を別途用意して、mesonでDPDKアプリケーションを単体ビルドできる環境を用意します。main.c
のみhelloworldのものをコピーして利用します。
実際のサンプルファイルは以下のリポジトリに置いてあります。
こちらもDockerビルド環境でビルドできるようにセットアップされているため、以下のようにビルドすることが可能です。
$ mkdir dpdk-helloworld && cd $_
$ din ghcr.io/anyakichi/dpdk-helloworld:main
builder@dpdk-helloworld:/build$ extract -y
builder@dpdk-helloworld:/build$ setup
builder@dpdk-helloworld:/build/dpdk$ build -y
コンテナ内でそのまま実行も可能です。
builder@dpdk-helloworld:/build/dpdk$ ./build/helloworld-static --no-huge
DPDK本体のビルドと同じように、din --platform arm64
で起動すると、ARM64のバイナリのビルド・実行も可能です。
DPDKのサンプルにおいてDPDK本体はmesonなのにアプリケーションはmakeという中途半端な状態なのですが、dpdk-helloworldをサンプルにしてもらうと外部アプリケーションもmesonで構成することができます。
まとめ
- DockerでDPDKを簡単にビルド
- クロスビルドもqemu-user-staticとDockerの
--platform
で簡単に - Dockerのエミュレーション環境ではbinfmtの設定をしてsudoできるように
- DPDKの単体アプリケーションをmesonでビルドできるように
ソースコードは以下に公開されています。
さて、しかし明言はしていませんでしたが、ghcr.io/anyakichi/dpdk-builder:main などのコンテナ環境は、今回はUbuntu 22.04で構築していました。DPDKのアプリケーションをpkg-configのオプションでstatic linkとしても、実はDPDKのライブラリ自体はstatic linkになるのですが、さらにそのDPDKが依存しているライブラリはdynamic linkになります。ということは実行環境のライブラリバージョンによって実行可否が決まることになり、実際ここで構築したバイナリはUbuntu 22.04では動いてもUbuntu 20.04では動きません。
一応ghcr.io/anyakichi/dpdk-builder:main-focal というコンテナもあり、これはUbuntu 20.04ベースになっていて、Ubuntu 20.04で動くバイナリも作ることは可能です。ただ、そうするとあらゆるディストリビューションのあらゆるバージョンのDockerイメージを用意しておかなくてはいけないということで、これは結構面倒くさいです。
というわけで、次回はDPDKおよびそのアプリケーションのクロスビルドについて考えてみます。つまり、CPUのアーキテクチャが異なる、もしくはディストリビューションの種類・バージョンが異なる場合でも、その環境を含むrootfsを用意することで、その環境に適したバイナリを生成できる汎用的なビルド環境を構成してみます。
Discussion