Skip to content

Daily Study

更新: 5/26/2025 字数: 0 字 时长: 0 分钟

Daily Plan

#todo

K8s学习

Dockerfile常见指令

  • FROM: 指定基础镜像。所有后续指令都将基于此镜像。这是 Dockerfile 的第一条指令。例如: FROM ubuntu:latest
  • RUN: 在当前镜像之上的新层中执行任何命令并提交结果。常用于安装软件包。例如: RUN apt-get update && apt-get install -y python3
  • CMD: 提供容器启动时执行的默认命令。Dockerfile 中只能有一条 CMD 指令。如果有多条,只有最后一条会生效。如果 docker run 时指定了命令,则 CMD 的命令会被覆盖。例如: CMD ["python3", "app.py"]
  • ENTRYPOINT: 配置容器启动时运行的命令。与 CMD 类似,但 ENTRYPOINT 的命令不会被 docker run 命令行参数轻易覆盖,除非使用 --entrypoint 选项。通常用于将容器配置为可执行文件。例如: ENTRYPOINT ["nginx", "-g", "daemon off;"]
  • WORKDIR: 为 RUN, CMD, ENTRYPOINT, COPYADD 指令设置工作目录。如果目录不存在,会自动创建。例如: WORKDIR /app
  • COPY: 从构建上下文(通常是 Dockerfile 所在的目录)复制文件或目录到镜像的文件系统中。例如: COPY . /app
  • ADD: 功能与 COPY 类似,但有一些额外的特性,比如可以处理远程 URL 和自动解压归档文件。一般推荐优先使用 COPY,因为它的行为更明确。例如: ADD http://example.com/file.txt /appADD archive.tar.gz /app
  • ENV: 设置环境变量。这些环境变量在后续的 RUN 指令中可以使用,并且在容器运行时也会存在。例如: ENV APP_VERSION=1.0
  • ARG: 定义构建时变量。这些变量只在 Dockerfile 构建过程中可用,容器运行时不可用。可以在 docker build 时通过 --build-arg 参数传递。- - 例如: ARG USER_ID=1000
  • EXPOSE: 声明容器运行时监听的网络端口。这实际上是一个文档说明,并不会自动发布端口。在 docker run 时需要使用 -p-P 参数来实际映射端口。例如: EXPOSE 80
  • VOLUME: 创建一个挂载点,用于持久化数据或在容器间共享数据。例如: VOLUME /data
  • USER: 设置运行后续 RUN, CMDENTRYPOINT 指令时使用的用户名或 UID,以及可选的用户组或 GID。例如: USER appuser
  • LABEL: 为镜像添加元数据,如作者、版本等。例如: LABEL maintainer="example@example.com"
  • ONBUILD: 当构建的镜像作为另一个构建的基础镜像时,ONBUILD 指令才会被执行。例如: ONBUILD RUN echo "Building on top of this image"
  • HEALTHCHECK: 指定如何测试容器以检查其是否仍在工作。例如: HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1
  • SHELL: 允许覆盖用于 RUN, CMD, ENTRYPOINT 指令中 shell 形式命令的默认 shell。默认 shell 在 Linux 上是 ["/bin/sh", "-c"],在 Windows 上是 ["cmd", "/S", "/C"]。例如: SHELL ["/bin/bash", "-c"]

镜像打包技巧

  • 保持镜像精简 (Keep Images Small):
    • 选择合适的基础镜像: 从一个尽可能小的官方基础镜像开始(例如 alpine 版本)。
    • 清理不必要的依赖和文件: 在 RUN 指令的同一层中删除缓存和不需要的软件包。例如,apt-get cleanrm -rf /var/lib/apt/lists/*
    • 使用 .dockerignore 文件: 排除构建上下文中不需要的文件和目录,减少发送到 Docker 守护进程的数据量,加快构建速度。
  • 利用构建缓存 (Leverage Build Cache):
    • 合理安排指令顺序: 将不经常变化的指令(如安装固定版本的依赖)放在 Dockerfile 的前面,将经常变化的指令(如 COPY 源代码)放在后面。这样可以最大限度地利用缓存。
    • 避免不必要的缓存失效: 确保只有在真正需要时才修改文件。
  • 多阶段构建 (Multi-stage Builds):
    • 使用多阶段构建可以将编译、测试等构建过程和最终的运行时环境分离。最终镜像只包含运行应用程序所必需的文件,大大减小镜像体积并提高安全性。
    • 例如,一个阶段使用包含构建工具的镜像编译代码,另一个阶段将编译好的产物复制到一个干净的运行时镜像中。
  • 最小化层数 (Minimize Layers):
    • 虽然缓存很重要,但过多的层也会增加镜像的复杂性和潜在的体积。尽可能将相关的 RUN 命令合并到一条指令中,使用 && 连接。
    • 例如: RUN apt-get update && apt-get install -y package1 package2 && rm -rf /var/lib/apt/lists/*
  • 明确指令 (Be Specific):
    • 明确指定软件包版本: 例如 apt-get install -y python3=3.9.*,避免因基础镜像更新导致构建失败或行为不一致。
    • 使用 COPY 而不是 ADD: 除非你需要 ADD 的特定功能(如解压或添加远程文件),否则优先使用 COPY,因为它的行为更透明。
  • 安全考虑 (Security Considerations):
    • 不要以 root 用户运行: 在 Dockerfile 的末尾使用 USER 指令切换到非 root 用户运行应用程序,以减少潜在的安全风险。
    • 不存储敏感数据: 不要在 Dockerfile 中硬编码密码、密钥等敏感信息。使用环境变量、卷或者 Docker secrets 来管理。
    • 定期更新基础镜像和依赖: 修复已知的安全漏洞。
  • 使用 CMDENTRYPOINT 的最佳实践:
    • 通常将 ENTRYPOINT 用于设置镜像的主要执行命令,将 CMD 用于传递默认参数。
    • 推荐使用 JSON 数组格式(exec form),例如 CMD ["executable", "param1", "param2"],而不是 shell 格式 CMD executable param1 param2,以避免 shell 解析带来的问题。

如下可以将 300MB 大小的镜像变成只有 20MB 的镜像,甚至压缩上传到 DockerHub 后大小只有 10MB!:

# Dockerfile 
FROM golang:1.16-buster AS builder 
RUN mkdir /src 
ADD . /src 
WORKDIR /src 
RUN go env -w GO111MODULE=auto 
RUN go build -o main . 
FROM gcr.io/distroless/base-debian10 
WORKDIR / 
COPY --from=builder /src/main /main 
EXPOSE 3000 
ENTRYPOINT ["/main"]
  1. 多阶段构建 (Multi-Stage Build)
    • 第一阶段 (FROM golang:1.24-buster AS builder) 用于编译
    • 第二阶段 (FROM gcr.io/distroless/base-debian10) 只包含运行时所需组件
    • 这样避免了编译环境、开发工具链、依赖包等进入最终镜像
  2. Distroless 基础镜像
    • gcr.io/distroless/base-debian10 是专为运行应用程序设计的极简镜像
    • 不包含 shell、包管理器和其他非必要工具
    • 比标准 Debian 镜像小很多,通常只有几十 MB
  3. 只复制必要文件
    • COPY --from=builder /src/main /main 仅复制编译好的二进制文件
    • 不包含源代码、中间构建产物或开发依赖

菜就多练

本站访客数 人次 本站总访问量