[コンテナ再入門]ホストにMySQLがインストールされていると、MySQLのコンテナが起動しないことがある

Docker/Kubernetes 実践コンテナ開発入門

Docker/Kubernetes 実践コンテナ開発入門

Docker/Kubernetes 実践コンテナ開発入門 の4章でMySQLのDockerコンテナを立ち上げる手順があるのだが、そこで詰まったのでメモ。

状況

  • ホスト Ubuntu18.04 server 64bit
  • Docker 18.09.3

Docker in Dockerの構成で、mysql:5.7 イメージを元にしたMySQLのDockerコンテナを起動させようとしたところ、起動しては以下のエラーを吐いてコンテナが停止する、という挙動を繰り返した。

$ docker container exec -it manager docker service lslogs todo_mysql_master
todo_mysql_master.1.(略)    | ERROR: mysqld failed while attempting to check config
todo_mysql_master.1.(略)    | command was: "mysqld --verbose --help"
todo_mysql_master.1.(略)    | 
todo_mysql_master.1.(略)    | mysqld: Can't read dir of '/etc/mysql/conf.d/' (Errcode: 13 - Permission denied)
todo_mysql_master.1.(略)    | mysqld: [ERROR] Fatal error in defaults handling. Program aborted!

「Docker in Docker」「MySQL」「起動しない」といったワードで検索していたところ、こちらの記事を発見。

qiita.com

まんまこのシチュエーションであった。

先に結論

コンテナを実行するホスト(母艦) にMySQLがインストールされていると、priviledged モードを有効にしたコンテナ上でのMySQL起動がAppArmorという強制アクセス制御システムの働きにより阻害されることがある。

何が起きていたか

書籍の手順では、Docker Swarmのような複数台のホストにまたがるコンテナオーケストレーションの挙動を1台のホスト(=読者のノートPCなど)上で再現して体験させるため、Docker in Dockerで「Dockerをホストするためのコンテナ群」の上に「MySQLやNginxなど本来複数台のホストにまたがって展開させたいコンテナ群」を構築することになっていた(3章 3.5.節以降)。
このDocker in Dockerで「Dockerをホストするためのコンテナ群」を構築する際、「Dockerをホストするためのコンテナ群」に本来のホスト(=読者のノートPCなど)とほぼ同じ権限をもたせるためにpriviledged モードを有効にしていたようだ (ようだ、というか、「Dockerをホストするためのコンテナ群」を起動するためのdocker-composeのYAMLファイルにはちゃんとprivileged: trueと書いてあったのだが、あまり意味がわかっておらず読み飛ばしていた。。。)。

docs.docker.com

こちらのドキュメントの「Runtime privilege and Linux capabilities」の項を読むと、priviledged モードというのはコンテナホストのデバイス等にアクセスを許可するためのフラグらしい。これがないと Docker in DockerのようにDockerコンテナ内部からDockerを起動させるような芸当ができない。
基本的にはホストとコンテナ間は疎結合である方が望ましいので、priviledged モードは開発環境以外では使わないものらしい。

AppArmorとは

www.usupi.org

AppArmor とは、プログラム単位でMAC(Mandatory Access Control - 強制アクセス制御) を行うためのセキュリティ機構です。
MACとは、従来のファイルのパーミッションの設定等とは関係なく、 強制的にアクセス制限を設けることができる機構です。

役割としてはSELinuxなどと同じようなもので、AppArmorの場合はプログラム単位で制限がかけられるらしい。 今回は、MySQLがAppArmorの管理対象だったところに Docker in Docker上でさらにMySQLを実行しようとしたため、AppArmorが「許可していないリソース上で MySQL が動作している」と認識して実行をブロックした、ということだったようだ。

対処

前述のQiita記事 Docker で MySQL コンテナーがなぜか起動できない問題 - Qiita に記載されていた2つの解消方法のうち、AppArmor の監視から MySQL を除外する方法を採った。

$ sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/
$ sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld

教訓

書籍やハンズオンで環境構築を行う場合は、なるべくまっさらなVMなどを用意してやりましょう。

…そうはいっても毎回そう上手く環境を用意できないかもしれないので、後で同じような状況で詰まる人(将来の自分を含む)の役にたてばと簡単にメモをまとめました。

参考にさせていただいたURL