首页 > 解决方案 > 在构建期间填充 Postgres Docker 映像(未运行)

问题描述

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

  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 图像的“初始化脚本”实用程序。

建筑形象:

docker build -t mydbimage .

运行图:

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

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

docker logs mydbcontainer

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

标签: databasepostgresqldocker

解决方案


您可以剖析上游Dockerfile及其docker-entrypoint.sh并选择所需的片段来初始化您的数据库:

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更改为未声明为卷的目录的原因。

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


推荐阅读