5 分钟读懂 Dockerfile,看完就会写
一句话解释 Dockerfile
Dockerfile 就是用来打包应用的"说明书",告诉 Docker 怎么把你的代码变成一个可以运行的镜像。
最简单的例子
dockerfile
# 1. 基础镜像 - 从哪开始
FROM openjdk:17-jdk-slim
# 2. 工作目录 - 后续命令在哪执行
WORKDIR /app
# 3. 复制文件 - 把代码放进去
COPY target/app.jar /app/app.jar
# 4. 暴露端口 - 容器运行时哪个端口对外可见
EXPOSE 8080
# 5. 启动命令 - 容器启动后执行什么
CMD ["java", "-jar", "app.jar"]
逐行解读
FROM - 从哪开始
dockerfile
# 格式
FROM <镜像名>:<标签>
# 示例
FROM openjdk:17-jdk-slim # Java 17 精简版
FROM node:18-alpine # Node.js 18 精简版
FROM nginx:latest # 最新版 Nginx
FROM python:3.9 # Python 3.9
基础镜像就是模板,FROM 之后的所有操作都基于这个镜像。
WORKDIR - 在哪干活
dockerfile
# 格式
WORKDIR /路径
# 示例
WORKDIR /app # 进入 /app 目录
WORKDIR /home/node # 进入 /home/node 目录
相当于 cd 命令,设置后续命令的工作目录。
COPY - 复制文件
dockerfile
# 格式
COPY <源路径> <目标路径>
# 示例
COPY target/app.jar /app/app.jar # 复制文件
COPY ./src /app/src # 复制文件夹
COPY package*.json /app/ # 支持通配符
推荐用 COPY,不用 ADD(ADD 功能更强但可替代性高)。
RUN - 执行命令
dockerfile
# 格式
RUN <命令>
# 示例
RUN apt-get update # 更新 apt
RUN apt-get install -y curl # 安装 curl
RUN mkdir -p /app/logs # 创建目录
RUN echo "hello" > /app/hello.txt # 写文件
RUN 会在构建镜像时执行,常用于安装依赖、配置环境。
EXPOSE - 声明端口
dockerfile
# 格式
EXPOSE <端口号>
# 示例
EXPOSE 8080 # 声明容器运行在 8080 端口
EXPOSE 3000 80 # 声明多个端口
只是声明,不实际映射。
-p运行时指定。
CMD - 启动命令
dockerfile
# 格式
CMD ["命令", "参数1", "参数2"]
# 示例
CMD ["java", "-jar", "app.jar"] # 启动 Java 应用
CMD ["node", "server.js"] # 启动 Node 服务
CMD ["nginx", "-g", "daemon off;"] # 启动 Nginx
容器启动时执行,只能有一个 CMD。
实战:Spring Boot 项目
dockerfile
# 1. 构建阶段:用 maven 镜像打包
FROM maven:3.8-openjdk-8 AS builder
WORKDIR /app
COPY pom.xml .
COPY src ./src
# 打包成 jar
RUN mvn package -DskipTests
# 2. 运行阶段:用 jre 镜像运行
FROM openjdk:8-jre-slim
WORKDIR /app
# 从 builder 阶段复制 jar
COPY --from=builder /app/target/app.jar /app/app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]
为什么用两阶段?
- 构建阶段需要 Maven(较大)
- 运行阶段只需要 JRE(较小)
- 最终镜像体积小很多
实战:Vue 前端项目
dockerfile
# 1. 构建阶段
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 2. 运行阶段
FROM nginx:alpine
# 从 builder 复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html
# 复制 Nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
常用指令速查
| 指令 | 作用 | 示例 |
|---|---|---|
| FROM | 基础镜像 | FROM node:18 |
| WORKDIR | 工作目录 | WORKDIR /app |
| COPY | 复制文件 | COPY . /app |
| RUN | 执行命令 | RUN npm install |
| EXPOSE | 声明端口 | EXPOSE 3000 |
| CMD | 启动命令 | CMD ["npm", "start"] |
| ENV | 环境变量 | ENV NODE_ENV=prod |
| ARG | 构建参数 | ARG version |
| ENTRYPOINT | 入口点 | 与 CMD 类似 |
| VOLUME | 数据卷 | VOLUME /data |
构建和运行
bash
# 构建镜像
docker build -t myapp:latest .
# 运行容器
docker run -d -p 8080:8080 --name myapp myapp:latest
# 参数说明
-d # 后台运行
-p 8080:8080 # 端口映射(主机:容器)
--name # 容器名称
快速上手模板
Java 后端
dockerfile
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]
Node.js 后端
dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
Vue/React 前端
dockerfile
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
总结
记住 5 个核心指令:
FROM - 从哪开始
COPY - 放哪文件
RUN - 做什么操作
EXPOSE - 端口暴露
CMD - 启动什么
看懂这 5 个,基本就能读懂大多数 Dockerfile 了。