使用Postgres的DOCKER容器,警告:无法打开统计文件“pg_stat_tmp/global.stat”:操作不允许。

42
我有一个 DOCKER 容器,使用 .yml、Dockerfile 等几个不同的镜像构建而成。目前为止,一切都构建并运行得很好,除了我在标题中提到的这个问题。
index-db_1   | 2021-02-22 23:18:33.388 UTC [31] WARNING:  could not open statistics file "pg_stat_tmp/global.stat": Operation not permitted

该数据库索引被映射到Docker包的根目录上的主机文件夹中,就数据库而言,其他所有东西似乎都可以正常工作。我正在使用Mac,但如果我从CLI为数据库文件夹列出权限,则会得到以下结果:
-rw-------@  1 sscotti  staff      3 Feb 22 11:01 PG_VERSION
drwx------@  6 sscotti  staff    192 Feb 22 11:54 base
drwx------@ 60 sscotti  staff   1920 Feb 22 16:00 global
drwx------@  2 sscotti  staff     64 Feb 22 11:01 pg_commit_ts
drwx------@  2 sscotti  staff     64 Feb 22 11:01 pg_dynshmem
-rw-------@  1 sscotti  staff   4782 Feb 22 11:02 pg_hba.conf
-rw-------@  1 sscotti  staff   1636 Feb 22 11:01 pg_ident.conf
drwx------@  5 sscotti  staff    160 Feb 22 17:46 pg_logical
drwx------@  4 sscotti  staff    128 Feb 22 11:01 pg_multixact
drwx------@  2 sscotti  staff     64 Feb 22 11:01 pg_notify
drwx------@  2 sscotti  staff     64 Feb 22 11:01 pg_replslot
drwx------@  2 sscotti  staff     64 Feb 22 11:01 pg_serial
drwx------@  2 sscotti  staff     64 Feb 22 11:01 pg_snapshots
drwx------@  2 sscotti  staff     64 Feb 22 16:00 pg_stat
drwx------@  5 sscotti  staff    160 Feb 22 17:50 pg_stat_tmp
drwx------@  3 sscotti  staff     96 Feb 22 11:01 pg_subtrans
drwx------@  2 sscotti  staff     64 Feb 22 11:01 pg_tblspc
drwx------@  2 sscotti  staff     64 Feb 22 11:01 pg_twophase
drwx------@  4 sscotti  staff    128 Feb 22 11:01 pg_wal
drwx------@  3 sscotti  staff     96 Feb 22 11:01 pg_xact
-rw-------@  1 sscotti  staff     88 Feb 22 11:01 postgresql.auto.conf
-rw-------@  1 sscotti  staff  28073 Feb 22 11:01 postgresql.conf
-rw-------@  1 sscotti  staff     36 Feb 22 16:00 postmaster.opts
-rw-------   1 sscotti  staff     94 Feb 22 16:00 postmaster.pid

"pg_stat"文件夹实际上是空的。
而"pg_stat_temp"文件夹中有:
-rw-------  1 sscotti  staff   1952 Feb 22 17:54 db_0.stat
-rw-------  1 sscotti  staff  20360 Feb 22 17:54 db_13395.stat
-rw-------  1 sscotti  staff   1151 Feb 22 17:54 global.stat

这个.yml文件包含以下内容:
  index-db:
      image: postgres
      restart: unless-stopped
      volumes:
          - ./OrthancIndex:/var/lib/postgresql/data

