hadolint

Dockerfile linter,验证用 Haskell 编写的内联 bash。「 Dockerfile linter, validate inline bash, written in Haskell. 」

Github stars Tracking Chart

Haskell Dockerfile Linter

更智能的 Dockerfile linter,可帮助您构建最佳实践 Docker 镜像。 linter 将 Dockerfile 解析为 AST 并在 AST 之上执行规则。 它站在 ShellCheck 的肩膀上,在 RUN 指令中输入 Bash 代码。

如何使用

您可以在本地运行 hadolint 来 lint 您的 Dockerfile。

hadolint <Dockerfile>
hadolint --ignore DL3003 --ignore DL3006 <Dockerfile> # exclude specific rules
hadolint --trusted-registry my-company.com:500 <Dockerfile> # Warn when using untrusted FROM images

Docker 提供了一种在大多数平台上运行 hadolint 的简单方法。只需将 Dockerfile 管道到 docker run

docker run --rm -i hadolint/hadolint < Dockerfile

安装

您可以从最新版本页面下载 OSX、Windows 和 Linux 的预构建二进制文件。 但是,如果它不适合您,请回到 Docker、brew 或源安装。

如果您使用的是 OSX,则可以使用 brew 来安装 hadolint。

brew install hadolint

在 Windows 上,您可以使用 scoop 来安装 hadolint。

scoop install hadolint

如前所示,hadolint 可用作 Docker 容器:

docker pull hadolint/hadolint

如果您需要具有 shell 访问权限的 Docker 容器,请使用 Docker 镜像的 Debian 变体:

docker pull hadolint/hadolint:latest-debian

您还可以在本地构建 hadolint。 您需要 Haskell堆栈 构建工具来构建二进制文件。

git clone https://github.com/hadolint/hadolint
cd hadolint
stack install

配置

hadolint 支持使用配置文件指定被忽略的规则。 配置文件应为 yaml 格式。 这是一个有效的配置文件作为示例:

ignored:
  - DL3000
  - SC1010

此外,当 Dockerfiles 中使用来自不受信任的存储库的映像时,hadolint 可以发出警告,您可以将 trustedRegistries 密钥附加到配置文件,如下所示:

ignored:
  - DL3000
  - SC1010
trustedRegistries:
  - docker.io
  - my-company.com:5000

配置文件可以在全局或按项目使用。 默认情况下,hadolint 将在当前目录中查找名称为 .hadolint.yaml 的配置文件

全局配置文件应放在 XDG_CONFIG_HOME 指定的文件夹中,名称为 hadolint.yaml。 总之,以下位置对配置文件有效,按顺序或首选项:

  • $PWD/.hadolint.yaml
  • $XDG_CONFIG_HOME/hadolint.yaml
  • ~/.config/hadolint.yaml

在Windows中,使用 %LOCALAPPDATA% 环境变量而不是 XDG_CONFIG_HOME

此外,您可以使用 --config 选项在命令行中传递自定义配置文件

hadolint --config /path/to/config.yaml Dockerfile

内联忽略(Inline ignores)

也可以通过在Dockerfile指令的正上方使用特殊注释来忽略规则。 忽略规则注释看起来像 # hadolint ignore=DL3001,SC1081。 例如:

# hadolint ignore=DL3006
FROM ubuntu
# hadolint ignore=DL3003,SC1035
RUN cd /tmp && echo "hello!"

内联忽略仅在位于指令正上方时才有效。

集成

要获得大部分的 hadolint,最好将它集成为 CI 或编辑器的检查,以便在编写 Dockerfile 时对其进行梳理。请参阅我们的集成文档。

规则

实施规则的不完整列表。 单击错误代码以获取更多详细信息。

  • 带有前缀 DL 的规则源自 hadolint。 查看 Rules.hs 以查找规则的实现。
  • 带有 SC 前缀的规则源自 ShellCheck(仅列出最常见的规则,还有几十个规则)

规则表(恕删略)

开发

如果您是一位经验丰富的 Haskeller,我们将非常感谢您在评审中分解我们的代码。

构建

  1. 克隆存储库
    git clone --recursive git@github.com:hadolint/hadolint.git
  2. 安装依赖项
    stack install

REPL

尝试解析器的最简单方法是使用 REPL。

# start the repl
stack repl
# parse instruction and look at AST representation
parseString "FROM debian:jessie"

测试

运行单元测试。

stack test

运行集成测试。

./integration_test.sh

AST

Dockerfile 语法在 Dockerfile 参考中有完整描述。 只需查看 language-docker 项目中的 Syntax.hs 即可查看 AST 定义。

备择方案

(First edition: vz edited at 2019.08.23)

Main metrics

