tkzwhr's notes

tkzwhrの技術、中国語などのメモです。

ARM64向けのdockerイメージをビルドしてローカルのregistryに登録する

いろんなところでハマったので、今後ハマらないようにするために手順を残しておく。

Buildxの有効化

マルチCPUアーキテクチャでビルドするためにビルド用のDockerコンテナ(ビルダーインスタンス)を用意するらしい。 buildxコマンドを使ってビルダーインスタンスを作れるので、下記のページを見ながらbuildxの有効化を行った。

docs.docker.jp

ビルダーインスタンスの作成

作成コマンドを実行して、シンプルなDockerfileをビルドしてみる。

Dockerfile

FROM debian:stable-slim
RUN apt update && apt install -y curl ca-certificates gnupg
$ docker buildx build --platform linux/arm64 -t test --load .

謎のエラーに遭遇

よく分からないエラーが発生してビルドが止まってしまった。

...
#6 28.29 dpkg: error processing archive /tmp/apt-dpkg-install-jPhItJ/37-libsasl2-modules_2.1.27+dfsg-1+deb10u1_arm64.deb (--unpack):
#6 28.29  dpkg-deb --control subprocess returned error exit status 1
#6 28.30 Error while loading /usr/sbin/dpkg-split: No such file or directory
#6 28.30 Error while loading /usr/sbin/dpkg-deb: No such file or directory
#6 28.30 dpkg: error processing archive /tmp/apt-dpkg-install-jPhItJ/38-publicsuffix_20190415.1030-1_all.deb (--unpack):
#6 28.30  dpkg-deb --control subprocess returned error exit status 1
#6 28.32 Errors were encountered while processing:
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/00-libssl1.1_1.1.1d-0+deb10u6_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/01-readline-common_7.0-5_all.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/02-krb5-locales_1.17-3+deb10u1_all.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/03-openssl_1.1.1d-0+deb10u6_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/04-ca-certificates_20200601~deb10u2_all.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/05-libkeyutils1_1.6-6_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/06-libkrb5support0_1.17-3+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/07-libk5crypto3_1.17-3+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/08-libkrb5-3_1.17-3+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/09-libgssapi-krb5-2_1.17-3+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/10-libsasl2-modules-db_2.1.27+dfsg-1+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/11-libsasl2-2_2.1.27+dfsg-1+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/12-libldap-common_2.4.47+dfsg-3+deb10u6_all.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/13-libldap-2.4-2_2.4.47+dfsg-3+deb10u6_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/14-libnghttp2-14_1.36.0-2+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/15-libpsl5_0.20.2-2_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/16-librtmp1_2.4+20151223.gitfa8646d.1-2_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/17-libssh2-1_1.8.0-2.1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/18-libcurl4_7.64.0-4+deb10u2_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/19-curl_7.64.0-4+deb10u2_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/20-libassuan0_2.5.2-1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/21-libreadline7_7.0-5_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/22-gpgconf_2.2.12-1+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/23-lsb-base_10.2019051400_all.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/24-libksba8_1.3.5-2_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/25-libnpth0_1.6-1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/26-dirmngr_2.2.12-1+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/27-gnupg-l10n_2.2.12-1+deb10u1_all.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/28-gnupg-utils_2.2.12-1+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/29-libsqlite3-0_3.27.2-3+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/30-gpg_2.2.12-1+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/31-pinentry-curses_1.1.0-2_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/32-gpg-agent_2.2.12-1+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/33-gpg-wks-client_2.2.12-1+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/34-gpg-wks-server_2.2.12-1+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/35-gpgsm_2.2.12-1+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/36-gnupg_2.2.12-1+deb10u1_all.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/37-libsasl2-modules_2.1.27+dfsg-1+deb10u1_arm64.deb
#6 28.32  /tmp/apt-dpkg-install-jPhItJ/38-publicsuffix_20190415.1030-1_all.deb
#6 28.39 E: Sub-process /usr/bin/dpkg returned an error code (1)
#6 ERROR: executor failed running [/dev/.buildkit_qemu_emulator /bin/sh -c apt update && apt install -y curl ca-certificates gnupg]: exit code: 100
------
 > [stage-0 3/7] RUN --mount=type=cache,target=/var/cache/apt     --mount=type=cache,target=/var/lib/apt     apt update && apt install -y curl ca-certificates gnupg:
