如何在构建Docker镜像时恢复Postgresdump?

时间:2018-02-06 13:05:54

标签: postgresql docker database-backups

我试图避免在我的工作流程中触摸共享开发人员数据库;为了使这更容易,我想在我的磁盘上为我需要的模式安装Docker镜像定义。然而,我在制作一个Dockerfile时会陷入困境,这个Dockerfile将创建一个已经恢复转储的Postgres图像。我的问题是,在构建Docker镜像时,Postgres服务器还没有运行。

虽然在shell中的容器中乱搞,但我尝试手动启动容器,但我不确定这样做的正确方法。 /docker-entrypoint.sh似乎没有做任何事情,而且我无法弄清楚如何正确地""启动服务器。

所以我需要做的是:

  • 以" FROM postgres"
  • 开头
  • 将转储文件复制到容器中
  • 启动PG服务器
  • 运行psql以恢复转储文件
  • 杀死PG服务器

(我不知道的步骤是斜体,其余的很简单。)

我想避免的是:

  • 手动将还原运行到现有容器中,整个想法是能够在不同数据库之间切换而无需触摸应用程序配置。
  • 保存已恢复的图像,我希望能够使用不同的转储轻松地重建数据库的图像。 (另外,对于具有不可重复的图像构建而言,它并不是非常感觉Docker。)

3 个答案:

答案 0 :(得分:1)

这可以通过提供以下example.pg转储文件来使用以下Dockerfile完成:

FROM postgres:9.6.16-alpine

LABEL maintainer="lu@cobrainer.com"
LABEL org="Cobrainer GmbH"

ARG PG_POSTGRES_PWD=postgres
ARG DBUSER=someuser
ARG DBUSER_PWD=P@ssw0rd
ARG DBNAME=sampledb
ARG DB_DUMP_FILE=example.pg

ENV POSTGRES_DB launchpad
ENV POSTGRES_USER postgres
ENV POSTGRES_PASSWORD ${PG_POSTGRES_PWD}
ENV PGDATA /pgdata

COPY wait-for-pg-isready.sh /tmp/wait-for-pg-isready.sh
COPY ${DB_DUMP_FILE} /tmp/pgdump.pg

RUN set -e && \
    nohup bash -c "docker-entrypoint.sh postgres &" && \
    /tmp/wait-for-pg-isready.sh && \
    psql -U postgres -c "CREATE USER ${DBUSER} WITH SUPERUSER CREATEDB CREATEROLE ENCRYPTED PASSWORD '${DBUSER_PWD}';" && \
    psql -U ${DBUSER} -d ${POSTGRES_DB} -c "CREATE DATABASE ${DBNAME} TEMPLATE template0;" && \
    pg_restore -v --no-owner --role=${DBUSER} --exit-on-error -U ${DBUSER} -d ${DBNAME} /tmp/pgdump.pg && \
    psql -U postgres -c "ALTER USER ${DBUSER} WITH NOSUPERUSER;" && \
    rm -rf /tmp/pgdump.pg

HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
  CMD pg_isready -U postgres -d launchpad

其中wait-for-pg-isready.sh是:

#!/bin/bash
set -e

get_non_lo_ip() {
  local _ip _non_lo_ip _line _nl=$'\n'
  while IFS=$': \t' read -a _line ;do
    [ -z "${_line%inet}" ] &&
        _ip=${_line[${#_line[1]}>4?1:2]} &&
        [ "${_ip#127.0.0.1}" ] && _non_lo_ip=$_ip
    done< <(LANG=C /sbin/ifconfig)
  printf ${1+-v} $1 "%s${_nl:0:$[${#1}>0?0:1]}" $_non_lo_ip
}

get_non_lo_ip NON_LO_IP
until pg_isready -h $NON_LO_IP -U "postgres" -d "launchpad"; do
  >&2 echo "Postgres is not ready - sleeping..."
  sleep 4
done

>&2 echo "Postgres is up - you can execute commands now"

对于两个“不确定步骤”:

  

启动PG服务器

nohup bash -c "docker-entrypoint.sh postgres &"可以解决

  

杀死PG服务器

这不是必须的

可以在https://github.com/cobrainer/pg-docker-with-restored-db

获得上述脚本以及更详细的自述文件。

答案 1 :(得分:0)

您可以使用卷。

PGDATA图片包含您可以设置的环境变量:{{1}}

请参阅文档:https://hub.docker.com/_/postgres/

然后,您可以使用所需的确切数据库数据指定预先创建的卷,并将其作为参数传递给图像。 https://docs.docker.com/storage/volumes/#start-a-container-with-a-volume

也可以在此处找到替代解决方案:Starting and populating a Postgres container in Docker

答案 2 :(得分:0)

对于您要初始化的任何系统(我记得在其他项目上使用过的系统)都可以使用的通用方法是:

不要在构建过程中尝试执行此操作,而是使用Docker Compose依赖项,以便最终获得:

  • 您的db服务将启动数据库,而无需进行任何初始化才能启用该数据库
  • 一项db-init服务:
    • 依赖db
    • 使用 dockerize
    • 等待数据库启动
    • 然后初始化数据库,同时保持幂等性(例如,使用架构迁移)
    • 然后退出
  • 您现在依赖于db-init而不是db的应用程序服务