とことんDevOps | 日本仮想化技術が提供するDevOps技術情報メディア

DevOpsに関連する技術情報を幅広く提供していきます。

日本仮想化技術がお届けするとことんDevOpsでは、DevOpsに関する技術情報や、日々のDevOps業務の中での検証結果など、DevOpsのお役立ち情報をお届けします。
主なテーマ: DevOps、CI/CD、アジャイル開発、コンテナ開発など
各種SNSのフォローもよろしくお願いいたします。

PodmanでMulti-archビルドを試す

本題に入る前にコンテナーイメージの話

DockerでもKubernetesでも、もちろんPodmanでも、コンテナプラットフォームではコンテナーイメージを利用します。 コンテナーイメージはDocker Hubのようなコンテナレジストリーからダウンロードして使います。

ベースイメージをカスタマイズする際は、作業用のマシンにDockerなどをインストールしてイメージのビルドを行うと思いますが、イメージを普通の方法でビルドした場合、同じCPUアーキテクチャーで利用できるコンテナイメージを作成できます。

しかし、最近は色々なCPUアーキテクチャーが一般に使われるようになりました。 例えばRaspberry Piは低価格ではありますが十分使えるARMボードの代表格です。 Apple Siliconを採用したMacを利用するユーザーも徐々に増えてきました。パブリッククラウドでもARM64アーキテクチャーのインスタンスを利用することもできるようになりつつあります。 ARM64アーキテクチャー向けのWindowsもWindows 11から正式版が提供されるようになり、徐々にARM64なWindows PCが増えるのではと期待されています。

というわけで、あなたが普段Intel CPUを使っている場合、コンテナーイメージを作成する場合に他のアーキテクチャーを想定しないと、他のCPUを実装するマシンでは実行できません。 さてそれだと他のアーキテクチャーを採用するマシンでは利用できません。それを解決するのがMulti-archイメージをビルドするという方法です。

Dockerの場合は次のような方法で、Multi-archイメージをビルドできます。

www.docker.com

しかし、例えばIntel x86_64なCPUを実装するマシンで果たしてどうやって他のアーキテクチャーのイメージをビルドするのかと言うと、QEMUという仮想化技術を使っています。 今回はPodmanを使って、Multi-archイメージをビルドしてみようと思います。

イメージをビルドしてみる

まず、こんな内容のファイルを作成してみます。これはRed Hat UBI9イメージを使ってPython3でWeb Serverを実行するだけのイメージを生成するだけのものです。

FROM docker.io/redhat/ubi9:latest

ENTRYPOINT ["python3", "-m","http.server","--bind","::"]
EXPOSE 8000

ファイル名は慣習的にDockerfileという名前で用意していたかと思います。 PodmanはDockerと高い互換性はありますが、でもDockerではありません。

Podmanの場合はContainerfileという名前でも自動で読み込んでくれます。他の名前のファイルを読み込む場合はDockerと同様に-fオプションを付ければよいようです。

最近のPodmanではpodman buildxというオプションが実装されています。使い勝手はdocker buildxに近いですが、全く同じというわけではなくちょっと違うので注意が必要です。実行すると、プラットフォームで指定したアーキテクチャーのイメージを順番にビルドしてくれます。

% podman buildx build --platform linux/arm64,linux/amd64 .

[linux/amd64] STEP 1/3: FROM docker.io/redhat/ubi9:latest
[linux/amd64] STEP 2/3: ENTRYPOINT ["python3", "-m","http.server","--bind","::"]
--> 2401eb60f4b
[linux/amd64] STEP 3/3: EXPOSE 8000
[linux/amd64] COMMIT
--> 3265d23466b
[linux/arm64] STEP 1/3: FROM docker.io/redhat/ubi9:latest
Trying to pull docker.io/redhat/ubi9:latest...
[Warning] one or more build args were not consumed: [TARGETARCH TARGETOS TARGETPLATFORM]
3265d23466b185cacba10f12e6834b19c011d336189186da1b5634c0d71731c6
Getting image source signatures
Copying blob sha256:a1d81c2404c27010bc762d7500fbf84cfb3724fca8e749f726ead9fa62158394
Copying blob sha256:8f38d96729f236ea7fd7c1073d21bb4135a49398db0eeff45301eb133278ed91
Copying config sha256:46308029455491e4bbaa7f3e5245b2e2f6fb6ddb411c5537823116a5dbc91095
Writing manifest to image destination
Storing signatures
[linux/arm64] STEP 2/3: ENTRYPOINT ["python3", "-m","http.server","--bind","::"]
--> 9f91c9fabcf
[linux/arm64] STEP 3/3: EXPOSE 8000
[linux/arm64] COMMIT
--> 22850a8f470
[Warning] one or more build args were not consumed: [TARGETARCH TARGETOS TARGETPLATFORM]
22850a8f4709d01ae104e63e00efbcde609964ab2d303c79b563d9cf6af3ee15

