dockerfile常见的指令
dockerfile常见的指令
面试口述要点(约 1 分钟)
Dockerfile 通过声明式指令定义镜像构建过程,常见指令分为基础设置、文件操作、运行时配置三类:
基础指令:
FROM <image>:<tag>:指定基础镜像,必须是第一条指令;多阶段构建可多次使用,如FROM golang:1.20 AS builder。LABEL <key>=<value>:添加元数据,如版本、维护者、描述。
文件与环境:
COPY <src> <dest>:复制本地文件到镜像,推荐用于源码;支持通配符与--chown设置权限。ADD <src> <dest>:类似 COPY 但支持 URL 下载与自动解压 tar,非必要不用(行为不透明)。WORKDIR <path>:设置工作目录,后续 RUN/CMD/ENTRYPOINT 的执行路径;不存在则自动创建。ENV <key>=<value>:设置环境变量,构建时与运行时均生效;如ENV PATH=/app/bin:$PATH。ARG <name>=<default>:构建参数,仅构建时生效,可通过--build-arg传入;常用于版本号、代理配置。
运行时配置:
RUN <command>:构建时执行命令并提交为新层,如安装依赖;推荐合并多条命令减少层数RUN apt update && apt install -y curl && rm -rf /var/lib/apt/lists/*。CMD ["executable","param1"]:容器启动默认命令,可被docker run参数覆盖;推荐 exec 格式避免 shell 包装。ENTRYPOINT ["executable"]:容器启动入口点,不可被docker run参数覆盖(仅追加参数);与 CMD 配合使用,ENTRYPOINT 固定可执行文件,CMD 提供默认参数。EXPOSE <port>:声明容器监听端口,不实际映射(需-p);文档化作用。VOLUME ["/data"]:声明挂载点,运行时可绑定宿主目录或匿名卷。USER <user>:<group>:切换用户身份运行后续指令与容器进程,安全实践避免 root。HEALTHCHECK:定义健康检查命令,如HEALTHCHECK CMD curl -f http://localhost/ || exit 1。
相关高频面试题与简答
问:CMD 与 ENTRYPOINT 的区别?如何配合使用?
答:CMD 可被docker run参数完全覆盖,ENTRYPOINT 不可覆盖只能追加参数;常见模式ENTRYPOINT ["python"]+CMD ["app.py"],允许覆盖脚本但保持解释器不变。问:COPY 与 ADD 怎么选择?
答:优先用 COPY,语义明确;ADD 会自动解压 tar 且支持 URL,行为不透明易出错,仅在需要解压时使用;下载文件推荐RUN curl后删除压缩包减少层体积。问:如何减少 Dockerfile 构建层数与镜像体积?
答:合并 RUN 命令(用&&连接)、删除临时文件与缓存(如rm -rf /var/lib/apt/lists/*)、多阶段构建分离编译与运行环境、选用轻量 base 镜像(Alpine/distroless)、使用 .dockerignore 排除无关文件。问:多阶段构建的典型场景?
答:编译型语言(Go/Java/C++):第一阶段编译生成二进制,第二阶段仅复制可执行文件到轻量镜像,避免将编译工具链打包进最终镜像,显著减小体积。问:ARG 与 ENV 的区别?
答:ARG 仅构建时生效,运行时不可见,用于传递构建参数(如版本号);ENV 构建与运行时均生效,会持久化到镜像;敏感信息不应用 ARG(构建历史可见)或 ENV(环境变量泄露),应用 secret mount。问:如何优化 Docker 镜像缓存利用率?
答:按变更频率排序指令:先 COPY 依赖文件(package.json/requirements.txt)并 RUN 安装,再 COPY 源码,利用层缓存避免依赖重复安装;使用--cache-from指定缓存源。
典型 Dockerfile 示例
# 多阶段构建 - 编译阶段
FROM golang:1.20-alpine AS builder
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o app
# 运行阶段
FROM alpine:3.18
RUN apk add --no-cache ca-certificates
WORKDIR /app
COPY --from=builder /build/app .
USER nobody:nobody
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
ENTRYPOINT ["./app"]
CMD ["--port=8080"]