如何借助Hadolint编写高质量的 Dockerfile

2024-03-07 13:21:32 浏览数 (2)

前言

在容器化的世界中,Dockerfile 就像是构建轻量、便携和自包含应用环境的蓝图。但是创建组织良好且优化的 Dockerfile 可能有些棘手,需要仔细关注细节并遵循最佳实践。这就是 Hadolint 登场的地方,就像一位超级英雄,帮助您编写完美的 Dockerfile。

Hadolint是一个开源工具,它会自动检查您的Dockerfile是否存在任何问题。它使用一组预定义的规则和ShellCheck来检查您Dockerfile的每一行,确保您的镜像安全、快速,并符合行业标准。

在这个指南中,我们将学习如何使用 Hadolint 来编写高质量的 Dockerfile。

我们将探索 Hadolint 的代码检查过程、它的许多规则,以及如何将 Hadolint 纳入您的开发工作流程。

我们还将发现如何创建小巧、高效且安全免受常见安全弱点影响的镜像。

hadolint简介

Haskell Dockerfile Linter Hadolint 是一个 Dockerfile 文件检查工具,帮助您构建符合最佳实践的 Docker 镜像。我在所有项目中都使用它,以确保我创建的镜像小巧、安全、高效且易于维护。

使用代码检查工具来检查 Dockerfile 的原因有很多:

  • 遵循 Docker 镜像的最佳实践
  • 在编写 Dockerfile 时加快反馈速度,因为检查工具-可以在构建镜像之前发现语法错误和安全漏洞
  • 可以检查代码风格是否符合规范
  • 可以提高 Dockerfile 的可读性和可维护性
  • 在 CI/CD 流水线中使用它们
  • 更深入地了解如何编写更好的 Dockerfile

Hadolint配备了强大且易于使用的CLI。您可以在多种平台上安装它,包括macOS。

代码语言:javascript复制
$ brew install hadolint

请使用以下命令确认安装是否成功:

代码语言:javascript复制
$ hadolint --help
hadolint - Dockerfile Linter written in Haskell
...

让我们创建一个Dockerfile来测试这个工具,现在将以下内容添加到Dockerfile中。

代码语言:javascript复制
FROM python
MAINTAINER johndoe@gmail.com
LABEL org.website="containiq.com"
 
RUN mkdir app && cd app
 
COPY requirements.txt ./
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
 
COPY . .
 
CMD python manage.py runserver 0.0.0.0:80000

现在使用这个命令验证 Dockerfile:

代码语言:javascript复制
$ hadolint Dockerfile
Dockerfile:1 DL3006 warning: Always tag the version of an image explicitly
Dockerfile:1 DL3049 info: Label `maintainer` is missing.
Dockerfile:2 DL4000 error: MAINTAINER is deprecated
Dockerfile:3 DL3052 warning: Label `org.website` is not a valid URL.
Dockerfile:5 DL3003 warning: Use WORKDIR to switch to a directory
Dockerfile:5 SC2164 warning: Use 'cd ... || exit' or 'cd ... || return' in case cd fails.
Dockerfile:7 DL3045 warning: `COPY` to a relative destination without `WORKDIR` set.
Dockerfile:8 DL3013 warning: Pin versions in pip. Instead of `pip install <package>` use `pip install <package>==<version>` or `pip install --requirement <requirements file>`
Dockerfile:8 DL3042 warning: Avoid use of cache directory with pip. Use `pip install --no-cache-dir <package>`
Dockerfile:9 DL3059 info: Multiple consecutive `RUN` instructions. Consider consolidation.
Dockerfile:9 DL3042 warning: Avoid use of cache directory with pip. Use `pip install --no-cache-dir <package>`
Dockerfile:11 DL3045 warning: `COPY` to a relative destination without `WORKDIR` set.
Dockerfile:13 DL3025 warning: Use arguments JSON notation for CMD and ENTRYPOINT arguments

每行的结构如下:<LINE_NUMBER><RULE_CODE><SEVERITY_LEVEL>:

让我们更详细地探讨这些参数。

代码规则

一个规则代码以DL或SC为前缀。DL前缀表示该规则来自Hadolint直接。SC前缀表示该规则来自SpellCheck,这是一个用于shell脚本的静态分析工具,与Hadolint一起提供。您可以在这里找到规则的综合列表。

每个规则都有一个专门的文档页面,列出了代码示例、原理和其他重要细节。请查看DL3006的专门页面。

您可以使用--ignore RULECODE选项忽略一个或多个规则。

代码语言:javascript复制
$ hadolint --ignore DL3013 --ignore DL3042 Dockerfile

您也可以在 Dockerfile 中忽略规则。我更喜欢这种方法,因为您可以逐行排除规则代码,这样更清晰地知道违规实际发生在哪里。

