Dockerfile基础
概述
Dockerfile 是构建 Docker 镜像的文本文件,包含一系列指令和参数,用于定义镜像的构建步骤和运行环境。本文档涵盖 Dockerfile 的核心指令分类、语法格式和最佳实践。
指令分类总览
| 模块 | 指令 |
|---|---|
| 基础镜像与构建阶段 | FROM、ARG |
| 文件操作与目录配置 | COPY、ADD、WORKDIR、VOLUME |
| 环境配置 | ENV、USER、SHELL、LABEL |
| 运行命令与依赖安装 | RUN、RUN --mount、RUN --network |
| 容器启动配置 | CMD、ENTRYPOINT、EXPOSE、HEALTHCHECK |
| 安全与资源控制 | SECURITY_OPT、CAP_ADD、CAP_DROP、SYSCTL |
| 多阶段构建 | COPY --from、FROM --from |
基础镜像与构建阶段
FROM
必选指令,指定构建的基础镜像:
FROM ubuntu:22.04
FROM nginx:alpine AS builder # 多阶段构建命名
FROM --platform=linux/amd64 python:3.11ARG
构建阶段专用参数(仅在 docker build 过程中生效):
ARG APP_VERSION=1.0
ARG RUN_USER=appuser
# 构建时覆盖:docker build --build-arg APP_VERSION=2.0 .文件操作与目录配置
COPY
将本地文件/目录复制到镜像中:
COPY pom.xml ./
COPY src/ ./src/
COPY --chown=1000:1000 app.jar /app/ADD
功能类似 COPY,额外支持自动解压和 URL 下载:
ADD app.tar.gz /app/ # 自动解压
ADD --chown=app:app config.json /app/建议:URL 下载使用
RUN wget/curl替代ADD,更可控。
WORKDIR
设置工作目录(后续指令在该目录下执行):
WORKDIR /app
WORKDIR src # 相对路径,最终为 /app/srcVOLUME
声明持久化数据卷:
VOLUME /data
VOLUME ["/logs", "/config"]环境配置
ENV
设置环境变量(构建和运行阶段均生效):
ENV APP_ENV=prod
ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms512m -Xmx1024m"
ENV PATH=/app/bin:$PATHUSER
指定容器运行用户(安全最佳实践):
USER appuser
USER 1000:1000
USER --root RUN apt update # 临时提升权限LABEL
添加镜像元数据标签:
LABEL maintainer="devops@company.com"
LABEL version="1.0"
LABEL org.opencontainers.image.title="App Service"
LABEL org.opencontainers.image.description="Production backend"运行命令与依赖安装
RUN
构建阶段执行命令(每个 RUN 创建一个镜像层):
# Shell 格式
RUN apt update && apt install -y nginx
# Exec 格式(推荐)
RUN ["/bin/bash", "-c", "echo hello"]最佳实践:合并多个命令为单个 RUN,减少镜像层数。
RUN –mount
构建时临时挂载(指令结束后自动卸载):
# 缓存加速
RUN --mount=type=cache,target=/var/cache/apt \
apt update && apt install -y python3
# 挂载秘密文件(避免明文)
RUN --mount=type=secret,id=mysecret \
cp /run/secrets/mysecret /app/config.jsonRUN –network
控制 RUN 指令的网络模式:
RUN --network=none apt update # 禁用网络
RUN --network=host curl localhost:8080容器启动配置
CMD
容器启动默认命令(可被 docker run 参数覆盖):
# Exec 格式(推荐)
CMD ["nginx", "-g", "daemon off;"]
# Shell 格式
CMD nginx -g 'daemon off;'
# 参数格式(配合 ENTRYPOINT)
CMD ["--config", "/app/config.yaml"]ENTRYPOINT
容器入口点(不可被 docker run 参数覆盖):
# Exec 格式(推荐)
ENTRYPOINT ["java", "-jar"]
CMD ["app.jar"]
# docker run java-service --spring.profiles.active=prod
# 实际执行:java -jar app.jar --spring.profiles.active=prodEXPOSE
声明容器暴露端口(仅文档说明):
EXPOSE 80
EXPOSE 443/tcp 53/udp
EXPOSE 8080 9100HEALTHCHECK
定义健康检查规则:
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1安全与资源控制
CAP_ADD / CAP_DROP
管理 Linux 内核能力:
CAP_ADD ["NET_ADMIN", "SYS_TIME"]
CAP_DROP ["SETUID", "SETGID"]
CAP_DROP ALL # 移除所有非必要能力SYSCTL
配置内核参数:
SYSCTL ["net.ipv4.ip_forward=1", "net.core.somaxconn=1024"]多阶段构建
构建过程与运行环境分离,大幅减小最终镜像体积。
# ===== 第一阶段:构建阶段 =====
FROM maven:3.9.6-openjdk-17-slim AS builder
WORKDIR /app
COPY pom.xml ./
RUN mvn dependency:go-offline
COPY src/ ./src/
RUN mvn clean package -DskipTests
# ===== 第二阶段:运行阶段 =====
FROM openjdk:17-jdk-alpine
COPY --from=builder /app/target/app.jar /app/app.jar
ENTRYPOINT ["java", "-jar", "/app/app.jar"]完整生产级 Dockerfile 示例
# ===== 第一阶段:构建阶段 =====
FROM maven:3.9.6-openjdk-17-slim AS builder
WORKDIR /app/build
LABEL maintainer="DevOps-Team <devops@company.com>"
LABEL org.opencontainers.image.title="Java-Backend-Service"
LABEL org.opencontainers.image.version="v2.1.0"
COPY --chown=1000:1000 pom.xml ./
RUN mvn dependency:go-offline -B
COPY --chown=1000:1000 src/ ./src/
RUN mvn clean package -DskipTests
# ===== 第二阶段:运行阶段 =====
FROM openjdk:17-jdk-alpine3.19
ENV TZ=Asia/Shanghai \
APP_PORT=8080 \
JAVA_OPTS="-Xms512m -Xmx1024m -XX:MaxRAMPercentage=80.0" \
APP_HOME=/app/runtime
ARG RUN_USER=appuser
ARG RUN_UID=1000
RUN addgroup --gid ${RUN_UID} ${RUN_USER} \
&& adduser --uid ${RUN_UID} --gid ${RUN_UID} --disabled-password ${RUN_USER}
WORKDIR ${APP_HOME}
COPY --from=builder --chown=${RUN_USER}:${RUN_USER} /app/build/target/*.jar app.jar
USER ${RUN_USER}
EXPOSE ${APP_PORT} 9100
VOLUME ["${APP_HOME}/logs", "${APP_HOME}/conf"]
HEALTHCHECK --interval=30s --timeout=5s --retries=3 --start-period=60s \
CMD curl -f http://localhost:${APP_PORT}/actuator/health || exit 1
ENTRYPOINT ["java", "-jar"]
CMD ["app.jar"]指令速查表
| 指令 | 用途 | 格式示例 |
|---|---|---|
FROM |
基础镜像 | FROM nginx:alpine |
ARG |
构建参数 | ARG VERSION=1.0 |
COPY |
复制文件 | COPY app.jar /app/ |
ADD |
复制+解压 | ADD app.tar.gz /app/ |
WORKDIR |
工作目录 | WORKDIR /app |
VOLUME |
数据卷声明 | VOLUME /data |
ENV |
环境变量 | ENV APP_ENV=prod |
USER |
运行用户 | USER appuser |
LABEL |
元数据标签 | LABEL version="1.0" |
RUN |
构建命令 | RUN apt update |
CMD |
默认命令 | CMD ["nginx"] |
ENTRYPOINT |
入口点 | ENTRYPOINT ["java"] |
EXPOSE |
端口声明 | EXPOSE 80 |
HEALTHCHECK |
健康检查 | HEALTHCHECK CMD curl |
CAP_ADD |
添加能力 | CAP_ADD ["NET_ADMIN"] |
CAP_DROP |
移除能力 | CAP_DROP ["SETUID"] |
常见问题与注意事项
镜像层数过多
每个 RUN、COPY、ADD 都会创建新层,合并相关命令可减少层数:
# 不推荐
RUN apt update
RUN apt install -y nginx
RUN apt clean
# 推荐
RUN apt update && apt install -y nginx && apt clean使用非 root 用户运行
生产环境推荐使用非 root 用户运行容器,提升安全性:
RUN adduser -D appuser
USER appuserCMD 和 ENTRYPOINT 区别
ENTRYPOINT:固定入口,不可被覆盖CMD:默认参数,可被docker run覆盖- 组合使用:
ENTRYPOINT ["java"]+CMD ["-jar", "app.jar"]
多阶段构建的好处
- 仅保留运行时必需文件
- 丢弃编译工具、源代码等构建依赖
- 大幅减小最终镜像体积