MySQL v8.0.30 以降の Docker image で確認される permission error について
はじめに
こんにちは。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
}
この処理では実行内容を実行しています。
- 以下のフラグに値が存在する場合、MySQL 設定に関連する値を取得し、その値からディレクトリを作成する
general-log-file \
keyring_file_data \
pid-file \
secure-file-priv \
slow-query-log-file \
- 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 では一緒にサービスを育てる仲間を募集しています。
もし弊社に興味を持っていただけたら 弊社の紹介ページ をご覧いただけたら幸いです。