为什么官方镜像不够用?如何把你的应用打包成镜像?一个案例全搞定
你有没有遇到过这种情况:
-
想在 Docker 里运行自己的 Java 或 Python 项目,但官方镜像里没有你的代码
-
需要在一个镜像里安装 vim、curl 等工具,每次进容器都要重新装
-
希望像 Docker Hub 上的官方镜像一样,一键 docker run 自己的应用
这时候,你就需要 Dockerfile。
一、什么是 Dockerfile?📝
一句话定义:
Dockerfile 是一个文本文件,里面写好了 构建镜像的“配方”。Docker 按照这个文件里的指令,一步步自动生成你想要的镜像。
类比一下:
-
镜像 = 软件安装包
-
Dockerfile = 制作这个安装包的 说明书 / 菜谱
二、为什么需要 Dockerfile?🤔
你可能会问:Docker Hub 上什么镜像都有(Nginx、MySQL、Redis…),直接 pull 下来用不就行了?
问题在于: 官方镜像是 通用 的,不包含你的 应用代码 和 个性化配置。
举个例子:
-
你写了一个 Python Flask 应用,需要在容器里运行
-
官方 python:3.9 镜像只有 Python 环境,没有你的代码和依赖
-
每次手动 docker cp 或者进容器安装依赖,太麻烦
Dockerfile 的作用就是: 把你自己的应用 + 运行环境 + 配置 打包成一个全新的镜像,然后可以:
-
像官方镜像一样一键启动
-
上传到 Docker Hub 分享给别人
-
在任意装有 Docker 的机器上运行
三、Dockerfile 构建镜像的原理 🏗️
简单理解流程:
你编写 Dockerfile(比如 FROM python:3.9、COPY . /app、RUN pip install)
执行 docker build -t 镜像名 . Docker 会:
-
把当前目录作为 构建上下文 发送给 Docker 服务端
-
逐条执行 Dockerfile 中的指令
-
每条指令生成一个 临时容器,执行后打包成一个 镜像层
-
利用 缓存 加速构建(没变化的部分直接用之前的结果)
最终产出你需要的镜像
你可以用 docker run 运行,或者 docker save 导出,或者 docker push 上传
Dockerfile + 上下文目录 → docker build → 镜像(Image) 镜像 → docker run → 容器(Container) 镜像 → docker save → tar 文件 tar 文件 → docker load → 镜像
四、实战案例:打包一个 Python Flask 应用 🐍
我们写一个最简单的 Web 应用,然后用 Dockerfile 打包成镜像。
1. 准备应用文件
新建一个目录 myapp,里面放两个文件:
app.py
from flask import Flask app = Flask(__name__) @app.route('/') def hello(): return "Hello, Docker!" if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
requirements.txt
flask==2.3.0
2. 编写 Dockerfile
在同一个目录下创建 Dockerfile(文件名固定,无扩展名):
dockerfile
# 1. 基于官方 Python 镜像 FROM python:3.9-slim # 2. 设置工作目录(容器内) WORKDIR /app # 3. 复制依赖文件并安装 COPY requirements.txt . RUN pip install –no-cache-dir -r requirements.txt # 4. 复制应用代码 COPY app.py . # 5. 声明容器运行时监听的端口 EXPOSE 5000 # 6. 启动命令 CMD ["python", "app.py"]
3. 构建镜像
在 myapp 目录下执行:
docker build -t my-flask-app:1.0 .
- -t
指定镜像名和标签
-
最后的 . 表示 构建上下文 为当前目录
构建过程输出类似:
Step 1/6 : FROM python:3.9-slim —> 1d3b7f3c4e5f Step 2/6 : WORKDIR /app … Successfully built 7a8b9c0d1e2f Successfully tagged my-flask-app:1.0
4. 运行容器
docker run -d -p 5000:5000 –name myapp my-flask-app:1.0
访问 http://localhost:5000,就能看到 Hello, Docker! 🎉
5. 后续操作
-
把镜像推到 Docker Hub:docker tag my-flask-app:1.0 你的用户名/my-flask-app:1.0 + docker push
-
导出镜像文件:docker save -o my-flask-app.tar my-flask-app:1.0
-
别人拿到 tar 后:docker load -i my-flask-app.tar
五、Dockerfile 常用指令速查表 📋
| FROM |
指定基础镜像 |
FROM ubuntu:20.04 |
| WORKDIR |
设置工作目录 |
WORKDIR /app |
| COPY |
复制本地文件到镜像 |
COPY . /app |
| ADD |
类似 COPY,支持解压和 URL |
ADD app.tar.gz / |
| RUN |
构建时执行命令 |
RUN apt update && apt install -y curl |
| ENV |
设置环境变量 |
ENV PORT=8080 |
| EXPOSE |
声明容器端口 |
EXPOSE 8080 |
| CMD |
容器启动时的默认命令(可被覆盖) |
CMD ["python", "app.py"] |
| ENTRYPOINT |
容器启动的命令(不可被覆盖) |
ENTRYPOINT ["python"] |
| ARG |
构建参数 |
ARG VERSION=1.0 |
💡 CMD 和 ENTRYPOINT 的区别:
- ENTRYPOINT
是容器的主进程,CMD 是它的默认参数
-
推荐组合:ENTRYPOINT ["python"] + CMD ["app.py"],这样 docker run 镜像 test.py 可以覆盖 app.py
六、最佳实践与注意事项 ✅
充分利用缓存 把不容易变化的指令放前面(如 FROM、WORKDIR、RUN 安装依赖),经常变化的指令放后面(如 COPY 代码)。这样改代码后,前面层还能用缓存。
合并 RUN 命令 尽量 RUN apt update && apt install -y … 一行写完,减少镜像层数。
清理临时文件 在同一个 RUN 里删除 /var/lib/apt/lists/* 等缓存,减小镜像体积。
使用 .dockerignore 文件 像 .git、__pycache__、node_modules 等不要打包进镜像,可以写在 .dockerignore 中。
尽量指定标签 不要只用 latest,建议给镜像打上版本号如 1.0、v2。
七、总结 🎯
|
Dockerfile 是什么 |
构建镜像的脚本文件 |
|
为什么需要它 |
把应用+环境打包成可移植的镜像 |
|
构建原理 |
逐条执行指令,分层构建,利用缓存 |
|
常用指令 |
FROM, WORKDIR, COPY, RUN, CMD, EXPOSE |
|
案例 |
打包一个 Python Flask 应用 |
学会了 Dockerfile,你就可以 把自己的任何应用容器化,享受 Docker 带来的便捷部署和可移植性。




