制作自己的 Docker 镜像有两种主流方法:基于容器修改的
"docker commit" 命令和基于声明式脚本的
"Dockerfile" 构建。以下是详细步骤与对比,结合最佳实践:
🐳 一、方法 1:使用
"docker commit"(适合快速调试)
步骤流程:
1. 启动基础容器
docker run -it ubuntu:22.04 /bin/bash # 以交互模式运行Ubuntu容器[1,5](@ref)
2. 在容器内修改配置
apt-get update && apt-get install -y nginx # 安装Nginx
echo "Hello Docker" > /var/www/html/index.html # 自定义首页
3. 退出并提交为新镜像
exit # 退出容器
docker commit -m "Added Nginx" <容器ID> my-nginx:v1 # 提交修改[1,5](@ref)
4. 验证新镜像
docker run -d -p 8080:80 my-nginx:v1 nginx -g "daemon off;" # 运行并映射端口
适用场景:
- 临时调试或学习容器内部操作
- 简单环境修改(如紧急修复配置)
缺点:
- ❗ 缺乏可重复性,难以版本化管理
- ❗ 镜像臃肿(包含操作历史缓存文件)
📝 二、方法 2:使用
"Dockerfile"(推荐生产使用)
核心步骤:
1. 编写
"Dockerfile"在项目根目录创建
"Dockerfile",示例:
# 基础镜像(选择官方轻量版本)
FROM python:3.9-slim
# 设置工作目录
WORKDIR /app
# 复制依赖清单(利用缓存层)
COPY requirements.txt .
# 安装依赖并清理缓存
RUN pip install --no-cache-dir -r requirements.txt && rm -rf /tmp/*
# 复制应用代码
COPY . .
# 暴露端口
EXPOSE 5000
# 启动命令
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"][3,4,6](@ref)
2. 创建
".dockerignore" 文件避免复制无关文件(如缓存、日志):
.git
__pycache__
*.log
3. 构建镜像
docker build -t my-app:v1 . # -t 指定镜像名称和标签[2,4](@ref)
4. 运行容器
docker run -d -p 5000:5000 --name app-container my-app:v1
🔧 三、Dockerfile 关键指令详解
指令 作用 示例
"FROM" 指定基础镜像(必需)
"FROM node:18-alpine"
"COPY" vs
"ADD" 复制文件(
"ADD" 支持URL/解压,但推荐
"COPY" 保持透明性)
"COPY ./src /app/src"
"RUN" 执行命令(多条命令用
"&&" 合并减少层数)
"RUN apt update && apt install -y curl"
"ENV" 设置环境变量
"ENV NODE_ENV=production"
"EXPOSE" 声明容器监听端口(需配合
"-p" 映射到宿主机)
"EXPOSE 8080"
"CMD" 容器启动命令(可被
"docker run" 覆盖)
"CMD ["npm", "start"]"
"ENTRYPOINT" 入口命令(不可覆盖,常与
"CMD" 组合使用)
"ENTRYPOINT ["java", "-jar"]" +
"CMD ["app.jar"]"
🚀 四、进阶优化技巧
1. 减少镜像体积
- 使用多阶段构建(Multi-stage):编译阶段用完整镜像,运行阶段用轻量镜像
# 阶段1:构建应用
FROM golang:1.19 AS builder
COPY . /src
RUN cd /src && go build -o app
# 阶段2:运行环境
FROM alpine:latest
COPY --from=builder /src/app /app
CMD ["/app"]
- 选择小型基础镜像(如
"alpine"、
"slim")
2. 加速构建与安全性
- 利用缓存:将变动频率低的指令(如
"COPY requirements.txt" +
"RUN pip install")放在前面
- 避免敏感信息泄露:使用
"--secret" 或环境变量注入密码,而非硬编码在镜像中
- 定期更新基础镜像修复漏洞:
"FROM ubuntu:22.04@sha256:..."(指定哈希更安全)
💎 五、两种方法对比
特性
"docker commit"
"Dockerfile"
可重复性 ❌ 依赖人工操作 ✅ 脚本化构建,版本可控
镜像体积 ❗ 包含操作历史,易臃肿 ✅ 层优化后体积更小
维护成本 高(需记录操作步骤) 低(修改文件即可)
适用场景 临时调试/简单修改 生产环境、自动化部署
📦 六、发布镜像(可选)
1. 推送到 Docker Hub
docker login
docker tag my-app:v1 username/my-app:v1 # 重命名镜像
docker push username/my-app:v1 # 推送[3](@ref)
2. 私有仓库部署使用 Harbor 或 Nexus 搭建企业级镜像仓库,通过
"docker push registry.example.com/my-app:v1" 发布。
⚠️ 七、避坑指南
- 避免使用
"root" 运行:在
"Dockerfile" 中添加
"USER nonroot" 减少安全风险
- 清理构建缓存:
"RUN" 命令末尾添加
"&& rm -rf /var/lib/apt/lists/*" 删除无用文件
- 测试镜像:运行后检查日志、端口连通性及依赖完整性:
docker exec -it app-container sh # 进入容器调试
curl http://localhost:5000 # 测试服务
💡 总结
- 新手入门:从
"docker commit" 理解镜像与容器的关系,快速验证简单需求。
- 生产部署:必用
"Dockerfile" + 多阶段构建,结合
".dockerignore" 和镜像扫描工具(如 Trivy)确保安全高效。
- 持续优化:定期重构 Dockerfile,采用更小的基础镜像并合并指令层,最终实现 轻量化、可审计、易维护 的镜像生产流程。
评论区