修复 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 挂载,因此权限问题应该会消失。

您的其他容器将使用数据容器卷作为配置卷。

可在此处找到有关创建和使用数据容器的信息。

https://docs.docker.com/engine/userguide/containers/dockervolumes/#creating-and-mounting-a-data-volume-container

设置数据卷容器后,您可以在 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 -dproject-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

使用委托以只读模式设置主机路径。