为什么 postgres 容器在 Gitlab CI 中忽略 /docker-entrypoint-initdb.d/*

Why is postgres container ignoring /docker-entrypoint-initdb.d/* in Gitlab CI

Gitlab CI 一直忽略 this project.

/docker-entrypoint-initdb.d/* 中的 sql 文件

这里是 docker-compose.yml:

version: '3.6'

services:

  testdb:
    image: postgres:11
    container_name: lbsn-testdb
    restart: always
    ports:
      - "65432:5432"
    volumes:
      - ./testdb/init:/docker-entrypoint-initdb.d

这里是 .gitlab-ci.yml:

stages:
  - deploy

deploy:
  stage: deploy
  image: debian:stable-slim
  script:
    - bash ./deploy.sh

部署脚本基本上使用 rsync 通过 SSH 将存储库的内容部署到服务器:

rsync -rav --chmod=Du+rwx,Dgo-rwx,u+rw,go-rw -e "ssh -l gitlab-ci" --exclude=".git" --delete ./ "gitlab-ci@$DEPLOY_SERVER:test/"

然后通过 ssh 进入服务器以停止并重新启动容器:

ssh "gitlab-ci@$DEPLOY_SERVER" "cd test && docker-compose down && docker-compose up --build --detach"

这都是goes well, but when the container starts up, it is supposed to run all the files that are in /docker-entrypoint-initdb.d/* as we can see here.

但是,当在服务器上执行 docker logs -f lbsn-testdb 时,我可以看到它显示

/usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*

我不知道为什么会这样。当 运行 这个容器在本地或者甚至当我 ssh 到那个服务器时,克隆 repo 并手动启动容器,一切顺利并解析 sql 文件。只是不是在 Gitlab CI 做的时候。

有什么想法吗?

这比我预期的要容易,而且与 Gitlab CI 完全无关,但与文件权限有关。

我将 --chmod=Du+rwx,Dgo-rwx,u+rw,go-rw 传递给了 rsync,这看起来非常安全,因为只有用户才能执行操作。我承认我可能是从互联网上的某个地方复制粘贴的。但是随后文件被安装到 Docker 容器,并且在那里它们也具有这些权限:

-rw------- 1 1005 1004 314 May  8 15:48 100-create-database.sql

在主机上,我的 gitlab-ci 用户拥有这些文件,它们显然也属于容器中 ID 为 1005 的某个用户,除此用户外,其他用户没有任何权限。

虽然在容器内执行操作的用户是 postgres,但它无法读取这些文件。它没有抱怨,而是忽略了它们。这可能会引发关于……

的问题

Now that I pass --chmod=D755,F644 看起来是这样的:

-rw-r--r--  1 1005 1004  314 May  8 15:48 100-create-database.sql

并且 docker 日志说

/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/100-create-database.sql

首先想到的太容易了:-/

我发现这个主题发现了使用 docker-compose 工具安装 PostgreSQL 的类似问题。

解决方法基本相同。对于提供的配置:

version: '3.6'

services:

  testdb:
    image: postgres:11
    container_name: lbsn-testdb
    restart: always
    ports:
      - "65432:5432"
    volumes:
      - ./testdb/init:/docker-entrypoint-initdb.d

您的部署脚本应为您的 postgres 容器卷设置 0755 权限,如本例中的 chmod -R 0755 ./testdb。使所有子目录可见很重要,因此需要 chmod -R 选项。

官方 Postgres 图像是 运行 内部 postgres 用户下的 UID 70。您在主机中的应用程序用户很可能有不同的 UID,例如 1000 或类似的东西。这就是 postgres init 脚本由于权限错误而错过安装步骤的原因。这个问题出现好几年了,但在最新的PostgreSQL版本(目前是12.1)中仍然存在

请注意系统中所有初始化文件可读时的安全漏洞。最好使用 shell 环境变量将秘密传递到 init 脚本中。

这是一个 docker-compose 示例:

 postgres:
    image: postgres:12.1-alpine
    container_name: app-postgres
    environment:
      - POSTGRES_USER
      - POSTGRES_PASSWORD
      - APP_POSTGRES_DB
      - APP_POSTGRES_SCHEMA
      - APP_POSTGRES_USER
      - APP_POSTGRES_PASSWORD
    ports:
      - '5432:5432'
    volumes:
      - $HOME/app/conf/postgres:/docker-entrypoint-initdb.d
      - $HOME/data/postgres:/var/lib/postgresql/data

用于创建用户的相应脚本 create-users.sh 可能如下所示:

#!/bin/bash

set -o nounset
set -o errexit
set -o pipefail

POSTGRES_USER="${POSTGRES_USER:-postgres}"
POSTGRES_PASSWORD="${POSTGRES_PASSWORD}"
APP_POSTGRES_DB="${APP_POSTGRES_DB:-app}"
APP_POSTGRES_SCHEMA="${APP_POSTGRES_SCHEMA:-app}"
APP_POSTGRES_USER="${APP_POSTGRES_USER:-appuser}"
APP_POSTGRES_PASSWORD="${APP_POSTGRES_PASSWORD:-app}"

DATABASE="${APP_POSTGRES_DB}"

# Create single database.
psql --variable ON_ERROR_STOP=1 --username "${POSTGRES_USER}" --command "CREATE DATABASE ${DATABASE}"

# Create app user.
psql --variable ON_ERROR_STOP=1 --username "${POSTGRES_USER}" --command "CREATE USER ${APP_POSTGRES_USER} SUPERUSER PASSWORD '${APP_POSTGRES_PASSWORD}'"
psql --variable ON_ERROR_STOP=1 --username "${POSTGRES_USER}" --command "GRANT ALL PRIVILEGES ON DATABASE ${DATABASE} TO ${APP_POSTGRES_USER}"
psql --variable ON_ERROR_STOP=1 --username "${POSTGRES_USER}" --dbname "${DATABASE}" --command "CREATE SCHEMA ${APP_POSTGRES_SCHEMA} AUTHORIZATION ${APP_POSTGRES_USER}"
psql --variable ON_ERROR_STOP=1 --username "${POSTGRES_USER}" --command "ALTER USER ${APP_POSTGRES_USER} SET search_path = ${APP_POSTGRES_SCHEMA},public"

如果您之前已经 运行 了 postgres 服务,当您重新启动它时,初始化文件将被忽略,所以请尝试使用 --build 再次构建映像

docker-compose up --build -d

再一次 运行 之前:

检查现有卷

docker volume ls

然后删除您正在使用的 pg 服务

docker volume rm {volume_name}

-> 确保该卷未被容器使用,如果是,则也移除容器