首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Docker Entrypoint 脚本实用指南

Docker Entrypoint 脚本实用指南

作者头像
用户11081884
发布2026-07-20 20:11:14
发布2026-07-20 20:11:14
210
举报

什么是 Entrypoint 脚本

Entrypoint 脚本是容器启动时第一个被执行的程序。与直接在 Dockerfile 里写命令不同,它允许你在主应用起来之前做一些准备工作:初始化数据库连接、加载配置、验证环境变量等。

为什么值得用

生产环境里,应用往往要根据部署环境动态调整配置。Entrypoint 脚本能在容器启动阶段完成环境检测、服务依赖验证、敏感信息注入这些事,减少运行时因配置问题挂掉的概率。

另一个好处是安全性。把启动流程集中在脚本里管理,可以避免用户通过命令行参数绕过关键步骤。

基本用法

第一步:写脚本

创建 entrypoint.sh,开头加 shebang 行:

代码语言:javascript
复制
#!/bin/sh
# 预处理逻辑
exec "$@"

第二步:集成到 Dockerfile

代码语言:javascript
复制
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

第三步:构建和运行

代码语言:javascript
复制
docker build -t my-app .
docker run my-app

常用脚本模式

按环境切换配置

代码语言:javascript
复制
#!/bin/sh
if [ "$ENVIRONMENT"="production" ]; then
    exportCONFIG_FILE=/app/config/prod.yaml
else
    exportCONFIG_FILE=/app/config/dev.yaml
fi
exec "$@"

等待依赖服务就绪

代码语言:javascript
复制
#!/bin/sh
until pg_isready -h$DB_HOST-p$DB_PORT; do
    echo"等待数据库..."
    sleep2
done
exec "$@"

ENTRYPOINT 与 CMD 的区别

这两个指令容易混淆:

  • ENTRYPOINT 定义容器启动时执行的主命令,不会被 docker run 的参数覆盖
  • CMD 为 ENTRYPOINT 提供默认参数,可以被 docker run 的参数替换
代码语言:javascript
复制
# ENTRYPOINT + CMD 组合
ENTRYPOINT ["echo"]
CMD ["Hello World"]

# docker run my-app             → 输出 "Hello World"
# docker run my-app "自定义内容" → 输出 "自定义内容"
代码语言:javascript
复制
# 只用 CMD
CMD ["echo", "Hello World"]

# docker run my-app    → 输出 "Hello World"
# docker run my-app ls → 执行 ls,echo 被替换

exec 的必要性

脚本里启动主进程时,一定要用 exec

代码语言:javascript
复制
exec my-app "$@"  # 正确
my-app "$@"       # 错误:会多产生一个子进程

exec 的原因:主进程变成容器的 PID 1,能正确接收 SIGTERM 等系统信号;不用 exec 则 Shell 进程和应用进程同时存在,信号传不到应用,docker stop 时容器会等超时才强杀。

调试技巧

代码语言:javascript
复制
#!/bin/bash
set-x  # 开启命令跟踪
set-e  # 出错立即退出
echo"[$(date)] 开始执行 Entrypoint"
echo"[$(date)] 当前环境: $ENVIRONMENT"
exec "$@"

在容器外直接测脚本:

代码语言:javascript
复制
chmod+x entrypoint.sh
./entrypoint.sh

完整示例:多环境 Java 应用

代码语言:javascript
复制
#!/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:

代码语言:javascript
复制
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"]

常见坑

  • 权限问题:脚本在镜像内必须有可执行权限,推荐在 Dockerfile 的 RUNchmod +x,不要依赖宿主机的文件权限
  • 行尾符:Windows 下编辑的脚本,行尾可能是 \r\n,在 Linux 容器里会报错。推荐用 .gitattributesdos2unix 处理
  • Shell 兼容性:尽量用 /bin/sh 而不是 /bin/bash,Alpine 等精简镜像里没有 bash
  • 超时设置:等待依赖服务时记得加超时,否则容器可能永远卡在启动阶段
  • 临时文件清理:脚本里创建的临时文件,确保在退出前清掉

“无他,惟手熟尔”!有需要的用起来!

如果你觉得这篇文章有用,欢迎点赞、转发、收藏、留言、推荐❤!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-04-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Nicholas与Pypi 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是 Entrypoint 脚本
  • 为什么值得用
  • 基本用法
  • 常用脚本模式
  • ENTRYPOINT 与 CMD 的区别
  • exec 的必要性
  • 调试技巧
  • 完整示例:多环境 Java 应用
  • 常见坑
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档