entrypoint 脚本是 docker 容器启动时执行初始化任务的首选方式,需用绝对路径、检查退出码、以 exec "$@" 结尾确保主进程为 pid 1 并能接收信号。
在 docker 容器启动阶段自动执行初始化任务,关键不是“怎么写命令”,而是“谁来执行、何时执行、如何收尾”。规范的启动命令和自动化脚本必须保证初始化逻辑可靠、主进程可控、信号可传递——否则容器会假死、无法优雅停止、日志不可查。
ENTRYPOINT 脚本是首选方式
把初始化逻辑封装进一个独立的 entrypoint.sh 文件,设为容器的 ENTRYPOINT,是最稳定、最符合 Docker 哲学的做法:
- 脚本开头必须写
#!/bin/sh(推荐 sh 而非 bash,兼容性更好) - 所有路径用绝对路径,避免工作目录不确定导致失败
- 每步操作后检查退出码,失败立即
exit 1,防止带病运行 - 初始化完成后,必须以
exec "$@"结尾,让 CMD 或运行时传入的命令真正成为 PID 1 - 赋予可执行权限:
chmod +x entrypoint.sh
Dockerfile 中的正确写法
不要用 CMD 拼接多条命令,也不要直接覆盖 CMD 启动服务。标准写法如下:
COPY entrypoint.sh /entrypoint.shENTRYPOINT ["/entrypoint.sh"]CMD ["your-app-start-command", "--config", "/etc/app.conf"]
这样设计后,运行 docker run myapp 时,先执行 entrypoint.sh 完成初始化(比如改配置、等 DB、生成密钥),再通过 exec 接管 CMD 命令,确保主进程可接收 SIGTERM、支持 docker stop。
常见初始化任务示例
entrypoint.sh 中可安全集成的典型操作包括:
- 等待依赖服务就绪:
until nc -z db 5432; do sleep 2; done - 动态替换配置占位符:
sed -i "s/DB_HOST/$DB_HOST/g" /app/config.yml - 设置文件权限:
chown -R app:app /var/lib/app && chmod -R 750 /var/lib/app - 首次运行初始化:
if [ ! -f /var/lib/app/.initialized ]; then /usr/local/bin/init-db.sh && touch /var/lib/app/.initialized; fi
避免踩坑的硬性要求
以下做法看似简单,实则破坏容器生命周期管理,应严格规避:
- 在 CMD 中用
sh -c "init.sh && exec app"—— shell 进程成了 PID 1,收不到信号 - 脚本中漏掉
exec "$@",导致主程序作为子进程运行,docker stop 失效 - 初始化失败不 exit,容器“启动成功”但实际服务未就绪
- 使用后台启动(如
service nginx start),脱离前台进程模型 - 在 entrypoint.sh 中调用
docker命令或依赖宿主机环境