イメージのビルドは従来のようにpodman image build(もしくはpodman build)を実行する方法もありますが、今回はpodman buildx buildを使う方法を中心に解説します。

$ platarch=linux/amd64,linux/arm64
$ podman image build --jobs=2 --platform=$platarch --manifest shazam .

ビルドしたイメージを確認してみる

できたイメージのイメージIDは、今回の場合は次になります。

[linux/arm64] COMMIT
--> 22850a8f470

[linux/amd64] COMMIT
--> 3265d23466b

イメージを確認してみます。名前無しのイメージが2つ追加されています(一番下のイメージはベースイメージです)。

% podman images
REPOSITORY             TAG         IMAGE ID      CREATED             SIZE
<none>                 <none>      22850a8f4709  About a minute ago  249 MB
<none>                 <none>      3265d23466b1  About a minute ago  231 MB
docker.io/redhat/ubi9  latest      463080294554  7 days ago          249 MB

イメージIDをもとに、イメージのアーキテクチャーを確認してみます。

% podman image inspect 22850a8f4709 |grep Architecture
          "Architecture": "arm64",
% podman image inspect 3265d23466b1 |grep Architecture
          "Architecture": "amd64",

ビルドしたイメージをDocker Hubに登録

あとはイメージをDocker Hubに登録すれば、共有できます。 Docker Hubの利用は初めての場合はアカウントを登録してください。Docker Pro以上のライセンスを持っている場合はそのアカウントでログインすればよいです。 その場合はFreeライセンスよりも制限が緩和されます。

hub.docker.com

Docker Hubのドメインはdocker.ioを指定すれば良いです。 まずはログインします。PodmanでDocker Hubにログインする場合はpodman login docker.ioと実行します。次にユーザー名とパスワードをそれぞれ入力しますが、Docker Hubのアカウントに2FAを設定している場合は、ユーザー名とAccess Tokensをそれぞれ入力します。

% podman login docker.io

イメージにタグを設定します。今回はDocker Hubにイメージを登録する想定なので、docker.io/your-username/image-name:tagsのような名前付けにします。

(例)

% podman image tag 22850a8f4709 docker.io/ytooyama/multiarch-example:latest-arm64
% podman image tag 3265d23466b1 docker.io/ytooyama/multiarch-example:latest-amd64

上記タグ付けしたイメージをリポジトリーに登録するには、つぎのように実行します。

% podman image push docker.io/ytooyama/multiarch-example:latest-arm64 && \
 podman image push docker.io/ytooyama/multiarch-example:latest-amd64

ちなみに、Podman Desktopをインストールしている場合は、ログインやイメージのPushなどはPodman Desktopから実行できるので便利かもしれません。

レジストリのログインはPodman Desktopの設定で

ボタンを押すとイメージのPushが可能

これにより、Docker Hubのytooyama/multiarch-exampleに、2つのタグのイメージが登録されます。

登録されたイメージ(の例)

イメージの利用

作成したイメージは他のコンテナプラットフォームでは次のように使えます。

amd64 (x86_64) マシンでは

$ podman container run -d -p 8000:8000 ytooyama/multiarch-example:latest-amd64

arm64/aarch64マシンでは

$ podman container run -d -p 8000:8000 ytooyama/multiarch-example:latest-arm64

Dockerで使う場合は、上記のpodmanコマンドをdockerに置き換えて実行するだけです。

KubernetesでPodを作成する場合は(但:ノードのアーキテクチャーに対応するイメージを利用すること)

apiVersion: v1
kind: Pod
metadata:
  name: hello-multiarch
spec:
  containers:
    - name: hello-multiarch
      image: ytooyama/multiarch-example:latest-amd64
      ports:
      - containerPort: 8000

$ kubectl create -f pod.yaml

KubernetesでDeployment APIでPodを作成する場合は(但:ノードのアーキテクチャーに対応するイメージを利用すること)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-multiarch
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-multiarch
  template:
    metadata:
      labels:
        app: hello-multiarch
    spec:
      containers:
      - name: hello-multiarch
        image: ytooyama/multiarch-example:latest-amd64
        ports:
        - containerPort: 8000

$ kubectl create -f deployment.yaml

あとはKubernetes Serviceを使えば、アクセスできるようになるはずです。

前回の記事のようにPodmanでDocker-composeコマンドを使ったアプリケーションの実行も普通にできるので、macOSでのローカルのコンテナ開発ではPodman + Podman Desktopでも良いのではなんて思い始めました。Podmanは他と比べて起動や処理が速くて気に入ってます。

devops-blog.virtualtech.jp

今回参考にした情報