Docker Compose创建MySQL卷目录所有者异常的原因与解决方法
使用环境
Linux Mint 21.1 Cinnamon + Docker Desktop
docker-compose.yaml 文件内容
version: '3.7' services: backend: container_name: admin_api build: context: . dockerfile: Dockerfile environment: DB_HOST: db DB_DATABASE: database_name DB_USERNAME: admin_user DB_PASSWORD: not_root_password ports: - 8000:8000 volumes: - .:/app networks: - app depends_on: - db db: container_name: admin_db image: mysql:8 ports: - 3306:3306 volumes: - ./db-data:/var/lib/mysql environment: - MYSQL_ROOT_PASSWORD=root_password - MYSQL_PASSWORD=not_root_password - MYSQL_USER=admin_user - MYSQL_DATABASE=database_name networks: - app networks: app:
本地用户ID信息
执行id命令输出:
alex@dell:~/Projects/laravel-admin$ id uid=1000(alex) gid=1000(alex) groups=1000(alex),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(kvm),115(lpadmin),136(sambashare)
异常现象
成功执行docker compose up后,db-data目录被创建且数据正常,但所有者为100998:
alex@dell:~/Projects/laravel-admin$ ls -la total 392 drwxr-xr-x 14 alex alex 4096 May 24 23:12 . drwxrwxr-x 4 alex alex 4096 May 23 20:11 .. drwxr-xr-x 7 alex alex 4096 May 23 20:12 app -rwxr-xr-x 1 alex alex 1686 May 16 17:38 artisan drwxr-xr-x 3 alex alex 4096 May 23 20:12 bootstrap -rw-r--r-- 1 alex alex 1853 May 16 17:38 composer.json -rw-r--r-- 1 alex alex 289022 May 23 21:43 composer.lock drwxr-xr-x 2 alex alex 4096 May 23 23:35 config drwxr-xr-x 5 alex alex 4096 May 23 20:12 database drwxr-xr-x 8 100998 alex 4096 May 24 23:12 db-data <------- 此处所有者为异常值100998 -rw-r--r-- 1 alex alex 709 May 24 23:06 docker-compose.yaml -rw-r--r-- 1 alex alex 351 May 24 21:49 Dockerfile -rw-r--r-- 1 alex alex 258 May 16 17:38 .editorconfig -rw-r--r-- 1 alex alex 1156 May 24 21:14 .env ...
尝试解决后的问题
在db服务中添加user: "1000:1000"配置:
... db: user: "1000:1000" <--- 新增配置 ...
执行docker compose up时,db服务启动报错:
admin_db | 2023-05-24 21:20:05+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.33-1.el8 started. admin_db | 2023-05-24 21:20:06+00:00 [Note] [Entrypoint]: Initializing database files admin_db | mysqld: Can't create/write to file '/var/lib/mysql/is_writable' (OS errno 13 - Permission denied) admin_db | 2023-05-24T21:20:06.029099Z 0 [Warning] [MY-011068] [Server] The syntax '--skip-host-cache' is deprecated and will be removed in a future release. Please use SET GLOBAL host_cache_size=0 instead. admin_db | 2023-05-24T21:20:06.029218Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 8.0.33) initializing of server in progress as process 41 admin_db | 2023-05-24T21:20:06.031268Z 0 [ERROR] [MY-010460] [Server] --initialize specified but the data directory exists and is not writable. Aborting. admin_db | 2023-05-24T21:20:06.031276Z 0 [ERROR] [MY-013236] [Server] The designated data directory /var/lib/mysql/ is unusable. You can remove all files that the server added to it. admin_db | 2023-05-24T21:20:06.031309Z 0 [ERROR] [MY-010119] [Server] Aborting admin_db | 2023-05-24T21:20:06.031453Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.33) MySQL Community Server - GPL. admin_db exited with code 1
此时db-data目录所有者变为alex,但目录为空:
alex@dell:~/Projects/laravel-admin$ ls -la total 392 drwxr-xr-x 14 alex alex 4096 May 24 23:20 . drwxrwxr-x 4 alex alex 4096 May 23 20:11 .. drwxr-xr-x 7 alex alex 4096 May 23 20:12 app -rwxr-xr-x 1 alex alex 1686 May 16 17:38 artisan drwxr-xr-x 3 alex alex 4096 May 23 20:12 bootstrap -rw-r--r-- 1 alex alex 1853 May 16 17:38 composer.json -rw-r--r-- 1 alex alex 289022 May 23 21:43 composer.lock drwxr-xr-x 2 alex alex 4096 May 23 23:35 config drwxr-xr-x 5 alex alex 4096 May 23 20:12 database drwxr-xr-x 2 alex alex 4096 May 24 23:20 db-data <-------- 所有者正常 ...
疑问
Docker为何会创建所有者为100998的db-data目录?该如何解决这个问题?
原因分析
100998用户ID的由来:这是Docker Desktop在Linux上启用的用户命名空间映射导致的。为提升安全性,Docker Desktop会将容器内的用户ID映射到主机上一个非特权的ID区间(通常从100998开始)。MySQL容器默认以
mysql用户运行,其容器内UID为999,经过映射后,主机上显示的UID就变成了100998。添加user:1000:1000启动失败的原因:MySQL镜像的初始化脚本需要对
/var/lib/mysql目录拥有读写权限。指定user:1000:1000后,容器内进程以UID1000运行,但此时挂载目录在容器内的权限对应主机原映射的100998,容器内的1000用户无权限操作该目录,导致初始化失败。
解决方案
方法1:关闭Docker Desktop的用户命名空间映射(最简单)
- 打开Docker Desktop设置
- 进入Settings > Features in development
- 取消勾选Enable user namespace mapping选项
- 重启Docker Desktop
- 删除现有
db-data目录,重新执行docker compose up
此方法会让容器内用户ID直接映射到主机对应ID,MySQL容器内的mysql用户(UID999)会在主机上显示为999;若需要目录属于alex(UID1000),可使用方法2。
方法2:自定义MySQL镜像,适配本地用户ID
- 创建
Dockerfile.mysql文件:
FROM mysql:8 # 将mysql用户的UID和GID修改为1000(与主机alex用户一致) RUN usermod -u 1000 mysql && groupmod -g 1000 mysql # 确保数据目录权限正确 RUN chown -R mysql:mysql /var/lib/mysql
- 修改docker-compose.yaml中db服务的配置:
db: container_name: admin_db build: context: . dockerfile: Dockerfile.mysql ports: - 3306:3306 volumes: - ./db-data:/var/lib/mysql environment: - MYSQL_ROOT_PASSWORD=root_password - MYSQL_PASSWORD=not_root_password - MYSQL_USER=admin_user - MYSQL_DATABASE=database_name networks: - app
- 删除现有
db-data目录,执行docker compose build构建镜像,再执行docker compose up启动容器
此方法让容器内mysql用户的UID与主机alex用户一致,挂载目录所有者会是alex,同时MySQL进程可正常读写数据。
方法3:手动调整主机目录权限(临时方案)
- 停止容器:
docker compose down - 修改
db-data目录权限:sudo chown -R 999:999 db-data - 重新启动容器:
docker compose up
此方法缺点是每次重新创建目录都需要手动调整权限,缺乏持久性。
内容的提问来源于stack exchange,提问作者Alex

