NHN Cloud Meetup 編集部
Docker Buildxでマルチアーキテクチャ対応のイメージを構築する
2020.10.19
9,270
はじめに
最近まで、GoogleのクラウドプロジェクトにKubernetesクラスタを作成していましたが、有料のため金銭的なコストをかけずにマルチノードクラスタを実践できる環境を構成したいと思い、自宅にあった4台の開発ボードordroid-xu4を活用してみることにしました。
エラー発生
Dockerをセットする過程で問題が発生しました。Dockerをインストールしてテストするため、簡単にビルドしたイメージをPullで受け取りコンテナを実行したところ、以下のように失敗しました。
jaeeunyoo@skynet-201:~$ docker pull frontiersofme/py-app Using default tag: latest latest: Pulling from frontiersofme/py-app ... Status: Image is up to date for frontiersofme/py-app:latest docker.io/frontiersofme/py-app:latest jaeeunyoo@skynet-201:~$ docker run -it -p 8081:8081 frontiersofme/py-app standard_init_linux.go:211: exec user process caused "exec format error"
なぜダメなのか?
表示されるエラーメッセージを検索したところ、私の状況ではビルドされたイメージの実行環境(CPUアーキテクチャ)が異なるためでした。(xu4はarm32v7)
hello-worldはなぜうまくいくのだろう?
jaeeunyoo@skynet-201:~$ docker run hello-world Hello from Docker! This message shows that your installation appears to be working correctly. ...
ところが、hello-worldのサンプルは次のように正常に実行されました。
GitHubに公開されているhello-worldプロジェクトを見ると、Dockerfileにメジャー(major)したアーキテクチャに対して、クロスコンパイル(cross-compile)することを確認しました。
# explicitly use Debian for maximum cross-architecture compatibility FROM debian:buster-slim RUN set -eux; \ apt-get update; \ apt-get install -y --no-install-recommends \ ca-certificates \ gnupg dirmngr \ wget \ \ gcc \ libc6-dev \ make \ \ libc6-dev-arm64-cross \ libc6-dev-armel-cross \ libc6-dev-armhf-cross \ libc6-dev-i386-cross \ libc6-dev-mips64el-cross \ libc6-dev-ppc64el-cross \ libc6-dev-s390x-cross \ \ gcc-aarch64-linux-gnu \ gcc-arm-linux-gnueabi \ gcc-arm-linux-gnueabihf \ gcc-i686-linux-gnu \ gcc-mips64el-linux-gnuabi64 \ gcc-powerpc64le-linux-gnu \ gcc-s390x-linux-gnu \ \ file \ ; \ rm -rf /var/lib/apt/lists/* ...
他にも異なるデバイスで実行させるビルド方法はいくつかありますが、組込みSW開発者でない限り、あまり興味をひく内容ではなく、簡単にビルドや配布を行うためにDockerを使用しようとする立場では、かなり面倒なように感じました。
Docker Buildxの紹介
諦めようとしたとき、たまたまDocker Buildxを見つけました。
Buildxは、さまざまなプラットフォームに向けてビルドする機能などを含むCLIの拡張プラグインで、19.03バージョンから使用できます。現在は試験的な機能(experimental feature)として提供されているため、使用するにはその機能を手動で有効にする必要があります。
使用方法
MacOS基準で作成しました。
Docker バージョンを確認
NHNEntui-MacBook-Pro-45:~ nhnent$ docker --version Docker version 19.03.12, build 48a66213fe
19.03から適用されるため、それより前のバージョンでは使用できません。
Docker CLI (試験的な機能)の有効化
MacOS
# 有効前 NHNEntui-MacBook-Pro-45:~ nhnent$ docker buildx docker: 'buildx' is not a docker command. See 'docker --help' # 有効後 NHNEntui-MacBook-Pro-45:~ nhnent$ docker buildx Usage: docker buildx COMMAND Build with BuildKit Management Commands: imagetools Commands to work on images in registry Commands: bake Build from a file build Start a build create Create a new builder instance inspect Inspect current builder instance ls List builder instances rm Remove a builder instance stop Stop builder instance use Set the current builder instance version Show buildx version information Run 'docker buildx COMMAND --help' for more information on a command.
ビルダーインスタンスを確認
NHNEntui-MacBook-Pro-45:~ nhnent$ docker buildx ls NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS default * docker default default running linux/amd64, linux/arm64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
inux/amd64、linux/arm64、linux/ppc64le、linux/s390x、linux/386、linux/arm/v7、linux/arm/v6に対してビルドが提供されます。
ビルダー作成および使用設定
docker buildx create –name [builder instance名] –driver [ドライバ名] –use
# マルチアーキテクチャービルダーとして使用設定 NHNEntui-MacBook-Pro-45:~ nhnent$ docker buildx create --name multi-arch-builder --driver docker-container --use multi-arch-builder # 現在のビルダーインスタンス情報 NHNEntui-MacBook-Pro-45:~ nhnent$ docker buildx inspect --bootstrap [+] Building 6.0s (1/1) FINISHED => [internal] booting buildkit 6.0s => => pulling image moby/buildkit:buildx-stable-1 5.0s => => creating container buildx_buildkit_multi-arch-builder0 1.0s Name: multi-arch-builder Driver: docker-container Nodes: Name: multi-arch-builder0 Endpoint: unix:///var/run/docker.sock Status: running Platforms: linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
Buildxでイメージをビルド、およびPush
NHNEntui-MacBook-Pro-45:multiarch nhnent$ docker buildx build --platform linux/arm/v7 -t frontiersofme/multiarch-py-app --push . [+] Building 105.2s (8/8) FINISHED => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 125B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/python:3.8 12.7s => [internal] load build context 0.0s => => transferring context: 28B 0.0s => [1/3] FROM docker.io/library/python:3.8@sha256:2c1045587e4452d49544c6dce92efe21c3b4b33864cfb56fdee66a2c8585c769 39.4s => => resolve docker.io/library/python:3.8@sha256:2c1045587e4452d49544c6dce92efe21c3b4b33864cfb56fdee66a2c8585c769 ...
対象のボードにイメージを Pull、その後コンテナを実行
# イメージを Pull jaeeunyoo@skynet-201:~$ docker pull frontiersofme/multiarch-py-app Using default tag: latest latest: Pulling from frontiersofme/multiarch-py-app e7cf402ee4b1: Already exists cff6bd4a89fc: Already exists e48f5852a753: Already exists e58a93b33dd4: Already exists a3c3db37cc57: Already exists 2c8297f1a358: Already exists 6d14eca818f3: Already exists 704121b65f11: Already exists 6cdf5a94358e: Already exists 9f9eec9ff6d5: Pull complete a54ba2fcc3f8: Pull complete Digest: sha256:3b46e7ef76d3512d31ddef962b07a5d46f999a9e10b7367d3548112b34af2cd7 Status: Downloaded newer image for frontiersofme/multiarch-py-app:latest docker.io/frontiersofme/multiarch-py-app:latest # コンテナ実行 jaeeunyoo@skynet-201:~$ docker run -it -p 10001:10001 frontiersofme/multiarch-py-app * Serving Flask app "app" (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off * Running on http://0.0.0.0:10001/ (Press CTRL+C to quit) 192.168.0.3 - - [27/Aug/2020 23:47:25] "GET / HTTP/1.1" 200 - 192.168.0.3 - - [27/Aug/2020 23:47:25] "GET / HTTP/1.1" 200 - 192.168.0.3 - - [27/Aug/2020 23:47:25] "GET /favicon.ico HTTP/1.1" 404 - ..
まとめ
現在は試験的な機能として提供されていますが、当該機能に対する需要は非常に高く、実際に低消費電力、高性能ARM 64bit基盤のインスタンスを提供するサービスも増えています。早く正式機能になることを期待しています。