Docker 允许开发人员将应用程序及其依赖项打包成一个轻量级、便携的容器。然而,在性能和安全性要求高的生产环境中,创建高效且安全的 Docker 镜像尤为重要。在本文中,我们将探讨最佳实践,帮助您编写更优化且更安全的 Dockerfile,确保您的容器更小巧、更快、更稳健。
I. 选择正确的基础图像
基础镜像构成了容器的基础。选择一个轻量级的基础镜像可以大大减小镜像的体积,同时也能减少安全风险。
- 尽可能使用官方的 Docker 镜像,因为它们会得到维护并定期更新。
- 优先选择轻量级的镜像,如 alpine,而不是像 ubuntu 或 debian 这样的完整 OS 镜像。Alpine 大约 5 MB,Ubuntu 则是 100 多 MB:例如,使用下面的 Dockerfile 指令:
FROM node:20-alpine
II. 利用多阶段构建来创建更小的映像
多阶段构建允许你将构建阶段与最终生产镜像分离,确保最终的镜像里只有运行环境需要的文件。这有助于减小镜像的体积并去除构建时所需的依赖。
- 使用多阶段构建一次性编译或构建您的应用程序,并将必要的构建产物复制到下一阶段。
III. 减少层次
每个 Dockerfile 中的命令都会在最终镜像中添加一个新的层。减少层数并合并命令可以使得镜像更高效。
- 将多个
RUN
命令合并到一个层中。 - 不要添加不必要的文件到镜像中。
# 请使用以下替代方案,而不是使用:
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean
# 使用以下代码:
RUN apt-get update && \
apt-get install -y curl && \
apt-get clean
全屏模式 退出全屏
使用 .dockerignore
文件
就像 .gitignore
一样,.dockerignore
帮助排除不必要的文件,以减少 Docker 镜像的大小,并防止敏感文件(如 env 文件或 Git 目录)包含在构建过程中。
将不必要的文件(如文档、.git
目录和本地配置文件等)加入 .dockerignore
列表中。
# .dockerignore 文件
# 忽略 node_modules 目录
# 忽略 .git 目录
# 忽略 .env 文件
# README.md (说明文件)
全屏 退出全屏
V. 设置用户权限配置
默认,Docker 容器以 root 用户运行,这可能带来安全风险。尽量用非 root 用户运行容器,是个好习惯。
- 使用 USER 指令切换到非 root 用户身份。
- 在 Dockerfile 中添加一个用户,如果基础镜像中没有该用户。
# 添加并切换到用户
运行 `addgroup -S appgroup && adduser -S appuser -G appgroup`
切换用户到 `appuser`
命令 `./myapp`
点击这里进入全屏模式,点击这里退出全屏模式
第六部分. 使用构建参数配置优化缓存设置
Docker 在构建时会缓存每个层,这有助于加快后续的构建。然而,但如果缓存不当,可能会导致依赖项过时,或让构建效率降低。通过使用构建参数,可以帮助控制何时刷新缓存。
- 例如,将用于复制源代码的
COPY
命令放在安装依赖之后。例如:- 将经常变化的命令(例如用于复制源代码的
COPY
命令)放在更稳定的命令(如安装依赖)之后。
- 将经常变化的命令(例如用于复制源代码的
# 首先安装依赖包(可缓存)
COPY package.json .
RUN npm install
# 然后添加源代码(可能会经常变动)
COPY . .
CMD ["npm", "start"]
进入全屏 退出全屏
通过在源代码之前复制package.json
文件,您可以使Docker缓存依赖层,从而节省重建时间。
VII. 使用官方提供的 Docker 镜像扫描工具
Docker 镜像可能包含安全漏洞。定期使用如 Docker Scan 或 AWS ECR Image Scanning 这样的工具来扫描您的镜像,以便发现并解决潜在的问题。
- 将安全扫描集成到 CI/CD 管道中,以便尽早捕获漏洞。
- 例如使用 Docker Scan 这样的工具。
VIII. 避免硬编码秘密
避免将敏感信息(如 API 密钥、密码或令牌)直接写入 Dockerfile 中。相反,应通过环境变量或 Docker Secrets 来安全传递这些信息。
- 使用
ARG
和ENV
进行动态配置,但确保它们的安全传递。 - 生产部署时,建议使用 Docker Secrets 或其他密钥管理工具。
ARG API_KEY
ENV API_KEY=$API_KEY
进入全屏模式,退出全屏模式
IX. 安装依赖后,清理一下依赖。
安装包或依赖后,务必清理产生的临时文件和缓存,以保持容器精简。
- 使用
apt-get clean
或其他包管理器的相应命令。 - 安装完成后,删除任何临时文件。
更新软件包列表并安装curl,然后清理缓存和删除临时文件.
RUN apt-get update && \
apt-get install -y curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
进入全屏,退出全屏
第X点:使用 COPY 代替 ADD
虽然 ADD 可用于复制文件和获取远程的 URL,但使用 COPY
进行本地文件传输更安全也更明确。仅在需要解压 tar 文件或下载远程的文件时才使用 ADD
。
-
使用
COPY
复制本地文件以避免意外行为。 - 只在需要像获取远程文件这样的高级用例时使用
ADD
。
此处省略
这里是一个包含最佳做法的Dockerfile示例:
# Stage 1: 构建阶段 - 使用多阶段构建以生成更小的镜像文件
FROM node:20-alpine AS builder
# 设置工作目录
WORKDIR /app
# 安装依赖(缓存层)
COPY package.json package-lock.json ./
RUN npm install --production && \
# 清理 npm 缓存
npm cache clean --force
# 复制源文件
COPY . .
# 构建应用
RUN npm run build
# 移除开发依赖和不必要的文件
RUN rm -rf ./src ./tests ./node_modules && \
npm install --production && \
# 清理任何临时文件
npm cache clean --force && \
rm -rf /var/cache/apk/* /tmp/*
# Stage 2: 生产环境 - 创建一个更轻量的最终镜像文件
FROM node:20-alpine
# 设置工作目录
WORKDIR /app
# 从构建阶段复制必要的文件
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
# 添加一个非 root 用户确保安全
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
# 暴露应用运行的端口
EXPOSE 3000
# 启动应用程序
CMD ["node", "dist/index.js"]
# .dockerignore
# 忽略的文件和目录,如 node_modules 和 .git 等
node_modules
.git
.env
README.md
Dockerfile
进入全屏 退出全屏
共同學(xué)習(xí),寫下你的評(píng)論
評(píng)論加載中...
作者其他優(yōu)質(zhì)文章