这是一个Docker容器,可以忽略它吗?
关于相同的Ubuntu设置添加评论。
数据库文件夹:
drwx------ 19 systemd-coredump root 4096 Jun 30 13:12 OrthancIndex
数据库:
drwx------ 6 systemd-coredump systemd-coredump  4096 Jun 11 13:00 base
drwx------ 2 systemd-coredump systemd-coredump  4096 Jun 30 13:12 global
drwx------ 2 systemd-coredump systemd-coredump  4096 Mar 12 16:12 pg_commit_ts
drwx------ 2 systemd-coredump systemd-coredump  4096 Mar 12 16:12 pg_dynshmem
-rw------- 1 systemd-coredump systemd-coredump  4782 Mar 12 16:12 pg_hba.conf
-rw------- 1 systemd-coredump systemd-coredump  1636 Mar 12 16:12 pg_ident.conf
drwx------ 4 systemd-coredump systemd-coredump  4096 Jul  1 13:27 pg_logical
drwx------ 4 systemd-coredump systemd-coredump  4096 Mar 12 16:12 pg_multixact
drwx------ 2 systemd-coredump systemd-coredump  4096 Mar 12 16:12 pg_notify
drwx------ 2 systemd-coredump systemd-coredump  4096 Mar 12 16:12 pg_replslot
drwx------ 2 systemd-coredump systemd-coredump  4096 Mar 12 16:12 pg_serial
drwx------ 2 systemd-coredump systemd-coredump  4096 Mar 12 16:12 pg_snapshots
drwx------ 2 systemd-coredump systemd-coredump  4096 Jun 30 13:12 pg_stat
drwx------ 2 systemd-coredump systemd-coredump  4096 Jul  1 13:29 pg_stat_tmp
drwx------ 2 systemd-coredump systemd-coredump  4096 Jun 24 21:04 pg_subtrans
drwx------ 2 systemd-coredump systemd-coredump  4096 Mar 12 16:12 pg_tblspc
drwx------ 2 systemd-coredump systemd-coredump  4096 Mar 12 16:12 pg_twophase
-rw------- 1 systemd-coredump systemd-coredump     3 Mar 12 16:12 PG_VERSION
drwx------ 3 systemd-coredump systemd-coredump  4096 Jul  1 12:37 pg_wal
drwx------ 2 systemd-coredump systemd-coredump  4096 Mar 12 16:12 pg_xact
-rw------- 1 systemd-coredump systemd-coredump    88 Mar 12 16:12 postgresql.auto.conf
-rw------- 1 systemd-coredump systemd-coredump 28073 Mar 12 16:12 postgresql.conf
-rw------- 1 systemd-coredump systemd-coredump    36 Jun 30 13:12 postmaster.opts
-rw------- 1 systemd-coredump systemd-coredump    94 Jun 30 13:12 postmaster.pid

pg_stat_temp

-rw------- 1 systemd-coredump systemd-coredump  2660 Jul  1 13:30 db_0.stat
-rw------- 1 systemd-coredump systemd-coredump 31157 Jul  1 13:30 db_13395.stat
-rw------- 1 systemd-coredump systemd-coredump  1151 Jul  1 13:30 global.stat

我在Ubuntu上也遇到了同样的错误:
postgres_index-db_1   | 2021-07-01 18:06:45.140 UTC [266] WARNING:  could not open statistics file "pg_stat_tmp/global.stat": Operation not permitted
postgres_index-db_1   | 2021-07-01 18:13:45.583 UTC [273] WARNING:  could not open statistics file "pg_stat_tmp/global.stat": Operation not permitted
postgres_index-db2_1  | 2021-07-01 18:19:43.716 UTC [282] WARNING:  could not open statistics file "pg_stat_tmp/global.stat": Operation not permitted
postgres_index-db2_1  | 2021-07-01 18:21:43.749 UTC [284] WARNING:  could not open statistics file "pg_stat_tmp/global.stat": Operation not permitted

尽管在这里用户和组是systemd-coredump。

1
我遇到了完全相同的问题,目前还没有找到任何解决方案。 - domser
1
我遇到了完全相同的问题。我已经将文件挂载到我的本地文件系统中,但是收到了这个错误消息。有一个值得注意的地方,当我使用 Docker Volume 时,不会出现该消息。这让我认为这是 OSX 权限和 Docker 之间的某种不匹配。 - fbl
1
@fbl 你如何在 .yaml 文件中进行更改?将其作为 Docker 卷挂载而不是绑定到主机上的文件夹?我认为这会对 OS X 上的性能和权限产生影响,但在 LINUX 主机上可能会有很大的差异。我仍然希望能够轻松地从主机访问数据。 - SScotti
1
@fbl 还希望它是持久的。 - SScotti
我也遇到了同样的问题。这是对类似问题的一个非常有趣的回答。https://dev59.com/Al0Z5IYBdhLWcg3w-UZ-#32193782 - whatapalaver
显示剩余5条评论
6个回答

