使用 Dockerfile 创建已恢复备份数据库的 SQL Server Docker 镜像。

4
以下 Docker 文件创建自定义 SQL Server 镜像,并从备份 (rmsdev.bak) 恢复数据库。
FROM mcr.microsoft.com/mssql/server:2019-latest
ENV MSSQL_PID=Developer
ENV SA_PASSWORD=Password1?
ENV ACCEPT_EULA=Y

USER mssql

COPY rmsdev.bak /var/opt/mssql/backup/

# Launch SQL Server, confirm startup is complete, restore the database, then terminate SQL Server.
RUN ( /opt/mssql/bin/sqlservr & ) | grep -q "Service Broker manager has started" \
    && /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P $SA_PASSWORD -Q 'RESTORE DATABASE rmsdev FROM DISK = "/var/opt/mssql/backup/rmsdev.bak" WITH MOVE "rmsdev" to "/var/opt/mssql/data/rmsdev.mdf", MOVE "rmsdev_Log" to "/var/opt/mssql/data/rmsdev_log.ldf", NOUNLOAD, STATS = 5' \
    && pkill sqlservr

CMD ["/opt/mssql/bin/sqlservr"]

问题在于,一旦恢复完成,备份文件就不再需要了,我想从镜像中删除它。

不幸的是,由于 Docker 镜像的形成方式(层),我无法像希望的那样简单地 'rm' 文件。

在构建场景中,多阶段 Dockerfile 不易适用于此案例。另一种方法是运行容器,恢复备份,然后提交一个新的镜像,但我想要做的是仅使用正确的Dockerfile和docker build。

有人知道怎么做吗?


在镜像中拥有数据库是不寻常的。通常,您会希望将数据存储在卷中,这样当容器关闭时,任何更改都会被持久化。如果您想要在镜像中使用数据库并且想要减小镜像大小,那么我认为多阶段构建是最佳选择。 - Hans Kilian
1个回答

5
如果您知道镜像中数据目录的位置,并且该镜像没有将该目录声明为VOLUME,则可以使用多阶段构建来完成此操作。第一阶段将设置数据目录,如您所示。第二阶段将从第一阶段复制填充的数据目录,但不包括备份文件。这个技巧可能取决于两个阶段运行相同版本的基础软件构建。
对于 SQL Server,Docker Hub 页面GitHub 存储库 都很难找到,令人惊讶的是,两者都没有涉及数据存储的问题(正如 @HansKillian 在评论中指出的那样,您几乎总是希望将数据库数据存储在某种卷中)。GitHub 存储库包括围绕 Kubernetes StatefulSet 构建的 Helm chart,从中我们可以发现数据目录将被 挂载/var/opt/mssql 上。
因此,我可能会编写一个多阶段构建,如下所示:
# Put common setup steps in an initial stage
FROM mcr.microsoft.com/mssql/server:2019-latest AS setup
ENV MSSQL_PID=Developer
ENV SA_PASSWORD=Password1?  # (weak password, easily extracted with `docker inspect`)
ENV ACCEPT_EULA=Y           # (legally probably the end user needs to accept this not the image builder)

# Have a stage specifically to populate the data directory
FROM setup AS data
# (copy-and-pasted from the question)
USER mssql
COPY rmsdev.bak /  # not under /var/opt/mssql
RUN ( /opt/mssql/bin/sqlservr & ) | grep -q "Service Broker manager has started" \
    && /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P $SA_PASSWORD -Q 'RESTORE DATABASE rmsdev FROM DISK = "/rmsdev.bak" WITH MOVE "rmsdev" to "/var/opt/mssql/data/rmsdev.mdf", MOVE "rmsdev_Log" to "/var/opt/mssql/data/rmsdev_log.ldf", NOUNLOAD, STATS = 5' \
    && pkill sqlservr

# Final stage that actually will actually be run.
FROM setup
# Copy the prepopulated data tree, but not the backup file
COPY --from=data /var/opt/mssql /var/opt/mssql
# Use the default USER, CMD, etc. from the base SQL Server image

标准的Docker Hub开源数据库镜像,如mysqlpostgres通常在其Dockerfile中声明一个VOLUME用于数据库数据,这将强制数据存储在卷中。这意味着重要的事情是,您不能像这样设置图像中的数据;您必须在外部填充数据,然后将数据树复制到Docker镜像系统之外。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接