Overview
Name With Ownerhadolint/hadolint
Primary LanguageHaskell
Program languageHaskell (Language Count: 4)
PlatformDocker, Linux, Mac, Windows
License:GNU General Public License v3.0
所有者活动
Created At2015-11-15 20:20:58
Pushed At2025-03-24 08:35:52
Last Commit At2025-03-22 18:03:08
Release Count83
Last Release Namev2.13.1-beta (Posted on 2024-10-03 21:14:16)
First Release Namev1.0 (Posted on )
用户参与
Stargazers Count11.2k
Watchers Count72
Fork Count453
Commits Count1.2k
Has Issues Enabled
Issues Count628
Issue Open Count218
Pull Requests Count388
Pull Requests Open Count23
Pull Requests Close Count53
项目设置
Has Wiki Enabled
Is Archived
Is Fork
Is Locked
Is Mirror
Is Private

Linux/OSX Build Status
Windows Build status
GPL-3 licensed
GitHub release
Github downloads

Haskell Dockerfile Linter

A smarter Dockerfile linter that helps you build best practice Docker
images. The linter is parsing the Dockerfile into an AST and performs rules on
top of the AST. It is standing on the shoulders of ShellCheck to lint
the Bash code inside RUN instructions.

:globe_with_meridians: Check the online version on
hadolint.github.io/hadolint

Screenshot

How to use

You can run hadolint locally to lint your Dockerfile.

hadolint <Dockerfile>
hadolint --ignore DL3003 --ignore DL3006 <Dockerfile> # exclude specific rules
hadolint --trusted-registry my-company.com:500 <Dockerfile> # Warn when using untrusted FROM images

Docker comes to the rescue to provide an easy way how to run hadolint on most
platforms.
Just pipe your Dockerfile to docker run:

docker run --rm -i hadolint/hadolint < Dockerfile

Install

You can download prebuilt binaries for OSX, Windows and Linux from the latest
release page. However, if it doesn't work for you, please fall back to
Docker, brew or source installation.

If you are on OSX you can use brew to install hadolint.

brew install hadolint

On Windows you can use scoop to install hadolint.

scoop install hadolint

As shown before, hadolint is available as a Docker container:

docker pull hadolint/hadolint

If you need a Docker container with shell access, use the Debian or Alpine
variants of the Docker image:

docker pull hadolint/hadolint:latest-debian
docker pull hadolint/hadolint:latest-alpine

You can also build hadolint locally. You need Haskell and the stack
build tool to build the binary.

git clone https://github.com/hadolint/hadolint
cd hadolint
stack install

Configure

hadolint supports specifying the ignored rules using a configuration file. The configuration
file should be in yaml format. This is one valid configuration file as an example:

ignored:
  - DL3000
  - SC1010

Additionally, hadolint can warn you when images from untrusted repositories are being
used in Dockerfiles, you can append the trustedRegistries keys to the configuration
file as shown below:

ignored:
  - DL3000
  - SC1010

trustedRegistries:
  - docker.io
  - my-company.com:5000

Configuration files can be used globally or per project. By default, hadolint will look for
a configuration file in the current directory with the name .hadolint.yaml

The global configuration file should be placed in the folder specified by XDG_CONFIG_HOME,
with the name hadolint.yaml. In summary, the following locations are valid for the configuration
file, in order or preference:

  • $PWD/.hadolint.yaml
  • $XDG_CONFIG_HOME/hadolint.yaml
  • ~/.config/hadolint.yaml

In windows, the %LOCALAPPDATA% environment variable is used instead of XDG_CONFIG_HOME

Additionally, you can pass a custom configuration file in the command line with
the --config option

hadolint --config /path/to/config.yaml Dockerfile

Inline ignores

It is also possible to ignore rules by using a special comment directly above the Dockerfile
instruction you want to make an exception for. Ignore rule comments look like
# hadolint ignore=DL3001,SC1081. For example:

# hadolint ignore=DL3006
FROM ubuntu

# hadolint ignore=DL3003,SC1035
RUN cd /tmp && echo "hello!"

Inline ignores will only work if place directly above the instruction.

Integrations

To get most of hadolint it is useful to integrate it as a check to your CI
or to your editor to lint your Dockerfile as you write it. See our
Integration docs.

Rules

An incomplete list of implemented rules. Click on the error code to get more
detailed information.

  • Rules with the prefix DL originate from hadolint. Take a look at
    Rules.hs to find the implementation of the rules.

  • Rules with the SC prefix originate from ShellCheck (Only the most
    common rules are listed, there are dozens more)

