Dockerfileチェッカー - セキュアで効率的なコンテナイメージ作成の検証とは?

昨今Dockerを使って開発を行う機会が増え、Dockerfileも徐々に複雑になりメンテナンスが大変になっていないでしょうか?
Dockerfileをベストプラクティス に従っているか確認を行います。
ルール重要度詳細
DL1001Ignoreインラインの Ignore pragma # hadolint Ignore=DLxxxx の使用は控えてください。
DL3000ErrorWORKDIR には絶対パスを使用してください。
DL3001InfoDockerコンテナ内での実行が意味をなさない一部のbashコマンド(ssh, vim, shutdown, service, ps, free, top, kill, mount, ifconfig)があります。
DL3002Warning最後のユーザーはrootであるべきではありません。
DL3003Warningディレクトリの切り替えには WORKDIR を使用してください。
DL3004Errorsudoは予期せぬ動作を引き起こすため使用しないでください。root権限が必要な場合はgosuのようなツールを使用してください。
DL3005Errorapt-get dist-upgrade は使用しないでください。
DL3006Warningイメージのバージョンは常に明示的にタグ付けしてください。
DL3007Warninglatestの使用は、イメージ更新時にエラーの原因となりやすいため、リリースタグなどでバージョンを明示的に指定(Pin)してください。
DL3008Warningapt-get install ではバージョンを固定(Pin)してください。
DL3009Infoインストール後は apt-get lists を削除してください。
DL3010Infoアーカイブをイメージ内に展開するときは ADD を使用してください。
DL3011Error有効なUNIXポート範囲は0から65535です。
DL3012Error複数の HEALTHCHECK 命令があります。
DL3013Warningpip ではバージョンを固定(Pin)してください。
DL3014Warning-y スイッチを使用してください。
DL3015Info--no-install-recommends を指定して余分なパッケージのインストールを避けてください。
DL3016Warningnpm ではバージョンを固定(Pin)してください。
DL3018Warningapk add ではバージョンを固定(Pin)してください。apk add <package> の代わりに apk add <package>=<version> を使用します。
DL3019Info--no-cache スイッチを使用して --update の使用を回避し、インストール完了後に /var/cache/apk/* を削除してください。
DL3020Errorファイルやフォルダには ADD ではなく COPY を使用してください。
DL3021Error2つ以上の引数を持つ COPY では、最後の引数は / で終わる必要があります。
DL3022WarningCOPY --from は定義済みの FROM エイリアスを参照する必要があります。
DL3023ErrorCOPY --from は自身の FROM エイリアスを参照することはできません。
DL3024ErrorFROM エイリアス(ステージ名)は一意である必要があります。
DL3025WarningCMD および ENTRYPOINT の引数には JSON 表記を使用してください。
DL3026ErrorFROM イメージには許可されたレジストリのみを使用してください。
DL3027Warningapt はエンドユーザー向けツールです。代わりに apt-get または apt-cache を使用してください。
DL3028Warninggem install ではバージョンを固定(Pin)してください。gem install <gem> の代わりに gem install <gem>:<version> を使用します。
DL3029WarningFROM--platform フラグを使用しないでください。
DL3030Warning手動入力を避けるため -y スイッチを使用してください: yum install -y <package>
DL3032Warningyum コマンドの後に yum clean all がありません。
DL3033Warningバージョンを指定してください: yum install -y <package>-<version>
DL3034Warningzypper コマンドに非対話型スイッチがありません: zypper install -y
DL3035Warningzypper dist-upgrade は使用しないでください。
DL3036Warningzypper 使用後に zypper clean がありません。
DL3037Warningバージョンを指定してください: zypper install -y <package>[=]<version>
DL3038Warning手動入力を避けるため -y スイッチを使用してください: dnf install -y <package>
DL3040Warningdnf コマンドの後に dnf clean all がありません。
DL3041Warningバージョンを指定してください: dnf install -y <package>-<version>
DL3042Warningpip install --no-cache-dir <package> でキャッシュディレクトリの使用を避けてください。
DL3043ErrorONBUILD 命令内から ONBUILD, FROM あるいは MAINTAINER がトリガーされました。
DL3044Error定義しているのと同じ ENV ステートメント内で環境変数を参照しないでください。
DL3045WarningWORKDIR が設定されていない状態で相対パスに COPY しています。
DL3046Warninguseradd-l フラグがなく、UIDが大きいとイメージが肥大化します。
DL3047Infowget--progress フラグがないと、大容量ファイルのダウンロード時にビルドログが肥大化します。
DL3048Style無効なラベルキーです。
DL3049Infoラベル <label> がありません。
DL3050Info余分なラベルが存在します。
DL3051Warningラベル <label> が空です。
DL3052Warningラベル <label> は有効なURLではありません。
DL3053Warningラベル <label> は有効な時刻形式ではありません(RFC3339準拠である必要があります)。
DL3054Warningラベル <label> は有効なSPDXライセンス識別子ではありません。
DL3055Warningラベル <label> は有効なgitハッシュではありません。
DL3056Warningラベル <label> はセマンティックバージョニングに準拠していません。
DL3057IgnoreHEALTHCHECK 命令がありません。
DL3058Warningラベル <label> は有効なメールアドレス形式ではありません(RFC5322準拠である必要があります)。
DL3059Info連続する複数の RUN 命令があります。統合を検討してください。
DL3060Infoyarn install 実行後に yarn cache clean がありません。
DL3061Error命令の順序が無効です。Dockerfileは FROM, ARG またはコメントで始まる必要があります。
DL4000ErrorMAINTAINER は非推奨です。
DL4001WarningWget または Curl のいずれかを使用し、両方は使用しないでください。
DL4003Warning複数の CMD 命令が見つかりました。
DL4004Error複数の ENTRYPOINT 命令が見つかりました。
DL4005Warningデフォルトシェルを変更するには SHELL を使用してください。
DL4006Warningパイプを使用する RUN の前に SHELL オプション -o pipefail を設定してください
SC1000$ は特殊な意味を持たないため、エスケープする必要があります。
SC1001この \c はこの文脈では通常の 'c' になります。
SC1007代入の場合は = の後のスペースを削除してください(空文字の場合は var='' ... を使用)。
SC1010done の前にセミコロンまたは改行を使用してください(リテラルの場合は引用符で囲む)。
SC1018これはUnicodeの非改行スペースです。削除してスペースとして再入力してください。
SC1035ここにはスペースが必要です
SC1045foo &; bar ではありません。foo & bar です。
SC1065パラメータを宣言しようとしていますか?シェルスクリプトでは行いません。() を使用し、$1, $2 などでパラメータを参照してください。
SC1066代入の左辺で $ を使用しないでください。
SC1068代入の = の前後にスペースを入れないでください。
SC1077コマンド展開には、バッククォート(`)を使用してください(´ ではありません)。
SC1078二重引用符で囲まれた文字列を閉じ忘れていませんか?
SC1079これは実際には終了引用符ですが、次の文字のせいで疑わしく見えます。
SC1081スクリプトは大文字と小文字を区別します。If ではなく if を使用してください。
SC1083この {/} はリテラルです。式を確認するか(;/\n が抜けていませんか?)、引用符で囲んでください。
SC1086for ループのイテレータ名に $ を使用しないでください。
SC1087配列を展開する場合は、${array[idx]} のように中括弧が必要です。
SC1095関数名と本体の間にはスペースまたは改行が必要です。
SC1097予期しない == です。代入には =、比較には [ .. ] または [[ .. ]] を使用してください。
SC1098eval を使用する場合は、特殊文字を引用符で囲むかエスケープしてください(例: eval "a=(b)")。
SC1099# の前にはスペースが必要です。
SC2002無駄な cat です。cmd < file | .. または cmd file | .. を検討してください。
SC2015A && B || C は if-then-else ではないことに注意してください。A が真の場合でも C が実行される可能性があります。
SC2026この単語は引用符の外にあります。'nest '"'single quotes'"' instead' のように入れ子にするつもりでしたか?
SC2028echo はエスケープシーケンスを展開しません。printf の使用を検討してください。
SC2035ダッシュで始まる名前がオプションとして扱われないように、./*glob* または -- *glob* を使用してください。
SC2039POSIX sh では、定義されていない機能です。
SC2046単語の分割を防ぐためにこれを引用符で囲んでください
SC2086グロブ展開と単語分割を防ぐために二重引用符で囲んでください。
SC2140単語の形式が "A"B"C" になっています(Bが示されています)。"ABC" または "A\"B\"C" のつもりでしたか?
SC2154変数が参照されていますが、割り当てられていません。
SC2155戻り値をマスクしないように、宣言と代入を分けて行ってください。
SC2164cd が失敗した場合に備えて cd ... || exit を使用してください。