MacOS 系统上的 MySQL Docker 容器 INFILE/ INTO OUTFILE 语句



我有一个Java程序和一个mysql Docker容器(图片:mysql:5.7.20)。 我的MacOS是High Sierra 10.13.4。

简而言之,问题

在 MacOS (10.13.4.) 上使用 Docker。在 docker 容器中(图片:mysql:5.7.20)主要是查询(从 java 程序执行)

  • LOAD DATA INFILE ...
  • SELECT ... INTO OUTFILE ...

工作正常,但有时 Java 程序会抛出异常:

  • SQLException: 无法创建/写入文件"..."(错误代码:2 - 没有这样的文件或目录)
  • SQLException:无法获取"..."的统计信息错误代码:2 - 没有这样的文件或目录)
  • SQLException:MySQL 服务器使用 --secure-file-priv 选项运行,因此它无法执行此语句
  • SQLException: 文件 '...'未找到(错误代码:2 - 没有此类文件或目录)

顺便说一句,该文件存在,权限应该没问题(请参阅更长的版本)

更长的版本

该过程如下:

  • 创建.csv文件
  • 此.csv文件被复制到一个目录中,该目录是为 docker 容器挂载的
    • docker 撰写卷部分:- "./data/datahub/import:/var/lib/mysql-files/datahub/import"
  • 然后MySQL将这个.csv文件读入一个表中:
    • LOAD DATA INFILE '.csv-file' REPLACE INTO TABLE 'my-table';
  • 然后该数据库上的一些东西发生了
  • 之后MySQL写入.csv输出文件
    • SELECTTBL.SKU,TBL.,TBL.data_source_valuesINTO OUTFILE 'output.csv' FIELDS TERMINATED BY '|' ENCLOSED BY '"' ESCAPED BY '"' FROM (SELECT ...中删除

这个项目对这个过程有一些Java集成测试。这些测试大多是绿色的,但有时它们会失败:

  • SQLException: 无法创建/写入文件"..."(错误代码:2 - 没有这样的文件或目录)
  • SQLException:无法获取"..."的统计信息错误代码:2 - 没有这样的文件或目录)
  • SQLException:MySQL 服务器使用 --secure-file-priv 选项运行,因此它无法执行此语句
  • SQLException: 文件 '...'未找到(错误代码:2 - 没有此类文件或目录)

docker-compose 文件如下所示:

version: '3'
services:
datahub_db:
image: "mysql:5.7.20"
restart: always
environment:
- MYSQL_ROOT_PASSWORD=${DATAHUB_DB_ROOT_PASSWORD}
- MYSQL_DATABASE=${DATAHUB_DB_DATABASE}
volumes:
- "datahub_db:/var/lib/mysql"
- "./data/datahub/import:/var/lib/mysql-files/datahub/import"
- "./data/akeneo/import:/var/lib/mysql-files/akeneo/import"
ports:
- "${DATAHUB_DB_PORT}:3306"
...
volumes:
datahub_db:

来自该 Docker 数据库容器的日志显示以下内容(但有时,当所有测试均为绿色时也会发生这种情况)

  • datahub_db_1 | 2018-06-01T10:04:33.937646Z 144 [Note] Aborted connection 144 to db: 'datahub_test' user: 'root' host: '172.18.0.1' (Got an error reading communication packets)

数据中心容器内的.csv文件显示以下内容,ls -lha

root@e02e2074fb6b:/var/lib/mysql- 
files/datahub/import/test/products/kaw# ls -lha
total 4.0K
drwxr-xr-x 3 root root  96 Jun  1 09:36 .
drwxr-xr-x 3 root root  96 Jun  1 09:36 ..
-rw-r--r-- 1 root root 378 Jun  1 06:47 deactivated_product_merged_bub.csv

我认为没有问题,这个文件属于root,因为大多数情况下这个文件可以被MySQL读取。当我通过 Docker 容器内的su mysql更改为用户mysql时,我得到以下结果:

$ ls -al
total 4
drwxr-xr-x 3 mysql mysql  96 Jun  1 09:36 .
drwxr-xr-x 3 mysql mysql  96 Jun  1 09:36 ..
-rw-r--r-- 1 mysql mysql 378 Jun  1 06:47 deactivated_product_merged_bub.csv

这时,一些奇怪的事情发生了。

  • 使用root用户,我可以进行cat deactivated_product_merged_bub.csv
  • 对于MySQL用户,我无法得到:

输出:

$ cat deactivated_product_merge_bub.csv
cat: deactivated_product_merge_bub.csv: No such file or directory

