Closed8

マルチプラットフォーム対応Docker imageを配布してGitHub Codespacesで動かす

ran350ran350

やりたいこと

Docker ImageをDockerHubにpushして、GitHub Codespaceで動作させたい

ただし,

  • Docker Imageは,ARM64/AMD64 両環境に対応したマルチプラットフォーム対応であること

なぜマルチプラットフォーム対応(AMD64/ARM64)したいか

AMD64

2024年1月現在,GitHub Codespaces がこの環境のみサポートしているから

GitHub Community Disscussion によると

Currently Codespaces only offers Linux as the OS and x86_64 as the architecture for the host machines. Other OSes and architectures are under consideration, and would likely come from Azure's pool of VM types: azure.microsoft.com/en-us/pricing/details/virtual-machines/series

ARM64

本プロジェクトの開発者のうち,M1 MacなどARM64環境でDevContainerを立ち上げたい人が一定数いるから(私含め)

経緯

  • CyTeXというGitHub Codespace上で動作するLaTeX環境をメンテしている。
  • 今までは既存のDocker Imageをpullしてビルドしていたが、自プロジェクト用のImageを用意したくなった。
  • 理由としては、Dockerfile を変更する必要が生じて、どうせならビルド済みImageを配布した方が良いだろうとなったため
  • というのは、無料枠での GitHub Codespaces では利用上限があるため、できるだけCPU稼働時間が少ない方が良いから

最終到達目標

  • 私のM1 Mac(ARM64) で DevContainer を立ち上げられること
  • GitHub Codespaces (AMD64) で環境を立ち上げられること
ran350ran350

結論

  1. DockerHub リポジトリを作成

  2. Dockerfile を用意

  3. docker buildx コマンドでマルチプラットフォーム対応イメージをビルド & push

    docker buildx build --no-cache \
    --push \
    --platform linux/amd64,linux/arm64/v8 \
    -t イメージ:タグ .
    
  4. docker-compose.yaml を作成

    docker-compose.yaml
    docker-compose.yaml
    version: "3.8"
    services:
    サービス名:
        image: イメージ名 # Dockerfileを使ってビルドしたい場合,コメントアウトする
        # build: .     # Dockerfileを使ってビルドしたい場合,コメントアウトを外す
        command: sleep infinity
        volumes:
        - ../:/workdir
        - ~/.gitconfig:/root/.gitconfig
        environment:
        SHELL: "/bin/bash"
    
  5. devcontainer.json を作成

    devcontainer.json
    devcontainer.json
    {
        "name": "DevContainer名",
        "dockerComposeFile": "docker-compose.yaml",
        "service": "サービス名", # docker-composeで動作させたいサービス
        "workspaceFolder": "/workdir",
        "shutdownAction": "stopCompose",
        "customizations": {}
    }
    
  6. DevContainer と Codespaces でビルドして動作確認

ran350ran350

現状できていること

既存のDocker Imageを利用したDevContainer/Codespaces環境は,すでに構築できている.
これから独自のDocker Imageを作成して入れ替えたい.

  • devcontainer.json
  • docker-compose.yaml
  • Dockerfileはない,これから作る

作業方針

作業の全体像が見えていないので手探りであるが、現時点のイメージ

  1. Dockerfile をいじいじ
  2. ローカルDockerでビルド
  3. DevContainerを起動して動作確認
  4. マルチプラットフォーム対応Imageへのビルド
  5. DockerHubへpush
  6. GitHub Codespaces で起動して動作確認

特に,マルチプラットフォーム対応Imageへのビルドは全く初挑戦なのでかなり試行錯誤になりそう

ran350ran350

Dockerfile の変更,DevContainerの起動

Dockerfile を追加してDevContainerを起動すると,問題なく動作した.

Dockerfile

Dockerfileを追加

Dockerfile
FROM ubuntu:18.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y \
    xdvik-ja \ 
    evince \
    texlive-full \
    latexmk \
    language-pack-ja \
    wget \
    xzdec \
    git \
    cpanminus \
    make \
    perl \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

RUN tlmgr init-usertree
RUN kanji-config-updmap-sys ipaex

WORKDIR /workdir

VOLUME ["/workdir"]

CMD ["bash"]
docker-compose.yml

ローカルのDockerfileを使用してコンテナをビルドするよう変更

docker-compose.yml
version: "3.8"
services:
  cytex-texlive:
-    image: 既存のdocker image
+    build: .
    command: sleep infinity
    volumes:
      - ../:/workdir
      - ./.latexmkrc:/root/.latexmkrc
      - ~/.gitconfig:/root/.gitconfig
    environment:
      SHELL: "/bin/bash"
devcontainer.json

特に変更なし

devcontainer.json
{
    "name": "cytex",
    "dockerComposeFile": "docker-compose.yml",
    "service": "cytex-texlive",
    "workspaceFolder": "/workdir",
    "shutdownAction": "stopCompose",
    "customizations": {
        "vscode": {
            "settings": {
                "extensions.verifySignature": false
            },
            "extensions": [
				"james-yu.latex-workshop",
				"MS-CEINTL.vscode-language-pack-ja",
                "mhutchie.git-graph",
                "eamodio.gitlens"
			]
        }
    }
}
ran350ran350

