サイボウズ社の Docker 研修資料を見ていると Dockerfile の静的解析ツールが紹介されており、どれくらい解析するのか興味が湧いたので試してみました。
hadolint
エラーを事前に検知してくれたり、よりよい Dockerfile の書き方を指摘してくれます。 Haskell で描かれており、スターは 4000 程度です。 vscode とも連携することができます。
インストール
# Mac $ brew install hadolint # Windows $ scoop install hadolint # Docker $ docker pull hadolint/hadolint # Build locally $ git clone https://github.com/hadolint/hadolint $ cd hadolint $ stack install
使い方
$ hadolint Dockerfile # Dockerコンテナの場合 $ docker run --rm -i hadolint/hadolint < Dockerfile
VS Code との連携はこちら
使用例
自分が書いた Dockerfile を静的解析してみます。
FROM golang as qiitaexporter-builder RUN CGO_ENABLED=0 go get github.com/tenntenn/qiitaexporter FROM golang as blogsync-builder RUN CGO_ENABLED=0 go get github.com/x-motemen/blogsync FROM alpine:latest WORKDIR /Documents COPY setup.sh blogsync.template /Documents RUN chmod +x setup.sh RUN mkdir -p ~/.config/blogsync COPY config.yaml.tmp /root/.config/blogsync RUN apk --no-cache add libintl && \ apk --no-cache add --virtual .gettext gettext && \ cp /usr/bin/envsubst /usr/local/bin/envsubst && \ apk del .gettext COPY --from=qiitaexporter-builder /go/bin/qiitaexporter /bin/qiitaexporter COPY --from=blogsync-builder /go/bin/blogsync /bin/blogsync ENTRYPOINT ./setup.sh
$ hadolint Dockerfile Dockerfile:1 DL3006 Always tag the version of an image explicitly Dockerfile:4 DL3006 Always tag the version of an image explicitly Dockerfile:7 DL3007 Using latest is prone to errors if the image will ever update. Pin the version explicitly to a release tag Dockerfile:10 DL3021 COPY with more than 2 arguments requires the last argument to end with / Dockerfile:16 DL3018 Pin versions in apk add. Instead of `apk add <package>` use `apk add <package>=<version>` Dockerfile:24 DL3025 Use arguments JSON notation for CMD and ENTRYPOINT arguments
重複を除き 5 点も指摘されました。
- イメージのバージョンを明示的にタグ付する。
- イメージが更新される場合、latest を使用するとエラーが発生しやすくなる。バージョンをリリースタグに明示的に固定する。
- 2 つ以上の引数を持つ
COPY
では、最後の引数が/
で終わる。 apk add
の時、バージョンを指定する。CMD
,ENTRYPOINT
に JSON 表記を使う。
このような粒度で指摘されます。 apk など AlpineLinux 独自のものにも対応されています。 問題点の説明と修正方法が GitHub の wiki で説明されており親切です。
DL3006 · hadolint/hadolint Wiki · GitHub
設定ファイル
3 パターンの方法で設定ファイルを適応できます。
Dockerfile
と同じディレクトリに.hadolint.yaml
を設置XDG_CONFIG_HOME
で指定するフォルダにhadolint.yaml
を設置- 実行時に
hadolint --config /path/to/config.yaml Dockerfile
と指定
# .hadolint.yaml # 無視するルール ignored: - DL3000 - SC1010 # 信頼するレジストリ(hadolintは信頼できないリポジトリからのイメージを使う場合、警告をだす) trustedRegistries: - docker.io - my-company.com:5000
行単位で設定する
行単位で無視するルールを設定することもできます。
# hadolint ignore=DL3006 FROM ubuntu # hadolint ignore=DL3003,SC1035 RUN cd /tmp && echo "hello!"
出力
なにも指摘がない場合には終了ステータス 0、指摘がある場合には終了ステータス 1 で終了します。
# &&はコマンドがステータス0の時のみ次へ $ hadolint Dockerfile && echo NO_WARNING NO_WARNING # ||はコマンドがステータス1の時のみ次へ $ hadolint Dockerfile || echo WARNING_EXIST Dockerfile:9 DL3006 Always tag the version of an image explicitly WARNING_EXIST
また、--format
で tty, json, checkstyle, codeclimate, codacy と出力形式を選択することができます。
これら出力に対して柔軟であるため、CI 等のワークフローにも組み込みやすくなっています。
おわりに
さまざまな種類の警告やエラーを出してくれるようで、これを導入すると Dockerfile が書きやすくなるなと感じました。 正しい書き方は教えてくれるものの、軽量化までは導いてくれません。 当たり前ですが、軽量化など Dockerfile の構成は別途学ぶ必要があります。 ひとまず、明日職場の Dockerfile 全部 hadolint 掛けてこようと思います。