【问题标题】:Populating Postgres Docker image during building (not running)在构建期间填充 Postgres Docker 映像(未运行)
【发布时间】:2019-03-04 22:09:54
【问题描述】:

我想通过两个任务准备自定义图像(基于官方Postges image):

  1. 下载数据(如通过wget获取CSV文件),
  2. 将数据加载到数据库中(创建表、插入)。

我想在构建映像期间执行这两个步骤,而不是在运行容器期间执行,因为每个步骤都需要大量时间,并且我想构建一次映像并快速运行多个容器。

我知道如何在构建映像期间执行第 1 步(下载数据),但我不知道如何在构建映像期间将数据加载到数据库中,而不是运行容器(第 2 步)。

示例:

(下载 - 在构建映像期间,加载 - 在运行容器期间)

Dockerfile:

FROM postgres:10.7

RUN  apt-get update \
  && apt-get install -y wget \
  && rm -rf /var/lib/apt/lists/* 

COPY download.sh /download.sh
RUN /download.sh

download.sh:

#!/bin/bash

cd /docker-entrypoint-initdb.d/
wget https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/northwindextended/northwind.postgre.sql

要下载数据,我自己运行脚本。要加载数据,我使用 Postgres 官方图像中的“initialization scripts”实用程序。

建筑形象:

docker build -t mydbimage .

运行图:

docker run --name mydbcontainer -p 5432:5432 -e POSTGRES_PASSWORD=postgres -d mydbimage 

运行后,可以看到加载数据需要多少时间:

docker logs mydbcontainer

这个示例数据集很小,但是对于更大、长时间运行的容器来说很尴尬。

【问题讨论】:

  • 您无法真正使用来自任何标准数据库图像的预填充数据来创建图像。不过,您可以使用已挂载的主机目录启动数据库并为其拍摄快照作为一种简单的解决方法。
  • 我想避免创建卷,第一次运行时创建备份数据库,然后再恢复它。我认为有一种方法可以使用“默认”用户/密码启动数据库,加载数据并将其保存为图像层。但是如何处理标准图像而不是创建空图像并自己安装Postgres?
  • 您希望您的数据库将其数据存储在一个卷上,否则您将遇到性能问题。容器文件系统慢,卷文件系统快

标签: database postgresql docker


【解决方案1】:

您可以剖析上游Dockerfile 及其docker-entrypoint.sh,然后选择所需的sn-ps 来初始化您的数据库:

FROM postgres:10.7

ENV PGDATA /var/lib/postgresql/datap-in-image
RUN mkdir -p "$PGDATA" && chown -R postgres:postgres "$PGDATA" && chmod 777 "$PGDATA" # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values)

RUN set -x \
  && apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/* \
  && wget https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/northwindextended/northwind.postgre.sql \ 
    -O /docker-entrypoint-initdb.d/northwind.postgre.sql \
  && cp ./docker-entrypoint.sh ./docker-entrypoint-init-only.sh \
  && sed -ri '/exec "\$@"/d' ./docker-entrypoint-init-only.sh \
  && ./docker-entrypoint-init-only.sh postgres \
  && rm ./docker-entrypoint-initdb.d/northwind.postgre.sql ./docker-entrypoint-init-only.sh \
  && apt-get purge -y --auto-remove ca-certificates wget

构建、运行和测试:

docker build -t mydbimage .

# bring up the database
docker run --rm mydbimage --name pgtest

# run this in another terminal to check for the imported data 
docker exec -ti pgtest psql -v ON_ERROR_STOP=1 --username "postgres" --no-password --dbname postgres --command "\d"

注意事项:

  • 通过此设置,没有为数据库设置无密码。您可以在构建期间添加它,但随后它将保留在映像中。您需要采取预防措施,以免任何人访问您的图像。根据您的设置,这可能很难实现,甚至是不可能的。
  • 第二个问题是写入数据库是短暂的。构建过程中没有卷来持久化导入的数据。这就是为什么 PGDATA 更改为未声明为卷的目录的原因。

基本上这些是在启动容器时而不是在上游存储库中构建时处理导入的原因。如果您有用作只读的非机密数据,在构建期间导入可能仍然有意义,以节省时间并在容器启动期间更容易处理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-09
    • 2016-10-26
    • 1970-01-01
    相关资源
    最近更新 更多