【第2回】Minecraft Bedrockサーバー用コンテナを作る

こんにちは。「Minecraft Bedrockサーバー用コンテナを作る」の第2回です。

おさらい

前回は作業用コンテナを使用し、Dockerfileを作成するための情報を収集しました。今回はその情報を基にDockerfileを作成し、コンテナを起動します。

blog.kenor.io

Dockerfile

以下のDockerfileでBedrock Serverのコンテナを構築可能です。

BedrockサーバーのDockerfile

このDockerfileの内容について説明します。

ビルド処理の詳細

FROM

FROM debian:bookworm-slim AS builder

ここには、第1回の動作検証に利用したdebian:bookworm-slimのコンテナイメージを指定します。

WORKDIR

WORKDIR /work

作業ディレクトリとして/workを指定します。ここにBedrockサーバーの起動に必要なファイルをまとめます。

SHELL

SHELL ["/bin/bash", "-o", "pipefail", "-c"]

Bashの使用を明記し、pipefailオプションを指定することで、パイプライン中のエラーを正しく検出します。

ARG

ARG USER_AGENT='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
ARG DOWNLOAD_URL='https://www.minecraft.net/en-us/download/server/bedrock'
ARG REGEX_PATTERN='https://www.minecraft.net/bedrockdedicatedserver/bin-linux/bedrock-server-[^/]+\.zip'

これらの変数はBedrockサーバーのダウンロード時に使用します。

USER_AGENT

最もシェアが高いと思われる、WindowsGoogle Chromeのユーザーエージェントを設定します。Bedrockサーバーのダウンロードに必要で、curlコマンド実行時に指定します。

DOWNLOAD_URL

BedrockサーバーダウンロードページのURLです。

第1回では日本語版のページからバイナリのダウンロードリンクを見つけましたが、マルチバイト文字が問題を起こす可能性を考慮し、英語版のページを設定しています。

www.minecraft.net

REGEX_PATTERN

Bedrockサーバーのダウンロードリンクを正規表現で特定するためのパターンです。

RUN

RUN apt-get -qq update \
    && DEBIAN_FRONTEND=noninteractive apt-get -qq install -y --no-install-recommends \
        ca-certificates=* \
        curl=7.88.1-* \
        unzip=6.0-* \
    && curl -sSA "$USER_AGENT" "$DOWNLOAD_URL" \
        | grep -Eo "$REGEX_PATTERN" \
        | xargs curl -sSOA "$USER_AGENT" \
    && unzip -q bedrock-server-*.zip -d bedrock-server \
    && mkdir /work/lib \
    && ldd /work/bedrock-server/bedrock_server \
        | grep -oP '[^\s]+(?= \()' \
        | xargs -I{} cp {} /work/lib

複雑なので、処理毎に分けて説明します。

パッケージのインストール

Bedrockサーバーのダウンロードに必要なパッケージをインストールします。

RUN apt-get -qq update \
    && DEBIAN_FRONTEND=noninteractive apt-get -qq install -y --no-install-recommends \
        ca-certificates=* \
        curl=7.88.1-* \
        unzip=6.0-* \

DEBIAN_FRONTENDの指定

コンテナイメージのビルド時はインタラクティブな操作をおこなわないため、DEBIAN_FRONTDEND=noninteractiveとします。

設定しないと以下のメッセージが表示されますが、気にならないようなら設定しなくても良いでしょう。

debconf: unable to initialize frontend: Dialog
debconf: (TERM is not set, so the dialog frontend is not usable.)
debconf: falling back to frontend: Readline
debconf: unable to initialize frontend: Readline
debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.36.0 /usr/local/share/perl/5.36.0 /usr/lib/x86_64-linux-gnu/perl5/5.36 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl-base /usr/lib/x86_64-linux-gnu/perl/5.36 /usr/share/perl/5.36 /usr/local/lib/site_perl) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 7.)
debconf: falling back to frontend: Teletype

--no-install-recommendsオプション

不要な関連パッケージのインストールを回避します。