我以 MySQL 用户的身份做了一个stat deactivated_product_merged_bub.csv,突然我可以对该文件进行cat(如您所见,我chmod 777该文件以使cat正常工作 - 但它不起作用)。

  • stat为根

输出:

root@e02e2074fb6b:/var/lib/mysql-files/datahub/import/test/products/kaw# stat 
deactivated_product_merged_bub.csv 
File: 'deactivated_product_merged_bub.csv'
Size: 378         Blocks: 8          IO Block: 4194304 regular file
Device: 4fh/79d Inode: 4112125     Links: 1
Access: (0777/-rwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2018-06-01 09:23:38.000000000 +0000
Modify: 2018-06-01 06:47:44.000000000 +0000
Change: 2018-06-01 09:04:53.000000000 +0000
Birth: -
  • stat作为 MySQL 用户

输出:

$ stat deactivated_product_merged_bub.csv
File: 'deactivated_product_merged_bub.csv'
Size: 378         Blocks: 8          IO Block: 4194304 regular file
Device: 4fh/79d Inode: 4112125     Links: 1
Access: (0777/-rwxrwxrwx)  Uid: (  999/   mysql)   Gid: (  999/   mysql)
Access: 2018-06-01 09:32:25.000000000 +0000
Modify: 2018-06-01 06:47:44.000000000 +0000
Change: 2018-06-01 09:04:53.000000000 +0000
Birth: -

问题

有谁知道,这里发生了什么,或者有提示我可以搜索更深入地挖掘什么?

我的猜测是,这是因为将Docker与MacOS和挂载的卷一起使用。

在我看来,您可能会在这里遇到两个单独的问题,都与MySQL服务器的配置有关。

MySQL 服务器使用 --secure-file-priv 选项运行,因此它 无法执行此语句。

此选项要求将任何文件加载或文件导出放置在文件系统中的指定存储位置。您可以使用以下命令从MySQL命令行客户端或MySQL工作台找到该位置:

mysql> show variables like 'secure-file-priv';

由此产生的结果应标识可以加载和写出文件的位置。启用安全文件权限时,不应允许其他位置。

(读取通信数据包时出错)

这通常是由于加载或导出的数据超过了MySQL变量最大允许数据包。

同样,您可以使用以下命令从MySQL命令行客户端或MySQL工作台找到最大允许数据包的值:

mysql> show variables like 'max-allowed-packet';

这个问题已经得到解决并得到了很好的回答: https://dba.stackexchange.com/questions/19135/mysql-error-reading-communication-packets

总结一下: 在/etc/my.cnf 或 my.ini 的 [mysqld] 部分下:

[mysqld]
max_allowed_packet=268435456

‬In the running MySQL instance:

SET GLOBAL max_allowed_packet = 268435456;

(无需重新启动服务。

顺便说一句,您使用的MySQL帐户必须已被授予"FILE"权限才能加载或导出。由于您使用的是MySQL根(管理)帐户,因此这不应该是一个因素,但是我想我会为遇到此问题的任何人将其包括在内。

我希望这有所帮助。

您可能正在尝试访问 docker for mac 默认共享路径之外的文件(来自 docker osx 文档)

默认情况下,您可以在/Users/、/Volumes/、/private/和/tmp 直接。添加或删除导出到 的目录树 Docker,使用 Docker 首选项鲸鱼菜单中的文件共享选项卡 -> 首选项 -> 文件共享。(请参阅首选项。

https://docs.docker.com/docker-for-mac/osxfs/#namespaces

在这种情况下,docker for mac 使用的是由 Mac OS 上的 hyperkit 运行的 Linux 虚拟机。客户端在 macOSx 上运行,并在 VM 中的守护程序上运行。这解释了您必须在受限制的路径列表中共享文件。

我认为您在 docker 容器和主机之间共享文件夹的权限有问题。您需要通过在 .env 文件中设置 UID 来将容器的用户与主机的用户映射。

UID=501 # run echo $UID to get current user id
version: '3'
services:
datahub_db:
image: "mysql:5.7.20"
user: $UID
restart: always
environment:
- MYSQL_ROOT_PASSWORD=${DATAHUB_DB_ROOT_PASSWORD}
- MYSQL_DATABASE=${DATAHUB_DB_DATABASE}
volumes:
- "datahub_db:/var/lib/mysql"
- "./data/datahub/import:/var/lib/mysql-files/datahub/import"
- "./data/akeneo/import:/var/lib/mysql-files/akeneo/import"
ports:
- "${DATAHUB_DB_PORT}:3306"
...
volumes:
datahub_db:

最新更新