マルチプラットフォーム対応イメージへのビルド手法の検討

まずは選択肢を調査

Multi-platform images | Docker Docs を見てみると,以下の3戦略がありそう

You can build multi-platform images using three different strategies, depending on your use case:

各選択肢を検討

1. QEMU

QEMU が何かをあまりよくわかっていないが,↓で似たことをやろうとしていて失敗していた.
arm64のM2 MacでDockerを使ってx86-64の実行環境を作る
理由が記載されていないので詳しくはわからないが,一旦他の選択肢を見てみる.

docker-buildxとmulti-platform build周りについてまとめ で↓と紹介されていた.

buildxを使って例えばamd64環境でarm向けのイメージを作成する場合は、buildx本体以外にもQEMUというエミュレータをインストールしておく必要があるらしい。
QEMUについて詳しく知りたい人は下記を読むと良さそうだけど、多分buildxについては下記の記事にある user mode emulation を使ってarmなどのCPUアーキテクチャをエミュレーションを行うために利用しているっぽい。

armなどのCPUアーキテクチャをエミュレーションを行いたいわけでないので一旦スルーする.

2. multiple nodes of different architectures

詳しくは咀嚼しきれなかったが,docker buildxコマンドを使ってmulti-platform buildできるっぽい.

buildx について入門記事を調べてみると,↓の良さげな記事を発見.
docker-buildxとmulti-platform build周りについてまとめ

一旦docker buildxを試したい.

3. cross-compilatoin

この選択肢も一応見ておく.

Multi-platform images | Docker Docs より,

Depending on your project, if the programming language you use has good support for cross-compilation, multi-stage builds in Dockerfiles can be effectively used to build binaries for target platforms using the native architecture of the build node. Build arguments such as BUILDPLATFORM and TARGETPLATFORM are automatically available for use in your Dockerfile, and can be leveraged by the processes running as part of your build.

クロスコンパイル可能なプログラミング言語を使っているプロジェクトなら有用とのこと.
ただ今回は,Docker上でtexliveを動かすというプロジェクトなので違う気がする.

暫定結論

docker buildx とやらが良さそうなので,こいつを試してこう

ran350ran350

docker buildx によるマルチプラットフォーム ビルドを試す

を参考に進めていく

環境構築

ビルド & DockerHub へのpushしてみる

$ docker buildx build --no-cache \
  --push \
  --platform linux/amd64,linux/arm64/v8 \
  -t ran350/cytex-texlive:0.0.1 . \
  .

40分くらいかかって完了した.結構かかるな 🤔

DockerHub を見てみる

OS/ARCH をみると,ちゃんと linux/amd64linux/arm64 が含まれている.

ran350ran350

DockerHub へ push した image を使ってビルドしてみる

docker-compose.yaml の変更

ローカルのDockerfileではなく,DockerHub のimageを使ってビルドするよう docker-compose.yamlを変更する.

docker-compose.yaml
version: "3.8"
services:
  cytex-texlive:
-     build: .
+    image: ran350/cytex-texlive:0.0.1

    command: sleep infinity
    volumes:
      - ../:/workdir
      - ./.latexmkrc:/root/.latexmkrc
      - ~/.gitconfig:/root/.gitconfig
    environment:
      SHELL: "/bin/bash"

DevContainer でビルド & 動作確認

問題なく動作した 🙌

Codespaces でビルド & 動作確認

問題なく動作した 🙌

ran350ran350

結論

  1. DockerHub リポジトリを作成

  2. Dockerfile を用意

  3. docker buildx コマンドでマルチプラットフォーム対応イメージをビルド & push

    docker buildx build --no-cache \
    --push \
    --platform linux/amd64,linux/arm64/v8 \
    -t イメージ:タグ .
    
  4. docker-compose.yaml を作成

    docker-compose.yaml
    docker-compose.yaml
    version: "3.8"
    services:
    サービス名:
        image: イメージ名 # Dockerfileを使ってビルドしたい場合,コメントアウトする
        # build: .     # Dockerfileを使ってビルドしたい場合,コメントアウトを外す
        command: sleep infinity
        volumes:
        - ../:/workdir
        - ~/.gitconfig:/root/.gitconfig
        environment:
        SHELL: "/bin/bash"
    
  5. devcontainer.json を作成

    devcontainer.json
    devcontainer.json
    {
        "name": "DevContainer名",
        "dockerComposeFile": "docker-compose.yaml",
        "service": "サービス名", # docker-composeで動作させたいサービス
        "workspaceFolder": "/workdir",
        "shutdownAction": "stopCompose",
        "customizations": {}
    }
    
  6. DevContainer と Codespaces でビルドして動作確認

このスクラップは2024/01/21にクローズされました