Docker(3)Docker 镜像 & Dockerfile
Docker 镜像 & Dockerfile
一、整体认知:镜像是如何诞生的?
Dockerfile → docker build → 镜像(多层只读)→ docker run → 容器(可写层)
核心结论
-
✅ Dockerfile 是“源代码”
-
✅ 镜像是“构建产物”
-
✅ 容器是“运行实例”
-
✅ 分层结构是 Docker 的灵魂
二、镜像分层结构(结合你发的图)
纯文本
纯文本
┌───────────────┐ ← 容器层(可写,临时)
│ Container │
├───────────────┤
│ CMD / ENTRY │ ← 镜像层4(不新增体积)
├───────────────┤
│ Nginx Install│ ← 镜像层3(RUN)
├───────────────┤
│ ADD Source │ ← 镜像层2(ADD)
├───────────────┤
│ Yum Install │ ← 镜像层1(RUN)
├───────────────┤
│ CentOS 7 │ ← 基础镜像层(FROM)
└───────────────┘
关键点
|
特性 |
说明 |
|---|---|
|
每层只读 |
镜像一旦构建不可更改 |
|
层可复用 |
不同镜像可共享同一层 |
|
写时复制 |
修改才复制到容器层 |
|
缓存命中 |
上层不变,下层直接复用 |
三、Dockerfile 如何驱动分层构建(逐条对照)
1️⃣ FROM(基础层)
dockerfile
dockerfile
FROM centos:7
✅ 对应:
-
镜像最底层
-
所有后续层的基础
📌 原则:
-
越小越好
-
越稳定越好
2️⃣ RUN(构建层,核心)
dockerfile
dockerfile
RUN yum install -y gcc gcc-c++ make
✅ 对应:
-
镜像层 1
-
每一条 RUN = 一个新层
📌 优化写法:
dockerfile
dockerfile
RUN yum install -y gcc make && \
yum clean all && \
rm -rf /var/cache/yum
3️⃣ ADD / COPY(文件层)
dockerfile
dockerfile
ADD nginx-1.20.tar.gz /usr/local/
✅ 对应:
-
镜像层 2
-
引入外部代码或源码
📌 规则:
-
ADD:自动解压(慎用)
-
COPY:语义清晰(推荐)
4️⃣ RUN(编译安装层)
dockerfile
dockerfile
RUN cd /usr/local/nginx && ./configure && make && make install
✅ 对应:
-
镜像层 3
-
构建期执行,不占容器运行时
5️⃣ CMD / ENTRYPOINT(运行定义层)
dockerfile
dockerfile
CMD ["nginx", "-g", "daemon off;"]
✅ 对应:
-
不生成新镜像层
-
决定容器启动行为
|
指令 |
是否可覆盖 |
场景 |
|---|---|---|
|
CMD |
✅ |
默认参数 |
|
ENTRYPOINT |
❌ |
固定主程序 |
四、容器运行时发生了什么?
-
Docker 从镜像复制所有只读层
-
在最上层挂载 可写容器层
-
执行 CMD / ENTRYPOINT
-
容器停止 → 可写层销毁
-
镜像始终不变 ✅
📌 这就是 环境一致性 的根本原因
五、Dockerfile 核心指令速查表(考试级)
|
指令 |
是否建层 |
作用 |
建议 |
|---|---|---|---|
|
FROM |
✅ |
基础镜像 |
必写 |
|
RUN |
✅ |
构建命令 |
合并写 |
|
COPY |
✅ |
拷文件 |
首选 |
|
ADD |
✅ |
拷+解压 |
少用 |
|
CMD |
❌ |
启动命令 |
可覆盖 |
|
ENTRYPOINT |
❌ |
固定入口 |
生产推荐 |
|
ENV |
❌ |
环境变量 |
必用 |
|
WORKDIR |
❌ |
工作目录 |
代替 cd |
|
EXPOSE |
❌ |
声明端口 |
仅说明 |
|
USER |
❌ |
运行身份 |
非 root |
|
VOLUME |
❌ |
数据卷 |
存数据 |
六、镜像构建三大核心机制(图中红字)
✅ 1. 分层构建
-
每层对应 Dockerfile 指令
-
独立、可复用、可缓存
✅ 2. 缓存复用
-
指令不变 → 层不变 → 秒级构建
-
改一行代码 → 只重跑该行及之后
✅ 3. 写时复制(CoW)
-
镜像层共享
-
修改才复制
-
节省磁盘 & 内存
七、Dockerfile 最佳实践(实战级)
✅ 使用 .dockerignore
✅ 合并 RUN,清理缓存
✅ 变量抽成 ENV
✅ 代码放最后(利用缓存)
✅ 多阶段构建减小体积
✅ 非 root 用户运行
✅ 明确 tag,不用 latest
八、多阶段构建(进阶,但非常值得)
dockerfile
dockerfile
FROM gcc AS builder
RUN gcc main.c -o app
FROM alpine
COPY --from=builder /app /app
CMD ["/app"]
常见面试题:
1️⃣ 有没有自己写过镜像?写过哪些?怎么写的?
✅ 写过,实际生产中使用过
常见写过的基础镜像:
-
业务应用镜像
-
Java(Spring Boot)
-
Python(Flask / FastAPI / Django)
-
Node.js(Express / NestJS)
-
-
中间件镜像
-
Nginx(自定义配置)
-
Redis(修改配置、加密码)
-
-
CI/CD 工具镜像
-
Maven + JDK
-
Node + Yarn + Build 工具
-
-
基础运行镜像
-
Alpine + 必要依赖(精简运行时)
-
怎么写的(标准流程):
-
编写
Dockerfile -
使用多阶段构建(Multi-stage build)
-
选择合适的基础镜像(alpine / distroless)
-
拷贝代码 / 依赖
-
暴露端口
-
定义启动命令(CMD / ENTRYPOINT)
-
构建镜像
bash
bash
docker build -t myapp:1.0 . -
推送镜像仓库
bash
bash
docker push myapp:1.0
✅ 示例(Spring Boot):
dockerfile
dockerfile
FROM maven:3.9-openjdk-17 AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn package -DskipTests
FROM openjdk:17-jdk-alpine
COPY --from=build /app/target/app.jar app.jar
ENTRYPOINT ["java","-jar","app.jar"]
2️⃣ Dockerfile 常用指令有哪些?
|
指令 |
作用 |
|---|---|
|
FROM |
指定基础镜像(必须) |
|
MAINTAINER |
维护者信息(已不推荐) |
|
LABEL |
镜像元数据(推荐) |
|
RUN |
构建时执行命令 |
|
CMD |
容器启动时默认命令 |
|
ENTRYPOINT |
容器主进程 |
|
EXPOSE |
声明端口 |
|
ENV |
设置环境变量 |
|
ARG |
构建参数 |
|
ADD |
复制文件(支持 URL、自动解压) |
|
COPY |
复制文件(推荐) |
|
VOLUME |
定义挂载点 |
|
WORKDIR |
设置工作目录 |
|
USER |
指定运行用户 |
|
HEALTHCHECK |
健康检查 |
|
ONBUILD |
子镜像触发指令 |
3️⃣ 常见易混指令区别(高频考点)
✅ ADD vs COPY
|
对比项 |
ADD |
COPY |
|---|---|---|
|
复制本地文件 |
✅ |
✅ |
|
支持 URL |
✅ |
❌ |
|
自动解压 tar |
✅ |
❌ |
|
推荐使用 |
❌(复杂) |
✅(简单明确) |
✅ 官方建议:
能用
COPY就不要用ADD
✅ CMD vs ENTRYPOINT
|
对比项 |
CMD |
ENTRYPOINT |
|---|---|---|
|
作用 |
默认参数 |
主程序 |
|
是否可被覆盖 |
✅ 容易被 |
❌ 不易被覆盖 |
|
组合使用 |
常与 ENTRYPOINT 搭配 |
定义容器主进程 |
|
常见用法 |
默认值 |
固定启动命令 |
✅ 推荐写法(黄金组合):
dockerfile
dockerfile
ENTRYPOINT ["nginx"]
CMD ["-g","daemon off;"]
✅ 覆盖行为:
bash
bash
docker run nginx -t
# CMD 被替换,ENTRYPOINT 不变
4️⃣ Docker 镜像怎么优化?(非常重要)
✅ 1. 使用更小的基础镜像
-
alpine(最小) -
distroless(最安全) -
避免
latest
dockerfile
dockerfile
FROM node:18-alpine
✅ 2. 多阶段构建(Multi-stage Build)
✅ 减少最终镜像体积
dockerfile
dockerfile
FROM golang:1.21 AS builder
WORKDIR /app
RUN go build -o app
FROM alpine
COPY --from=builder /app/app .
CMD ["./app"]
✅ 3. 合并 RUN 指令(减少层数)
❌ 不好:
dockerfile
dockerfile
RUN apt update
RUN apt install -y curl
✅ 好:
dockerfile
dockerfile
RUN apt update && apt install -y curl \
&& rm -rf /var/lib/apt/lists/*
✅ 4. 清理缓存 & 临时文件
dockerfile
dockerfile
rm -rf /var/cache/apk/*
rm -rf ~/.cache
✅ 5. 合理使用 .dockerignore
避免把以下内容打进镜像:
纯文本
纯文本
.git
node_modules
target
*.log
✅ 6. 非 root 用户运行
dockerfile
dockerfile
RUN addgroup -S app && adduser -S app -G app
USER app
✅ 7. 镜像分层设计(复用性)
-
不常变的内容放前面
-
经常变的放后面
更多推荐

所有评论(0)