Dockerfileの静的解析ツールが便利すぎた


背景

Dockerfileを静的解析したいと思い便利なツールがないかと探していたら発見しました。
DockerfileのLintツール

hadolint/hadolint

エラーが出るDockerfileをビルド前に検知してくれます。
ちなみにHaskellで書かれているようです。
現時点での最新バージョンはv1.15.0でmac等にも対応している。
GitHubのスター数は1000程である。

lintとは

wikiより引用

lint とは、主にC言語のソースコードに対し、コンパイラよりも詳細かつ厳密なチェックを行うプログラムである。
型の一致しない関数呼び出し
初期化されていない変数の参照
宣言されているが使われていない変数
同じ関数を参照しているが、戻り値を使う場合と使わない場合がある[疑問点 – ノート]
関数が戻り値を返す場合と返さない場合がある
など、コンパイラではチェックされないが、バグの原因になるような曖昧な記述についても警告される

導入手順

特に特別な手順はありません
バイナリをダウンロードして実行するだけで解析が始まります。

$ curl -L -O https://github.com/hadolint/hadolint/releases/download/v1.15.0/hadolint-Linux-x86_64
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   611    0   611    0     0    935      0 --:--:-- --:--:-- --:--:--   935
100 3561k  100 3561k    0     0   536k      0  0:00:06  0:00:06 --:--:--  767k

$ chmod +x hadolint-Linux-x86_64

実行

実行はバイナリを実行し引数にdockerfileを与えるのみで解析してくれます。

FROM debian:latest
MAINTAINER ryuichi1208

COPY package.json usr/src/app
RUN cd /usr/src/app \
    && npm install node-static

EXPOSE 80
EXPOSE 80000

上記のようなDockerfileを解析かけてみます

$ ./hadolint-Linux-x86_64 Dockerfile
Dockerfile:1 DL3007 Using latest is prone to errors if the image will ever update. Pin the version explicitly to a release tag
Dockerfile:2 DL4000 MAINTAINER is deprecated
Dockerfile:5 SC2164 Use 'cd ... || exit' or 'cd ... || return' in case cd fails.
Dockerfile:5 SC1109 This is an unquoted HTML entity. Replace with corresponding character.
Dockerfile:5 SC1070 Parsing stopped here. Mismatched keywords or invalid parentheses?
Dockerfile:5 DL3003 Use WORKDIR to switch to a directory
Dockerfile:9 DL3011 Valid UNIX ports range from 0 to 65535

はい結果は上記の通り。
ポートの範囲がおかしいよとか
現行では推奨しない書き方だったり
コンテナサイズについてまでコメントしてくれます。
もちろんエラーも出してくれます。

ルールの一覧はREADMEをご確認ください。

意図的にやってるんだよ!ってメッセージは除外できるような機能もありますのでそちらを。

$ hadolint --ignore DL3003 --ignore DL3006 <Dockerfile>

ちなみに指摘が一切ない場合は下記のように終了ステータスは0を返してくれる。
これをもとに何らかの自動化処理を入れるのもありですね。

$ ./hadolint-Linux-x86_64 Dockerfile ; echo $?
0

Jsonでいい感じに出力する

CIなんかで流す場合にJsonだと都合がいいことがあります。
「--format」でjsonを指定します。

docker run --rm -i hadolint/hadolint hadolint - --format json < Dockerfile | jq .
[
  {
    "line": 7,
    "code": "DL3003",
    "message": "Use WORKDIR to switch to a directory",
    "column": 1,
    "file": "/dev/stdin",
    "level": "warning"
  },
  {
    "line": 7,
    "code": "DL3018",
    "message": "Pin versions in apk add. Instead of `apk add <package>` use `apk add <package>=<version>`",
    "column": 1,
    "file": "/dev/stdin",
    "level": "warning"
  },
  {
    "line": 45,
    "code": "DL3018",
    "message": "Pin versions in apk add. Instead of `apk add <package>` use `apk add <package>=<version>`",
    "column": 1,
    "file": "/dev/stdin",
    "level": "warning"
  },
  {
    "line": 45,
    "code": "DL4006",
    "message": "Set the SHELL option -o pipefail before RUN with a pipe in it",
    "column": 1,
    "file": "/dev/stdin",
    "level": "warning"
  }
]

まとめ

いちいちbuildする手間も省けるので個人的には大活躍している。
アップデートは現在も続いており簡単なDockerfile作成時はパスを通したディレクトリへ置いておくことで
サクッとチェックできるのでお勧めです。