🐜

M2MacでMySQL5.7のコンテナがうごかなくなる件を対処した

2024/02/08に公開

かなり低いレイヤーで起こっている問題なので、記述している内容が正しくない場合もあるとおもいます。
(私の理解力の限界なのでご理解のうえ読んでいただけると幸いです...💦)
解消まで時間がかかったので、自分みたいな[初心者用]備忘録としてのこしておきます。

M2MacDocker Desktopアプリの一定以上のバージョン、さらに特定のDockerイメージを使おうとした際にcpuのアーキテクチャが合わずに色々発生するようです。

RUNTEQ受講生が同じような状況になった際に解決しやすいように、初心者向けにまとめてみます。
(添削前なので、読みづらかったらすみません)

起こった環境

  • MacBook Pro 2022 Apple M2
  • macOS Sonoma v14
  • Docker Desktop v4.27.0
  • mysql 5.7(使ったDockerイメージ)

やろうとしたこと

Dockerのコンテナを起動する一連の操作をする中で、問題が発生しています。

  1. イメージをビルド
  2. コンテナを作成&起動
    (この段階で、うまく起動しない、起動してもエラーでコンテナが落ちるということが複数発生しました。)
  3. コンテナ内に入り、DB操作

手順

エラーが発生し、解消するまでに行った手順をすべて書いておきます。
初心者向けにそれぞれの作業に解説もいれておくので、解消法だけ知りたい方には読みづらいかと思いますが、ご了承ください。

1. Dockerイメージをビルド

DockerFileのあるディレクトリ内で下記コマンド

オプション解説

-tオプションで名前をつけられます。
コマンド自体はdocker build .で完結してます。

docker build . -t #{任意のイメージ名}

現在いるディレクトリにあるDockerFileを使って、イメージを作るという感じです。
イメージはオブジェクト指向でいう、クラスをイメージすると良いとどこかの記事に書いてありました。

2. イメージから、コンテナを作成&起動

buildがクラス作成であれば、コンテナ作成はインスタンス化と考えると良いと、これもどこかの記事に書いてありました。(イメージしやすくていいですね。)

オプション解説

-dオプションをつけると、バックグランドで動作します。(通常起動だと、ターミナルにログがで続けます、僕はログを見たい人なので-d付けない起動のほうが好きです。)
--nameオプションで名前をつけられます。
-pオプションは、外部のポートとコンテナ内部のポートを接続するオプション
(例: 手元の環境のポート3306(localhost:3306)にアクセスすると、コンテナ内部でポート3306で動いているDBに接続される)
ポート3306は、よくDBで使われるポートだそうです。

docker run -d --name #{任意のコンテナ名} -p 3306:3306 #{使用するイメージ}

runコマンドは、コンテナを作成するcreateとコンテナを起動するstartを一緒に行ってくれます。

3. CPUアーキテクチャの不一致による警告

ここで下記の警告文がでます。

WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested

おそらくimageから作る仮想環境のcpuのアーキテクチャと、手元のMacのcpuアーキテクチャが合ってないということだと思います。(むずかしいので、分かる方に咀嚼して教えてもらいたい)
要するにamdじゃなくてarmだからうまく動かないかも知れないよ〜ってことじゃないかと思います。

参照:CPUアーキテクチャの種類

4. --platformオプションを使ってrunする

警告が出ている状態で、進めると重要なログが表示されなかったりするみたいなので解消してみます。
(ちなみに私は、この警告のせいでコンテナが起動しないのだと思って対応していましたが、実際は別の理由でした。後述します。)

警告文解消法

--platformオプションを付けてrunすることで、コンテナ起動時のプラットフォームを指定できるようです。

docker run  --platform linux/x86_64 --name #{任意のコンテナ名} -p 3306:3306 #{使用するイメージ}

使用する場面は、マルチアーキテクチャイメージが利用可能な場合、異なるアーキテクチャのエミュレーションが必要な環境(例えば、Apple Silicon(M1, M2チップ)を搭載したMacなど)で特に有用とのこと。(???)

5. 起動直後におちるコンテナ

警告文でなくなったので、安心してコンテナ内部に入ろうとします。

docker exec -it <コンテナ名またはコンテナID> bash

オプション解説

-itオプションは-i-tをいっしょにまとめて入力しています。
-iオプションを書いてないと、コンテナのbashに入ったあと、入力ができなくなるのでコンテナの中に入ってコマンドを打つなら必須です。

-tオプションは、どのコンテナの中に入るのかコンテナ名、コンテナIDで指定するためのオプションです。(試してないのですが、指定しなかった場合は直近のコンテナに入るとかになるのでしょうか?)

話はもどり、コンテナに入ろうとしたところ、下記エラーメッセージが発生

Error response from daemon: container #{コンテナID} is not running

コンテナが動いていないみたいです

どうもなんらかの理由で、起動直後におちてしまったみたいです。
こういう時はコンテナのログを見に行きます。

6. コンテナに起こったことをログで確認する

dockerコンテナのlogは、下記コマンドでみれます。

docker logs #{コンテナID}

コンテナIDは、作成時に割り振られるので作成の度に変わります。
コンテナIDの確認には、現在作っているコンテナの情報を一覧表示するコマンドを使います。

docker ps -a

一番左の列に表示されているのがコンテナIDです。
-aオプションを付けると、今停止しているコンテナも表示されるので、基本的に付けておきましょう

(こんな感じに表示されます)

コンテナIDもあったので、ログをみてみましょう。

docker logs #{コンテナID}

ログの中腹あたりでエラー[ERROR]が発生していますね!

エラー内容

[ERROR] InnoDB: Linux Native AIO interface is not supported on this platform. Please check your OS documentation and install appropriate binary of InnoDB.

