在Docker MySQL容器中启用日志记录

32

我正试图熟悉docker生态系统,并尝试设置一个mysql数据库容器。使用docker-compose,这看起来像是:

version: '2'
services:
  db:
    image: mysql:5.6.33@sha256:31ad2efd094a1336ef1f8efaf40b88a5019778e7d9b8a8579a4f95a6be88eaba
    volumes:
      - "./db/data:/var/lib/mysql"
      - "./db/log:/var/log/mysql"
      - "./db/conf:/etc/mysql/conf.d"
    restart: "yes"
    environment:
      MYSQL_ROOT_PASSWORD: rootpw
      MYSQL_DATABASE: db
      MYSQL_USER: db
      MYSQL_PASSWORD: dbpw

我的配置文件目录中只包含一个文件:

[mysqld]
log_error       =/var/log/mysql/mysql_error.log
general_log_file=/var/log/mysql/mysql.log
general_log     =1
slow_query_log  =1
slow_query_log_file=/var/log/mysql/mysql_slow.log
long_query_time =2
log_queries_not_using_indexes = 1

很遗憾,这种方式我无法获得任何日志文件。设置本身是正确的,且 cnf 文件被使用。连接到容器并创建 3 个文件后,请使用 chown 将它们归属于 mysql 并重新启动容器,则日志记录将按预期工作。

我相信这是一个常见的情况,而我目前的运行方式似乎非常愚蠢。 正确的做法是什么?

我可以通过将所有这些内容移动到 Dockerfile 中来改进我的方法,但这对我来说仍然很奇怪。

4个回答

26
我之前也在找同样的东西,现在有更好的方法来做了。 docker mysql 的文档中写道:

Many configuration options can be passed as flags to mysqld. This will give you the flexibility to customize the container without needing a cnf file. For example, if you want to change the default encoding and collation for all tables to use UTF-8 (utf8mb4) just run the following:

$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
在一个docker-compose的世界中,可以通过服务的"command"部分传递这些参数。
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

在我的使用情况下,我只是想打开日志并指定日志文件的路径:
 command: mysqld --general-log=1 --general-log-file=/var/lib/mysql/general-log.log

有了足够的容量(例如:- ./logs/mysql.log:/var/lib/mysql/general-log.log),就很容易找到它们。

这非常简单,避免了处理本地配置的麻烦。它适用于任何MySQL Docker镜像,并将保持镜像所提供的my.cnf

编辑:将路径从/var/log/mysql/更改为/var/lib/mysql/,以确保有一个可写的MySQL文件夹。


--general_log_file 而不是 --general-log-file - Alex
@Alex,它是--general-log-file,因为它是一个命令行参数,而不是服务器变量。请参见https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_general_log_file和“命令行格式”。 - ponsfrilus

9

我因为一个奇怪的PDO绑定问题需要临时启用日志记录,并想要查看实际执行的查询。这个问题是搜索结果中排名最靠前的,但我对任何答案都不满意。假设您已经设置了容器的卷,我以下面的方式使其工作:

  1. 在数据库上运行以下查询:
SET global general_log = on;
SET global general_log_file='/var/log/mysql/mysql.log';
SET global log_output = 'file'; 

  1. 使用 docker ps 命令获取容器的ID。
  2. 运行命令 docker exec -it <id> /usr/bin/tail -f /var/log/mysql/mysql.log
  3. 完成后运行以下查询以关闭全局日志记录:SET global general_log = off;

如果您在设置general_log_file变量时遇到问题,可能需要通过/bin/bash进入容器,然后手动创建具有正确权限的日志文件。


错误代码:1231。变量“general_log_file”无法设置为“/var/log/mysql/mysql.log”的值。 - Michael Paccione
@MichaelPaccione 你可能需要手动创建文件。你可以 /bin/bash 进入容器来执行此操作。我不确定自从最初回答以来发生了什么变化,因为我不记得需要这样做。 - Bower

8
连接到容器并创建了三个文件后,将它们的所有权更改为mysql并重新启动容器,日志记录将按预期工作。这指向主机卷权限问题。当您从容器映射到主机时,用户ID上没有进行映射,并且容器内附加到UID的名称可能与外部非常不同。您需要使用容器用户可以写入的内容初始化目录权限。一种简单的方法是创建一个具有在主机和容器上写入文件访问权限的组,然后将各种用户添加到此组中,包括您的镜像和主机操作系统。另一个选择是使用命名文件系统,您无需直接从主机访问它,并使用映像的目录权限对其进行初始化。
编辑:使用docker-compose.yml的命名卷示例非常简单:
version: '2'
volumes:
  mysql-data:
    driver: local
  mysql-log:
    driver: local
  mysql-conf:
    driver: local

services:
  db:
    image: mysql:5.6.33
    volumes:
      - "mysql-data:/var/lib/mysql"
      - "mysql-log:/var/log/mysql"
      - "mysql-conf:/etc/mysql/conf.d"
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: rootpw
      MYSQL_DATABASE: db
      MYSQL_USER: db
      MYSQL_PASSWORD: dbpw

请注意,我还从您的图像名称中删除了sha256,这个引用会阻止您能够拉取修补过的图像版本。我还更喜欢“除非停止”重启策略,以便Docker在重新启动时执行预期操作。

名称卷的文档似乎部分过时且不完整。这些数据存储在哪里?我是否正确,仍然需要知道mysql容器的uid和gid,以使用这些权限启动卷? - mheinzerling
命名卷储存在Docker的内部文件夹中(通常为/var/lib/docker)。如果您尝试在那里访问它们,则会创建与主机卷相同的问题。相反,您应该仅通过Docker容器访问它们。您可以在多个容器中挂载相同的卷,因此您可以有一个容器来执行更新和备份等任务。 - BMitch
我会继续使用我的 sha,以确保我测试和部署相同的版本,但 unless-stopped 是一个很好的提示。 - mheinzerling
1
对于测试/阶段/生产版本控制,我建议使用私有注册服务器并标记您的特定镜像。您可以使用多个标签拥有相同的镜像,使得像v5被标记为测试,然后被标记为分期非常容易管理。您可以从Docker Hub拉取,重新标记或甚至使用自己的添加进行构建,然后推送到您的私有注册表中。所有测试/阶段/生产服务器都只能从该私有注册表中拉取。 - BMitch
我猜我的conf目录的最佳实践是基于mysql的新镜像,否则我必须以某种方式预填卷? - mheinzerling
预填充卷就像 tar -cC $(pwd)/conf . | docker run --rm -it -v mysql-conf:/target busybox tar -xC /target 一样容易,还有许多类似的选项。在compose文件中,将 external: true 添加到该卷定义中,以便它不会添加项目名称并期望该卷已经存在(文档)。 - BMitch

0

除了 ponsfrilus的回答,你也可以通过docker run命令来实现相同的功能:

docker run --name some-mysql --restart always -v //d/MySqlDockerData:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:latest --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --log_error=/var/lib/mysql/mysql_error.log --general_log_file=/var/lib/mysql/mysql.log --general_log=1 --slow_query_log=1 --slow_query_log_file=/var/lib/mysql/mysql_slow.log --long_query_time=2 --log_queries_not_using_indexes=1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接