MySQL v8.0.30 以降の Docker image で確認される permission error について

2023-11-13

はじめに

こんにちは。Belong でエンジニアをしている Mohiro です。
今回は MySQL v8.0.30 以降の Docker image で確認されている permission error の原因と対処法についてまとめました。

こちらは以前 MySQL のバージョンアップグレードの業務を行った際に発生したエラーについてまとめたものとなっています。 MySQL の issue に同様の話題がいくつか挙げられているため、比較的引っかかりやすいポイントなのかと思います。
私と同じエラーに遭遇した方の助けになるかと思い今回記事を書かせていただきました。

作業環境

Mac OS Ventura Version13.6

エラー概要

MySQL v8.0.30 を起動すると、以下のようなエラーメッセージが発生し起動に失敗します。

...
chown: changing ownership of './sys/dev': Read-only file system
chown: changing ownership of './sys/dev/char': Read-only file system
chown: changing ownership of './sys/dev/char/7:6': Read-only file system
chown: changing ownership of './sys/dev/char/4:22': Read-only file system
chown: changing ownership of './sys/dev/char/4:4': Read-only file system
chown: changing ownership of './sys/dev/char/4:50': Read-only file system
chown: changing ownership of './sys/dev/char/7:130': Read-only file system
...

使用した docker-compose.yml は以下の通りです。

version: '3.8'

services:
  book_db:
    image: mysql:8.0.30
    container_name: book_db
    command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --general_log=1 --log_output=FILE --general_log_file=mysqld.log
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: book_db
      MYSQL_USER: test_u
      MYSQL_PASSWORD: test_pw
    platform: linux/amd64
    volumes:
      - type: bind
        source: ./db/init
        target: /docker-entrypoint-initdb.d

原因

MySQL v8.0.30 から docker-entrypoint.sh に追加された以下の処理によりエラーが発生していました。
ソースコード

docker_create_db_directories() {
	local user; user="$(id -u)"

	local -A dirs=( ["$DATADIR"]=1 )
	local dir
	dir="$(dirname "$SOCKET")"
	dirs["$dir"]=1

	# "datadir" and "socket" are already handled above (since they were already queried previously)
	local conf
	for conf in \
		general-log-file \
		keyring_file_data \
		pid-file \
		secure-file-priv \
		slow-query-log-file \
	; do
		dir="$(mysql_get_config "$conf" "$@")"

		# skip empty values
		if [ -z "$dir" ] || [ "$dir" = 'NULL' ]; then
			continue
		fi
		case "$conf" in
			secure-file-priv)
				# already points at a directory
				;;
			*)
				# other config options point at a file, but we need the directory
				dir="$(dirname "$dir")"
				;;
		esac

		dirs["$dir"]=1
	done

	mkdir -p "${!dirs[@]}"

	if [ "$user" = "0" ]; then
		# this will cause less disk access than `chown -R`
		find "${!dirs[@]}" \! -user mysql -exec chown --no-dereference mysql '{}' +
	fi
}

この処理では実行内容を実行しています。

  1. 以下のフラグに値が存在する場合、MySQL 設定に関連する値を取得し、その値からディレクトリを作成する
general-log-file \
keyring_file_data \
pid-file \
secure-file-priv \
slow-query-log-file \
  1. root user で起動した場合、owner が MySQL user でないディレクトリの owner を MySQL user に変更する

今回の私の実装では general-log-file が指定されているかつ root user により起動していたため、上記の chown 処理が実行されていました。
しかし、このコンテナは非特権コンテナとして起動されていたため、ファイル変更の権限が付与されておらず permission error が発生していました。

対応策

非 root ユーザーとして起動するため、適当なユーザーを指定しました。

version: '3.8'

services:
  book_db:
    image: mysql:8.0.30
    container_name: book_db
    command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --general_log=1 --log_output=FILE --general_log_file=mysqld.log
    restart: always
    user: 1000:1000 // ユーザーを新たに指定
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: book_db
      MYSQL_USER: test_u
      MYSQL_PASSWORD: test_pw
    platform: linux/amd64
    volumes:
      - type: bind
        source: ./db/init
        target: /docker-entrypoint-initdb.d

補足

MySQL v8.0.30 から追加された処理の目的について

該当の issueを確認すると、処理自体の目的は以下にあるように、「コンテナで tmpfs がマウントされる場合は (/var)/run 以下となり MySQL の使う path と被り上書きされるので、それを防ぐ必要がある」ということみたいです。

We create directory in /var/run during image creation, but for example containerd mount tmpfs on /run directory. We can lose content of directory in this case, so we must ensure that it exists.

おわりに

今回は MySQL v8.0.30 以降のイメージで確認されている permission error の原因と対処法についてまとめました。
今回の記事が少しでもお役に立てれば幸いです。
弊社 Belong では一緒にサービスを育てる仲間を募集しています。
もし弊社に興味を持っていただけたら 弊社の紹介ページ をご覧いただけたら幸いです。