如何在构建 Docker 图像时恢复 Postgres 转储?
How to restore a Postgresdump while building a Docker image?
我试图避免在我的工作流程中接触共享开发数据库;为了使这更容易,我想在我的磁盘上有我需要的模式的 Docker 图像定义。然而,我坚持制作一个 Docker 文件,该文件将创建一个转储已恢复的 Postgres 图像。我的问题是,在构建 Docker 图像时,Postgres 服务器未 运行ning。
在 shell 中的容器中乱搞时,我尝试手动启动容器,但我不确定这样做的正确方法是什么。 /docker-entrypoint.sh
似乎什么也没做,我不知道如何 "correctly" 启动服务器。
所以我需要做的是:
- 从 "FROM postgres"
开始
- 将转储文件复制到容器中
- 启动PG服务器
- 运行
psql
恢复转储文件
- 杀死PG服务器
(我不知道的步骤用斜体字表示,其余的很简单。)
我想避免的是:
- 运行 手动恢复到现有容器中,整个想法是能够在不同数据库之间切换而无需触及应用程序配置。
- 保存恢复的图像,我希望能够使用不同的转储轻松地为数据库重建图像。 (同样,拥有不可重复的图像构建也不是很 Docker。)
您可以使用卷。
postgres
图像有一个您可以设置的环境变量:PGDATA
查看文档: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
这可以通过提供 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} "%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"
对于两个"unsure steps":
start the PG server
nohup bash -c "docker-entrypoint.sh postgres &"
能搞定
kill the PG server
没必要
以上脚本连同更详细的自述文件可在 https://github.com/cobrainer/pg-docker-with-restored-db
获得
我记得在其他项目中使用过的适用于您想要初始化的任何系统的通用方法是:
与其在构建期间尝试这样做,不如使用 Docker 组合依赖项,这样您最终会得到:
- 您的
db
服务无需任何初始化即可启动数据库
- 一项
db-init
服务:
-
- 依赖于
db
-
- 使用 say dockerize
等待数据库启动
-
- 然后在保持幂等性的同时初始化数据库(例如使用模式迁移)
-
- 并退出
- 您的应用程序服务现在依赖于
db-init
而不是 db
我试图避免在我的工作流程中接触共享开发数据库;为了使这更容易,我想在我的磁盘上有我需要的模式的 Docker 图像定义。然而,我坚持制作一个 Docker 文件,该文件将创建一个转储已恢复的 Postgres 图像。我的问题是,在构建 Docker 图像时,Postgres 服务器未 运行ning。
在 shell 中的容器中乱搞时,我尝试手动启动容器,但我不确定这样做的正确方法是什么。 /docker-entrypoint.sh
似乎什么也没做,我不知道如何 "correctly" 启动服务器。
所以我需要做的是:
- 从 "FROM postgres" 开始
- 将转储文件复制到容器中
- 启动PG服务器
- 运行
psql
恢复转储文件 - 杀死PG服务器
(我不知道的步骤用斜体字表示,其余的很简单。)
我想避免的是:
- 运行 手动恢复到现有容器中,整个想法是能够在不同数据库之间切换而无需触及应用程序配置。
- 保存恢复的图像,我希望能够使用不同的转储轻松地为数据库重建图像。 (同样,拥有不可重复的图像构建也不是很 Docker。)
您可以使用卷。
postgres
图像有一个您可以设置的环境变量:PGDATA
查看文档: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
这可以通过提供 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} "%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"
对于两个"unsure steps":
start the PG server
nohup bash -c "docker-entrypoint.sh postgres &"
能搞定
kill the PG server
没必要
以上脚本连同更详细的自述文件可在 https://github.com/cobrainer/pg-docker-with-restored-db
获得我记得在其他项目中使用过的适用于您想要初始化的任何系统的通用方法是:
与其在构建期间尝试这样做,不如使用 Docker 组合依赖项,这样您最终会得到:
- 您的
db
服务无需任何初始化即可启动数据库 - 一项
db-init
服务: -
- 依赖于
db
- 依赖于
-
- 使用 say dockerize 等待数据库启动
-
- 然后在保持幂等性的同时初始化数据库(例如使用模式迁移)
-
- 并退出
- 您的应用程序服务现在依赖于
db-init
而不是db