
Entrypoint 脚本是容器启动时第一个被执行的程序。与直接在 Dockerfile 里写命令不同,它允许你在主应用起来之前做一些准备工作:初始化数据库连接、加载配置、验证环境变量等。
生产环境里,应用往往要根据部署环境动态调整配置。Entrypoint 脚本能在容器启动阶段完成环境检测、服务依赖验证、敏感信息注入这些事,减少运行时因配置问题挂掉的概率。
另一个好处是安全性。把启动流程集中在脚本里管理,可以避免用户通过命令行参数绕过关键步骤。
第一步:写脚本
创建 entrypoint.sh,开头加 shebang 行:
#!/bin/sh
# 预处理逻辑
exec "$@"第二步:集成到 Dockerfile
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]第三步:构建和运行
docker build -t my-app .
docker run my-app按环境切换配置
#!/bin/sh
if [ "$ENVIRONMENT"="production" ]; then
exportCONFIG_FILE=/app/config/prod.yaml
else
exportCONFIG_FILE=/app/config/dev.yaml
fi
exec "$@"等待依赖服务就绪
#!/bin/sh
until pg_isready -h$DB_HOST-p$DB_PORT; do
echo"等待数据库..."
sleep2
done
exec "$@"这两个指令容易混淆:
ENTRYPOINT 定义容器启动时执行的主命令,不会被 docker run 的参数覆盖CMD 为 ENTRYPOINT 提供默认参数,可以被 docker run 的参数替换# ENTRYPOINT + CMD 组合
ENTRYPOINT ["echo"]
CMD ["Hello World"]
# docker run my-app → 输出 "Hello World"
# docker run my-app "自定义内容" → 输出 "自定义内容"# 只用 CMD
CMD ["echo", "Hello World"]
# docker run my-app → 输出 "Hello World"
# docker run my-app ls → 执行 ls,echo 被替换脚本里启动主进程时,一定要用 exec:
exec my-app "$@" # 正确
my-app "$@" # 错误:会多产生一个子进程用 exec 的原因:主进程变成容器的 PID 1,能正确接收 SIGTERM 等系统信号;不用 exec 则 Shell 进程和应用进程同时存在,信号传不到应用,docker stop 时容器会等超时才强杀。
#!/bin/bash
set-x # 开启命令跟踪
set-e # 出错立即退出
echo"[$(date)] 开始执行 Entrypoint"
echo"[$(date)] 当前环境: $ENVIRONMENT"
exec "$@"在容器外直接测脚本:
chmod+x entrypoint.sh
./entrypoint.sh#!/bin/sh
ENV=${ENV:-development}
# 检查必需变量
if [ -z"$DB_HOST" ]; then
echo"错误:DB_HOST 未设置"
exit1
fi
# 按环境配置 JVM 参数
case $ENVin
production)
echo"生产环境"
exportJAVA_OPTS="-Xmx2g -Xms1g"
;;
staging)
echo"预发布环境"
exportJAVA_OPTS="-Xmx1g -Xms512m"
;;
development|*)
echo"开发环境"
exportJAVA_OPTS="-Xmx512m -Xms256m"
;;
esac
# 等待数据库
echo"检查数据库连接: $DB_HOST:$DB_PORT"
timeout=30
while ! nc-z$DB_HOST$DB_PORT; do
timeout=$((timeout-1))
if [ $timeout-le0 ]; then
echo"数据库连接超时"
exit1
fi
echo"等待中... 剩余 $timeout 秒"
sleep1
done
echo"服务就绪,启动应用"
exec java $JAVA_OPTS-jar /app/app.jar "$@"对应的 Dockerfile:
FROM openjdk:11-jre-slim
RUN apt-get update && apt-get install -y netcat-openbsd && apt-get clean
COPY app.jar /app/app.jar
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
WORKDIR /app
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
ENTRYPOINT ["/entrypoint.sh"]RUN 里 chmod +x,不要依赖宿主机的文件权限\r\n,在 Linux 容器里会报错。推荐用 .gitattributes 或 dos2unix 处理/bin/sh 而不是 /bin/bash,Alpine 等精简镜像里没有 bash“无他,惟手熟尔”!有需要的用起来!
如果你觉得这篇文章有用,欢迎点赞、转发、收藏、留言、推荐❤!
本文分享自 Nicholas与Pypi 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!