マルチステージビルドを使うためコンテナのイメージサイズに影響はありませんが、インストール時間が延びるので指定しましょう。

インストールするパッケージ

ca-certificatescurlはBedrockサーバーをHTTPSプロトコルでダウンロードするときに必要です。

unzipはダウンロードしたファイルがZIPでアーカイブされているため、それを展開するために必要です。

パッケージはバージョンをゆるく指定していますが、これはhadolintでエラーを出さないためです。

ミッションクリティカルなシステムでなければ、セキュリティも考慮しディストリビューターが提供する最新のパッケージを利用して問題ないでしょう。

Bedrockサーバーのダウンロード

    && curl -sSA "$USER_AGENT" "$DOWNLOAD_URL" \
        | grep -Eo "$REGEX_PATTERN" \
        | xargs curl -sSOA "$USER_AGENT" \

ARGで設定した3つの変数をここで利用します。

処理の流れ

  • curl -sSA "$USER_AGENT" "$DOWNLOAD_URL"でダウンロードページの内容を取得
  • grep -Eo "$REGEX_PATTERN"でダウンロードリンクを特定
  • xargs curl -sSOA "$USER_AGENT"でダウンロードリンクからBedrockサーバーをダウンロード

アーカイブの展開

    && unzip -q bedrock-server-*.zip -d bedrock-server \

ダウンロードしたBedrockサーバーのアーカイブを展開します。後続作業のため、-dオプションでディレクトリを指定します。

ライブラリ配置用ディレクトリ作成

    && mkdir /work/lib{,64} \

Bedrockサーバーの起動に必要なライブラリの配置先ディレクトリとしてliblib64を作成します。

ライブラリのコピー

    && ldd /work/bedrock-server/bedrock_server \
        | grep -oP '(?<= => )[^\s]+?(?= \()' \
        | xargs -I{} cp {} /work/lib \
    && cp /lib64/ld-linux-x86-64.so.2 /work/lib64

Bedrockサーバーの起動に必要なライブラリを抽出し、先ほど作成したライブラリ用のディレクトリにコピーします。

第1回のlddコマンド実行結果をもう一度確認してみましょう。