なんの話?と思いつつプラットフォームがどうのって書いてるのでM2Mac関連なんだろうなあとため息を付きつつ記事を探します。
こちらの記事に解決法がありました🙏

(参考にした記事)[https://gihyo.jp/dev/serial/01/mysql-road-construction-news/0167]

つまり、MySQLまたはMariaDBがLinux Native AIO(非同期I/O)インターフェースを使用することができないことを示しているそうです。

対応方法は幾つかあるみたいですが、Linux Native AIOを使わないと明言することで回避できるとのことでした。

DockerFileに--innodb_use_native_aio=0という記述を加えます。
native_aio=0とすることで使用しないとできるようです。

DockerFileにdb設定書かれてる方はこっち▼

FROM --platform=linux/x86_64 mysql:5.7
ENV MYSQL_ROOT_PASSWORD=college
COPY init.d /
EXPOSE 3306/tcp 33060/tcp
CMD ["mysqld", "--innodb_use_native_aio=0"]

docker-compose.ymlにdb設定書いてる方はこっち▼

services:
  db:
    # commandを追記 or commandに追記
    command: mysqld --innodb_use_native_aio=0

7. 工程をやり直す

DockerFileを書き換えたので、イメージから作り直す必要があります。
作業としては、

  • イメージを作り直す
  • コンテナを作り直す
  • コンテナを起動させる
  • コンテナに入る
    ですね!

練習がてらに、それぞれ不要になったものを削除していきます。

7.1 使わなくなったコンテナを削除する

イメージを削除するためには、紐づいてるコンテナを先に削除する必要があります。

コンテナを削除するために、現在存在しているコンテナ情報一覧を確認します。
このあたりのやり方は、この記事内の以下の項目を確認してください。

削除したいコンテナ情報が確認できたら、コンテナを削除しましょう。
コマンドは、こうなります。

docker rm [コンテナ名 or コンテナId]

これで、コンテナの削除は終了です。
念のため、再度コンテナ情報一覧を出して、本当に削除されているか確認してくださいね。

7.2 使わなくなったイメージを削除し、新しいイメージを作成する

現在のイメージ一覧は、以下のコマンドで表示できます。

docker images

コマンドを打つと、画像のようなイメージ一覧が表示されます。

もしかしたら<none>と書かれているイメージがあるかもしれませんが、それについては別の記事で解説することにします。(自分のnotionにまとめる予定)

イメージを削除するには、イメージIDが必要となります。
削除するコマンドは以下となります。

docker rmi [イメージId]
削除できない時

状況によりますが、強制的に削除したい時は

docker rmi -f [イメージId]

使わないイメージを削除できたら、書き換えたDockerFileを使って再度ビルドを行います。
ビルドはDockerFileから、イメージを作成することでしたね。

docker build . -t [任意のイメージ名]

これで新しいイメージが作成できたはずです。

7.3 新しいコンテナを作成・起動し、コンテナ内に入る

新しいコンテナを作成・起動します

docker run  --platform linux/x86_64 --name #{任意のコンテナ名} -p 3306:3306 #{使用するイメージ}

再度、コンテナ内に入ります。

docker exec -it <コンテナ名またはコンテナID> bash

すると、また入れないと思うので、再度ログを確認します。

docker logs #{コンテナID}

見慣れないエラーが出ています。

qemu: uncaught target signal 11 (Segmentation fault) - core dumped

このエラーは以下の記事に解決法が書かれていました。
https://ky-yk-d.hatenablog.com/entry/2024/02/02/112659

8. qemuではなくRosettaを使うように設定を変更する

記事によると...
MySQL 5.7の公式Dockerイメージにはarm版が存在せず、amd版をApple Silicon上で動作させていたが、バージョンが上がったことでqemuでは動作しなくなった模様。

と書かれています(内容はむずかしいのですが)、対応方法はとても簡単です。

Docker DesktopアプリでqemuというものではなくRosettaを使うという設定をすれば解決できます。

Rosettaについては、以下の記事が参考になりました。

Docker Desktopアプリのダッシュボードを確認し、設定を開きます。

General項目のUse Rosetta for x86/amd64 emulation on Apple Siliconにチェックを入れます。
最後に右下のApply & restartをクリックすると設定が有効になるはずです。

※ 時々Rosettaをインストールしてくださいと言われることがあります。

その場合、画面に従ってインストールをしてください。
しかし、さらに時々ここでのインストールが一生おわらない時があります。(原因不明のエラー)

こうなってしまった場合、Rosettaを手動インストールしてみてください。

softwareupdate --install-rosetta

下記の記事に手動インストールのことが書いてありますので興味ある方は見てみてください。
Docker Desktop for Apple silicon

9. 再度、コンテナを起動し、コンテナ内に入る

Docker Desktopアプリの設定を変更したら、再度コンテナ内に入ってみましょう。
今回は既にコンテナを作っているので、以下のコマンドで起動できるはずです。

docker start [コンテナ名&コンテナId]

コンテナを起動したら、コンテナ内に入ります。

docker exec -it <コンテナ名またはコンテナID> bash

左にbashという文字が表示されたらコンテナ内に入れています。
(設定により変わるかも知れません。)

おつかれさまでした。
これで一通りのエラーを解消できたと思います。

長くなりましたが、この記事で行いたかったことは

Appleシリコン製内蔵MacDocker Desktop v4.27.0以降のバージョンでMySQL5.7のイメージを使えるにすることでした。

Dockerの操作についても、一通り書いてみたのでどういう時にどういう操作をすればいいのか理解が深まれば幸いです。

お疲れ様でした。

Discussion