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

时间:2019-05-08 17:20:29

标签: postgresql docker gitlab gitlab-ci gitlab-ci-runner

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,但是当容器启动时,应该运行/docker-entrypoint-initdb.d/*中的所有文件,就像我们看到的here一样。

但是,相反,在服务器上执行docker logs -f lbsn-testdb时,我可以看到它说明了

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

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

关于这是为什么的任何想法?

3 个答案:

答案 0 :(得分:1)

这比我预期的要容易,致命的是与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

太容易想到了:-/

答案 1 :(得分:0)

我发现本主题发现使用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初始化脚本由于权限错误而错过安装步骤的原因。这个问题出现了好几年,但是在最新的PostgreSQL版本中仍然存在(当前是12.1)

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

这是一个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"

答案 2 :(得分:0)

如果您之前已经运行过postgres服务,则在重新启动该文件时会忽略其初始化文件,因此请尝试使用--build重新构建映像

docker-compose up --build -d

,然后再次运行:

使用以下命令检查现有卷

docker volume ls

然后删除用于pg服务的那个

docker volume rm {volume_name}

->确保该容器未使用该卷,如果是,则也将其删除