背景
普段私はMacで作業しています。3年くらい前からApple Silicon M1のMac miniをメインの作業機として使っています。
そんなある日、ちょっとDocker Composeでアプリケーションをデプロイしたらうまく動かなかったので、久しぶりにIntel Macを起こしました。 毎回これをやるといつまで経ってもIntel Macから卒業できないので、対処しようと思いました。
動作環境と症状について
今回の環境はこちらです。
$ uname -m arm64 $ sw_vers ProductName: macOS ProductVersion: 12.6.8 BuildVersion: 21G725
実行すると現れるエラー。イメージ由来の問題みたいです。
$ docker compose up -d [+] Running 1/2 ⠦ db 1 layers [⣿] 0B/0B Pulling 2.6s ✔ 0821f3a5b3ec Download complete 0.6s no match for platform in manifest: not found
docker-compose.yml
はこのような感じで書いています。極めて普通な感じです。
$ cat docker-compose.yml version: '3' services: db: image: mysql:8.0-debian environment: MYSQL_ROOT_PASSWORD: my_secret_pw ports: - "3306:3306" web: build: . container_name: web depends_on: - db volumes: - ./php/:/var/www/html/ ports: - "30080:80" stdin_open: true tty: true
Dockerfile
はこんな感じです。 Webサービス側はphpイメージを使っています。PHP8.2 + Apache2が導入されているイメージです。
$ cat Dockerfile FROM php:8.2-apache RUN docker-php-ext-install mysqli
あまり本題とは関係ないですが、index.php
のコードは以下のとおりです。
テストコードなので、認証情報関連はベッタリにしてます。
<?php $db_host = 'db'; $db_user = 'root'; $db_password = 'my_secret_pw'; $db_db = 'information_schema'; $db_port = 3306; $mysqli = new mysqli( $db_host, $db_user, $db_password, $db_db, $db_port ); if ($mysqli->connect_error) { echo 'Errno: '.$mysqli->connect_errno; echo '<br>'; echo 'Error: '.$mysqli->connect_error; exit(); } echo 'Success: A proper connection to MySQL was made.'; echo '<br>'; echo 'Host information: '.$mysqli->host_info; echo '<br>'; echo 'Protocol version: '.$mysqli->protocol_version; $mysqli->close(); ?>
失敗した理由
さらなるテストの結果、やはりMySQLイメージにApple Siliconで動作するイメージがないようです。 PHPイメージはARM64対応しているみたいですね。
$ docker image pull mysql:8.0-debian 2c10bf0e0b27: Already exists no match for platform in manifest: not found $ docker image pull php:8.2-apache a6d0bb13cd94: Already exists b515004c3b0d: Download complete 65c3267c7b37: Download complete 35be195075a3: Download complete dd06eedb7624: Download complete c3eb3ed58b0c: Download complete 3b10997c9d6e: Download complete 4ee097f9a366: Download complete 50aa8be75fea: Download complete 2d6175e9b527: Download complete e255c1ce22a7: Download complete 1bab033462b2: Download complete 559343ab0c4a: Download complete 62975eb3413b: Download complete 02cbea39f639: Download complete ac9dce739201: Download complete docker.io/library/php:8.2-apache
対処方法
Rosetta 2を入れておきます(これはのちの調査で、Ventura以降なら有効な方法です)。
$ /usr/sbin/softwareupdate --install-rosetta --agree-to-license By using the agreetolicense option, you are agreeing that you have run this tool with the license only option and have read and agreed to the terms. If you do not agree, press CTRL-C and cancel this process immediately. 2023-08-28 20:39:47.220 softwareupdate[67322:1816036] Package Authoring Error: 042-15018: Package reference com.apple.pkg.RosettaUpdateAuto is missing installKBytes attribute Installing: 0.0% Install of Rosetta 2 finished successfully
platform: linux/amd64
を指定してみます。
$ cat docker-compose.yml version: '3' services: db: image: mysql:8.0-debian platform: linux/amd64 environment: MYSQL_ROOT_PASSWORD: my_secret_pw ports: - "3306:3306" web: build: . platform: linux/amd64 depends_on: - db volumes: - ./php/:/var/www/html/ ports: - "30080:80" stdin_open: true tty: true
起動しました。ただしエミュレーションなので、ネイティブで動かすときより遅いです。 あくまで動作テストするだけなら良いでしょう。
$ docker compose up -d [+] Running 3/3 ✔ Network docker-mysqlphp_default Created 0.0s ✔ Container db Started 0.2s ✔ Container docker-mysqlphp-web-1 Started $ docker compose ps NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS db mysql:8.0-debian "docker-entrypoint.s…" db 6 seconds ago Up 5 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp docker-mysqlphp-web-1 docker-mysqlphp-web "docker-php-entrypoi…" web 6 seconds ago Up 5 seconds 0.0.0.0:30080->80/tcp
さらにテストしたところ、一方だけplatform
を指定して試したらうまく動きませんでした。
image with reference docker-mysqlphp-web was found but does not match the specified platform: wanted linux/arm64, actual: linux/amd64
起動タイミングの問題か直ぐアクセスしすぎたようでエラーになりましたが、10秒くらい待てばちゃんと動くのを確認しました。
$ curl http://localhost:30080 <br /> <b>Fatal error</b>: Uncaught mysqli_sql_exception: Connection refused in /var/www/html/index.php:8 Stack trace: #0 /var/www/html/index.php(8): mysqli->__construct('db', 'root', Object(SensitiveParameterValue), 'information_sch...', 3306) #1 {main} thrown in <b>/var/www/html/index.php</b> on line <b>8</b><br /> $ curl http://localhost:30080 Success: A proper connection to MySQL was made.<br>Host information: db via TCP/IP<br>Protocol version: 10
まとめ
Docker HubのMySQLイメージ は、platform: linux/amd64
を指定すれば使えることがわかりました。
また、docker-compose.yml
でplatform
を指定する場合は、他のイメージについても指定が必要なのがわかりました。
macOS MontereyまでのバージョンはDocker DesktopでRosetta 2を使うことができないので、エミュレートして動くために起動が遅いということも理解できました。最初のうちはそこらへんの理解が浅かったため、「あれっ...ちゃんと動かない!」などと判断してしまいました。あと10秒くらい待てば良かったのに...。
ちなみにmacOS Ventura以降で動かすと、「Use Rosetta for x86/amd64 exmulation on Apple Silicon」というオプションがDocker Desktopに生えてくるようです。この環境は諸事情でMontereyなので、その設定はパネルには出てこない模様です。
なお、こう指定しても動くことを確認しました。アーキテクチャーが混在するのでちょっと気持ちが悪い感じもありますが、少なくともWebサーバー側はネイティブで動くので速くなります。
$ cat docker-compose.yml version: '3' services: db: image: mysql:8.0-debian platform: linux/amd64 environment: MYSQL_ROOT_PASSWORD: my_secret_pw ports: - "3306:3306" web: build: . platform: linux/arm64 depends_on: - db volumes: - ./php/:/var/www/html/ ports: - "30080:80" stdin_open: true tty: true ... [+] Running 3/3 ✔ Network docker-mysqlphp2_default Created 0.0s ✔ Container db Started 0.2s ✔ Container docker-mysqlphp2-web-1 Started $ curl http://localhost:30080/ Success: A proper connection to MySQL was made.<br>Host information: db via TCP/IP<br>Protocol version: 10
当然ながら、ARM64をサポートするMariadbを組み込んだ場合は問題なく動作します。 コンテナかつApple Silicon環境のDockerで、どうしてもMySQLを動かしたいという強いこだわりがなければ、Mariadbイメージを使うのもありです。
$ cat docker-compose.yml version: '3' services: db: image: mariadb:10.11.5 platform: linux/arm64 container_name: db environment: MYSQL_ROOT_PASSWORD: my_secret_pw ports: - "3306:3306" web: build: . platform: linux/arm64 depends_on: - db volumes: - ./php/:/var/www/html/ ports: - "30080:80" stdin_open: true tty: true ... [+] Running 3/3 ✔ Network docker-mysqlphp2_default Created 0.0s ✔ Container db Started 0.2s ✔ Container docker-mysqlphp2-web-1 Started $ curl http://localhost:30080/ Success: A proper connection to MySQL was made.<br>Host information: db via TCP/IP<br>Protocol version: 10
使ったイメージ
おまけ
最近のDocker Desktopはビルドのステータスとか一覧で出してくれるようですね。現在のビルドの状況と、過去のビルドの結果がまとまっています。 こういうのを見るのも好きです。