dockerFile

dockerFile

1.编写dockerfile文件

dockerfile是一个文本文件,其中包含一个一个的指令,用指令来说明要执行什么操作来构建镜像。将来docker可以根据dockerfile帮我们构建镜像。

指令 说明 示例
FROM 指定基础镜像 FROM centos:7
ENV 设置环境变量(key value形式) ENV key value
COPY 拷贝本地文件到镜像的指定目录 COPY ./test.tar.gz /tmp
RUN 执行Linux的shell命令 RUN tar -zxvf /tmp/test.tar.gz
EXPOSE 指定容器运行时监听的端口 EXPOSE 8081
ENTRYPOINT 镜像中应用的启动命令,容器运行时调用 ENTRYPOINT java -jar xxx.jar

ADD(进阶复制,不推荐优先使用)

兼容 COPY 所有功能,额外支持:

  1. 自动解压 tar/gz 压缩包
  2. 拉取网络远程文件(构建依赖外网,稳定性差)

dockerfile

# 自动解压压缩包
ADD code.tar.gz /app

RUN 构建时执行命令(分层关键)

两种书写格式:

  1. shell 格式(底层调用 /bin/sh)

dockerfile

RUN apt update && apt install -y curl
  1. exec 数组格式(无 shell 进程,更安全)

dockerfile

RUN ["apt","update"]

重要优化规则

多条命令必须用 && 合并到同一个 RUN,减少镜像层数;安装软件后删除缓存缩小镜像体积:

dockerfile

