oinume journal

Scratchpad of what I learned

Apple Silicon向けDocker Desktop for Macでコンテナがハングしないようにする

TL;DR

  • Apple Silicon(M1) Docker Desktop for Macでgoogle/cloud-sdkのDocker Imageを使ってコンテナ内でCloud Datastore Emulatorを立ち上げると、CPUが100%で張り付いてハングするという問題があった。
  • 解決方法として、該当のDocker Imageをarm64v8アーキテクチャでビルドして、そのイメージでコンテナを立ち上げるようにしたら問題は起きなくなったので、その方法の紹介

問題の詳細

Apple Silicon版のDocker Desktop for MacはRosetta2を使いインテルアーキテクチャ(amd64 / x86_64)をエミュレーションして実行されている。エミュレーションが行われているため、ネイティブでarm64v8のコンテナを実行するよりCPUを使ってしまうという問題がある。これはKnown Issuesとして以下のように書かれている。

However, attempts to run Intel-based containers on Apple Silicon machines under emulation can crash as qemu sometimes fails to run the container. In addition, filesystem change notification APIs (inotify) do not work under qemu emulation. Even when the containers do run correctly under emulation, they will be slower and use more memory than the native equivalent.

In summary, running Intel-based containers on Arm-based machines should be regarded as “best effort” only. We recommend running arm64 containers on Apple Silicon machines whenever possible, and encouraging container authors to produce arm64, or multi-arch, versions of their containers.

自分が遭遇した現象としては、google/cloud-sdkのイメージを使ってgcloudコマンドでDatastore Emulatorを立ち上げようとすると、3回に1回ぐらいの確率でCPUが100%になり、コンテナが全く応答しなくなるという問題だった。

We recommend running arm64 containers on Apple Silicon machines whenever possible

とDocker Desktop on MacのKnown Issuesに書かれているので、これにしたがってgoogle/cloud-sdkのarm64v8のDocker Imageをビルドしてみた。

google/cloud-sdk arm64v8 Imageをビルドする

公式には提供されていないので、自分でDockerfileを作ってイメージをビルドする必要がある。 https://hub.docker.com/u/arm64v8 には様々なarm64v8のDocker Imageがあるので、debian:buster-slimをベースにして以下のようなDockerfileを作る。ちなみに今回はgoogle-cloud-sdk-datastore-emulatorしか使わないのでこれだけをインストールしているが、他のEmulatorが必要であれば公式のDockerfileを参考にインストールすれば良い。

FROM arm64v8/debian:buster-slim

ARG CLOUD_SDK_VERSION=341.0.0
ENV CLOUD_SDK_VERSION=$CLOUD_SDK_VERSION

RUN groupadd -r -g 1000 cloudsdk && \
    useradd -r -u 1000 -m -s /bin/bash -g cloudsdk cloudsdk

RUN mkdir -p /usr/share/man/man1/ && \
    apt-get update && \
    apt-get -y install \
        curl \
        gnupg \
        sudo \
        python3 \
        python3-crcmod \
        bash \
        openjdk-11-jre-headless

RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
RUN curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -
RUN apt-get update && \
    apt-get install -y \
    google-cloud-sdk \
    google-cloud-sdk-datastore-emulator
RUN gcloud config set core/disable_usage_reporting true && \
    gcloud config set component_manager/disable_update_check true && \
    gcloud config set metrics/environment github_docker_image_emulator

そしてDocker Imageをビルドする。

$ docker build -t cloud-sdk-emulators-arm64v8:341.0.0 .

最後に

今回はGoのユニットテストからory/dockertestを使ってDatastore Emulatorを立ち上げていたのだが、コンテナを何個立ち上げても全くハングしなくなりとても安定した。今回はDatastore Emulatorだったけど、他のImageでも起こりうる問題だとは思うので、もしApple siliconのマシンでDockerを動かしていて同じような症状で困っている人は参考にしてもらえると良いと思う。