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 所有功能,额外支持:
- 自动解压
tar/gz压缩包 - 拉取网络远程文件(构建依赖外网,稳定性差)
dockerfile
# 自动解压压缩包
ADD code.tar.gz /app
RUN 构建时执行命令(分层关键)
两种书写格式:
- shell 格式(底层调用
/bin/sh)
dockerfile
RUN apt update && apt install -y curl
- 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 指令有两种写法:
- exec 格式(推荐,不会启动shell)
ENTRYPOINT ["executable", "param1", "param2"]
CMD ["param1", "param2"]
- 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"
五、常见坑总结
- shell格式 PID1 是sh,收不到SIGTERM,
docker stop强制杀进程,无法优雅关闭。生产一律用[]exec格式。 - Dockerfile 多个 CMD/ENTRYPOINT,仅最后一行生效。
- ENTRYPOINT + CMD 组合:CMD是默认参数,不是命令;run后面的参数替换CMD。
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
浙公网安备 33010602011771号