Featured image of post Docker 镜像自定义启动脚本

Docker 镜像自定义启动脚本

最近在做云应用的场景化,需要将许多应用部署到云应用中,在部署过程中遇到了一个问题:需要为一些应用增加自动创建数据库的能力。

部分应用依赖数据库,但是不会自动创建缺失的 database,一键部署暂时也不会支持这种能力。为了实现能直接部署更多的应用,不得不想一个办法解决这个问题。在经过一些思考、对比后,最后决定通过修改镜像的方式实现,即在镜像启动前连接 MySQL,自动创建 database。

通常情况下,可以直接修改应用源码中的 Dockerfile,并通过源码构建新的镜像。但考虑到,许多用户部署应用时,需要重复构建流程。而许多应用依赖的资源都存在网络问题,如果直接修改 Dockerfile ,并从源码重新构建镜像的话,构建失败的概率会比较大,用户体验较差。直接 FROM已有的 Docker 镜像,增加构建命令会是一个更好的选择:改动小,构建也更快。

因为我们要在镜像启动前创建数据库,所我们要修改镜像的启动脚本,从 CMD 和 ENTRYPOINT 指令下手。这里我们 ENTRYPOINT 更适合资源准备的场景,我们创建一个新的 ENTRYPOINT 命令,并通过 CMD 传入原镜像的启动指令,在 Bash 文件中通过 exec 执行,即可自定义启动准备过程,并且安装原有的命令启动镜像,完美解决问题。

这里以 Wiki.js 为例,需要设置以 USER: root 运行,并自动创建 database,我们可以创建以下的 Dockerfile

# Wiki 官方镜像
FROM requarks/wiki:2

# 运行用户
USER root

# apk 加速
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories

# 安装 mysql client
RUN apk add mysql-client

# 使用 entrypoint 修改启动任务
COPY ./entrypoint.sh ./entrypoint.sh

# 给予运行权限
RUN chmod +x ./entrypoint.sh

ENTRYPOINT [ "./entrypoint.sh" ]

CMD ["node", "server"]

entrypoint.sh

#!/bin/sh

# 创建数据库
echo "创建数据库:${DB_NAME}"
echo "create database if not exists ${DB_NAME}" | mysql -h ${DB_HOST} -P ${DB_PORT} -u ${DB_USER} -p${DB_PASS}
echo "创建数据库成功:${DB_NAME}"

# 执行 CMD
# $@:全部的参数,参数之间使用空格分隔
exec "$@"
Licensed under CC BY-NC-SA 4.0