代码语言:javascript复制
# hadolint ignore=DL3013
RUN pip install --upgrade pip

Hadolint拥有一个活跃的开源社区。新的规则代码定期添加,因此请确保定期检查您是否在运行最新版本的Hadolint。

安全级别

严重级别表示违规的严重程度。共有六个级别:错误(error)、警告(warning)、信息(info)、样式(style)、忽略(ignore)和无(none)。

CLI 包括一个 --failure-threshold(缩写为 -t)选项,用于排除特定严重级别导致失败。例如,如果您只希望 Hadolint 在错误违规时失败。

代码语言:javascript复制
$ hadolint -t error Dockerfile

请注意,来自其他严重级别的不符合规范行为仍将被报出来,但不会导致失败。

如果您不同意某个规则代码的严重级别,您可以通过使用--<SEVERITY_LEVEL> RULECODE选项轻松更改它。例如,以下命令将DL3006升级为错误,将DL3045降级为信息(这两个代码默认为警告):

代码语言:javascript复制
$ hadolint --error DL3006 --info DL3045 Dockerfile
Dockerfile:1 DL3006 error: Always tag the version of an image explicitly
Dockerfile:7 DL3045 info: `COPY` to a relative destination without `WORKDIR` set.

标签检查

Dockerfile标签是注释您的Docker镜像的绝佳工具。Hadolint提供了一些验证选项,以确保您的标签设置正确。

--require-label LABELSCHEMA选项验证您的标签是否遵循特定格式。您可以在这里查看所有可接受的格式值。

代码语言:javascript复制
$ hadolint --require-label maintainer:text --require-label org.website:url Dockerfile
Dockerfile:2 DL3049 info: Label `maintainer` is missing.
Dockerfile:3 DL3052 warning: Label `org.website` is not a valid URL.

The --strict-labels 选项会验证在您的模式中定义的标签之外是否有额外的标签。

代码语言:javascript复制
$ hadolint --require-label maintainer:text --strict-labels Dockerfile
Dockerfile:3 DL3050 info: Superfluous label(s) present.

配置文件

将选项手动传递到每次 Hadolint 运行中可能会很烦人且容易出错。Hadolint 很方便地提供了配置文件支持,可以将所有选项存储在一个地方。这个文件可以存在于各种位置,但我通常会将其放在存储库的根目录下,命名为 .hadolint.yaml。

代码语言:javascript复制
override:
 error:
   - DL3006
 info:
   - DL3045
label-schema:
 maintainer: text
 org.website: url
strict-labels: true

修复 Dockerfile

逐个解决每个错误是学习 Dockerfile 最佳实践的绝佳方法。如上所述,每条规则都有非常清晰和详细的文档页面。尝试一下,完成后再回顾这篇文章。

到这一步,Hadolint 应该不会报任何错误。你的文件应该看起来类似于这样:

代码语言:javascript复制
FROM python:3.10
LABEL maintainer="johndoe@gmail.com"
LABEL org.website="https://www.airplane.dev/"
 
WORKDIR /app
 
COPY requirements.txt ./
# hadolint ignore=DL3013
RUN pip install --upgrade --no-cache-dir pip && 
 pip install --no-cache-dir -r requirements.txt
 
COPY . .
 
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

需要进一步解释的一些变化:

  • 我们将使用最新可用的 Python 次要版本(目前为 3.10)标记 Python 基础镜像。我们不包括补丁版本(3.10.2),因为 Python 的补丁版本向后兼容,通常包含有用的 bug 修复。
  • 我通常喜欢使用/app工作目录来保持我的 Docker 镜像一致,但您可以使用任何您想要的新目录或现有目录。
  • 我们忽略 DL3013,因为我们想要下载最新版本的 pip。没有必要将其固定到特定版本。

集成

Hadolint包含许多方便的集成功能,可以在整个开发过程中自动运行代码检查工具。我最喜欢的集成有:

  • VS Code:直接在编辑器中运行Hadolint
  • pre-commit:在每次git提交时运行Hadolint
  • GitHub Actions:在GitHub的CI/CD中运行Hadolint

集成非常重要,特别是在较大的团队中,因为一些开发人员会忘记手动运行代码检查工具。我在开始新的Docker项目时立即设置这些集成。

总结

正如您所看到的,这个工具很容易上手,它可以在几秒钟内提高您的 Dockerfile 的质量。Hadolint 并不是唯一一个用于 Dockerfile 的代码检查工具。Docker 引擎本身也包含一个,但更多用于检查基本错误。此外,还有来自 Snyk 的一个代码检查工具,可能更专注于安全问题。

0 人点赞