Dockerfile 详解
作者: ryan 发布于: 2025/11/17 更新于: 2025/11/17 字数: 0 字 阅读: 0 分钟
Docker 是一种革命性的容器化技术,它允许开发者将应用程序及其依赖项打包到一个可移植的容器中,从而实现“一次构建,到处运行”。而 Dockerfile 正是构建 Docker 镜像的核心文件。它是一份纯文本指令脚本,Docker 引擎通过读取它来自动化地构建镜像。本文将从基础概念入手,逐步深入讲解 Dockerfile 的语法、指令、最佳实践,并配以实际示例,帮助你快速掌握 Dockerfile 的编写技巧。
一、什么是 Dockerfile?
Dockerfile 是一个文本文件(无后缀名,通常命名为 Dockerfile),包含了一系列指令(Instruction)和参数(Argument)。Docker 根据这些指令逐行执行,生成一个分层的 Docker 镜像。
每个指令都会创建一个新的镜像层(Layer),这些层是只读的,最终的容器运行时会在最顶层添加一个可写层。
核心原则:每条指令 = 一个镜像层,层越多镜像越大,构建越慢。
二、Dockerfile 的基本结构
一个典型的 Dockerfile 包含以下部分:
# 1. 基础镜像
FROM ubuntu:20.04
# 2. 元信息(可选)
LABEL maintainer="your-email@example.com"
LABEL version="1.0"
LABEL description="This is a sample Node.js app"
# 3. 环境变量
ENV NODE_VERSION=18
# 4. 工作目录
WORKDIR /app
# 5. 复制文件
COPY . .
# 6. 执行命令
RUN npm install
RUN npm run build
# 7. 暴露端口
EXPOSE 3000
# 8. 启动命令
CMD ["npm", "start"]三、核心指令详解
| 指令 | 作用 | 示例 |
|---|---|---|
FROM | 指定基础镜像(必须是第一条指令) | FROM node:18-alpine |
WORKDIR | 设置工作目录(后续指令在此路径执行) | WORKDIR /usr/src/app |
COPY | 复制本地文件到镜像中 | COPY package*.json ./ |
ADD | 类似 COPY,但支持 URL 和解压 tar | ADD http://example.com/file.tar.gz /tmp/ |
RUN | 在构建时执行命令(创建新层) | RUN apt-get update && apt-get install -y curl |
CMD | 指定容器启动时运行的默认命令 | CMD ["node", "app.js"] |
ENTRYPOINT | 配置容器启动后执行的主命令(不易被覆盖) | ENTRYPOINT ["nginx", "-g", "daemon off;"] |
EXPOSE | 声明容器运行时监听的端口(仅文档作用) | EXPOSE 8080 |
ENV | 设置环境变量 | ENV PORT=3000 |
ARG | 构建时参数(仅构建时有效) | ARG NODE_ENV=production |
VOLUME | 定义匿名卷 | VOLUME /data |
USER | 设置运行容器时的用户 | USER nginx |
LABEL | 添加元数据 | LABEL org.opencontainers.image.source="https://github.com/..." |
HEALTHCHECK | 定义健康检查 | `HEALTHCHECK CMD curl -f http://localhost/ |
四、指令优化
1. FROM:选择合适的基镜像
FROM alpine:3.18 # 轻量级 Linux
FROM node:18-slim # 官方 Node.js 镜像
FROM python:3.11-alpine # Python 环境建议:优先使用官方镜像 + -slim 或 -alpine 版本,减少镜像体积。
2.COPY 和 ADD
COPY:推荐用于复制本地文件/目录ADD:支持远程 URL 和自动解压(不推荐用于 tar,除非必要)
COPY . /app/ # 推荐
ADD app.tar.gz /app/ # 自动解压3. RUN合并命令减少层数
# 错误:创建多层
RUN apt-get update
RUN apt-get install -y python3
# 正确:合并为一行
RUN apt-get update && apt-get install -y python3 \
&& rm -rf /var/lib/apt/lists/*技巧:使用 && 连接命令,末尾清理缓存(如 apt, pip, npm)以减小镜像大小。
4.CMD 和ENTRYPOINT
| 区别 | CMD | ENTRYPOINT |
|---|---|---|
可被 docker run 覆盖 | 是 | 否(除非用 --entrypoint) |
| 典型用途 | 默认参数 | 主命令 |
ENTRYPOINT ["node", "server.js"]
CMD ["--port", "3000"]运行:
docker run myapp # node server.js --port 3000
docker run myapp --port 8080 # node server.js --port 80805.ARG vs ENV
# 构建时传入
ARG BUILD_ENV=dev
# 运行时可用
ENV NODE_ENV=$BUILD_ENV构建命令:
docker build --build-arg BUILD_ENV=app -t myapp .五、构建与使用
1. 编写文件
创建 Dockerfile:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]2.构建镜像
docker build -t my-node-app:latest .3.运行容器
docker run -p 3000:3000 --name myapp my-node-app六、最佳实践
使用 .dockerignore 排除不必要的文件(如 node_modules, .git):
node_modules .git *.log最小化镜像层数 合并 RUN 指令,删除临时文件。
使用多阶段构建(Multi-stage Build) 减少最终镜像大小:
# 构建阶段
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 运行阶段
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/index.js"]避免 latest 标签 使用具体版本:node:18.19.0-alpine
安全考虑
- 以非 root 用户运行:
USER node - 定期扫描镜像:
docker scan myapp
七、完整示例:构建一个 Nginx 静态网站
# Dockerfile
FROM nginx:alpine
LABEL maintainer="dev@example.com"
# 移除默认页面
RUN rm -rf /usr/share/nginx/html/*
# 复制自定义网站
COPY ./html /usr/share/nginx/html
# 暴露 80 端口
EXPOSE 80
# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]构建并运行:
docker build -t my-static-site .
docker run -d -p 8080:80 --name website my-static-site访问 http://localhost:8080
资源推荐:
