Dockerfileを書くとき、ベストプラクティスに則っているか、RUNの実行に問題はないかなど、意識していますか?コンテナイメージのサイズは目に見えるので意識しやすのですが、Dockerfileがベストプラクティスに則っていなくても警告なく動いてしまうので、ついつい意識が逸れてしまいます。ベストプラクティスを覚えていくのもなかなかに大変です。そこで今回はDockerfileの静的解析ツール、Hadolintを使える環境を用意していきたいと思います。
Hadolintってなに?
Haskell製のDockerfile静的解析ツールです。Docker公式で公開しているベストプラクティスに則っているかをチェックすることができます。RUNの中身はShellCheckで静的解析してくれるので、ビルドしてみたらRUNでコケた、なんてことも減らせると思います。
インストール
macOSならHomebrewでインストールできます。
brew install hadolint
GitHubのReleasesからバイナリをダウンロードすることも可能です。
コマンドをインストールしたくない方は、Dockerイメージが公開されているので、そちらを使うといいと思います。
標準入力からDockerfileを渡すことで静的解析することができます。
docker run --rm -i hadolint/hadolint < /path/to/Dockerfile or cat /path/to/Dockerfile | docker run --rm -i hadolint/hadolint
HadolintのDockerfileを確認してみると、CMD ["/bin/hadolint", "-"]
でコマンドを実行していることがわかります。
このままコマンドラインオプションを渡すとCMDが上書きされhadolintが実行されません。
オプションを指定して静的解析を実行する場合はhadolint/hadolint hadolint [options]
のようにコマンド部分も指定する必要がありました。
Webアプリも公開されているので、こちらを試してみるのもいいかもしれません。
使ってみる
hadolint - Dockerfile Linter written in Haskell Usage: hadolint [-v|--version] [-c|--config FILENAME] [DOCKERFILE...] [--file-path-in-report FILEPATHINREPORT] [--no-fail] [--no-color] [-V|--verbose] [-f|--format ARG] [--error RULECODE] [--warning RULECODE] [--info RULECODE] [--style RULECODE] [--ignore RULECODE] [--trusted-registry REGISTRY (e.g. docker.io)] [--require-label LABELSCHEMA (e.g. maintainer:text)] [--strict-labels] [-t|--failure-threshold THRESHOLD] 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 --file-path-in-report FILEPATHINREPORT The file path referenced in the generated report. This only applies for the 'checkstyle' format and is useful when running Hadolint with Docker to set the correct file path. --no-fail Don't exit with a failure status code when any rule is violated --no-color Don't colorize output -V,--verbose Enables verbose logging of hadolint's output to stderr -f,--format ARG The output format for the results [tty | json | checkstyle | codeclimate | gitlab_codeclimate | codacy | sonarqube | sarif] (default: tty) --error RULECODE Make the rule `RULECODE` have the level `error` --warning RULECODE Make the rule `RULECODE` have the level `warning` --info RULECODE Make the rule `RULECODE` have the level `info` --style RULECODE Make the rule `RULECODE` have the level `style` --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 --require-label LABELSCHEMA (e.g. maintainer:text) The option --require-label=label:format makes Hadolint check that the label `label` conforms to format requirement `format` --strict-labels Do not permit labels other than specified in `label-schema` -t,--failure-threshold THRESHOLD Exit with failure code only when rules with a severity equal to or above THRESHOLD are violated. Accepted values: [error | warning | info | style | ignore | none] (default: info)
サンプルプロジェクトを用意しました。警告の出るDockerfileや、CIの設定が入っているので、forkして手元にcloneしておいてください。
GitHub - VirtualTech-DevOps/hadolint-sample
それではさっそく、実行してみましょう。
hadolint Dockerfile
以下のようなメッセージが出たと思います。
Dockerfile:1 DL3006 warning: Always tag the version of an image explicitly Dockerfile:3 DL3027 warning: Do not use apt as it is meant to be a end-user tool, use apt-get or apt-cache instead Dockerfile:4 DL3059 info: Multiple consecutive `RUN` instructions. Consider consolidation. Dockerfile:4 DL3027 warning: Do not use apt as it is meant to be a end-user tool, use apt-get or apt-cache instead Dockerfile:6 DL3059 info: Multiple consecutive `RUN` instructions. Consider consolidation. Dockerfile:7 DL3000 error: Use absolute WORKDIR
左から、ファイル名、問題のあった行番号、エラーコード、エラーレベル、メッセージの順で出力されています。
DLやSCから始まるエラーコードがリポジトリのWikiにまとまっています。エラーの詳細と、どう記述したらよかったのかが書いてありますので、こちらを確認しながら、修正していくのが楽かと思います。
エラーや警告が出ていても、アプリの作りや手順の都合で、どうしても直せない状況はよくあると思います。そういう場合は--ignore=エラーコード
で無視することができます。
hadolint Dockerfile --ignore=DL3059
先ほど出ていたDL3059 info
が報告されなくなったと思います。ただし、コマンドラインオプションからエラーコードで抑制してしまうと、そのエラーについて、すべての警告が無視されてしまいます。 Dockerfile内の無視してほしい行にのみignoreを追加することで、特定の行のみ無視することができます。
先ほどのDockerfileを以下のように修正し、hadolintを実行してみてください。
# hadolint ignore=DL3059 RUN mkdir tmp
Dockerfile:6 DL3059 info: Multiple consecutive
RUNinstructions. Consider consolidation.
の報告のみが、出力されなくなったと思います。
このように、Dockerfile内にルールを記述できるので、設定による環境差が生まれづらくなります。また、コミットメッセージになぜ無視するのか
を記述できるため、他の人への共有も楽になるのではないでしょうか。
インテグレーション
Hadolintは様々なアプリや、サービスから使用することが可能です。インテグレーションについて、公式で以下のようなドキュメントが公開されています。
hadolint/docs/INTEGRATION.md at master · hadolint/hadolint · GitHub
Visual Studio Codeで静的解析
弊社ではVisual Studio Code(以下VS Code)の使用を推奨していますので、VS CodeのExtensionをインストールしてみたいと思います。
以下のページからインストール画面に飛ぶか、VS CodeのMarketplace検索窓からhadolint
を検索し、インストールしてみてください。
インストールするとすぐに使えるようになると思います。 もしうまく動かない場合は、Hadolintを設置したディレクトリが$PATHに追加されているか確認してみてください。VS CodeからHadolintのバイナリを実行しているので、パスが通っていないと実行できません。
それではVS CodeでDockerfileを開いてみましょう。
問題のある行にマウスオーバーすると・・・
問題点と改善方法がポップアップで報告されます。エラーコードはWikiへのリンクになっているので、そこからWikiに飛ぶのもいいでしょう。
CircleCIで静的解析
CircleCIの設定はこちらの記事を参考にしてみてください。
先ほどforkしたサンプルプロジェクトには既にCircleCIの設定ファイルが含まれています。CircleCIにプロジェクトを追加した時点でJobが実行されたと思います。もし実行されなければ、適当なコミットをPushしてみてください。
実際にJobが実行されると以下のようになります。
ベストプラクティスに則っていないDockerfileがPushされると、自動でHadolintが実行され、警告を出してJobがFailedしました。
まとめ
Dockerfile内にignoreを記述できるので、仕方なく、といった部分も吸収できるのはいいなと思いました。ただ、これを多用すると見通しが悪くなり、セキュリティもどんどんボロボロになっていくので、ignoreを増やすより、根本解決したほうがよさそうです。
エディタから静的解析を行うことで、ベストプラクティスに則ったコードが書きやすくなります。また、ベストプラクティスに則っていないコードをPushしないことで、手戻りも発生しにくくなるとのではないでしょうか。
CIで静的解析できればPull requestsで弾くことができるので、リポジトリを綺麗な状態に保つことができます。Dockerfileの構成についてレビューの手間も省けるでしょう。
エディタもCIも、どちらも導入に大きなデメリットはないと思います、是非活用してみてください。