database - 在构建期间填充 Postgres Docker 映像(未运行)
问题描述
我想通过两个任务准备自定义图像(基于官方Postges 图像):
- 下载数据(例如,通过 wget 获取 CSV 文件),
- 将数据加载到数据库中(创建表、插入)。
我想在构建映像期间执行这两个步骤,而不是在运行容器期间执行,因为每个步骤都需要大量时间,并且我想构建一次映像并快速运行多个容器。
我知道如何在构建映像期间执行第 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
这个示例数据集很小,但是对于更大、长时间运行的容器来说很尴尬。
解决方案
您可以剖析上游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
更改为未声明为卷的目录的原因。
基本上这就是为什么在启动容器时而不是在上游存储库中构建时处理导入的原因。如果您有用作只读的非机密数据,则在构建期间导入可能仍然有意义,以节省时间并在容器启动期间更容易处理。
推荐阅读
- javascript - 数组解析并转换为具有特定输出的新数组列表
- python - 返回随机值
- arrays - 如何使用 Google 表格中查询功能的 select 语句从单元格中获取文本?
- node.js - 对 Google Cloud NodeJs API 的首次请求比后续请求花费更多时间
- laravel - 模型没有查询结果,Laravel
- php - 您无权访问此资源
- r - 编织完成后上传文件
- javascript - Laravel:使用 npm 包 - ReferenceError
- java - 如何通过网关访问微服务的 Socket
- reactjs - React redux mapStateToProps - 无法作为道具访问状态