Dockerfile基础

Dockerfile基础

概述

Dockerfile 是构建 Docker 镜像的文本文件,包含一系列指令和参数,用于定义镜像的构建步骤和运行环境。本文档涵盖 Dockerfile 的核心指令分类、语法格式和最佳实践。


指令分类总览

模块 指令
基础镜像与构建阶段 FROMARG
文件操作与目录配置 COPYADDWORKDIRVOLUME
环境配置 ENVUSERSHELLLABEL
运行命令与依赖安装 RUNRUN --mountRUN --network
容器启动配置 CMDENTRYPOINTEXPOSEHEALTHCHECK
安全与资源控制 SECURITY_OPTCAP_ADDCAP_DROPSYSCTL
多阶段构建 COPY --fromFROM --from

基础镜像与构建阶段

FROM

必选指令,指定构建的基础镜像:

FROM ubuntu:22.04
FROM nginx:alpine AS builder   # 多阶段构建命名
FROM --platform=linux/amd64 python:3.11

ARG

构建阶段专用参数(仅在 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/src

VOLUME

声明持久化数据卷:

VOLUME /data
VOLUME ["/logs", "/config"]

环境配置

ENV

设置环境变量(构建和运行阶段均生效):

ENV APP_ENV=prod
ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms512m -Xmx1024m"
ENV PATH=/app/bin:$PATH

USER

指定容器运行用户(安全最佳实践):

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.json

RUN –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=prod

EXPOSE

声明容器暴露端口(仅文档说明):

EXPOSE 80
EXPOSE 443/tcp 53/udp
EXPOSE 8080 9100

HEALTHCHECK

定义健康检查规则:

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"]

常见问题与注意事项

镜像层数过多

每个 RUNCOPYADD 都会创建新层,合并相关命令可减少层数:

# 不推荐
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 appuser

CMD 和 ENTRYPOINT 区别

  • ENTRYPOINT:固定入口,不可被覆盖
  • CMD:默认参数,可被 docker run 覆盖
  • 组合使用:ENTRYPOINT ["java"] + CMD ["-jar", "app.jar"]

多阶段构建的好处

  • 仅保留运行时必需文件
  • 丢弃编译工具、源代码等构建依赖
  • 大幅减小最终镜像体积

参考链接