12

简单而愚蠢

我尝试了另一种方式:将临时文件留在容器中,这样您就不需要处理用户权限 - 这很有效。 我通过行内命令修改了docker-compose.yml中的Postgresql配置:

postgresdb:    
    image: 'postgres'
    command: postgres -c stats_temp_directory=/tmp
    .
    .
    .

这是一个快速简单的解决方案,但它不能设置多个postgres配置参数。随着时间的推移,我找到了另一种解决方案。

高级 (添加于22/01/14 09:00PM CET)

高级解决方案包括以下步骤:

  1. 准备所需的postgresql.conf - 在此处,您可以设置任何需要的postgres服务器参数。解决此线程中的问题所必需的是:
    stats_temp_directory = '/tmp/stat_temporary'
    
    1. 创建bash文件,在docker-compose.yml中使用docker-entrypoint-initdb.d,将配置文件复制到docker的postgres配置目录中并创建临时文件夹。

    如果您按照这种方式设置了docker-compose.yml

    postgres-db:
        image: postgres
        container_name: 'dbcontainer'
        volumes:
          # point to your postgres init scripts (folder or file)
          - $PWD/db_init:/docker-entrypoint-initdb.d
          # if you need persistent data, point data to local folder
          - $PWD/database:/var/lib/postgresql/data
          # if you want some data restore, point to your backup
          - $PWD/db_backup:/db_backup
          # point docker to directory with your config
          - $PWD/db_config:/db_config
    

    然后数据库将使用位于db_init目录中的脚本进行初始化。(或者你可以直接指定一个sql或bash文件。如果你指定了目录,初始化脚本将按字母顺序运行所有文件。 将包含初始化bash脚本的文件放置在db_init文件夹中,它将在docker内部启动:

    echo starting script...
    # create temporary directory for postgres in docker
    mkdir /tmp/stat_temporary 
    
    # copy your postgresql.conf to postgresql config location in docker
    cp /db_config/postgresql.conf var/lib/postgresql/data/postgresql.conf
    
    # alternatively you can run any pg script you need, here I restore backup to new database
    pg_restore -U postgres -v -Fc -d analysis /db_backup/analysis_backup.bak
    echo finished
    
    运行此脚本后,Docker上的数据库服务将重新启动,并加载您设置的新参数。

请查看我的最后一条评论。 - SScotti
高级解决方案非常简单...只需在$PWD目录中创建bash文件,添加卷条目,重新启动容器-不再出现警告!谢谢! - remed.io

3

我写下这篇文章不仅是为了将来的自己,也是为了回答这个问题:看着文档并采用@Fide的解决方案,以下内容似乎在运行PostGIS映像的MacOSX Monterey上(这只是建立在Postgres映像之上)可以工作……

请注意,以下内容取自一个shell脚本,用于启动带有主机系统上持久本地存储的Postgres+PostGIS映像:

WORK_DIR="$HOME/Documents/git/project"
DOCKER_NM="postgis"
DOCKER_IMG="postgis/postgis"
POSTGRES_PWD="XXX"
PORT_NO="5432"
docker run --name $DOCKER_NM \
    -e POSTGRES_PASSWORD=$POSTGRES_PWD \
    -e PGDATA=/var/lib/postgresql/data/pgdata \
    -v "$WORK_DIR/data/postgres":/var/lib/postgresql/data \
    -p "$PORT_NO:5432" -d $DOCKER_IMG \
    postgres -c stats_temp_directory=/tmp

如果您直接从终端中运行(即不通过zsh/bash)则需要export每个参数,而不仅仅是指定它们。
这样做后,全局.stat错误似乎已经消失了……不过我应该注意到,我刚刚才发现了这一点,并且容器运行时间不到60分钟。另一个选择是按照该页面上的说明创建和使用一个持久化自定义配置文件(扩展@SScotti上面的评论),并将其从本地文件系统挂载:
-v "$PWD/my-postgres.conf":/etc/postgresql/postgresql.conf

@Fide stats_timestamp 2022-03-28 12:44:10.89023-05 晚于收集器的时间戳 2022-03-28 12:44:10.865062-05 ,针对数据库 13445 。我最近尝试了类似的操作,但会定期出现此错误。不确定是否会成为问题。 - SScotti

2
使用本地卷进行挂载需要在postgres容器内进行用户映射。在https://hub.docker.com/_/postgres的README中有一个名为任意--用户注释(Arbitrary --user Notes)的部分,其中描述了解决问题的方法。
其中一种推荐的方法是使用docker卷,初始化挂载的卷内容,关闭容器镜像,运行递归所有权更改,然后正常重启容器。
$ docker volume create pgdata
$ docker run -it --rm -v pgdata:/var/lib/postgresql/data -e POSTGRES_PASSWORD=mysecretpassword postgres
The files belonging to this database system will be owned by user "postgres".
...
( once it's finished initializing successfully and is waiting for connections, stop it )
$ docker run -it --rm -v pgdata:/var/lib/postgresql/data bash chown -R 1000:1000 /var/lib/postgresql/data
$ docker run -it --rm --user 1000:1000 -v pgdata:/var/lib/postgresql/data postgres

尚未尝试过,但值得尝试的是将stats_temp_directory设置为Docker容器中的目录。请参见:https://www.postgresql.org/docs/10/runtime-config-statistics.html。不确定如何从Docker中完成此操作。默认值为:#stats_temp_directory ='pg_stat_tmp'。 - SScotti
我尝试着对我的一个现有容器进行了操作,只是关闭了它,编辑了postgresql.conf文件,将stats_temp_directory设置为'/tmp',然后重新启动。这可能暂时解决了问题。如果这样行得通的话,只需要弄清楚如何在Docker重启或初始化时配置即可。 - SScotti

2

虽然不是对原问题的回答,但由于我的声誉值不足,我不能添加评论。所以,这里有一个可行的docker-compose.yml文件,使用tmpfs解决方案作为答案(适用于@SScotti和其他想尝试这种方法而不会弄乱默认命令或配置的人):

环境文件 (.env):

POSTGRES_VERSION=13.6
DATABASE_NAME=dbname
DATABASE_USER=dbuser
DATABASE_PASS=dbpass

Compose文件 (docker-compose.yml):

version: '3.6'
services:
  postgres:
    image: postgres:${POSTGRES_VERSION}-alpine
    restart: always
    container_name: postgres
    environment:
      POSTGRES_DB: ${DATABASE_NAME}
      POSTGRES_USER: ${DATABASE_USER}
      POSTGRES_PASSWORD: ${DATABASE_PASS}
    volumes:
      - /etc/timezone:/etc/timezone:ro
      - .volumes/pgdata:/var/lib/postgresql/data
      - type: tmpfs
        target: /var/lib/postgresql/data/pg_stat_tmp
        tmpfs:
          # 256 Mb - beware the default, it's infinity(!)
          size: 268435456

编辑:首次运行注意事项
首次运行时,postgres 尝试初始化数据库并失败了,因为数据目录(位于data目录中的现有/挂载的tmpfs pg_stats_tmp)不是空的。

为了避免这种情况,您需要在compose文件中先不包含tmpfs部分来运行服务,当postgres完成初始化后,将服务关闭并在再次启动服务之前在compose文件中启用tmpfs部分。


我有时间的时候可能会尝试一下。这似乎是一个受欢迎的问题和解决方案。 - SScotti
尝试后,似乎工作正常。另外,如果我正在使用Docker桌面版和/或Docker CLI,最好的方法是优雅地关闭postgres和mysql吗?有时它们看起来可以很好地关闭,但其他时候SIGKILL会失败,我不得不重新启动docker。 - SScotti
@SScotti - 停止正在运行的容器最好的方法是 docker stop ${ID_OR_NAME},请参阅:docker stop。 精心制作的镜像将对 SIGTERM 作出反应并正确关闭。 使用 docker-compose,您必须使用 docker-compose stop ${SERVICE_NAME} 停止服务,省略服务名称将停止在 compose 文件中定义的完整堆栈(即所有服务)。 将 stop 替换为 down 还将删除容器和网络。 - Adminradio

1
我遇到了同样的问题——仔细研究后,最终找到了一个简单的解决方案。
首先是一些基本背景知识——你的pg_stat_temp_directory位置是在数据目录下的一个子目录。
show data_directory ;

如果它返回类似于Unix基础系统的默认值
/var/lib/postgresql/data
并且您的命令用于显示stats_temp。
show stats_temp_directory ;

也会返回默认值。 pg_stat_tmp 那么你的stats_temp_directory的完整路径是/var/lib/postgresql/data/pg_stat_tmp。
我使用了绑定映射来将PG容器数据文件映射到我的主机上,这样即使容器停止后,我也可以保留数据。
docker run -d --name gutlo-postgres -p 5434:5432 -v /data/postgres-docker/14:/var/lib/postgresql/data -e POSTGRES_PASSWORD=<PASSWORD>  postgres:latest

现在每次启动容器时,它会自动在stats_temp目录下创建文件,其中有一个叫做global.stat的文件会出问题。
ls -la global.stat 

-rw------- 1 ssengupta admin 3648 May 13 16:24 global.stat

的翻译是:

-rw------- 1 ssengupta admin 3648 5月13日 16:24 global.stat


 ls -la . | head -2 | tail -1

drwxr-xr-x@ 14 ssengupta admin 448 May 13 16:26 .

这是一个文件夹的权限信息,其中“ssengupta”是文件夹的所有者,“admin”是文件夹所属组,“448”是文件夹的大小(以字节为单位),“May 13 16:26”是文件夹的最后修改时间。

  • 现在你看到了问题所在。容器能够创建文件global.stat(它的目录文件“。”具有打开rwx权限),但文件本身是没有打开权限创建的,因此我的容器无法访问其自己创建的文件。

根据Docker手册,有一个temp挂载的概念。因此,只需为stats_temp目录创建一个临时挂载点,Docker将使用tempfs / RAM - 这将消除权限问题。

--mount type=tmpfs,destination=/var/lib/postgresql/data/pg_stat_tmp

此外,它也会提高性能,尽管您可能无法察觉到。

可以尝试一下,虽然其他解决方案“有用”。在 Docker-Compose 文件中,使用 tmpfs:/var/lib/postgresql/data/pg_stat_tmp,这个方法如何实现? - SScotti

1

我的尝试…

连接到数据库容器:

docker compose run --no-deps -it db bash

并在数据目录上执行 ls 命令:

root@dfc6399e2981:/var/lib/postgresql/data# ls -l
total 60
drwx------  7 root     root       224 Sep  8 23:38 base
drwx------ 60 root     root      1920 Sep  8 23:38 global
drwx------  2 postgres postgres    64 Sep  8 23:35 pg_commit_ts
drwx------  2 postgres postgres    64 Sep  8 23:35 pg_dynshmem
-rw-------  1 postgres postgres  4821 Sep  8 23:35 pg_hba.conf
-rw-------  1 postgres postgres  1636 Sep  8 23:35 pg_ident.conf
drwx------  5 root     root       160 Sep  8 23:43 pg_logical
drwx------  4 postgres postgres   128 Sep  8 23:35 pg_multixact
drwx------  2 postgres postgres    64 Sep  8 23:35 pg_notify
drwx------  2 postgres postgres    64 Sep  8 23:35 pg_replslot
drwx------  2 postgres postgres    64 Sep  8 23:35 pg_serial
drwx------  2 postgres postgres    64 Sep  8 23:35 pg_snapshots
drwx------  2 root     root        64 Sep  8 23:35 pg_stat
drwx------  6 root     root       192 Sep  9 00:20 pg_stat_tmp
drwx------  3 postgres postgres    96 Sep  8 23:35 pg_subtrans
drwx------  2 postgres postgres    64 Sep  8 23:35 pg_tblspc
drwx------  2 postgres postgres    64 Sep  8 23:35 pg_twophase
-rw-------  1 postgres postgres     3 Sep  8 23:35 PG_VERSION
drwx------  4 postgres postgres   128 Sep  8 23:35 pg_wal
drwx------  3 postgres postgres    96 Sep  8 23:35 pg_xact
-rw-------  1 postgres postgres    88 Sep  8 23:35 postgresql.auto.conf
-rw-------  1 postgres postgres 28835 Sep  8 23:35 postgresql.conf
-rw-------  1 root     root        36 Sep  8 23:35 postmaster.opts
-rw-------  1 postgres postgres    94 Sep  8 23:35 postmaster.pid

显然,需要注意的是一些东西是由root所有的。另外,进行比较和对比,从容器外部看到的是:

% ls -l db/data
total 120
-rw-------@  1 pedz  staff      3 Sep  8 18:35 PG_VERSION
drwx------@  7 pedz  staff    224 Sep  8 18:38 base
drwx------@ 60 pedz  staff   1920 Sep  8 18:38 global
drwx------@  2 pedz  staff     64 Sep  8 18:35 pg_commit_ts
drwx------@  2 pedz  staff     64 Sep  8 18:35 pg_dynshmem
-rw-------@  1 pedz  staff   4821 Sep  8 18:35 pg_hba.conf
-rw-------@  1 pedz  staff   1636 Sep  8 18:35 pg_ident.conf
drwx------@  5 pedz  staff    160 Sep  8 18:43 pg_logical
drwx------@  4 pedz  staff    128 Sep  8 18:35 pg_multixact
drwx------@  2 pedz  staff     64 Sep  8 18:35 pg_notify
drwx------@  2 pedz  staff     64 Sep  8 18:35 pg_replslot
drwx------@  2 pedz  staff     64 Sep  8 18:35 pg_serial
drwx------@  2 pedz  staff     64 Sep  8 18:35 pg_snapshots
drwx------@  2 pedz  staff     64 Sep  8 18:35 pg_stat
drwx------@  6 pedz  staff    192 Sep  8 19:27 pg_stat_tmp
drwx------@  3 pedz  staff     96 Sep  8 18:35 pg_subtrans
drwx------@  2 pedz  staff     64 Sep  8 18:35 pg_tblspc
drwx------@  2 pedz  staff     64 Sep  8 18:35 pg_twophase
drwx------@  4 pedz  staff    128 Sep  8 18:35 pg_wal
drwx------@  3 pedz  staff     96 Sep  8 18:35 pg_xact
-rw-------@  1 pedz  staff     88 Sep  8 18:35 postgresql.auto.conf
-rw-------@  1 pedz  staff  28835 Sep  8 18:35 postgresql.conf
-rw-------@  1 pedz  staff     36 Sep  8 18:35 postmaster.opts
-rw-------@  1 pedz  staff     94 Sep  8 18:35 postmaster.pid

所以,在db容器中我执行了以下操作:

chown -R postgres:postgres /var/lib/postgresql/data

我现在可以从容器外部看到pg_stat_tmp的更新,它已经运行了30分钟,没有警告信息,所以我认为它已经“修复”了,尽管我不知道足够关于Docker的镜像,不能确定问题是否会在以后再次出现。也许有更多Docker知识的人可以发表意见。
更新:这并没有解决问题。与其删除这个答案,我想我会把它留在这里。有些文件属于root,这很奇怪。即使我使用了chown -R,仍然有一些文件属于root:
root@ec24992481d1:/var/lib/postgresql# find . -user 0 -exec ls -ld {} +
-rw------- 1 root root    8 Sep  9 00:34 ./data/pg_logical/replorigin_checkpoint
-rw------- 1 root root 2225 Sep  9 01:12 ./data/pg_stat_tmp/db_0.stat
-rw------- 1 root root 6665 Sep  9 01:12 ./data/pg_stat_tmp/db_13757.stat
-rw------- 1 root root 7035 Sep  9 01:12 ./data/pg_stat_tmp/db_16384.stat
-rw------- 1 root root   94 Sep  9 00:29 ./data/postmaster.pid
root@ec24992481d1:/var/lib/postgresql# 

这可能是对更熟悉Docker的人的提示。

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