------
Dockerfile:5
--------------------
   4 |
   5 | >>> RUN --mount=type=cache,target=/var/cache/apt \
   6 | >>>     --mount=type=cache,target=/var/lib/apt \
   7 | >>>     apt update && apt install -y curl ca-certificates gnupg
   8 |
--------------------
error: failed to solve: rpc error: code = Unknown desc = executor failed running [/dev/.buildkit_qemu_emulator /bin/sh -c apt update && apt install -y curl ca-certificates gnupg]: exit code: 100

調べてみると、githubに似たようなissueを見つけた。

Error building python 3.6 slim · Issue #495 · docker/buildx · GitHub

これで動くようになるらしい。

$ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

どうやらQEMUの設定が十分ではなく、指定したCPUアーキテクチャに対応できていなかったようだった。

改めてgithubbuildxのページを見てみると、 別のコマンドも書いてあったので、ついでに実行しおいた上で、ビルダーインスタンスを作り直した。

$ docker run --privileged --rm tonistiigi/binfmt --install all
$ docker buildx rm custom
$ docker buildx create --name custom --use

もしかしたら multiarch/qemu-user-static の方だけで良いのかもしれないが、このあたりはあまりよく分かってない。 何はともあれ、これで動いたので一旦進めることにする。

ローカルのRegistryにプッシュする

実は上記のコマンドは最終的に失敗する。

 => ERROR exporting to oci image format                                                                            0.0s
------
 > exporting to oci image format:
------
failed to solve: rpc error: code = Unknown desc = docker exporter does not currently support exporting manifest lists

これは現状のDockerの仕様によるもので、CPUアーキテクチャがホストと異なるイメージは登録できない仕様になっているために起こっているエラーである。 Dockerhubにpushすればいいらしいが、さすがに個人利用のイメージをDockerhubに上げるのも気が引けるので、プライベートのRegistryにプッシュする。

$ docker buildx build --platform linux/arm64 -t localhost:5000/test --push .
(...省略)
#12 pushing layers done
#12 ERROR: failed to do request: Head https://localhost:5000/v2/test/blobs/sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: http: server gave HTTP response to HTTPS c
lient
------
 > exporting to image:
------
error: failed to solve: rpc error: code = Unknown desc = failed to do request: Head https://localhost:5000/v2/test/blobs/sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
a3: http: server gave HTTP response to HTTPS client

HTTPSエラーに遭遇

HTTPSでアクセスしようとしてエラーになってしまった。そもそもlocalhostなのでHTTPでいいのでHTTPSを無効化する。 ちなみに、 docker push の場合は /etc/docker/daemon.json に下記の設定を入れておくことで回避できるのだが、 なぜかbuildxのpushでは動作しなかった。

{
  "insecure-registries": ["localhost:5000"]
}

Stackoverflow先生に聞くと、下記がヒットした。

docker - push cache to insecure registry by buildx - Stack Overflow

どうやら設定ファイルを食わせる必要があるようだ。

~/buildkitd.toml

[registry."localhost:5000"]
  http = true
  insecure = true
$ docker buildx create --name custom --config $HOME/buildkitd.toml --use
custom
$ docker buildx build --platform linux/arm64 -t localhost:5000/test --push .
(...省略)
#14 pushing layers
#14 pushing layers 9.5s done
#14 pushing manifest for localhost:5000/test 0.0s done
#14 DONE 22.3s

登録できた🎉