base イメージは ShellCheck(shellcheck)を同梱する。base と、
base を継ぐ派生イメージのコンテナの中で、Bash スクリプトの静的検査をそのまま走らせられる。
bash-language-server などの言語サーバは Bash の診断を shellcheck に任せており、無いとエラーも
警告も出さずに診断が空になる。base に置くことで、コンテナの中で動かす言語サーバも診断を返せる。
shellcheck が入っていないイメージは建たない。 入れ損ないはビルドの時点で止まる。
利用者向けの読み方は コンテナ操作ガイド: Bash の静的検査 にある。
- base イメージへの
shellcheckの導入と、入れ損ないをビルドで止める仕組み - base から派生するイメージ(
general/go/php/php85/bi-tools/latex/trygroup)への伝播の規則 containers/lfmとcontainers/snapshotは base を継がないため対象に含まない- bash-language-server 自体は同梱しない
- CI の ShellCheck ジョブは runner の shellcheck を使い、この仕様の対象ではない
| 要素 | 置き場所 | 責務 |
|---|---|---|
| 導入 | containers/base/Dockerfile の 1 つ目の RUN の 1 回目の apt-get install |
poppler-utils などの行の後に、理由のコメントとともに shellcheck を置く |
| 入れ損ないの検出 | containers/base/Dockerfile の版の確認の RUN |
gh --version && ... && session-manager-plugin --version && shellcheck --version。無ければ shellcheck: command not found(終了コード 127)でビルドが止まる |
| 形の検査 | tests/containers/test_base_dockerfile_shellcheck.py |
Docker を起動せずに、上の 2 か所の形を固定する |
型(クラス)は持たない。Dockerfile の命令だけで構成する。
shellcheck は Ubuntu の標準のアーカイブ(universe)にあり、外部のリポジトリを要さない。
そのため 1 つ目の RUN の1 回目の apt-get install の一覧に置く。2 回目の一覧は後から
足したリポジトリのパッケージ(docker-ce / terraform / gh / nodejs / chromium-browser)
のためにあり、標準のアーカイブのパッケージを混ぜない。
shellcheck のための RUN は立てない。立てると派生イメージ 7 つが積む層が 1 つ増え、
apt-get update とクリーンアップ(apt-get clean / rm -rf)をもう 1 か所に持つことになる。
Dockerfile の apt-get update は 2 回である。
版の確認の RUN は USER ${USERNAME} より前にあり root で走る。/usr/bin/shellcheck は
PATH にあるため、パスを書かずに呼ぶ。
止める役はテストではなくビルドが持つ。 apt-get install はパッケージが一覧から消えても
失敗しないため、一覧の編集で shellcheck が落ちたときに止まるのは版の確認の側だけである。
テストは、版の確認の 1 語が消えないことを固定する。
版は固定せず、base を建てた時点で Ubuntu のアーカイブが配る版を入れる(2026-09 時点で
0.11.0-2、shellcheck --version は version: 0.11.0)。gh / terraform / nodejs と同じ
扱いである。bao のように ARG とチェックサムで固定しないのは、サーバの版と揃える制約が
無いためである。shellcheck=<版> と書かないのは、アーカイブが版を上げるとその版が消えて
ビルドが止まるためである。
依存を含めて新しく入るパッケージは shellcheck と libnuma1 の 2 つである(libc6 /
libffi8 / libgmp10 は既に入っている)。置き場所は /usr/bin/shellcheck。
| 項目 | 値 |
|---|---|
Installed-Size(shellcheck) |
24971 KB(arm64)/ 22867 KB(amd64、アーカイブの Packages.gz の値) |
/usr の増分 |
約 25 MB(arm64 の実測) |
環境変数・設定ファイルは持たない。
- 変更はイメージを建て直すまで反映されない。
devbase build base --no-cacheで base を 建て直し、使っている派生イメージ(いずれもFROM devbase-base:latest)も建て直し、稼働中の コンテナはdevbase down→devbase upで作り直す。devbase upだけでは反映されない devbase rebuildはここでは使えない。devbase build --expires=7のシノニム (lib/devbase/commands/container.pyのcmd_rebuild)で、期限内ならビルドを飛ばし、 コンテナも作り直さないcontainers/lfmはFROM nvidia/cuda:...で base を継がず、base からは/usr/local//usr/bin/gh//usr/bin/node//optなどを選んでCOPYするだけのため、/usr/bin/shellcheckは届かない。containers/snapshotはFROM ubuntu:26.04で base を 継がない。どちらかで要るようになったときは、そのイメージのapt-get installかCOPYの 一覧へ足す- 建てて確かめてあるのは arm64 である。amd64 はアーカイブに同じ版があり、依存も同じである ことまで確かめている
tests/containers/test_base_dockerfile_shellcheck.py(Docker を要さない):
shellcheckが 1 つ目のRUNの 1 回目のapt-get installの一覧(最初の;まで)に あること。2 回目の一覧に無いこと- 2 つ目以降の
RUNにshellcheckを入れるapt-get installが無く、apt-get updateが 2 回のままであること - 版の確認の
RUNを&&で分けた命令にshellcheck --versionがあること
補助の関数(コメント行を除く本文・RUN ブロックへの分割・1 回目の一覧の切り出し)は
このファイルに持ち、test_base_dockerfile_fonts.py から import しない。テストのファイル
どうしを依存させない。
イメージの中の検査は Docker のテストにしない。入っていることはビルドが守る。
test_base_image_font_matching.py の期待値へ足すと、この変更より前に建てた base を持つ全員の
pytest tests/ が赤くなり、赤の意味が「壊れている」と「イメージが古い」で混ざる。
「無ければ skip」の別のテストは「無い」を検査できない。
建てたイメージで手で確かめる観点:
docker run --rm --entrypoint /bin/bash devbase-base:latest -c 'shellcheck --version'が 終了コード 0 で終わり、version:の行を出すこと。base を建て直した後に建てたdevbase-general:latest/devbase-php:latestでも同じであることecho $fooの 1 行を持つ Bash スクリプトへshellcheckを走らせると、出力にSC2086を 含み、終了コード 1 で終わること(言語サーバが使うのはこの診断である)- 新しく入るのが
shellcheckとlibnuma1の 2 パッケージで、dpkg-query -W -f='${Installed-Size}\n' shellcheck libnuma1の合計が 30720 KB 以下であること。docker imagesの前後の差では測らない(--no-cacheの建て直しは他の取得物の版も入れ替える)
CI はイメージを建てるジョブを持たないため、イメージの中の観点は CI では確かめない。