文章目录
- 一、Docker原理
- 二、Docker常用参数(docker run)
- docker ps(查看容器)
- docker exec(进入正在运行的容器)
- 三、Dockerfile 参数详解
- 3.1 基础指令
- 3.2 镜像内执行操作指令
- 3.3 容器运行相关(容器启动后生效,build 阶段不执行)
- 3.4 启动命令(CMD / ENTRYPOINT 高频面试重点!)
- 3.5 挂载相关
- 3.6 其他指令
- 四、Dockerfile构建nginx镜像实操
- 4.1 编写 Dockerfile
- 4.2 构建镜像
- 4.3 查看已构建镜像
- 4.4 运行镜像
- 4.5 测试访问
- 4.6 通过挂载方式启动容器
- 4.7 测试挂载方式启动容器是否正常
- 五、面试常考题
- 5.1 为什么要用 Docker(面试简答)
- 5.2 Docker 优缺点
- 5.3 Dockerfile 关键面试坑点总结
- 5.4 CMD 和 ENTRYPOINT 的区别?
- 5.5 Docker镜像分层原理(高频面试)
- 面试追问1:为什么要分层?
- 面试追问2:容器删除,镜像层会消失吗?
- 面试追问3:Dockerfile优化(分层优化考点)
- 5.6 写时复制 CoW(Copy-on-Write)
- 原理
- 面试追问1:容器删除后,复制出来的文件会怎么样?
- 5.7 容器生命周期管理
- 重点区分面试考点
- 5.8 什么是容器退出策略 --restart?4 种重启策略
- 实操示例
一、Docker原理
Docker 底层依赖 Linux 内核三大技术:
- Namespace:实现进程、网络、文件系统等隔离
- Cgroups:限制 CPU、内存等资源
- UnionFS 联合文件系统:实现镜像分层、写时复制
容器本质是宿主机上一个被隔离和资源限制的进程,共享宿主机内核,所以相比虚拟机更加轻量。
二、Docker常用参数(docker run)
| 参数 | 简要说明 |
|---|---|
-d | –detach,后台守护运行容器 |
-i | –interactive,保持标准输入打开 |
-t | –tty,分配伪终端;-it组合进入交互式 shell |
--name 容器名 | 指定容器名称 |
--rm | 容器退出后自动删除容器(测试临时容器) |
-p 宿主机端口:容器端口 | –publish,端口映射 |
-P | –publish-all,自动随机宿主机端口,映射镜像 EXPOSE 端口 |
-v 宿主机路径:容器内路径 | –volume,挂载数据卷 / 绑定挂载 |
-e KEY=VAL | –env,设置环境变量 |
--env-file xxx.env | 从文件批量导入环境变量 |
--restart | 重启策略:no/on-failure/always/unless-stopped |
--network 网络名 | 指定容器加入的 docker 网络 |
--tmpfs /目录 | 内存临时文件系统,容器销毁数据丢失 |
--read-only | 容器根文件系统只读 |
--cpus N数量 | 限制最大 CPU 核数 |
-m 512m | –memory,限制最大内存 |
-w /path | –workdir,设置容器内工作目录 |
-h hostname | 设置容器主机名 |
-u uid | –user,指定容器运行用户,避免 root |
--privileged | 特权容器,获取宿主机高权限,慎用 |
docker ps(查看容器)
| 参数 | 简要说明 |
|---|---|
| 无参数 | 查看正在运行的容器 |
-a | –all,查看所有容器(包含已停止) |
-q | –quiet,只输出容器 ID |
-f filter | 过滤,例-f name=mysql |
--no-trunc | 不截断,显示完整容器 ID |
docker exec(进入正在运行的容器)
| 参数 | 简要说明 |
|---|---|
-i | 保持标准输入打开 |
-t | 分配伪终端,一般组合-it |
三、Dockerfile 参数详解
Dockerfile 用来构建镜像,构建命令:
docker build -t xxx:v1 .
规则:从上往下顺序执行;每一条指令生成一层镜像层;尽量合并指令减少层数;大写是规范(不强制,但约定俗成)。
3.1 基础指令
| 指令 | 用法示例 | 简单说明 |
|---|---|---|
| FROM | FROM mysql:8.0 | ✅必须第一条,指定基础镜像。所有镜像都要有 FROM;FROM scratch代表空白镜像 |
| MAINTAINER | MAINTAINER zhangsan <xxx@163.com> | 维护者信息,已经废弃,推荐用 LABEL 替代 |
| LABEL | LABEL author="test" version="v1" | 给镜像添加元数据标签,key=value;替代 MAINTAINER |
3.2 镜像内执行操作指令
| 指令 | 用法示例 | 简单说明 |
|---|---|---|
| RUN | RUN apt update && apt install -y nginx | 在镜像构建阶段执行 Shell 命令;每一条 RUN 产生一层镜像;多条命令用&&合并,减少层数。 |
| COPY | COPY ./index.html /usr/share/nginx/html/ | 复制宿主机本地文件/目录到镜像内;只支持本地源;不会解压压缩包。 |
| ADD | ADD test.tar.gz /opt/ | 增强版 COPY:①本地文件复制;②自动解压 tar 压缩包;③支持远程 URL 下载文件; ✅日常优先用 COPY,需要解压才用 ADD。 |
3.3 容器运行相关(容器启动后生效,build 阶段不执行)
| 指令 | 用法示例 | 简单说明 |
|---|---|---|
| WORKDIR | WORKDIR /app | 设置容器内工作目录;目录不存在自动创建;等价cd,推荐替代RUN mkdir && cd |
| ENV | ENV TZ=Asia/Shanghai | 设置环境变量,镜像和启动后的容器都生效;可多条,构建和运行阶段都能用 |
| EXPOSE | EXPOSE 80 443 | 声明容器要开放的端口,不是真正开放端口!仅文档说明,-p才是真正端口映射 |
| USER | USER www | 指定容器运行的用户;后续 RUN/CMD/ENTRYPOINT 都会用这个用户,默认 root;安全最佳实践 |
3.4 启动命令(CMD / ENTRYPOINT 高频面试重点!)
| 指令 | 用法示例 | 简单说明 |
|---|---|---|
| CMD | CMD ["nginx","-g","daemon off;"] | 容器默认启动命令。✅ 可以被docker run 镜像 新命令覆盖一个 Dockerfile只能最后一条 CMD 生效 |
| ENTRYPOINT | ENTRYPOINT ["/bin/sh","-c"] | 容器入口程序。✅docker run后面跟的参数追加传给 entrypoint,不会覆盖常用来做固定入口脚本 |
面试一句话区分:
CMD:默认命令,run 后面加参数直接替换 CMD;
ENTRYPOINT:固定入口,run 后面的参数是传给入口的参数。
3.5 挂载相关
| 指令 | 用法示例 | 简单说明 |
|---|---|---|
| VOLUME | VOLUME ["/data/mysql"] | 声明数据卷。构建镜像时预先定义挂载点,容器启动自动创建匿名卷; ⚠️ Dockerfile 里 VOLUME不能指定宿主机路径,宿主机挂载路径只能在 docker run -v指定 |
3.6 其他指令
| 指令 | 用法示例 | 简单说明 |
|---|---|---|
| ARG | ARG VERSION=1.0 | 构建阶段变量,只在docker build构建镜像时生效;容器运行时无效。build 时可通过--build-arg VERSION=2.0传参覆盖 |
| HEALTHCHECK | HEALTHCHECK --interval=20s --timeout=3s --retries=2 --start-period=10s \CMD curl -fs http://localhost/ | 容器健康检查,周期性检测容器内应用可用性;docker ps可查看状态,分为starting/healthy/unhealthy,仅标记状态,不会自动重启容器 |
| SHELL | SHELL ["/bin/bash", "-c"] | 修改 RUN 指令默认使用的 shell 解释器 |
四、Dockerfile构建nginx镜像实操
4.1 编写 Dockerfile
FROM rockylinux:9 # 维护者信息 LABEL maintainer="test" # 安装编译环境和必要工具 RUN yum install -y gcc make gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl-devel systemd-devel zlib zlib-devel wget curl # 获取 Nginx 源码 RUN wget https://nginx.org/download/nginx-1.29.0.tar.gz # 解压源码 RUN tar xf nginx-1.29.0.tar.gz # 配置 Nginx RUN cd nginx-1.29.0 && ./configure --prefix=/data/server/nginx # 编译并安装 RUN cd nginx-1.29.0 && make && make install # 定制首页 RUN echo "Nginx Web Page from RockyLinux" > /data/server/nginx/html/index.html # 暴露 HTTP 端口 EXPOSE 80 # 健康检查(已注释,可选) # interval: 检测间隔 20s;timeout 单次超时 3s;retries 连续失败 2 次标记 unhealthy #HEALTHCHECK --interval=20s --timeout=3s --retries=2 --start-period=10s \ # CMD curl -fs http://127.0.0.1/ || exit 1 # 设置容器启动命令 ENTRYPOINT ["/data/server/nginx/sbin/nginx", "-g", "daemon off;"]4.2 构建镜像
dockerbuild-tnginx-test:1.29.0.4.3 查看已构建镜像
docker images输出示例:
REPOSITORY TAG IMAGE ID CREATED SIZE nginx-test 1.29.0 0a0a482642a7 10 seconds ago 1.04GB4.4 运行镜像
docker run -itd --name nginx-test -p 80:80 nginx-test:1.29.0查看容器状态:
#docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9c2308bc017d nginx-test:1.29.0 "/data/server/nginx/…" 30 minutes ago Up 30 minutes 0.0.0.0:80->80/tcp, [::]:80->80/tcp nginx-test4.5 测试访问
浏览器访问:http://服务器 IP,即可看到自定义 Nginx 页面。
4.6 通过挂载方式启动容器
cd /data/images/nginx/html/ 编写nginx静态页面 vim index.html 编辑内容如下 hello nginx docker run -itd --name nginx-test2 -p 80:80 -v /data/images/nginx/html/index.html:/data/server/nginx/html/index.html nginx-test:1.29.04.7 测试挂载方式启动容器是否正常
五、面试常考题
5.1 为什么要用 Docker(面试简答)
- 解决环境不一致问题:开发、测试、生产依赖版本不同导致 bug。镜像打包全部依赖,环境统一。
- 提升交付效率:打包镜像,一键部署,简化上线流程,适配 CI/CD 流水线。
- 资源更省:对比虚拟机,更少内存、CPU 占用,单机可部署更多实例。
- 快速启停,方便测试:练习环境(Redis 集群、LNMP、WordPress)一键启动,一键销毁重置。
- 标准化:交付物是镜像,统一交付标准,不再交付源码 + 文档 + 一堆部署脚本。
- 方便横向扩展:容器轻量,快速多副本部署,方便后续上 K8s。
一句话简括:Docker 可以把应用及其依赖打包为镜像,实现环境一致性;容器基于内核隔离,轻量快速,资源开销低,方便自动化部署、持续交付。
5.2 Docker 优缺点
✅优点:环境一致、轻量、快速启停、资源利用率高、便于 CI/CD、镜像可复用;
❌缺点:依赖宿主机内核,隔离性弱于虚拟机,有状态数据持久化需要卷管理。
5.3 Dockerfile 关键面试坑点总结
- RUN:构建镜像阶段执行;CMD/ENTRYPOINT:容器 run 启动时执行,构建阶段不运行。
- EXPOSE只是声明端口,不会真正开放端口,端口映射需要靠
-p参数。 - ADD会自动解压 tar 包,COPY 不会;日常复制文件优先使用 COPY。
- VOLUME在 Dockerfile 内只能定义挂载点,不能写宿主机路径,宿主机挂载目录只能在
docker run -v指定。 - ARG仅构建阶段有效;ENV构建 + 容器运行阶段都生效。
5.4 CMD 和 ENTRYPOINT 的区别?
答:CMD 是容器默认命令,
docker run后面传命令会直接覆盖 CMD;ENTRYPOINT 是固定入口程序,docker run后面的参数会作为参数传给 ENTRYPOINT,不会覆盖入口程序。
5.5 Docker镜像分层原理(高频面试)
底层技术:联合文件系统 UnionFS
- 镜像由多层只读层叠加组成,每一条 Dockerfile 指令都会生成一层只读镜像层。
- 只读层:镜像本身所有层都是只读,容器启动时,会在镜像最上层额外添加一层可读写容器层。
- 写时复制(CoW,Copy-on-Write):
- 当容器需要修改文件时,不会改动底层只读镜像;
- 会把文件从只读层复制到顶层可读写层,在副本上做修改;底层原始文件保持不变。
- 层复用:构建镜像时,如果某一层内容不变,Docker 会直接复用缓存,加快构建速度。
✅ 一句话简答(面试口述)
Docker 镜像基于 UnionFS 联合文件系统,由多层只读层堆叠而成;每条 Dockerfile 指令生成一层。容器启动时新增一层可读写层,采用写时复制 CoW 机制,修改文件只复制到上层读写层,底层镜像不变;相同层可以缓存复用,提升构建效率。
面试追问1:为什么要分层?
- 复用镜像层,减少存储空间,多个镜像共用基础层,不用重复保存;
- 构建缓存:Docker build 会缓存每一层,修改 Dockerfile 某一行时,只重新构建后面的层,大幅加快构建速度;
- 方便版本管理,镜像可以逐层增删。
延伸知识点:不使用缓存构建镜像(实操)
参数 --no-cache
dockerbuild --no-cache-tnginx-test:1.29.0.面试追问2:容器删除,镜像层会消失吗?
不会。容器删除,只会删除容器最上层的读写层,底层所有只读镜像层仍然保留,镜像不会被删除。
面试追问3:Dockerfile优化(分层优化考点)
- 合并 RUN 指令,减少镜像层数(多条命令用
&&连接,避免每一条 RUN 生成一层) - 把变动频繁的指令放 Dockerfile 靠后位置(比如 COPY 业务代码放后面,基础依赖放前面,更好利用缓存)
- 清理临时文件在同一个 RUN 层内,不要分开写,否则删除操作会新增一层,镜像体积不会变小
错误示例:
RUN wget xxx.tar.gz RUN rm xxx.tar.gz上面写法,下载的压缩包还留在上一层,删不掉,镜像体积无法减小。
正确写法:RUN wget xxx.tar.gz && rm xxx.tar.gz
5.6 写时复制 CoW(Copy-on-Write)
属于镜像分层的核心考点,全称:Copy on Write,写时复制。
原理
Docker 镜像所有层都是只读。
容器启动的时候,会在镜像堆叠的最顶层新增一层可读写容器层。
- 读取文件:直接从下层只读镜像层读取;
- 修改/新增文件:
- 当容器要修改底层只读层里的文件,不会直接修改底层镜像;
- Docker 先把这个文件复制一份,放到顶层可读写层;
- 在复制出来的副本上做修改;底层原始文件保持原样不变。
✅ 一句话口述答案(面试背诵)
CoW写时复制:镜像全部是只读层。容器修改文件时,不会改动底层镜像,而是把文件复制到容器读写层,在副本上修改,底层镜像保持不变。
面试追问1:容器删除后,复制出来的文件会怎么样?
容器删除,顶层读写层直接销毁,里面所有复制修改过的文件全部清除,底层镜像不受任何影响。
除非使用-v挂载(绑定挂载或数据卷)的数据保存在宿主机,不属于容器读写层,销毁容器不会自动删除数据;但是匿名卷如果执行docker rm -v会被一起删除。
5.7 容器生命周期管理
容器一共有 5 个核心状态:
- created(已创建):
docker create创建容器,镜像文件层准备完成,未启动。只是容器元数据创建,进程没运行。 - running(运行中):
docker start / docker run,容器内主进程正常运行。 - paused(暂停):
docker pause,暂停容器内所有进程(cgroup 冻结进程,进程保留内存,不退出);docker unpause恢复。 - stopped(停止):
docker stop优雅停止(发 SIGTERM,等待超时后 SIGKILL) /docker kill强制 SIGKILL。主进程退出,容器文件与元数据保留。 - deleted(已删除):
docker rm删除容器,容器所有资源被清理,不能恢复。
状态流转简图:
create→ created →start→ running
running →pause→ paused →unpause→ running
running →stop/kill→ stopped →rm→ deleted
补充:
docker run = docker create + docker start
重点区分面试考点
docker stop:优雅关闭,先发 SIGTERM (15) 信号给容器主进程,默认等待 10s;超时没退出,再发送 SIGKILL (9) 强制杀死。docker kill:直接发送 SIGKILL (9),强制杀死进程,不会等待。
核心结论:容器生命周期由容器PID=1 的主进程控制:PID1 进程退出,容器直接进入 stopped 状态。
5.8 什么是容器退出策略 --restart?4 种重启策略
--restart控制容器退出时,Docker 引擎是否自动重启容器。
no(默认):容器退出永远不重启on-failure:只有异常退出(ExitCode≠0)才重启;正常退出不重启。可加最大次数on-failure:3最多重试 3 次always:无论正常 / 异常退出,总是重启;Docker 守护进程重启,容器也跟着启动unless-stopped:和 always 类似,但如果人工手动 stop 容器,之后 Docker 重启也不会自动拉起
实操示例
示例说明:创建 nginx 容器,演示不同 --restart 参数用法
# 1. 默认 no 策略(不写--restart即为no)dockerrun-itd--namenginx-test-p80:80 nginx:1.29.0# 2. on-failure 策略,最多重试3次dockerrun-itd--namenginx-test-p80:80--restarton-failure:3 nginx:1.29.0# 3. always 策略dockerrun-itd--namenginx-test-p80:80--restartalways nginx:1.29.0# 4. unless-stopped 策略dockerrun-itd--namenginx-test-p80:80--restartunless-stopped nginx:1.29.0