MySQLのDockerコンテナ起動時エラーを解決する: [MY-010095] [Server] Failed to access directory for --secure-file-priv.

今回は初っ端から公式ドキュメントに当たったことで早く解決できた。

結論

対処法1

[mysqld]
secure-file-priv = ""   # 追加

Server System Variablesの secure-file-priv を空にする。
空の場合、変数が無効となるためnotセキュアな設定になってしまう。

対処法2

FROM mysql:8.0.28
WORKDIR ./
ADD ./my.cnf /etc/mysql/my.cnf
COPY hogehoge /var/lib/mysql-files   # 追加

secure-file-priv のデフォルト値を確認*1し、デフォルト値と同じ名前のディレクトリをコンテナ内に作る。
本記事では対処法2について見ていく。

開発環境

# ホスト
> docker --version
Docker version 20.10.8, build 3967b7d

> docker-compose --version
docker-compose version 1.29.2, build 5becea4c

# コンテナ
root@{CONTAINER_ID}:/# mysql --version
mysql  Ver 8.0.28 for Linux on x86_64 (MySQL Community Server - GPL)

エラー内容

> docker-compose logs -f db
# (省略)
elpis-db | mysqld: Error on realpath() on '/var/lib/mysql-files' (Error 2 - No such file or directory)
elpis-db | 2022-03-06T01:25:22.939319Z 0 [ERROR] [MY-010095] [Server] Failed to access directory for --secure-file-priv. Please make sure that directory exists and is accessible by MySQL Server. Supplied value : /var/lib/mysql-files
elpis-db | 2022-03-06 01:25:22+00:00 [ERROR] [Entrypoint]: Unable to start server.
elpis-db exited with code 1

ディレクトリ構成

> tree
.
├── README.md
├── db
│   ├── Dockerfile
│   └── my.cnf
└── docker-compose.yml

CSVなどのインポートデータがまだ無い状態。

ソースコード

version: '3.8'
services:
  db:
    build:
      context: ./db
      dockerfile: Dockerfile
    container_name: elpis-db
    environment:
      - MYSQL_ROOT_PASSWORD=root
    ports:
      - 3306:3306
    volumes:
      - ./db:/db
    user: root
FROM mysql:8.0.28
WORKDIR ./
ADD ./my.cnf /etc/mysql/my.cnf
[mysql]
default-character-set=utf8mb4

[mysqld]
character-set-server=utf8mb4

[ERROR] [MY-010095] [Server] Failed to access directory for --secure-file-priv.

[ERROR] [MY-010095] [Server] Failed to access directory for --secure-file-priv. Please make sure that directory exists and is accessible by MySQL Server. Supplied value : /var/lib/mysql-files

--secure-file-priv とは

この変数は、LOAD DATA ステートメント、SELECT ... INTO OUTFILE ステートメントおよび LOAD_FILE() 関数によって実行される操作など、データインポートおよびエクスポート操作の影響を制限するために使用されます。 これらの操作は、FILE 権限を持つユーザーにのみ許可されます。
https://dev.mysql.com/doc/refman/8.0/ja/server-system-variables.html

今回はデータインポートもエクスポートもしていない段階でのエラー。
まだインポートもエクスポートもしていないのに何故エラーが起きる?

デフォルト値

--secure-file-priv のデフォルト値を確認してみる。

f:id:tokizuoh:20220306120440p:plain

https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html

ここでエラーメッセージに書かれている /var/lib/mysql-filesディレクトリがあることが分かる。

使用しているMySQLのDockerイメージは mysql:8.0.28のため、OSはdebian
そのため、デフォルト値は /var/lib/mysql-files ということが分かる。

エラー解決

Please make sure that directory exists and is accessible by MySQL Server. Supplied value : /var/lib/mysql-files

ということで、上記のエラーメッセージの通り、「/var/lib/mysql-filesあるのか?確認しろ」と言われているので、最終的にデフォルト値と同じ名前のディレクトリがコンテナ内にあればOK。 デフォルトでは無かったため、コンテナ内に作る。

FROM mysql:8.0.28
WORKDIR ./
ADD ./my.cnf /etc/mysql/my.cnf
COPY hogehoge /var/lib/mysql-files   # 追加

デフォルトでインポートやエクスポートするファイルの置き場は /var/lib/mysql-files が設定されているけど、/docker-entrypoint-initdb.d で初期化処理を書く場合はそっちを指定するケースが多そう。

参考

*1:デフォルト値はプラットフォーム固有のため公式ドキュメントで確認 > https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_secure_file_priv