マルチアーキテクチャーイメージビルド（基礎編）

コンテナのメリットの一つとしてポータビリティ（可搬性）があります。

アプリケーションをコンテナイメージとしてパッケージングすることで、プラットフォームに依存せずに利用できるという特徴は、昨今のコンテナの普及に大きく貢献していると言えます。

しかしこのポータビリティは、プラットフォームのCPUアーキテクチャーが同一の場合にのみ成立するものであり、アーキテクチャーをまたぐことはできません。様々なアーキテクチャーのプラットフォームを組み合わせて管理していくマルチクラウド環境においては、これは避けては通れない課題です。

この課題に対するソリューションとして開発されているのが、Docker BuildxやBuildahといったマルチアーキテクチャー対応のイメージビルドツールになります。

本記事ではこれらのマルチアーキテクチャーイメージのビルド機能を検証しました。

#マルチアーキテクチャーイメージとは
単一のイメージの中に複数のアーキテクチャー形式を含めることができるものを指します。
https://matsuand.github.io/docs.docker.jp.onthefly/desktop/multi-arch/

Docker HubやQuay.ioにおける公式イメージの多くはマルチアーキテクチャーに対応しており、Pullする際に自動で実行環境に合わせたアーキテクチャーのイメージが提供されるため、ユーザーはアーキテクチャーを意識せずに利用することができます。

Dockerコマンドのプラグインである[Docker Buildx]("https://matsuand.github.io/docs.docker.jp.onthefly/buildx/working-with-buildx/")や、コンテナイメージの操作に特化したツールである[Buildah]("https://buildah.io/")を使うことで、マルチアーキテクチャーイメージをビルドすることができます。


# Docker Buildxによるイメージビルド

ビルド環境としてIA MacにDocker Desktopを導入して使用します。

Docker BuildxはDocker Desktopに含まれています。
https://www.docker.com/products/docker-desktop


### マルチアーキテクチャーイメージをビルドする

以下ステップでイメージをビルドします。
①マルチアーキテクチャーイメージビルド用のビルダーインスタンスを作成する
②そのインスタンスを使用してマルチアーキテクチャーイメージをビルドする


またマルチアーキテクチャーイメージのビルドには、マルチアーキテクチャーイメージに対応するレジストリにイメージを保管する必要があります。ここではDocker Hubを使用します。

```
### 事前に使用するイメージレジストリにログインしておく
### ビルダーインスタンスを作成・設定する
$ docker buildx create --name multibuilder
multibuilder

### ビルダーインスタンス確認
$ docker buildx ls
NAME/NODE       DRIVER/ENDPOINT             STATUS   PLATFORMS
multibuilder    docker-container
  multibuilder0 unix:///var/run/docker.sock inactive
...

### 作成したビルダーインスタンスを使用する
$ docker buildx use multibuilder


### amd64とs390x（IBM Z）のマルチアーキテクチャーイメージをビルドする
$ cat Dockerfile
FROM nginx
COPY ./index.html /usr/share/nginx/html

$ cat ./index.html
multiarch image built on mac

$ chmod 644 index.html

### ビルド実行＆Docker HubにPush
$ docker buildx build --platform linux/amd64,linux/s390x -t xxx/nginx-multiarch:mac --push .
[+] Building 23.5s (15/15) FINISHED
...
### Mac上での稼動確認
$ docker run --name nginx -d -p 8080:80 docker.io/xxx/nginx-multiarch:mac
$ curl http://localhost:8080
multiarch image built on mac

```


###ビルドしたイメージをIBM Zで実行

実行環境にはIBM CloudのHyper Protect Virtual Server（Ubuntu 20.04）です。
これにPodmanを導入して実行しています。

```
### IBM Z上からイメージをPullする
$ podman pull xxx/nginx-multiarch:mac
✔ docker.io/xxx/itlmc-nginx-multiarch:mac
...

$ podman images
REPOSITORY                             TAG         IMAGE ID      CREATED       SIZE
docker.io/xxx/nginx-multiarch  mac         0fe47c2b2120  14 hours ago  137 MB

$ podman run --name nginx -d -p 8080:80 nginx-multiarch:mac
cca52fc38526e2ea0e7520702849ef5c082e3ef28450abd7e7c5300d5f2ceb9f

$ podman ps
CONTAINER ID  IMAGE                                      COMMAND               CREATED        STATUS            PORTS                 NAMES
cca52fc38526  docker.io/xxx/nginx-multiarch:mac  nginx -g daemon o...  4 seconds ago  Up 4 seconds ago  0.0.0.0:8080->80/tcp  nginx

$ curl http://localhost:8080
multiarch image built on mac

```

#Buildahによるイメージビルド

ビルド環境はIBM CloudのHyper Protect Virtual Server（Ubuntu 20.04）です。

###マルチアーキテクチャーイメージをビルドする
Buildahの場合、
①それぞれのアーキテクチャーのイメージをビルドし、
②それらのイメージのインデックスとなるマニフェストを作成する
というステップです。

このマニフェストファイルをマルチアーキテクチャーイメージとして利用します。

イメージレジストリはDocker Hubを使用します。


