前面了解了Docker的基本概念,今天来认识一下DockerFile。

Dockerfile 是一个文本文件,包含一系列指令来组装 Docker 镜像。每个指令执行一个特定动作,例如安装包、复制文件或定义启动命令。正确使用 Dockerfile 指令对于构建高效容器至关重要。

关键 Dockerfile 指令

  • FROM:设置新镜像的基础镜像。
  • RUN:在当前镜像之上的新层执行命令并提交结果。
  • CMD:指定容器启动时默认运行的命令。
  • COPY:从构建上下文复制文件和目录到容器文件系统。
  • ADD:与 COPY 类似,但具有解压归档等附加功能。
  • ENV:设置环境变量。
  • EXPOSE:告知 Docker 容器在运行时监听的端口。
  • ENTRYPOINT:配置容器作为可执行文件运行。
  • VOLUME:为外部存储卷创建挂载点。
  • WORKDIR:设置后续指令的工作目录。

Dockerfile精华知识点

使用最小基础镜像

基础镜像是您的 Docker 镜像的基础。选择轻量级基础镜像可以显著减少最终镜像大小并最小化攻击面。

  • Alpine Linux:一个流行的最小镜像,大约 5 MB 大小。
FROM alpine:latest

优点:体积小、安全性高、下载速度快。

缺点:可能需要额外配置;一些包可能缺失或因使用 musl 而不是 glibc 而表现不同。

  • Scratch:一个空镜像,适合可以编译静态二进制文件的语言(Go、Rust)。
FROM scratch
COPY myapp /myapp
CMD ["/myapp"]

减少层数

每个 RUNCOPYADD 指令都会向您的镜像添加一个新层。合并命令有助于减少层数和整体镜像大小。

低效:

RUN apt-get update
RUN apt-get install -y python
RUN apt-get install -y pip

高效:

RUN apt-get update && apt-get install -y \
    python \
    pip \
 && rm -rf /var/lib/apt/lists/*

优化层缓存

Docker 使用层缓存来加快构建速度。指令的顺序影响缓存效率。

  • 先复制依赖文件:先复制变化较少的文件(如 package.jsonrequirements.txt),然后再复制其余的源代码。
COPY package.json .
RUN npm install
COPY . .
  • 最小化早期层的变化:早期层的变化会使所有后续层的缓存失效。

明智地安装依赖

安装包后删除临时文件和缓存以减少镜像大小。

RUN pip install --no-cache-dir -r requirements.txt

谨慎管理密钥

永远不要在您的 Dockerfile 中包含敏感数据(密码、API 密钥)。

  • 使用环境变量:在运行时使用环境变量传递密钥。
  • 利用 Docker 密钥:使用 Docker Swarm 或 Kubernetes 机制管理密钥。

优化镜像大小

  • 删除不必要的文件:在同一 RUN 命令中清理缓存、日志和临时文件。这确保这些临时文件不会在任何中间层中持久存在,有效减少最终镜像大小。
RUN apt-get update && apt-get install -y --no-install-recommends package \
      && apt-get clean && rm -rf /var/lib/apt/lists/*
  • 最小化安装的包:使用 --no-install-recommends 等标志只安装所需的包。这避免了不必要的依赖项,进一步减小镜像大小。
RUN apt-get install -y --no-install-recommends package

注意:为了最大化减少镜像大小,请将此安装与清理命令结合在同一个 RUN 语句中,如上所示。

  • 使用优化工具:利用 Docker Slim 等工具可以自动分析和优化您的 Docker 镜像,通过移除不必要的组件和减小大小而不改变功能。

利用 .dockerignore

.dockerignore 文件允许您排除构建上下文中的文件和目录,减少发送到 Docker 守护进程的数据量,并保护敏感信息。

示例 .dockerignore:

.git
node_modules
Dockerfile
.dockerignore

采用多阶段构建

多阶段构建允许您使用中间镜像,并将仅必要的构件复制到最终镜像中。

Go 应用程序的示例:

# 构建阶段
FROM golang:1.16-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp

# 最终镜像
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/myapp .
CMD ["./myapp"]

以非根用户运行

为了增强安全性,避免以 root 用户运行应用程序。

RUN adduser -D appuser
USER appuser

扫描漏洞

  • 使用扫描工具TrivyAnchoreClair 等工具可以帮助识别已知漏洞。
  • 定期更新镜像:保持基础镜像和依赖项更新。

日志和监控

  • 将日志导向 STDOUT/STDERR:这允许更容易地收集和分析日志。
  • 集成监控系统:使用 Prometheus 或 ELK Stack 等工具监控容器健康。

案例

下面来看一下Node.js 应用程序的优化 Dockerfile 示例

# 使用基于 Alpine Linux 的官方 Node.js 镜像
FROM node:14-alpine

# 设置工作目录
WORKDIR /app

# 复制包文件并安装依赖
COPY package*.json ./
RUN npm ci --only=production

# 复制其余的应用程序代码
COPY . .

# 创建非根用户并切换到它
RUN addgroup appgroup && adduser -S appuser -G appgroup
USER appuser

# 暴露应用程序端口
EXPOSE 3000

# 定义运行应用程序的命令
CMD ["node", "app.js"]

其他建议

  • 固定版本:使用基础镜像和包的特定版本以确保构建的可重现性。
FROM node:14.17.0-alpine
  • 保持更新:定期更新依赖项和基础镜像以包含安全补丁。
  • 使用元数据:添加 LABEL 指令以提供镜像元数据。
LABEL maintainer="yourname@example.com"
  • 设置适当的权限:确保文件和目录具有适当的权限。
  • 避免使用根用户:始终切换到非根用户运行应用程序。

结论

创建高效的 Docker 镜像既是一门艺术,也是一门科学。通过遵循编写 Dockerfile 的最佳实践,您可以显著提高容器的性能、安全性和管理性。不断更新您的知识,了解容器化生态系统中的新工具和方法。记住,优化是一个持续的过程,总有改进的空间。

本文由mdnice多平台发布


Miniwa
29 声望0 粉丝