とりあえず動いてほしい
Docker (& Docker compose)で開発を始めるとき、慣れない種類の環境は立ち上げが辛い。execでbashに繋いで試行錯誤できればまだしも、ビルドでコケるわ起動と同時に異常終了するわで前段が長く感じることがしばしばある。
全知全能、百戦錬磨の技術者なら必要なもの全てを1発でDockerfileに書ききってしまうかもしれないが、どちらかというと稀な気がするのだ。
とにかく最初は、とりあえず動いてほしい。ゴリ押し上等だ。いいからテーピングだ。
結論
RUN命令でのエラー潰し
ビルド失敗の主原因であるRUN命令のエラーを無視する。別途shellを起動してcオプションで実行、or条件で"exit 0"すればよい。
RUN sh -c "something bad command || exit 0"
停止はしないが、エラー内容は標準エラー出力に流れたものが"docker compose logs"で確認できる。
CMD命令/commandでのエラー潰し
DockerfileのCMD命令はdocker-compose.yamlのcommandで上書きされる。なのでdocker-compose.yaml側でハックすればCMD命令がコケる場合もcommandでコケる場合も対処可能。
or条件で失敗時に適当なインタラクティブシェルを起動させる。shでOK。
services:
node:
command: sh -c "npm run dev || sh"
tty: true
なぜうまくいく?
ビルド失敗の条件は終了ステータス1以上
少なくともRUN命令では、実行コマンドの終了ステータスが1以上の時にビルド失敗として扱われて中断される。
RUN sh -c "something bad command || exit 0"
上の書き方にするとshが別途立ち上がってダブルクォーテーション内のコマンドを実行する為、Dockerが認識するのはshの終了コードになる。それでも通常は"something bad command"終了ステータスがそのままshの終了のものになるが、終了ステータスが0でないときも"exit 0"に渡してやればshの終了ステータスは常に0となり、エラーとして扱われなくなる。
コンテナが稼働し続けるのはプロセスが継続している間
例えばnginxイメージの起動コマンド"nginx"や、node系開発サーバでよく指定される"npm run dev"などは常駐プログラムの起動コマンドで、起動されたプロセスが動いている限りコンテナは終了しない。
command: sh -c "npm run dev || sh"
常駐系プログラムの起動が失敗した場合に適当なインタラクティブシェル(コンテナ内で起動可能なものならなんでもよい。"sh", "bash", "perl", "node", "php -a", "php artisan tinker"...)を代わりに起動するように指定する。
これだけだとインタラクティブシェルはttyを必要とするので結局停止してしまうが
tty: true
ttyを作成させることでインタラクティブシェルが無事に起動、常駐してくれる。
(参考)ttyとは何か
tty【コマンド】
わかりやすい!!
ttyコマンドで表示されるファイルの正体はデバイスファイルというものらしい。
Linuxのファイルの種類
わかりやすい!!
tty | xargs -I @ ls -la @
crw--w---- 1 ming tty 136, 12 Sep 27 15:27 /dev/pts/12
削除するとターミナルが落ちるかなと思って試してみたが、謎の力に守られているようだ。
sudo rm /dev/pts/12
[sudo] password for ming:
rm: cannot remove '/dev/pts/12': Operation not permitted