# 正确写法(一层,清理缓存)
RUN apt update && apt install -y nginx \
    && rm -rf /var/lib/apt/lists/*

# 错误写法(两层镜像,体积翻倍,缓存失效)
RUN apt update
RUN apt install -y nginx

CMD / ENTRYPOINT 容器启动命令(高频混淆点)

CMD:容器默认启动命令,会被 docker run 后的参数完全覆盖

ENTRYPOINT:容器启动后要执行的主程序(固定命令)

CMD:传给 ENTRYPOINT 的默认参数

如果没有 ENTRYPOINT,CMD 就变成容器启动命令。

重要:Dockerfile 里只能最后一个生效,前面写的 CMD / ENTRYPOINT 会被覆盖。

数组格式(推荐,信号传递正常,容器可优雅关闭)

dockerfile

CMD ["python","app.py"]

ENTRYPOINT:容器入口程序,run 后的参数只会追加,不会覆盖

典型场景:Java 项目固定 java -jar 前缀

dockerfile

# 固定入口
ENTRYPOINT ["java","-jar"]
# CMD 作为默认参数
CMD ["app.jar"]

# 实际启动等价 java -jar app.jar
# docker run app test.jar → java -jar test.jar

一、两种格式(很容易踩坑)

Dockerfile 指令有两种写法:

  1. exec 格式(推荐,不会启动shell)
ENTRYPOINT ["executable", "param1", "param2"]
CMD ["param1", "param2"]
  1. shell 格式(底层会包装 /bin/sh -c)
ENTRYPOINT command param1 param2
CMD command param1 param2

⚠️ shell格式坑:PID 1 是 shell,不是你的程序,导致信号(SIGTERM)无法传递,docker stop 不能优雅关闭进程。生产尽量不用 shell 格式。


二、4种组合场景(重点)

场景1:只有 CMD(没有 ENTRYPOINT)

CMD 就是容器启动命令。
Dockerfile:

FROM alpine
CMD ["echo", "hello world"]

运行:

# 直接启动,使用CMD
docker run --rm test
# 输出 hello world

# run后面追加命令,会**覆盖整个CMD**
docker run --rm test echo "override"
# 输出 override

✅ 规则:docker run 镜像 后面的命令 直接替换 CMD。

场景2:只有 ENTRYPOINT(没有 CMD)

ENTRYPOINT 是主程序,docker run 后面的参数会追加给 ENTRYPOINT。

FROM alpine
ENTRYPOINT ["echo"]
# 没有传参:echo 后面无内容
docker run --rm test

# run后面写参数,追加给echo
docker run --rm test hello
# 等价 echo hello

场景3:ENTRYPOINT + CMD(最常用!)

ENTRYPOINT 固定主程序,CMD 提供默认参数

FROM alpine
ENTRYPOINT ["echo"]
CMD ["default msg"]
# 不追加参数:使用CMD的默认参数
docker run --rm test
# echo "default msg"

# run后面追加参数 → 覆盖掉CMD,传给ENTRYPOINT
docker run --rm test hello docker
# echo "hello docker"

典型使用案例:mysql、redis 镜像都是这种模式!
镜像内置 ENTRYPOINT 启动脚本,CMD给默认启动参数,用户run时可以覆盖参数。

场景4:ENTRYPOINT shell格式 + CMD

不推荐!shell格式的ENTRYPOINT会吞掉参数,CMD失效。

FROM alpine
ENTRYPOINT echo
CMD ["test"]

docker run test 只会执行 echo,CMD参数传不进去。


三、实际业务示例:Java 应用(SpringBoot)

示例 Dockerfile

FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/demo.jar app.jar

# 主程序固定 java -jar app.jar
ENTRYPOINT ["java","-jar","app.jar"]
# 默认参数
CMD ["--spring.profiles.active=prod"]
# 1. 默认启动:java -jar app.jar --spring.profiles.active=prod
docker run demo-app

# 2. 覆盖CMD参数,切换环境
docker run demo-app --spring.profiles.active=dev
# 最终执行:java -jar app.jar --spring.profiles.active=dev

四、docker run 覆盖 ENTRYPOINT / CMD

  • --entrypoint:覆盖镜像里的 ENTRYPOINT(只能在run时指定)
# 覆盖ENTRYPOINT,把主程序改成/bin/bash
docker run --entrypoint /bin/bash demo-app

注意:--entrypoint 后面只能写可执行程序,参数放在镜像名之后。

docker run --entrypoint /bin/bash demo-app -c "ls /app"

五、常见坑总结

  1. shell格式 PID1 是sh,收不到SIGTERM,docker stop 强制杀进程,无法优雅关闭。生产一律用 [] exec格式。
  2. Dockerfile 多个 CMD/ENTRYPOINT,仅最后一行生效。
  3. ENTRYPOINT + CMD 组合:CMD是默认参数,不是命令;run后面的参数替换CMD。
  4. docker inspect <镜像名> 查看镜像内置 Entrypoint 和 Cmd:
docker inspect demo-app | grep -A10 "Cmd"
docker inspect demo-app | grep -A10 "Entrypoint"

六、快速对比表

配置 含义 docker run 追加参数行为
CMD 默认启动命令 run参数完全替换CMD
ENTRYPOINT 主程序 run参数追加给ENTRYPOINT
ENTRYPOINT + CMD 固定主程序 + 默认参数 run参数替换CMD,传给ENTRYPOINT

如果你想,我可以再写一个entrypoint脚本示例(容器启动前预处理配置,再启动业务进程,SIGTERM转发,生产最常用模式)。

VOLUME 持久化数据卷

声明容器内目录为持久化存储,自动挂载匿名卷,数据不会随容器删除丢失。

dockerfile

VOLUME /data/logs

11. USER 切换运行用户(生产安全规范)

默认容器以 root 运行,存在安全漏洞,推荐创建普通用户执行程序

dockerfile

RUN useradd -m appuser
# 后续所有指令使用 appuser 执行
USER appuser

12. HEALTHCHECK 容器健康自检

定时检测服务是否存活,docker ps 可查看健康状态

dockerfile

HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD curl -f http://127.0.0.1:8080/health || exit 1

三、构建镜像命令 docker build

基础语法

bash

运行

# . 代表【构建上下文】当前目录
docker build -t 镜像名:标签 上下文路径
# 示例:打包并命名 python-demo:v1
docker build -t python-demo:v1 .

常用参数

  • -t:给镜像打名称标签
  • -f Dockerfile.prod:指定自定义脚本文件
  • --build-arg KEY=VAL:传递构建参数
  • --no-cache:清空缓存,完整重新构建
  • --pull:构建前拉取最新基础镜像

关键概念:构建上下文.COPY

命令末尾的 . 是上下文目录,Docker 会把目录下全部文件上传给引擎;COPY只能读取上下文内文件,禁止 COPY ../xxx 访问上级目录

配套文件 .dockerignore(必写)

和.gitignore用法一致,打包时忽略无用文件,减小上下文、加速构建、屏蔽敏感文件。

plaintext

# 虚拟环境、缓存
venv/
__pycache__/
node_modules/
# 日志、编译产物
*.log
dist/
build/
# 敏感配置
.env
*.pem
# git、编辑器文件
.git/
.vscode/
.DS_Store
posted @ 2026-10-14 14:58  阿砖  阅读(4)  评论(0)    收藏  举报