root@8de161ca6300:/work/bedrock-server# ldd bedrock_server
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ffff54fe000)
        libcurl.so.4 => /lib/x86_64-linux-gnu/libcurl.so.4 (0x00007ffff544f000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ffff5370000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ffff5350000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ffff534b000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff516a000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ffffffcc000)
        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007ffff5163000)
        libnghttp2.so.14 => /lib/x86_64-linux-gnu/libnghttp2.so.14 (0x00007ffff5134000)
        libidn2.so.0 => /lib/x86_64-linux-gnu/libidn2.so.0 (0x00007ffff5103000)
        librtmp.so.1 => /lib/x86_64-linux-gnu/librtmp.so.1 (0x00007ffff50e4000)
        libssh2.so.1 => /lib/x86_64-linux-gnu/libssh2.so.1 (0x00007ffff50a3000)
        libpsl.so.5 => /lib/x86_64-linux-gnu/libpsl.so.5 (0x00007ffff508f000)
        libssl.so.3 => /lib/x86_64-linux-gnu/libssl.so.3 (0x00007ffff4fe4000)
        libcrypto.so.3 => /lib/x86_64-linux-gnu/libcrypto.so.3 (0x00007ffff4b5e000)
        libgssapi_krb5.so.2 => /lib/x86_64-linux-gnu/libgssapi_krb5.so.2 (0x00007ffff4b0b000)
        libldap-2.5.so.0 => /lib/x86_64-linux-gnu/libldap-2.5.so.0 (0x00007ffff4aac000)
        liblber-2.5.so.0 => /lib/x86_64-linux-gnu/liblber-2.5.so.0 (0x00007ffff4a9c000)
        libzstd.so.1 => /lib/x86_64-linux-gnu/libzstd.so.1 (0x00007ffff49e0000)
        libbrotlidec.so.1 => /lib/x86_64-linux-gnu/libbrotlidec.so.1 (0x00007ffff49d1000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007ffff49b2000)
        libunistring.so.2 => /lib/x86_64-linux-gnu/libunistring.so.2 (0x00007ffff47fc000)
        libgnutls.so.30 => /lib/x86_64-linux-gnu/libgnutls.so.30 (0x00007ffff45e0000)
        libhogweed.so.6 => /lib/x86_64-linux-gnu/libhogweed.so.6 (0x00007ffff4597000)
        libnettle.so.8 => /lib/x86_64-linux-gnu/libnettle.so.8 (0x00007ffff4547000)
        libgmp.so.10 => /lib/x86_64-linux-gnu/libgmp.so.10 (0x00007ffff44c6000)
        libkrb5.so.3 => /lib/x86_64-linux-gnu/libkrb5.so.3 (0x00007ffff43ec000)
        libk5crypto.so.3 => /lib/x86_64-linux-gnu/libk5crypto.so.3 (0x00007ffff43bf000)
        libcom_err.so.2 => /lib/x86_64-linux-gnu/libcom_err.so.2 (0x00007ffff43b9000)
        libkrb5support.so.0 => /lib/x86_64-linux-gnu/libkrb5support.so.0 (0x00007ffff43a9000)
        libsasl2.so.2 => /lib/x86_64-linux-gnu/libsasl2.so.2 (0x00007ffff438c000)
        libbrotlicommon.so.1 => /lib/x86_64-linux-gnu/libbrotlicommon.so.1 (0x00007ffff4369000)
        libp11-kit.so.0 => /lib/x86_64-linux-gnu/libp11-kit.so.0 (0x00007ffff4235000)
        libtasn1.so.6 => /lib/x86_64-linux-gnu/libtasn1.so.6 (0x00007ffff4220000)
        libkeyutils.so.1 => /lib/x86_64-linux-gnu/libkeyutils.so.1 (0x00007ffff4217000)
        libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007ffff4206000)
        libffi.so.8 => /lib/x86_64-linux-gnu/libffi.so.8 (0x00007ffff41fa000)
root@8de161ca6300:/work/bedrock-server#

これより、/lib64ディレクトリにはld-linux-x86-64.so.2/libにそれ以外をコピーすれば良さそうです。

lddコマンドでBedrockサーバーが参照するライブラリを特定できましたが、抽出には比較的複雑な正規表現が必要になります。

そこで、一致条件について理解しやすいよう以下に表を作成しました。grepコマンド実行部分も合わせて記します。

        | grep -oP '(?<= => )\S+?(?= \()' \
