Skip to content

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 包含以下部分:

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 和解压 tarADD 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:选择合适的基镜像

dockerfile
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,除非必要)
dockerfile
COPY . /app/           # 推荐
ADD app.tar.gz /app/   # 自动解压

3. RUN合并命令减少层数

dockerfile
# 错误:创建多层
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

区别CMDENTRYPOINT
可被 docker run 覆盖否(除非用 --entrypoint
典型用途默认参数主命令
dockerfile
ENTRYPOINT ["node", "server.js"]
CMD ["--port", "3000"]

运行:

bash
docker run myapp           # node server.js --port 3000
docker run myapp --port 8080  # node server.js --port 8080

5.ARG vs ENV

dockerfile
# 构建时传入
ARG BUILD_ENV=dev
# 运行时可用
ENV NODE_ENV=$BUILD_ENV

构建命令:

bash
docker build --build-arg BUILD_ENV=app -t myapp .

五、构建与使用

1. 编写文件

创建 Dockerfile:

dockerfile
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .

EXPOSE 3000

CMD ["npm", "start"]

2.构建镜像

bash
docker build -t my-node-app:latest .

3.运行容器

bash
docker run -p 3000:3000 --name myapp my-node-app

六、最佳实践

使用 .dockerignore 排除不必要的文件(如 node_modules, .git):

bash
node_modules .git *.log

最小化镜像层数 合并 RUN 指令,删除临时文件。

使用多阶段构建(Multi-stage Build) 减少最终镜像大小:

dockerfile
# 构建阶段
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
# 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;"]

构建并运行:

bash
docker build -t my-static-site .
docker run -d -p 8080:80 --name website my-static-site

访问 http://localhost:8080

资源推荐