「hadolint」にシバかれながら美しいDockerfileを書き上げる

hadolintとは

hadolintはDockerfile用のLintツールだ。

たとえば、下記のようなDockerfileを作って、チェックしてみる。

FROM alpine

RUN cd /tmp && echo 'hello'

すると、次のような警告をしてくれるようになる。

/dev/stdin:1 DL3006 Always tag the version of an image explicitly
/dev/stdin:3 DL3003 Use WORKDIR to switch to a directory

Lintルール

雰囲気をつかむために、いくつかのルールを抜粋しよう。

  • DL3002 - 最終ユーザをrootにしてはいけない
  • DL3006 - イメージには常に明示的にタグを指定する
  • DL3008 - バージョンを指定してapt-get installする
  • DL4000 - MAINTAINER は非推奨なので使わない

これら以外に、どんなルールでチェックされるかは、公式のREADMEのRulesを確認しよう。

それでは、前置きはこのぐらいにして実際に使ってみよう。

インストール

公式でDockerイメージが提供されているので、それを使うのが簡単だ。筆者はDocker版を使っている。

$ docker pull hadolint/hadolint

macOSであれば、Homebrewでインストールしてもよい。

$ brew install hadolint

使い方

ベーシックな使い方

ここではDocker版をベースに紹介する。Dockerfileを標準入力として実行するだけだ。

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

特定のルールを除外する

--ignoreオプションを使えば、特定のルールを除外できる。

$ docker run --rm -i hadolint/hadolint hadolint - --ignore DL3006 < Dockerfile

出力フォーマットの指定

--formatオプションで指定できる。 出力フォーマットは「tty、jsoncheckstyle、codeclimate、codacy」の中から選択できる。

tty

デフォルトはttyで、何も指定しない場合と同様の結果になる。

$ docker run --rm -i hadolint/hadolint hadolint - --format tty < Dockerfile
/dev/stdin:1 DL3006 Always tag the version of an image explicitly
/dev/stdin:3 DL3003 Use WORKDIR to switch to a directory

json

他のCLIツールと組み合わせるなら、json形式が役立つかもしれない。

$ docker run --rm -i hadolint/hadolint hadolint - --format json < Dockerfile | jq .
[
  {
    "line": 1,
    "code": "DL3006",
    "message": "Always tag the version of an image explicitly",
    "column": 1,
    "file": "/dev/stdin",
    "level": "warning"
  },
  {
    "line": 3,
    "code": "DL3003",
    "message": "Use WORKDIR to switch to a directory",
    "column": 1,
    "file": "/dev/stdin",
    "level": "warning"
  }
]

checkstyle

CIでCheckStyleを使っている場合は、checkstyle形式で出力すると便利だろう。codeclimate、codacyも同様の用途と思われる。

$ docker run --rm -i hadolint/hadolint hadolint - --format checkstyle < Dockerfile
<?xml version='1.0' encoding='UTF-8'?><checkstyle version='4.3'><file name='/dev/stdin' ><error line='1' column='1' severity='warning' message='Always tag the version of an image explicitly' source='DL3006' /><error line='3' column='1' severity='warning' message='Use WORKDIR to switch to a directory' source='DL3003' /></file></checkstyle>

ヘルプ

$ docker run --rm hadolint/hadolint hadolint --help
hadolint - Dockerfile Linter written in Haskell

Usage: hadolint [-v|--version] [-c|--config FILENAME] [-f|--format ARG]
                [DOCKERFILE...] [--ignore RULECODE]
                [--trusted-registry REGISTRY (e.g. docker.io)]
  Lint Dockerfile for errors and best practices

Available options:
  -h,--help                Show this help text
  -v,--version             Show version
  -c,--config FILENAME     Path to the configuration file
  -f,--format ARG          The output format for the results [tty | json |
                           checkstyle | codeclimate | codacy] (default: tty)
  --ignore RULECODE        A rule to ignore. If present, the ignore list in the
                           config file is ignored
  --trusted-registry REGISTRY (e.g. docker.io)
                           A docker registry to allow to appear in FROM
                           instructions

バージョン確認

$ docker run --rm -i hadolint/hadolint hadolint --version
Haskell Dockerfile Linter v1.13.0-2-g8623159

設定ファイル

hadolintはYAMLフォーマットの設定ファイルをサポートしている。

ignored:
  - DL3006

これをDockerfileと同じディレクトリに .hadolint.yaml という名前で保存しよう。実行するときは下記コマンドを叩く。

$ docker run --rm -v "$PWD:/work" -w /work hadolint/hadolint hadolint Dockerfile

.hadolint.yaml以外の名前のファイル名にしたい場合は、--configオプションで設定ファイルを指定すれば良い。

$ docker run --rm -v "$PWD:/work" -w /work hadolint/hadolint hadolint --config myconfig.yml Dockerfile

特定の行のチェックを除外する

特定の行を hadolint のチェック対象から除外する場合は、Dockerfileにその設定を直接記述することになる。

FROM alpine

# hadolint ignore=DL3003
RUN cd /tmp && echo 'hello'

このように書くと、記事冒頭の例から、一つ警告を除外することができる。ただし、乱用は厳禁だ。

おわりに

Dockerfileには様々なベストプラクティスやアンチパターンが存在する。長い時間をかけて習得するのも悪くないが、hadolintがあれば、一気にショートカットして、あなたのDockerfileのクオリティを上げることができる。

最初はちょびっと小うるさいが、慣れてくるとhadolintなしでDockerfileを書くなんてとんでもない!という気持ちになってくるので、ぜひ試してみてほしい。