正規表現 分類 説明
(?<= => ) 肯定的後読み =>の直後に続く部分を抽出対象とします。
\S+? マッチ 空白文字以外の1文字以上の連続をマッチさせます。これが実際に抽出される部分です。
(?= \() 肯定的先読み (の直前で終わる部分を抽出対象とします。

これにより、ライブラリのパス(/lib/x86_64-linux-gnu/...など)を正確に抽出します。

実行処理

FROM

FROM gcr.io/distroless/static-debian12:nonroot

最終的なコンテナイメージは、プログラムの実行に必要となるファイル以外は極力削り、コンテナイメージのサイズを小さくすることが求められます。

Bedrockサーバー用コンテナイメージもマルチステージビルドの活用と、Bedrockサーバー起動用のベースイメージを小さなものにすることで、ビルド後のコンテナイメージサイズを小さくします。

具体的には、Bedrockサーバー起動用にはgcr.io/distroless/base-debian12:nonrootを採用しました。

github.com

なお、第1回で動作検証にUbuntuベースのイメージではなくDebianベースのイメージを選択した理由は、同コンテナイメージがDebianベースであり極力環境を合わせるためでした。

WORKDIR

WORKDIR /bedrock-server

/bedrock-serverを作業用ディレクトリとして設定し、Bedrockサーバーの実行ファイルはこちらに配置します。

COPY

COPY --from=builder /work/bedrock-server/ /bedrock-server
COPY --from=builder /work/lib/ /lib
COPY --from=builder /work/lib64/ /lib64

ビルド用コンテナで準備したファイルを、所定のディレクトリにそれぞれコピーします。

なお、/libディレクトリ内のライブラリはデフォルトで読み込まれるようになっているため、LD_LIBRARY_PATHを設定する必要はありません。

EXPOSE

EXPOSE 19132/udp
EXPOSE 19133/udp

IPv4で利用するUDP 19132番ポートとIPv6で利用するUDP 19133番ポートを明記します。

ENTRYPOINT

ENTRYPOINT ["/bedrock-server/bedrock_server"]

Bedrockサーバーのバイナリを指定します。

コンテナのビルド

完成したDockerfileを使い、コンテナのビルドをおこないます。

$ docker build --platform=linux/amd64 -t bedrock-server .

実行結果を以下に記します。

[+] Building 30.9s (13/13) FINISHED                                                                                                                                                docker:desktop-linux
 => [internal] load build definition from Dockerfile                                                                                                                                               0.0s
 => => transferring dockerfile: 1.36kB                                                                                                                                                             0.0s
 => [internal] load metadata for docker.io/library/debian:bookworm-slim                                                                                                                            0.0s
 => [internal] load metadata for gcr.io/distroless/static-debian12:nonroot                                                                                                                         0.2s
 => [internal] load .dockerignore                                                                                                                                                                  0.0s
 => => transferring context: 2B                                                                                                                                                                    0.0s
 => [stage-1 1/5] FROM gcr.io/distroless/static-debian12:nonroot@sha256:6cd937e9155bdfd805d1b94e037f9d6a899603306030936a3b11680af0c2ed58                                                           0.4s
 => => resolve gcr.io/distroless/static-debian12:nonroot@sha256:6cd937e9155bdfd805d1b94e037f9d6a899603306030936a3b11680af0c2ed58                                                                   0.4s
 => CACHED [builder 1/3] FROM docker.io/library/debian:bookworm-slim@sha256:d365f4920711a9074c4bcd178e8f457ee59250426441ab2a5f8106ed8fe948eb                                                       2.0s
 => => resolve docker.io/library/debian:bookworm-slim@sha256:d365f4920711a9074c4bcd178e8f457ee59250426441ab2a5f8106ed8fe948eb                                                                      2.0s
 => CACHED [stage-1 2/5] WORKDIR /bedrock-server                                                                                                                                                   0.0s
 => [builder 2/3] WORKDIR /work                                                                                                                                                                    0.0s
 => [builder 3/3] RUN apt-get -qq update     && DEBIAN_FRONTEND=noninteractive apt-get -qq install -y --no-install-recommends         ca-certificates=*         curl=7.88.1-*         unzip=6.0-  24.4s
 => [stage-1 3/5] COPY --from=builder /work/bedrock-server/ /bedrock-server                                                                                                                        0.4s
 => [stage-1 4/5] COPY --from=builder /work/lib/ /lib                                                                                                                                              0.0s
 => [stage-1 5/5] COPY --from=builder /work/lib64/ /lib64                                                                                                                                          0.0s
 => exporting to image                                                                                                                                                                             3.5s
 => => exporting layers                                                                                                                                                                            3.5s
 => => exporting manifest sha256:a238cd187a47b3382e3eb202c209439a86be17dde8ec7865c8ec18ed8def11c8                                                                                                  0.0s
 => => exporting config sha256:159312040bbde2575469e938723f169cc72ca803ca290e4a7f1d7d9e1767d691                                                                                                    0.0s
 => => exporting attestation manifest sha256:198fd3771641c0b8e2f8afcd44ea5d53309e386bfe6d736d706f56eb6ead1195                                                                                      0.0s
 => => exporting manifest list sha256:99b3b93585f087dcad5376cf3e2321cecea3765f2295f77289aa356cfab17b16                                                                                             0.0s
 => => naming to docker.io/library/bedrock-server:latest                                                                                                                                           0.0s

View build details: docker-desktop://dashboard/build/desktop-linux/desktop-linux/gwgvz3h9efpt9z1okfc5skors

Bedrockサーバーはx86_64用のバイナリしか提供されていません。そのため、Apple Silicon搭載のMacを利用している場合はプラットフォームを必ず指定しましょう。

Bedrockサーバーの起動

ビルドしたコンテナでBedrockサーバーが起動するか確認します。

コンテナの起動時もプラットフォームを指定しましょう。また、UDP 19132番ポートも忘れずに指定します。

$ docker container run --platform linux/amd64 -p 19132:19132/udp -it bedrock-server

実行結果を以下に記します。

NO LOG FILE! - setting up server logging...
[2024-12-29 03:47:56:653 INFO] Starting Server
[2024-12-29 03:47:56:653 INFO] Version: 1.21.51.02
[2024-12-29 03:47:56:653 INFO] Session ID: 08ead009-93ae-45f5-b463-420e4fdb60ff
[2024-12-29 03:47:56:653 INFO] Build ID: 29823500
[2024-12-29 03:47:56:653 INFO] Branch: r/21_u5
[2024-12-29 03:47:56:653 INFO] Commit ID: 15737c809ed75cbc4a361ffa3c5c2df76ff78d42
[2024-12-29 03:47:56:653 INFO] Configuration: Publish
[2024-12-29 03:47:56:658 INFO] Level Name: Bedrock level
[2024-12-29 03:47:56:661 INFO] No CDN config file found for dedicated server
[2024-12-29 03:47:56:661 INFO] Game mode: 0 Survival
[2024-12-29 03:47:56:661 INFO] Difficulty: 1 EASY
[2024-12-29 03:47:56:670 INFO] Content logging to console is enabled.
[2024-12-29 03:47:56:933 INFO] Opening level 'worlds/Bedrock level/db'
[2024-12-29 03:47:57:126 INFO] [SERVER] Pack Stack - None
[2024-12-29 03:47:58:349 INFO] IPv4 supported, port: 19132: Used for gameplay and LAN discovery
[2024-12-29 03:47:58:349 INFO] IPv6 supported, port: 19133: Used for gameplay
[2024-12-29 03:47:58:381 INFO] Server started.
[2024-12-29 03:47:58:382 INFO] ================ TELEMETRY MESSAGE ===================
[2024-12-29 03:47:58:382 INFO] Server Telemetry is currently not enabled.
[2024-12-29 03:47:58:382 INFO] Enabling this telemetry helps us improve the game.
[2024-12-29 03:47:58:382 INFO]
[2024-12-29 03:47:58:382 INFO] To enable this feature, add the line 'emit-server-telemetry=true'
[2024-12-29 03:47:58:382 INFO] to the server.properties file in the handheld/src-server directory
[2024-12-29 03:47:58:382 INFO] ======================================================

サーバーのプロセスが起動しました。

Bedrockサーバーへの接続

MinecraftクライアントからBedrockサーバーへ接続できるか確認します。今回もiOSMinecraftを利用しました。

The Dedicated Server is displayed on the screen.
Bedrockサーバーが表示される

「Dedicated Server」をタップしてコンテナに接続します。

Successfully connected to the Bedrock Server container.
Bedrockサーバーのコンテナへの接続が成功

接続の確認ができたらゲームを終了します。コンテナ側の標準出力には、以下のようなメッセージが表示されます。

[2024-12-29 03:51:14:563 INFO] Player connected: takenorio, xuid: ****************
[2024-12-29 03:51:18:692 INFO] Player Spawned: takenorio xuid: ****************, pfid: ****************
[2024-12-29 03:51:34:486 INFO] Player disconnected: takenorio, xuid: ****************, pfid: ****************

標準入力からstopと入力してサーバーを停止するとコンテナも停止します。

stop
[2024-12-29 03:47:35:988 INFO] Server stop requested.
[2024-12-29 03:47:36:018 INFO] Stopping server...
Quit correctly

まとめ

今回は、Dockerfileからコンテナを作成し、Minecraftのアプリケーションから接続できることを確認しました。

次回は、ワールドデータの永続化と設定ファイルの管理について説明します。