docker学习(5)-Dockerfile
2026-04-15 18:01 xiashengwang 阅读(0) 评论(0) 收藏 举报一、Dockerfile 基础
1. Dockerfile是什么
Dockerfile 是一个文本文件,包含了一系列指令,用于自动化构建 Docker 镜像。每个指令都会在镜像中创建一个新的层。
2. 常用指令详解
| 指令 | 说明 | 示例 |
|---|---|---|
FROM |
指定基础镜像,必须是第一条指令 | FROM python:3.9-slim |
RUN |
在构建时执行命令,用于安装软件包等 | RUN apt-get update && apt-get install -y curl |
COPY |
将本地文件复制到镜像中,推荐使用 | COPY app.py /app/ |
ADD |
类似 COPY,但支持自动解压 tar 和 URL 下载 | ADD app.tar.gz /app/ |
WORKDIR |
设置工作目录,后续指令在该目录下执行 | WORKDIR /app |
ENV |
设置环境变量 | ENV NODE_ENV=production |
ARG |
定义构建参数,构建时通过 --build-arg 传递 | ARG VERSION=latest |
EXPOSE |
声明容器运行时监听的端口(仅文档作用) | EXPOSE 8080 |
CMD |
容器启动时执行的命令,可被 docker run 覆盖 | CMD ["python", "app.py"] |
ENTRYPOINT |
容器启动时执行的命令,不可被覆盖(可追加参数) | ENTRYPOINT ["python"] |
VOLUME |
声明数据卷,用于持久化 | VOLUME /data |
USER |
指定运行用户(安全) | USER appuser |
LABEL |
添加元数据 | LABEL version="1.0" |
HEALTHCHECK |
定义健康检查命令 | HEALTHCHECK --interval=10s --timeout=3s --retries=3 CMD curl -f http://localhost/ || exit 1 |
注意:
RUN尽量合并为一条,减少层数。CMD和ENTRYPOINT的区别:ENTRYPOINT定义容器的主要进程,CMD提供默认参数。通常组合使用:ENTRYPOINT ["python"]、CMD ["app.py"],这样docker run image script.py可覆盖app.py。
二、镜像分层与构建缓存
1. 镜像分层原理
Docker 镜像由多个只读层叠加而成。每条指令创建一个新层。当运行容器时,在最上面添加一个可写层。
优点:
- 共享基础层,节省磁盘空间和网络带宽。
- 构建时利用缓存,如果某层未改变,则直接利用缓存。
2. 构建缓存最佳实践
- 将不常变化的层放在前面,如依赖安装。
- 例如,先
COPY requirements.txt,再RUN pip install,这样只要requirements.txt不变,依赖层就会使用缓存。 - 频繁变化的代码放在后面,如
COPY .。
3. 查看镜像历史
docker history <image>
可看到各层的大小和构建指令。
三、编写高效的 Dockerfile
1. 选择合适的基础镜像
- alpine:体积小(5MB),但可能存在兼容性问题。
- slim:官方精简版,体积适中(~150MB),推荐用于 Python/Node.js。
- 全量版:体积大,但包含所有工具,适合开发。
原则:在满足需求的前提下,选择尽可能小的基础镜像。
2. 减少层数
- 合并
RUN指令,例如RUN apt-get update && apt-get install -y package && rm -rf /var/lib/apt/lists/*。
对于Debian/Ubuntu系(nginx,node,python),安装软件后删除缓存:rm -rf /var/lib/apt/lists/*
对于Alpine系(node:alpine、nginx:alpine),安装软件后删除缓存:RUN apk add --no-cache 你要装的软件
3. 清理临时文件
在同一个 RUN 中安装后删除缓存,避免镜像臃肿。
比如上面的最后一条命令:rm -rf /var/lib/apt/lists/*
4. 使用 .dockerignore
在同一个 RUN 中安装后删除缓存,避免镜像臃肿。
- 创建
.dockerignore文件,排除不需要的文件(如node_modules、.git、__pycache__),加快构建并减小上下文。
.dockerignore
# 通用
.git
.gitignore
.env
.DS_Store# Node
node_modules
npm-debug.log
dist# Python
__pycache__
.venv
*.pyc
5. 多阶段构建(Multi-stage Builds)
多阶段构建允许你在一个 Dockerfile 中使用多个 FROM 语句,最终只将需要的产物复制到最终镜像中,极大减小镜像体积。
# 构建阶段
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build# 运行阶段
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
上面这段,node:18只是用于编译,真正的输出镜像是基于nginx:alpine的。并且docker有缓存机制,node:18的npm安装不会每次都下载,只要package*.json不变,他就会跳过,节省编译时间。
6. 安全实践
- 避免以
root用户运行:创建专用用户并切换。 - 使用
COPY而非ADD,除非需要自动解压。 - 固定基础镜像版本:避免使用
latest,指定具体标签(如python:3.9-slim)。
四、实践任务
1:为 Python Flask 应用编写优化的 Dockerfile
- 使用 python:3.9-slim 作为基础镜像
- 设置非 root 用户运行
- 使用多阶段构建?不需要,但可尝试将依赖安装与代码复制分离,利用缓存
- 最终镜像尽可能小(<200MB)
1)创建dockerfile,如下:
# 使用官方 Python slim 镜像
FROM Python:3.9-slim#环境变量
ENV PYTHONUNBUFFERED=1 \PYTHONDONTWRITEBYTECODE=1#创建非root用户
RUN addgroup --system app && adduser --system --group app# 设置工作目录
WORKDIR /app# 安装系统依赖(如有需要)
RUN apt-get update && apt-get install -y --no-install-recommends gcc && rm -rf /var/lib/apt/lists/*# 复制依赖文件并安装
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt# 复制应用代码
COPY app.py .# 切换到非root用户
USER app# 暴露应用端口
EXPOSE 5000# 启动应用
CMD ["python", "app.py"]
2)构建镜像:
切换到项目的根目录,执行以下命令:
docker build -t flask-app-optimized .
语法是这样的:
docker build [选项] [参数]构建 -t 标签 在哪里找Dockerfile
3)查看镜像大小
docker images
怎么感觉比之前那个还大?

4)运行容器测试
docker run -d --name my-flask-app-optimized -p 5001:5000 flask-app-optimized
如果出错,可以查看log,命令如下:
docker logs 容器名

5)分析镜像层
使用 docker history 分析任一镜像的层大小

6)使用 .dockerignore
在项目根目录创建 .dockerignore 文件,内容示例:
__pycache__
*.pyc
*.pyo
*.pyd
.Python
.env
.git
.gitignore
.idea
.vscode
*.log
在构建时就不会使用这些文件,加快构建时间。
