背景
Apple SiliconのMacが販売されてそれなりの時間も経ち、エコシステムもできてきてお仕事の開発に使っている人も増えてきたように思う。
ところで、colimaのようなツールを使い、Docker環境をMacに作成した時、Apple Silicon上ではデフォルトで arm64 版のDocker*1がインストールされる。
$ docker info | grep Archi Architecture: aarch64
この上で何も考えずにイメージをビルドしたら arm64 のイメージができる。
この時、このイメージをリモートのレジストリ(GCR、GHCRなどを想像してほしい)にpushにしたら、もちろん arm64 のイメージがpushされる。
ここで、このイメージをx86_64の本番サーバにpullして走らせるような運用だったら、困ったことになるだろう...。
このような違うアーキテクチャのイメージをうっかりプッシュしてしまう事故は、意外と防ぐ仕組みが簡単ではない*2。
さらに言うと、pushされたイメージのアーキテクチャがなんであるかを確認するのも意外と骨が折れる。pullしてしまえば docker inspect
なりで確認すればすぐわかるが、何度もプッシュしていてそのうちいくつかに混ざってしまったような場合とか、そもそもイメージが大きい場合とかは難しいこともありそう。
と言うことで Docker Registory API を叩いてリモートから確認するコマンドを作った。
インストール
$ go install github.com/udzura/archof
Go 1.17 で動作確認しています。多分1.18などでも問題なさそう。
様子
$ archof docker.io/amd64/ubuntu:latest amd64 $ archof docker.io/arm64v8/ubuntu:latest arm64
認証が必要なやつはBearer認証に対応しているので、たとえばGCRだとこう言う感じで使えます。
$ archof gcr.io/udzura-dev/sample:latest --bearer "$(gcloud auth print-access-token)" amd64
内部
マニフェストを取得して、そこからConfigのDigestを取得してBlobを取得すればいいんですが、今回利用した go-containerregisrty はBlobの方のAPIをどう叩けばいいかよくわからず、URLを自分で構築して直接叩くことになった。いい方法があるんだろうか。
ref, _ := name.ParseReference(target) desc, _ := remote.Get(ref, remote.WithAuth(&authn.Bearer{Token: token})) reg := ref.Context() url := fmt.Sprintf("%s://%s/v2/%s/blobs/%s", reg.Scheme(), reg.RegistryStr(), reg.RepositoryStr(), sha, ) res, _ := desc.Client.Get(url) type BlobResponse struct { Architecture string `json:"architecture"` } b := BlobResponse{} if err := json.NewDecoder(res.Body).Decode(&b); err != nil { panic(err) } fmt.Println(b.Architecture)
雑感
Go の思い出しも兼ねて作ったが、特に変わったことをしていないので思い出せたのかどうか。
あとコマンドの名前の主語が大きいかも?(対象はコンテナイメージだけなのに) と思ったが、覚えやすいしえいやと付けました。ご了承ください。
とりあえず不安になった時にお使いください。というかpush防ぐ方法ってないんですかね...。