🐈

DockerによるDPDKアプリケーションのビルド(前編)

2024/01/05に公開

以前書いたDocker開発環境シリーズのゆるい続編です。今回はDPDKを題材にクロスコンパイルについて考えてみます。

https://zenn.dev/anyakichi/articles/0fb5865cc5e1e3
https://zenn.dev/anyakichi/articles/73765814e57cba
https://zenn.dev/anyakichi/articles/3b5b379975be74
https://zenn.dev/anyakichi/articles/398f27e5b431bf
https://zenn.dev/anyakichi/articles/2e2cfcb9af7728
https://zenn.dev/anyakichi/articles/3e94b4a4899fb6
https://zenn.dev/anyakichi/articles/56ee804875e15e
https://zenn.dev/anyakichi/articles/8b40fd81546783
https://zenn.dev/anyakichi/articles/57902c452b1e11

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

ファイルについては、末尾のFPOCFに書き換えただけです。

DPDKアプリケーションのビルド

さて、それでは本題のDPDKアプリケーションのビルドをしてみます。アプリケーションとしては、DPDKのexamples/helloworldにあるhelloworldプログラムをビルドしてみます。このディレクトリ内には

  • アプリケーション本体のmain.c
  • dpdkと同時にビルドするためのmeson.build
  • システムにインストールされたDPDKを前提に、単体ビルド可能なMakefile

という微妙なサンプルが入っているのですが、今回は

  • システムにインストールされたDPDKを前提に、単体ビルド可能なmeson.build

を別途用意して、mesonでDPDKアプリケーションを単体ビルドできる環境を用意します。main.cのみhelloworldのものをコピーして利用します。

実際のサンプルファイルは以下のリポジトリに置いてあります。

https://github.com/anyakichi/dpdk-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でビルドできるように

ソースコードは以下に公開されています。

https://github.com/anyakichi/docker-dpdk-builder
https://github.com/anyakichi/dpdk-helloworld

さて、しかし明言はしていませんでしたが、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