Please create an issue if you have an idea for a good rule., Rule, Description, :-------------------------------------------------------------, :----------------------------------------------------------------------------------------------------------------------------------------------------, DL3000, Use absolute WORKDIR., DL3001, For some bash commands it makes no sense running them in a Docker container like ssh, vim, shutdown, service, ps, free, top, kill, mount, ifconfig., DL3002, Last user should not be root., DL3003, Use WORKDIR to switch to a directory., DL3004, Do not use sudo as it leads to unpredictable behavior. Use a tool like gosu to enforce root., DL3005, Do not use apt-get upgrade or dist-upgrade., DL3006, Always tag the version of an image explicitly., DL3007, Using latest is prone to errors if the image will ever update. Pin the version explicitly to a release tag., DL3008, Pin versions in apt-get install., DL3009, Delete the apt-get lists after installing something., DL3010, Use ADD for extracting archives into an image., DL3011, Valid UNIX ports range from 0 to 65535., DL3012, Provide an email address or URL as maintainer., DL3013, Pin versions in pip., DL3014, Use the -y switch., DL3015, Avoid additional packages by specifying --no-install-recommends., DL3016, Pin versions in npm., DL3017, Do not use apk upgrade., DL3018, Pin versions in apk add. Instead of apk add <package> use apk add <package>=<version>., DL3019, Use the --no-cache switch to avoid the need to use --update and remove /var/cache/apk/* when done installing packages., DL3020, Use COPY instead of ADD for files and folders., DL3021, COPY with more than 2 arguments requires the last argument to end with /, DL3022, COPY --from should reference a previously defined FROM alias, DL3023, COPY --from cannot reference its own FROM alias, DL3024, FROM aliases (stage names) must be unique, DL3025, Use arguments JSON notation for CMD and ENTRYPOINT arguments, DL3026, Use only an allowed registry in the FROM image, DL3027, Do not use apt as it is meant to be a end-user tool, use apt-get or apt-cache instead, DL3028, Pin versions in gem install. Instead of gem install <gem> use gem install <gem>:<version>, DL4000, MAINTAINER is deprecated., DL4001, Either use Wget or Curl but not both., DL4003, Multiple CMD instructions found., DL4004, Multiple ENTRYPOINT instructions found., DL4005, Use SHELL to change the default shell., DL4006, Set the SHELL option -o pipefail before RUN with a pipe in it, SC1000, $ is not used specially and should therefore be escaped., SC1001, This \c will be a regular 'c' in this context., SC1007, Remove space after = if trying to assign a value (or for empty string, use var='' ...)., SC1010, Use semicolon or linefeed before done (or quote to make it literal)., SC1018, This is a unicode non-breaking space. Delete it and retype as space., SC1035, You need a space here, SC1045, It's not foo &; bar, just foo & bar., SC1065, Trying to declare parameters? Don't. Use () and refer to params as $1, $2 etc., SC1066, Don't use $ on the left side of assignments., SC1068, Don't put spaces around the = in assignments., SC1077, For command expansion, the tick should slant left (` vs ´)., SC1078, Did you forget to close this double-quoted string?, SC1079, This is actually an end quote, but due to next char, it looks suspect., SC1081, Scripts are case sensitive. Use if, not If., SC1083, This {/} is literal. Check expression (missing ;/\n?) or quote it., SC1086, Don't use $ on the iterator name in for loops., SC1087, Braces are required when expanding arrays, as in ${array[idx]}., SC1095, You need a space or linefeed between the function name and body., SC1097, Unexpected ==. For assignment, use =. For comparison, use [/[[., SC1098, Quote/escape special characters when using eval, e.g. eval "a=(b)"., SC1099, You need a space before the #., SC2002, Useless cat. Consider cmd < file | .. or cmd file | .. instead., SC2015, Note that A && B || C is not if-then-else. C may run when A is true., SC2026, This word is outside of quotes. Did you intend to 'nest '"'single quotes'"' instead'?, SC2028, echo won't expand escape sequences. Consider printf., SC2035, Use ./*glob* or -- *glob* so names with dashes won't become options., SC2039, In POSIX sh, something is undefined., SC2046, Quote this to prevent word splitting, SC2086, Double quote to prevent globbing and word splitting., SC2140, Word is in the form "A"B"C" (B indicated). Did you mean "ABC" or "A\"B\"C"?, SC2154, var is referenced but not assigned., SC2155, Declare and assign separately to avoid masking return values., SC2164, Use cd ... || exit in case cd fails., ## Develop

If you are an experienced Haskeller we would be really thankful if you would
tear our code apart in a review.

Setup

  1. Clone repository

    git clone --recursive git@github.com:hadolint/hadolint.git
    
  2. Install the dependencies

    stack install
    

REPL

The easiest way to try out the parser is using the REPL.

# start the repl
stack repl
# parse instruction and look at AST representation
parseString "FROM debian:jessie"

Tests

Run unit tests.

stack test

Run integration tests.

./integration_test.sh

AST

Dockerfile syntax is fully described in the Dockerfile reference. Just take
a look at Syntax.hs in the language-docker project to see the AST definition.

Alternatives