【问题标题】:How to create User/Database in script for Docker Postgres如何在 Docker Postgres 的脚本中创建用户/数据库
【发布时间】:2014-12-23 06:59:32
【问题描述】:

我一直在尝试通过创建自定义用户和数据库来为开发 postgres 实例设置容器。我正在使用official postgres docker image。在文档中,它指示您在 /docker-entrypoint-initdb.d/ 文件夹中插入一个 bash 脚本,以使用任何自定义参数设置数据库。

我的 bash 脚本:make_db.sh

su postgres -c "createuser -w -d -r -s docker"
su postgres -c "createdb -O docker docker"

Dockerfile

FROM library/postgres

RUN ["mkdir", "/docker-entrypoint-initdb.d"]
ADD make_db.sh /docker-entrypoint-initdb.d/

我从docker logs -f db(db 是我的容器名称)得到的错误是:

createuser:无法连接到数据库 postgres:无法连接到服务器:没有这样的文件或目录

似乎/docker-entrypoint-initdb.d/ 文件夹内的命令在 postgres 启动之前正在执行。我的问题是,如何使用官方的 postgres 容器以编程方式设置用户/数据库?有没有办法用脚本做到这一点?

【问题讨论】:

    标签: bash postgresql docker dockerhub


    【解决方案1】:

    编辑 - 自 2015 年 7 月 23 日起

    official postgres docker image 将运行在/docker-entrypoint-initdb.d/ 文件夹中找到的.sql 脚本。

    所以你只需要创建以下 sql 脚本:

    init.sql

    CREATE USER docker;
    CREATE DATABASE docker;
    GRANT ALL PRIVILEGES ON DATABASE docker TO docker;
    

    并将其添加到您的 Dockerfile 中:

    Dockerfile

    FROM library/postgres
    COPY init.sql /docker-entrypoint-initdb.d/
    

    但自 2015 年 7 月 8 日起,如果您只需要创建一个用户和数据库,使用 POSTGRES_USERPOSTGRES_PASSWORDPOSTGRES_DB 环境会更容易变量:

    docker run -e POSTGRES_USER=docker -e POSTGRES_PASSWORD=docker -e POSTGRES_DB=docker library/postgres
    

    或使用 Dockerfile:

    FROM library/postgres
    ENV POSTGRES_USER docker
    ENV POSTGRES_PASSWORD docker
    ENV POSTGRES_DB docker
    

    适用于 2015 年 7 月 23 日之前的图片

    来自the documentation of the postgres Docker image,据说

    [...] 它将获取在该目录 [/docker-entrypoint-initdb.d] 中找到的任何 *.sh 脚本,以便在启动服务之前进行进一步的初始化

    这里重要的是“在启动服务之前”。这意味着您的脚本 make_db.sh 将在 postgres 服务启动之前执行,因此错误消息 “无法连接到数据库 postgres”

    之后还有一条有用的信息:

    如果您需要在初始化过程中执行 SQL 命令,强烈建议使用 Postgres 单用户模式。

    同意这乍一看可能有点神秘。它说的是您的初始化脚本应该在执行其操作之前以单一模式启动 postgres 服务。所以你可以改变你的 make_db.ksh 脚本如下,它应该让你更接近你想要的:

    注意,最近in the following commit 发生了变化。这将适用于最新更改:

    export PGUSER=postgres
    psql <<- EOSQL
        CREATE USER docker;
        CREATE DATABASE docker;
        GRANT ALL PRIVILEGES ON DATABASE docker TO docker;
    EOSQL
    

    以前需要使用--single 模式:

    gosu postgres postgres --single <<- EOSQL
        CREATE USER docker;
        CREATE DATABASE docker;
        GRANT ALL PRIVILEGES ON DATABASE docker TO docker;
    EOSQL
    

    【讨论】:

    • 您可以使用:gosu postgres postgres --single &lt; /tmp/somefile.sql
    • 如何运行psql -U myDb -d myDb -f myDb.sql
    • 注意,任何 postgres Dockerfile 都不再支持 --single。
    • 虽然这被标记为正确答案,但这里有一个没有人谈论的细微差别:POSTGRES_USER/PASSWORD 将在您的数据库中设置超级用户。对于您的主数据库用户来说,这可能并不总是一个好主意。而是考虑创建一个单独的应用程序用户和数据库。
    • 截至 2021 年 9 月,这可以在 docker 的 PostgreSQL 官方页面上看到:警告/docker-entrypoint-initdb.d 中的脚本只有在使用数据目录启动容器时才会运行那是空的
    【解决方案2】:

    通过使用docker-compose

    假设您有以下目录布局:

    $MYAPP_ROOT/docker-compose.yml
               /Docker/init.sql
               /Docker/db.Dockerfile
    
    

    文件:docker-compose.yml

    version: "3.3"
    services:
      db:
        build:
          context: ./Docker
          dockerfile: db.Dockerfile
        volumes:
          - ./var/pgdata:/var/lib/postgresql/data
        ports:
          - "5432:5432"
    

    文件:Docker/init.sql

    CREATE USER myUser;
    
    CREATE DATABASE myApp_dev;
    GRANT ALL PRIVILEGES ON DATABASE myApp_dev TO myUser;
    
    CREATE DATABASE myApp_test;
    GRANT ALL PRIVILEGES ON DATABASE myApp_test TO myUser;
    

    文件:Docker/db.Dockerfile

    FROM postgres:11.5-alpine
    COPY init.sql /docker-entrypoint-initdb.d/
    

    组合和启动服务:

    docker-compose -f docker-compose.yml up --no-start
    docker-compose -f docker-compose.yml start
    

    【讨论】:

      【解决方案3】:

      使用 docker compose 有一个简单的替代方案(无需创建 Dockerfile)。只需创建一个 init-database.sh:

      #!/bin/bash
      set -e
      
      psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
          CREATE USER docker;
          CREATE DATABASE my_project_development;
          GRANT ALL PRIVILEGES ON DATABASE my_project_development TO docker;
          CREATE DATABASE my_project_test;
          GRANT ALL PRIVILEGES ON DATABASE my_project_test TO docker;
      EOSQL
      

      并在卷部分引用它:

      version: '3.4'
      
      services:
        postgres:
          image: postgres
          restart: unless-stopped
          volumes:
            - postgres:/var/lib/postgresql/data
            - ./init-database.sh:/docker-entrypoint-initdb.d/init-database.sh
          environment:
            - POSTGRES_USER=postgres
            - POSTGRES_PASSWORD=postgres
          ports:
            - 5432:5432
      
      volumes:
        postgres:
      

      【讨论】:

      • 这对我不起作用。似乎volumes指令在docker-entrypoint-initdb.d中创建了一个目录,而不是一个文件。错误是该文件是一个目录。
      【解决方案4】:

      您可以使用以下命令:

      docker exec -it yournamecontainer psql -U postgres -c "CREATE DATABASE mydatabase ENCODING 'LATIN1' TEMPLATE template0 LC_COLLATE 'C' LC_CTYPE 'C';"
      
      docker exec -it yournamecontainer psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE postgres TO postgres;"
      

      【讨论】:

      • ENCODING 'LATIN1' 很奇怪...你必须有非常特殊的需要避免使用utf8
      【解决方案5】:

      您现在可以将 .sql 文件放入 init 目录中:

      From the docs

      如果您想在从该镜像派生的镜像中进行额外的初始化,请在 /docker-entrypoint-initdb.d 下添加一个或多个 *.sql 或 *.sh 脚本(必要时创建目录)。在入口点调用 initdb 创建默认的 postgres 用户和数据库后,它将运行任何 *.sql 文件并获取该目录中找到的任何 *.sh 脚本,以在启动服务之前进行进一步的初始化。

      所以复制你的 .sql 文件就行了。

      【讨论】:

      • 用户/密码和数据库创建的环境变量仍然有效。 (9.5.3)
      • 我有一个在本地工作的项目。但是,当我将它移动到 AWS EC2 时,它说找不到 DB。我将 .sql 文件复制到正确的目录中,但它仍然返回该错误。知道我可以在哪里看吗?我是 Docker 新手。
      • 仅当有一个数据库实例绑定到单个卷时才适用,即如果卷文件夹中已有任何内容,它将不会运行任何脚本。这让我很头疼,因为我想为我的每个堆栈服务都有一个单独的数据库初始化程序。
      • 来自docsWarning: scripts in /docker-entrypoint-initdb.d are only run if you start the container with a data directory that is empty; any pre-existing database will be left untouched on container startup. One common problem is that if one of your /docker-entrypoint-initdb.d scripts fails (which will cause the entrypoint script to exit) and your orchestrator restarts the container with the already initialized data directory, it will not continue on with your scripts.
      【解决方案6】:

      我在启动服务后将自定义命令添加到在 CMD 中调用的环境中......我没有使用 postgres,但使用 Oracle:

      #set up var with noop command
      RUN export POST_START_CMDS=":"
      RUN mkdir /scripts
      ADD script.sql /scripts
      CMD service oracle-xe start; $POST_START_CMDS; tail -f /var/log/dmesg
      

      开始
      docker run -d ... -e POST_START_CMDS="su - oracle -c 'sqlplus @/scripts/script' " <image>
      

      .

      【讨论】:

        【解决方案7】:

        您需要在创建用户之前运行数据库。为此,您需要多个进程。您可以在 shell 脚本的子 shell (&) 中启动 postgres,或者使用像 supervisord 这样的工具来运行 postgres,然后运行任何初始化脚本。

        supervisord 和 docker 指南https://docs.docker.com/articles/using_supervisord/

        【讨论】:

        • 或者只是RUN service postgresql start ; su - postgres -c "psql -c \"CREATE USER test WITH PASSWORD 'test' CREATEDB\"" ; service postgresql stop
        【解决方案8】:

        使用 Postgres 最新映像(ID:b262c8b2fb54)和 Docker 版本 20.10.6,docker-compose 看起来像,

        version: '2'
        
        services:
          app:
            # the detail of app
          db:
            image: 'postgres'
            container_name: book-shop-db-postgres
            environment:
              - POSTGRES_USER=postgres
              - POSTGRES_PASSWORD=postgres
              - POSTGRES_DB=bookshop-db
        

        这将创建启动时提到的用户和数据库

        【讨论】:

          猜你喜欢
          • 2020-01-21
          • 1970-01-01
          • 2012-02-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-12
          • 1970-01-01
          相关资源
          最近更新 更多