You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker多阶段构建:如何运行不同镜像中的CMD与ENTRYPOINT脚本?

解决Docker多阶段构建中ENTRYPOINT与CMD共存的问题

核心问题分析

你的问题根源在于多阶段构建的每个FROM都会生成全新镜像,第一个Go镜像里的CMD不会被第二个Java镜像继承,而且第二个镜像缺少air等Go工具的二进制文件,直接把air写进ENTRYPOINT肯定跑不起来。要解决这个问题,关键是把第一个阶段编译好的air等工具复制到第二个镜像,再让entrypoint.sh转发CMD的命令。

具体解决方案

1. 修改Dockerfile,复制Go工具到运行镜像

把第一个阶段标记为构建镜像,然后复制air和dlv的二进制文件到第二个镜像,同时重新设置ENTRYPOINT和CMD:

# 第一阶段:构建Go工具
FROM golang:1.17.2 AS builder
COPY . /go/src/sample
WORKDIR /go/src/sample
RUN go install github.com/go-delve/delve/cmd/dlv@latest
RUN go install github.com/cosmtrek/air@latest

# 第二阶段:运行镜像
FROM eclipse-temurin:17-focal
# 从构建阶段复制air和dlv二进制到系统可执行路径
COPY --from=builder /go/bin/air /usr/local/bin/
COPY --from=builder /go/bin/dlv /usr/local/bin/
# 复制自定义entrypoint脚本
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# 设置ENTRYPOINT,CMD指定air启动命令
ENTRYPOINT ["/entrypoint.sh"]
CMD ["air", "-c", ".air.toml"]

2. 调整entrypoint.sh,让它转发CMD命令

你的entrypoint.sh需要在执行完自有配置后,运行CMD传入的命令。修改脚本内容,最后加上exec "$@"来转发参数:

#!/bin/sh
# 这里写你的自有配置逻辑,比如环境变量初始化、前置检查等
# 示例:设置环境变量
# export APP_ENV=development

# 执行CMD指定的命令(这里就是air的启动命令)
exec "$@"

3. 验证docker-compose配置

你的docker-compose.yml里已经设置了working_dir: /go/src/backend,和挂载路径./backend:/go/src/backend匹配,无需额外修改。

原理说明

  • 多阶段构建中,COPY --from=builder把第一个镜像里go install生成的二进制文件(默认在/go/bin)复制到第二个镜像的/usr/local/bin,让第二个镜像能直接运行air命令。
  • ENTRYPOINT脚本最后用exec "$@"会把CMD的参数作为命令执行,既保留了entrypoint的自定义配置逻辑,又能运行原来的热重载命令。

内容的提问来源于stack exchange,提问作者Alex Nikolsky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 13:31:00