Home About Contact
Multipass , Docker

Multipass + Docker を M1 mac で使う、Ktorアプリをコンテナで実行まで

Homebrew で multipass + docker をインストールして 先日つくった 最小限の Ktor アプリ をコンテナイメージにして、動かすところまでの覚え書きです。

バージョンの確認

macOS 15.2 を使用。 homebrew は:

$ brew --version
Homebrew 4.4.17

multipass をインストール

brew install multipass するだけです。 インストール後、バージョンを確認:

$ multipass --version
multipass   1.15.0+mac
multipassd  1.15.0+mac

このバージョン M4 Mac + macOS 15.2 + multipass は、今のところ作動しない。

$ multipass launch lts --name docker
launch failed: The following errors occurred:
Unexpected error in object_property_find_err() at ../../../qom/object.c:1330:
qemu-system-aarch64: Property 'host-arm-cpu.sme' not found

ここに解決方法が書いてあった:

インストール後に local.bridged-network を設定します。

どの名前を指せばいいのかを確認:

$ networksetup -listallhardwareports

...

Hardware Port: Wi-Fi
Device: en1
Ethernet Address: 9c:76:0e:31:00:8c

...

en1 を設定する:

$ multipass set local.bridged-network="en1"

ちなみに元に戻すには、空文字列をセットすればよい:

$ multipass set local.bridged-network=""

multipass launch で docker を指定:

$ multipass launch docker --bridged

multipass launch docker として、いきなり docker を指定していますが これは multipass を入れるとあらかじめ用意されているイメージに docker が存在しているからです。

次のように multipass find すると使えるイメージがリストされます。

$ multipass find
Image                       Aliases           Version          Description
20.04                       focal             20250109         Ubuntu 20.04 LTS
22.04                       jammy             20250108         Ubuntu 22.04 LTS
24.04                       noble,lts         20250115         Ubuntu 24.04 LTS
24.10                       oracular          20250110         Ubuntu 24.10

Blueprint                   Aliases           Version          Description
anbox-cloud-appliance                         latest           Anbox Cloud Appliance
charm-dev                                     latest           A development and testing environment for charmers
docker                                        0.4              A Docker environment with Portainer and related tools
jellyfin                                      latest           Jellyfin is a Free Software Media System that puts you in control of managing and streaming your media.
minikube                                      latest           minikube is local Kubernetes
ros2-humble                                   0.1              A development and testing environment for ROS 2 Humble.
ros2-jazzy                                    0.1              A development and testing environment for ROS 2 Jazzy.

起動した multipass docker の IPアドレスを確認:

$ multipass ls
Name                    State             IPv4             Image
docker                  Running           192.168.64.2     Ubuntu 24.04 LTS
                                          192.168.10.133
                                          172.17.0.1                                         

試しに multipass docker 内で nginx の docker を起動して、ホストのmacOSからアクセスしてみます。

$ multipass shell docker
ubuntu@docker $ docker run --rm -d -p 8080:80 nginx

この --rm オプションは docker を stop したらそのコンテナが削除されるオプションらしい。

まずは、multipass docker 内で curl でアクセスして作動を確認:

ubuntu@docker $ curl -X GET http://localhost:8080/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

ホスト側で http://192.168.10.133:8080/ にブラウザでアクセスすると nginx のページが表示されます。

この docker nginx のコンテナをストップするには:

ubuntu@docker $ docker ps -a

これで multipass docker 内の docker にあるコンテナのリストが出る。 一番左の列の CONTAINER ID をコピペして docker nginx をストップする:

ubuntu@docker $ docker stop e8f8d0618161

再度 docker ps -a するともう nginx のコンテナは表示されない。

本題 Ktor アプリを動かす

やっと本題です。

先日つくった Ktor アプリは Gradle プロジェクトなので、まず mutlipass docker に Java17 を入れます。

どのパッケージを入れるか?

ubuntu@docker $ apt search java  |grep 17

JDKを入れる場合は、 これ openjdk-17-jdk-headless を入れる:

$ sudo apt install openjdk-17-jdk-headless

Gradle プロジェクトを動かすだけなので、 JRE でよかろう。

ubuntu@docker $ sudo apt install openjdk-17-jre-headless

確認:

ubuntu@docker $ java -version
openjdk version "17.0.13" 2024-10-15
OpenJDK Runtime Environment (build 17.0.13+11-Ubuntu-2ubuntu124.04)
OpenJDK 64-Bit Server VM (build 17.0.13+11-Ubuntu-2ubuntu124.04, mixed mode, sharing)

先日の 最小限の ktor アプリ はこれ:

.
├── app
│   ├── build.gradle.kts
│   └── src
│       └── main
│           ├── kotlin
│           │   └── Application.kt
│           └── resources
│               └── application.conf
├── gradle
│   ├── libs.versions.toml
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
└── settings.gradle.kts

プロジェクトのルートに配置した Dockerfile に次の内容を記述:

FROM eclipse-temurin:17-jre
WORKDIR /app
COPY app/build/libs/fat.jar fat.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "fat.jar"]

まず app/build/libs/fat.jar を生成:

ubuntu@docker $ ./gradlew buildFatJar

生成できたか、確認:

ubuntu@docker $ find . -name fat.jar
./app/build/libs/fat.jar

その後、Dockerfile からイメージを生成:

ubuntu@docker $ docker build -t hello-ktor .

生成されたイメージは、カレントディレクトリにできるとかではない。 docker image ls するとわかる。

ubuntu@docker $ docker image ls
REPOSITORY               TAG       IMAGE ID       CREATED         SIZE
hello-ktor               latest    39f9e9079ab8   8 minutes ago   303MB

hello-ktor として存在している。 ならば、先ほど nginx を実行したのと同じようにして実行すればよいのでは?

もともと 8080 で起動するように設定していたので、-p オプションは 8080:8080 とする。

ubuntu@docker $ docker run --rm -d -p 8080:8080 hello-ktor
72d0d60fa533c500ad7404c8c7f18196b9e4bad3a8792166cc2853ceaf85f64a

起動した。 docker ps して確認してみる:

$ docker ps
CONTAINER ID   IMAGE                    COMMAND               CREATED          STATUS          PORTS                                                           NAMES
72d0d60fa533   hello-ktor               "java -jar fat.jar"   35 seconds ago   Up 35 seconds   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp                       compassionate_goodall

おお!なんか起動している。 curl で 1 の idを持つポケモン情報を取得してみる:

ubuntu@docker $ curl -X GET http://localhost:8080/1
{
    "id": 1,
    "name": "Squirtle"
}

できた。 ホストの macOS からも取得してみる:

multipass ls して IPアドレスを確認してから実行:

$ curl -X GET http://192.168.10.133:8080/2
{
    "id": 2,
    "name": "Charamander"
}

できました。

それでは、後始末します。 まず docker ps して作動中の該当コンテナ(hello-ktor)の container ID を確認。 その上で、その ID を指して停止します。

ubuntu@docker $ docker stop 72d0d60fa533

docker ps -a してインスタンスがいなくなっていることを確認しましょう。

さらに ホストの macOS に戻り multipass docker を停止:

$ multipass ls
$ multipass stop docker

まとめ

multipass docker 便利。 使い始めのハードルが低い。