修复 Docker 中的世界可写 MySql 错误
Fixing World-writable MySql error in Docker
我正在使用 docker-compose,对于 db 我定义了这样的容器:
db:
build: ../builds/mysql-5.7
environment:
- MYSQL_ROOT_PASSWORD=pass
- MYSQL_DATABASE=
- MYSQL_USER=
- MYSQL_PASSWORD=
expose:
- 3306
volumes:
- /c/Users/marcin/dock-test/composers/l1.app/mysql/data/:/var/lib/mysql/
- /c/Users/marcin/dock-test/composers/l1.app/mysql/conf.d/:/etc/mysql/conf.d/
- /c/Users/marcin/dock-test/composers/l1.app/mysql/log/:/var/log/mysql/
我的这张图片的 Docker 文件是:
# Base image
FROM mysql:5.7
# Set valid file permissions - otherwise MySql won't read those files
#COPY mysql-perm-fix.sh /etc/init.d/mysql-perm-fix.sh
#RUN chmod +x /etc/init.d/mysql-perm-fix.sh
#RUN update-rc.d mysql-perm-fix.sh defaults 100
#RUN mkdir /etc/mysql/conf.d/source
#RUN cp /etc/mysql/conf.d/source/my.cnf /etc/mysql/conf.d/my.cnf
#RUN chmod -R 644 /etc/mysql/conf.d
目前除了基本 MySql 图片外,所有内容都已评论。
问题是,当我启动我的容器时,我的 MySql cnf 文件不会被 MySql 使用,因为这个警告:
mysqld: [Warning] World-writable config file '/etc/mysql/conf.d/my.cnf' is ignored.
我正在使用 Windows 作为我的主机系统。问题是 Docker 以完全权限安装目录并且无法更改它们。
问题 - 如何解决?正如您在我的 Docker 文件中看到的那样,我尝试了一些解决方案,但其中 none 对我有用(但也许我做错了什么)。
目前我认为最合理的解决方案是将 MySql conf 文件不直接挂载到 /etc/mysql/conf.d/
中,而是挂载到其他目录中,然后将这些文件复制到 /etc/mysql/conf.d/
目录中 MySql 启动并设置它们不是 777 权限。我试过了,但在 Dockerfile 中,这些文件还不存在,因此无法复制。
有什么简单的解决办法吗?或者可以更改某些 MySql 设置以不关心 conf 文件权限?
我也不能简单地使用 Docker 文件中的 COPY 来复制 Mysql 配置文件(而不是使用卷),因为我想在多个站点使用这些图像,每个站点可能有不同的配置。
现在您正在使用卷主机挂载,并且因为您的主机是 Windows 它导致您出现权限问题。
由于您要为配置使用卷的主要原因是您可以在容器之间共享,因此我建议为此使用数据卷容器。
数据卷容器将包含您要共享的卷,并且它们将 Linux 挂载,因此权限问题应该会消失。
您的其他容器将使用数据容器卷作为配置卷。
可在此处找到有关创建和使用数据容器的信息。
设置数据卷容器后,您可以在 docker 运行 link 上使用 --volumes-from 标志到容器并附加卷。
您可以根据自己的喜好对所有卷或部分卷使用此方法。
如果您不需要在其他容器之间共享数据,另一种选择是只使用常规卷而不是托管装载的卷。这将在 Linux 中创建一个卷,但不会安装到 Windows 主机。您只需列出具有一个目录名称的卷即可做到这一点。
Volumes
- /var/lib/mysql
- /etc/mysql
使用 Windows 主机时,文件没有完全权限的解决方案似乎是与 "intermediate directory" 共享文件,然后将这些文件复制到 Docker 容器中的所需目录中。
在上面的例子中(MySQL容器)可以这样做(你也可以在其他情况下使用这个方法)
Docker文件:
# Base image
FROM mysql:5.7
# Copy starting scripts file
COPY start.sh /root/start.sh
# Run necessary services
CMD ["/bin/bash", "/root/start.sh"]
docker-compose.yml(仅显示数据库容器)
db:
build: ../builds/mysql-5.7
environment:
- MYSQL_ROOT_PASSWORD=pass
- MYSQL_DATABASE=
- MYSQL_USER=
- MYSQL_PASSWORD=
expose:
- 3306
volumes:
- /c/Users/marcin/dock-test/composers/l1.app/mysql/data/:/var/lib/mysql/
- /c/Users/marcin/dock-test/composers/l1.app/mysql/conf.d/:/etc/mysql/conf.d/source
- /c/Users/marcin/dock-test/composers/l1.app/mysql/log/:/var/log/mysql/
请注意上面我们将 conf.d 目录挂载到 /etc/mysql/conf.d/source
目录而不是 /etc/mysql/conf.d/
目录(因此 MySql 暂时不会加载此文件)。
start.sh
#!/bin/sh
cp /etc/mysql/conf.d/source/* /etc/mysql/conf.d/
/entrypoint.sh mysqld
上面我们现在将所有文件从 conf.d/source
直接复制到 conf.d
- 这些文件不与 Windows 主机共享,因此将使用 Linux 权限创建它们(在我的例子中,保留默认值——不使用 chmod 就可以了。
要验证自定义 mysql 配置值是否已加载,我 运行:
mysql -u root -p
然后输入我的密码。
当我键入 SHOW VARIABLES;
时,我会看到之前 my.cnf
中的一些设置(没有放置此文件具有不同的值),因此它按预期工作。
当然,这个解决方案的缺点是那些文件不会真正共享,所以如果这些文件在 Docker 机器上被更改,它们将不会在 Windows 主机上更新, 但在上述情况下,当我们想使用自定义配置文件时,它没有任何区别并解决了问题。
感谢@marcin-nabiałek 的启发,我得到了这个解决方案,而无需为 运行 命令编写自定义脚本,因为我仍然遇到权限问题。脚本内容可以使用 Dockerfile 命令完成(请参阅下面的 mariadb/Dockerfile
内容)。
我运行docker-compose -p my_project up --build -d
在project-root
目录下。
文件结构如下。 project-root
:
drwxr-xr-x 1 cmeza 197121 0 Aug 22 16:19 .git/
-rw-r--r-- 1 cmeza 197121 40 Aug 22 15:41 .gitignore
-rw-r--r-- 1 cmeza 197121 1056 Aug 22 13:24 Dockerfile
-rw-r--r-- 1 cmeza 197121 291 Aug 22 13:24 PROJECT.md
-rw-r--r-- 1 cmeza 197121 3642 Aug 22 13:24 README.md
drwxr-xr-x 1 cmeza 197121 0 Aug 22 13:24 bin/
-rw-r--r-- 1 cmeza 197121 944 Aug 22 15:42 docker-compose.yml
drwxr-xr-x 1 cmeza 197121 0 Aug 22 15:41 mariadb/
project-root/mariadb
:
-rw-r--r-- 1 cmeza 197121 193 Aug 22 15:46 Dockerfile
drwxrwxrwx 1 cmeza 197121 0 Aug 22 13:57 conf/
-rwxrwxrwx 1 cmeza 197121 5013 Aug 22 13:57 conf/my_custom.cnf
drwxrwxrwx 1 cmeza 197121 0 Aug 22 16:07 data/
-rwxrwxrwx 1 cmeza 197121 0 Aug 22 16:07 data/.gitignore
drwxrwxrwx 1 cmeza 197121 0 Aug 22 16:06 entrypoint/
-rwxrwxrwx 1 cmeza 197121 1163 Aug 22 16:06 entrypoint/default.sql
drwxrwxrwx 1 cmeza 197121 0 Aug 22 15:52 log/
-rwxrwxrwx 1 cmeza 197121 0 Aug 22 15:52 log/.gitignore
docker-compose.yml
(注意卷的相对路径):
(other services here)
db:
environment:
- MYSQL_ROOT_PASSWORD=my_super_secret_password
- MYSQL_DATABASE=my_db
ports:
- "3306:3306"
volumes:
- ./mariadb/entrypoint:/docker-entrypoint-initdb.d
- ./mariadb/conf:/etc/mysql/conf.d/my_conf_files
- ./mariadb/data:/var/lib/mysql
- ./mariadb/log:/var/log/mysql
build: ./mariadb
entrypoint:
- docker-entrypoint.sh
- mysqld
(some other services here)
mariadb/Dockerfile
:
# Base image
FROM mariadb:5.5
# Copy custom conf file(s)
# .\conf being your relative host path from this Dockerfile
# \etc\mysql\conf.d\ being the VM path
COPY .\conf\* \etc\mysql\conf.d\
# Make the conf files not writeable so mysql will read them
RUN chmod a-w \etc\mysql\conf.d\*
这让我得到了我需要的一切,而且我的头上还留着一些头发。如果这对其他人有帮助,请告诉我。
我刚遇到这个问题,对我来说解决方法是将 my.cnf
文件在 Windows 中设置为只读。
对于那些只需要设置几个配置选项的人,我有一个备选答案。
在 docker 撰写文件中,您可以执行类似的操作。
db:
image: mysql
command: >
bash -c "mysqld --user=root --group_concat_max_len=1844674407370954752"
environment:
- MYSQL_ROOT_PASSWORD=pass
- MYSQL_DATABASE=
- MYSQL_USER=
- MYSQL_PASSWORD=
expose:
- 3306
注意我运行 mysqld然后设置选项--group_concat_max_len作为例子。如果您需要更多选项,只需添加更多 -- 在带有选项名称的“”内。这是一个优雅的解决方案,不需要从默认 mysql 图像制作新图像。
command 在 docker 合成文件中所做的是覆盖图像中默认的 CMD 命令。图像默认命令只是 运行s mysqld(你可以在他们的 github 页面上查找),所以我也只是 运行 它但给它一些参数传入。请参阅此文件的最后一行以查看 CMD 命令。 (参考这个:https://github.com/docker-library/mysql/blob/master/5.5/Dockerfile)
使用这种方法,您 甚至不需要担心 mysql 配置文件 中的卷,这对我来说是个大问题,因为它必须是 777在做 docker-compose up 时可以工作,但由于世界可写问题会继续失败。
这对我有用
mysql:
networks:
- main
image: library/mysql:5.7
container_name: 'mysql'
command: >
bash -c "
chmod 644 /etc/mysql/conf.d/*.cnf
&& /entrypoint.sh mysqld
"
ports:
- "3308:3308"
volumes:
- ./my_local_dir/var/lib/mysql:/var/lib/mysql
- ./my_local_dir/etc/mysql/conf.d/:/etc/mysql/conf.d/
restart: always
environment:
MYSQL_ROOT_PASSWORD: 'root'
MYSQL_DATABASE: 'some'
- /c/Users/marcin/dock-test/composers/l1.app/mysql/conf.d/:/etc/mysql/conf.d/:delegated
使用委托以只读模式设置主机路径。
我正在使用 docker-compose,对于 db 我定义了这样的容器:
db:
build: ../builds/mysql-5.7
environment:
- MYSQL_ROOT_PASSWORD=pass
- MYSQL_DATABASE=
- MYSQL_USER=
- MYSQL_PASSWORD=
expose:
- 3306
volumes:
- /c/Users/marcin/dock-test/composers/l1.app/mysql/data/:/var/lib/mysql/
- /c/Users/marcin/dock-test/composers/l1.app/mysql/conf.d/:/etc/mysql/conf.d/
- /c/Users/marcin/dock-test/composers/l1.app/mysql/log/:/var/log/mysql/
我的这张图片的 Docker 文件是:
# Base image
FROM mysql:5.7
# Set valid file permissions - otherwise MySql won't read those files
#COPY mysql-perm-fix.sh /etc/init.d/mysql-perm-fix.sh
#RUN chmod +x /etc/init.d/mysql-perm-fix.sh
#RUN update-rc.d mysql-perm-fix.sh defaults 100
#RUN mkdir /etc/mysql/conf.d/source
#RUN cp /etc/mysql/conf.d/source/my.cnf /etc/mysql/conf.d/my.cnf
#RUN chmod -R 644 /etc/mysql/conf.d
目前除了基本 MySql 图片外,所有内容都已评论。
问题是,当我启动我的容器时,我的 MySql cnf 文件不会被 MySql 使用,因为这个警告:
mysqld: [Warning] World-writable config file '/etc/mysql/conf.d/my.cnf' is ignored.
我正在使用 Windows 作为我的主机系统。问题是 Docker 以完全权限安装目录并且无法更改它们。
问题 - 如何解决?正如您在我的 Docker 文件中看到的那样,我尝试了一些解决方案,但其中 none 对我有用(但也许我做错了什么)。
目前我认为最合理的解决方案是将 MySql conf 文件不直接挂载到 /etc/mysql/conf.d/
中,而是挂载到其他目录中,然后将这些文件复制到 /etc/mysql/conf.d/
目录中 MySql 启动并设置它们不是 777 权限。我试过了,但在 Dockerfile 中,这些文件还不存在,因此无法复制。
有什么简单的解决办法吗?或者可以更改某些 MySql 设置以不关心 conf 文件权限?
我也不能简单地使用 Docker 文件中的 COPY 来复制 Mysql 配置文件(而不是使用卷),因为我想在多个站点使用这些图像,每个站点可能有不同的配置。
现在您正在使用卷主机挂载,并且因为您的主机是 Windows 它导致您出现权限问题。
由于您要为配置使用卷的主要原因是您可以在容器之间共享,因此我建议为此使用数据卷容器。
数据卷容器将包含您要共享的卷,并且它们将 Linux 挂载,因此权限问题应该会消失。
您的其他容器将使用数据容器卷作为配置卷。
可在此处找到有关创建和使用数据容器的信息。
设置数据卷容器后,您可以在 docker 运行 link 上使用 --volumes-from 标志到容器并附加卷。
您可以根据自己的喜好对所有卷或部分卷使用此方法。
如果您不需要在其他容器之间共享数据,另一种选择是只使用常规卷而不是托管装载的卷。这将在 Linux 中创建一个卷,但不会安装到 Windows 主机。您只需列出具有一个目录名称的卷即可做到这一点。
Volumes
- /var/lib/mysql
- /etc/mysql
使用 Windows 主机时,文件没有完全权限的解决方案似乎是与 "intermediate directory" 共享文件,然后将这些文件复制到 Docker 容器中的所需目录中。
在上面的例子中(MySQL容器)可以这样做(你也可以在其他情况下使用这个方法)
Docker文件:
# Base image
FROM mysql:5.7
# Copy starting scripts file
COPY start.sh /root/start.sh
# Run necessary services
CMD ["/bin/bash", "/root/start.sh"]
docker-compose.yml(仅显示数据库容器)
db:
build: ../builds/mysql-5.7
environment:
- MYSQL_ROOT_PASSWORD=pass
- MYSQL_DATABASE=
- MYSQL_USER=
- MYSQL_PASSWORD=
expose:
- 3306
volumes:
- /c/Users/marcin/dock-test/composers/l1.app/mysql/data/:/var/lib/mysql/
- /c/Users/marcin/dock-test/composers/l1.app/mysql/conf.d/:/etc/mysql/conf.d/source
- /c/Users/marcin/dock-test/composers/l1.app/mysql/log/:/var/log/mysql/
请注意上面我们将 conf.d 目录挂载到 /etc/mysql/conf.d/source
目录而不是 /etc/mysql/conf.d/
目录(因此 MySql 暂时不会加载此文件)。
start.sh
#!/bin/sh
cp /etc/mysql/conf.d/source/* /etc/mysql/conf.d/
/entrypoint.sh mysqld
上面我们现在将所有文件从 conf.d/source
直接复制到 conf.d
- 这些文件不与 Windows 主机共享,因此将使用 Linux 权限创建它们(在我的例子中,保留默认值——不使用 chmod 就可以了。
要验证自定义 mysql 配置值是否已加载,我 运行:
mysql -u root -p
然后输入我的密码。
当我键入 SHOW VARIABLES;
时,我会看到之前 my.cnf
中的一些设置(没有放置此文件具有不同的值),因此它按预期工作。
当然,这个解决方案的缺点是那些文件不会真正共享,所以如果这些文件在 Docker 机器上被更改,它们将不会在 Windows 主机上更新, 但在上述情况下,当我们想使用自定义配置文件时,它没有任何区别并解决了问题。
感谢@marcin-nabiałek 的启发,我得到了这个解决方案,而无需为 运行 命令编写自定义脚本,因为我仍然遇到权限问题。脚本内容可以使用 Dockerfile 命令完成(请参阅下面的 mariadb/Dockerfile
内容)。
我运行docker-compose -p my_project up --build -d
在project-root
目录下。
文件结构如下。 project-root
:
drwxr-xr-x 1 cmeza 197121 0 Aug 22 16:19 .git/
-rw-r--r-- 1 cmeza 197121 40 Aug 22 15:41 .gitignore
-rw-r--r-- 1 cmeza 197121 1056 Aug 22 13:24 Dockerfile
-rw-r--r-- 1 cmeza 197121 291 Aug 22 13:24 PROJECT.md
-rw-r--r-- 1 cmeza 197121 3642 Aug 22 13:24 README.md
drwxr-xr-x 1 cmeza 197121 0 Aug 22 13:24 bin/
-rw-r--r-- 1 cmeza 197121 944 Aug 22 15:42 docker-compose.yml
drwxr-xr-x 1 cmeza 197121 0 Aug 22 15:41 mariadb/
project-root/mariadb
:
-rw-r--r-- 1 cmeza 197121 193 Aug 22 15:46 Dockerfile
drwxrwxrwx 1 cmeza 197121 0 Aug 22 13:57 conf/
-rwxrwxrwx 1 cmeza 197121 5013 Aug 22 13:57 conf/my_custom.cnf
drwxrwxrwx 1 cmeza 197121 0 Aug 22 16:07 data/
-rwxrwxrwx 1 cmeza 197121 0 Aug 22 16:07 data/.gitignore
drwxrwxrwx 1 cmeza 197121 0 Aug 22 16:06 entrypoint/
-rwxrwxrwx 1 cmeza 197121 1163 Aug 22 16:06 entrypoint/default.sql
drwxrwxrwx 1 cmeza 197121 0 Aug 22 15:52 log/
-rwxrwxrwx 1 cmeza 197121 0 Aug 22 15:52 log/.gitignore
docker-compose.yml
(注意卷的相对路径):
(other services here)
db:
environment:
- MYSQL_ROOT_PASSWORD=my_super_secret_password
- MYSQL_DATABASE=my_db
ports:
- "3306:3306"
volumes:
- ./mariadb/entrypoint:/docker-entrypoint-initdb.d
- ./mariadb/conf:/etc/mysql/conf.d/my_conf_files
- ./mariadb/data:/var/lib/mysql
- ./mariadb/log:/var/log/mysql
build: ./mariadb
entrypoint:
- docker-entrypoint.sh
- mysqld
(some other services here)
mariadb/Dockerfile
:
# Base image
FROM mariadb:5.5
# Copy custom conf file(s)
# .\conf being your relative host path from this Dockerfile
# \etc\mysql\conf.d\ being the VM path
COPY .\conf\* \etc\mysql\conf.d\
# Make the conf files not writeable so mysql will read them
RUN chmod a-w \etc\mysql\conf.d\*
这让我得到了我需要的一切,而且我的头上还留着一些头发。如果这对其他人有帮助,请告诉我。
我刚遇到这个问题,对我来说解决方法是将 my.cnf
文件在 Windows 中设置为只读。
对于那些只需要设置几个配置选项的人,我有一个备选答案。
在 docker 撰写文件中,您可以执行类似的操作。
db:
image: mysql
command: >
bash -c "mysqld --user=root --group_concat_max_len=1844674407370954752"
environment:
- MYSQL_ROOT_PASSWORD=pass
- MYSQL_DATABASE=
- MYSQL_USER=
- MYSQL_PASSWORD=
expose:
- 3306
注意我运行 mysqld然后设置选项--group_concat_max_len作为例子。如果您需要更多选项,只需添加更多 -- 在带有选项名称的“”内。这是一个优雅的解决方案,不需要从默认 mysql 图像制作新图像。
command 在 docker 合成文件中所做的是覆盖图像中默认的 CMD 命令。图像默认命令只是 运行s mysqld(你可以在他们的 github 页面上查找),所以我也只是 运行 它但给它一些参数传入。请参阅此文件的最后一行以查看 CMD 命令。 (参考这个:https://github.com/docker-library/mysql/blob/master/5.5/Dockerfile)
使用这种方法,您 甚至不需要担心 mysql 配置文件 中的卷,这对我来说是个大问题,因为它必须是 777在做 docker-compose up 时可以工作,但由于世界可写问题会继续失败。
这对我有用
mysql:
networks:
- main
image: library/mysql:5.7
container_name: 'mysql'
command: >
bash -c "
chmod 644 /etc/mysql/conf.d/*.cnf
&& /entrypoint.sh mysqld
"
ports:
- "3308:3308"
volumes:
- ./my_local_dir/var/lib/mysql:/var/lib/mysql
- ./my_local_dir/etc/mysql/conf.d/:/etc/mysql/conf.d/
restart: always
environment:
MYSQL_ROOT_PASSWORD: 'root'
MYSQL_DATABASE: 'some'
- /c/Users/marcin/dock-test/composers/l1.app/mysql/conf.d/:/etc/mysql/conf.d/:delegated
使用委托以只读模式设置主机路径。