```
### 事前に使用するイメージレジストリにログインしておく

$ cat Dockerfile
FROM nginx
COPY ./index.html /usr/share/nginx/html

$ cat index.html
multiarch image built on HPVS

$ chmod 644 index.html

### s390xイメージをビルドする
$ buildah bud --arch s390x -t docker.io/xxx/nginx-s390x:v1
...
Successfully tagged docker.io/xxx/nginx-s390x:v1
1e9bff381553835b9c8583c267e33bfc29c5874c2d878cdb2667da16fde2db2d

### amd64イメージをビルドする
$ buildah bud --arch amd64 -t docker.io/xxx/nginx-amd64:v1
...
Successfully tagged docker.io/xxx/nginx-amd64:v1
207da08ff0d56e125ffb4fcac0214dfd15387f7c511757959cb25af965a1a60c

$ buildah images
REPOSITORY                    TAG      IMAGE ID       CREATED         SIZE
docker.io/xxx/nginx-amd64     v1       207da08ff0d5   6 minutes ago   146 MB
docker.io/xxx/nginx-s390x     v1       1e9bff381553   9 minutes ago   144 MB
docker.io/library/nginx       latest   f6987c8d6ed5   2 days ago      146 MB


### イメージのPush
$ podman push docker.io/xxx/nginx-amd64:v1
...

$ podman push docker.io/xxx/nginx-s390x:v1
...


### それぞれのアーキテクチャーのイメージを参照するマルチアーキテクチャーイメージ（マニフェスト）を作成する
$ buildah manifest create nginx-multiarch:hpvs
5510878c5973d3dcf8daf301acfe0f215675ce5daa41eb11f0a14ca242c4ee63

$ buildah manifest add --override-arch=amd64 --override-os=linux --os=linux --arch=amd64 nginx-multiarch:hpvs docker.io/xxx/nginx-amd64:v1
5510878c5973d3dcf8daf301acfe0f215675ce5daa41eb11f0a14ca242c4ee63: sha256:87f0a1bdc43d86b6531693834026b32c12b7d29096b3eea756d65d7b05ea6c29

$ buildah manifest add --override-arch=s390x --override-os=linux --os=linux --arch=s390x nginx-multiarch:hpvs docker.io/xxx/nginx-s390x:v1
5510878c5973d3dcf8daf301acfe0f215675ce5daa41eb11f0a14ca242c4ee63: sha256:4dd94a2bc2f38584148b291f5532faafe889e811668f6c4366bdd88b2adf9a0e

### マルチアーキテクチャーイメージをPush
$ buildah manifest push --all nginx-multiarch:hpvs docker://xxx/nginx-multiarch:hpvs
...

### ローカルのイメージを一旦削除
$ buildah rmi 5510878c5973 207da08ff0d5 1e9bff381553
untagged: localhost/nginx-multiarch:hpvs
untagged: docker.io/xxx/nginx-amd64:v1
untagged: docker.io/xxx/nginx-s390x:v1

$ buildah images
REPOSITORY                TAG      IMAGE ID       CREATED      SIZE
docker.io/library/nginx   latest   f6987c8d6ed5   2 days ago   146 MB


### 改めてマルチアーキテクチャーイメージをPull
$ buildah pull docker.io/rkyce/nginx-multiarch:hpvs
...
Writing manifest to image destination
Storing signatures
1e9bff381553835b9c8583c267e33bfc29c5874c2d878cdb2667da16fde2db2d

$ buildah images
REPOSITORY                        TAG      IMAGE ID       CREATED          SIZE
docker.io/xxx/nginx-multiarch     hpvs     1e9bff381553   21 minutes ago   144 MB
docker.io/library/nginx           latest   f6987c8d6ed5   2 days ago       146 MB

### s390xのイメージがPullできていることを確認
$ podman inspect docker.io/xxx/nginx-multiarch:hpvs |grep s390x
        "Architecture": "s390x",

### 正常に稼動することを確認
$ podman run --name nginx -d -p 8080:80 docker.io/xxx/nginx-multiarch:hpvs
ef3bce605bc6e0f675f8546bb74298d6ee940077768e032caa2f3bdcaa0d5df3

$ podman ps
CONTAINER ID  IMAGE                                 COMMAND               CREATED        STATUS            PORTS                 NAMES
ef3bce605bc6  docker.io/xxx/nginx-multiarch:hpvs  nginx -g daemon o...  7 seconds ago  Up 8 seconds ago  0.0.0.0:8080->80/tcp  nginx

$ curl http://localhost:8080
multiarch image built on HPVS
```

###ビルドしたイメージをMacで実行

実行環境はIA MacのDocker Desktopです。

```
### MacからマルチアーキテクチャーイメージをPull
$ docker pull xxx/nginx-multiarch:hpvs

$ docker images
REPOSITORY                                                                                                                                          TAG               IMAGE ID       CREATED          SIZE
xxx/nginx-multiarch                                                                                                                               hpvs              207da08ff0d5   45 minutes ago   141MB


### amd64のイメージがPullできていることを確認
$ docker inspect xxx/nginx-multiarch:hpvs |grep Arch
        "Architecture": "amd64",

### 正常に稼動することを確認
$ docker run --name nginx -d -p 8080:80 xxx/nginx-multiarch:hpvs
2f43abf7796cf4428f8e333d6a07b32b29a2545eecd78417659734a4a2b1a12a

$ docker ps
CONTAINER ID   IMAGE                        COMMAND                  CREATED         STATUS         PORTS                                   NAMES
2f43abf7796c   xxx/nginx-multiarch:hpvs   "/docker-entrypoint.…"   6 seconds ago   Up 5 seconds   0.0.0.0:8080->80/tcp, :::8080->80/tcp   nginx

$ curl http://localhost:8080
multiarch image built on HPVS
```

# まとめ
Docker BuildxとBuildahでそれぞれマルチアーキテクチャーイメージのビルドができることを確認しました。

Docker Buildxは単一のリポジトリに複数のアーキテクチャーのイメージを包含できるのに対し、Buildahのマニフェストと実イメージが分かれる構成となっており、利便性に少し差がある印象です。
またDocker BuildxはDocker社の公式ドキュメントはじめ、Web上で参照できる情報が比較的充実していますが、Buildahはまだ情報が少なく、手探りの検証が必要になります。