昨年の2月くらいからリモートで業務するようになってから、1ヶ月くらいの出社期間を挟んでそろそろ1年近くになってきました。リモートでの業務自体は過去にフルリモートで数年勤務してたこともあるので問題はなかったのですが、最近テレカンの際に自分でも引くくらい話すのが下手になっているのを実感します。結構真面目に危機感を覚えました。
それはさておき掲題の件ですが、ぐーぐる先生に聞いても全然解決策が見つけられず、結構久々に苦戦しました。何かこれ、以前にも同じようなことでハマっていたような記憶があるので、備忘録として残しておきます。長くなってしまったので、お急ぎの方は「修正後」をご参照ください。
何がしたかったのか
php:7.4.12-apache
をベースに作成したApacheのコンテナ時に、シェルスクリプトを走らせたかったという所から始まりました。実際にはwp-cli
を使ってWordPressを入れていて、固定ページなどの実装をgit管理出来るように擬似的なマイグレーションの仕組みを作ったのですが、いちいちコンテナに入ってコマンド実行というのがイケてない気がしたのでこれならばdocker-compose up
するだけで勝手に適用されるかなというのが発端です。
何をしたのか
一部抜粋の形ですが、docker-compose.yml
とdockerfile
はこんな感じです。
FROM php:7.4.12-apache
# config file
COPY ./php.ini /usr/local/etc/php/
# apt
RUN apt-get update \
&& apt-get install -y libfreetype6-dev libjpeg62-turbo-dev libpng-dev libonig-dev mariadb-client \
&& docker-php-ext-install pdo_mysql mysqli gd iconv
# xdebug
RUN pecl install xdebug && \
docker-php-ext-enable xdebug
COPY ./xdebug.ini /usr/local/etc/php/conf.d/
RUN a2enmod rewrite
# use bash shell
SHELL ["/bin/bash", "-l", "-c"]
EXPOSE 80
CMD ["apache2-foreground"]
多分割とよく見る感じのdockerfileかと思います。
version: '3.7'
services:
app:
depends_on:
- db
build: ./docker/app
command: bash -c "sh /var/www/bin/migrations.sh"
volumes:
- ./bin:/var/www/bin
- ./.data/app:/var/www/html:delegated
- ./.data/log/app/:/var/log/apache2/
restart: always
ports:
- "8888:80"
command
にシェルスクリプトの実行コマンドを渡すことで、コンテナ起動時に自動で実行されるようにしました。
これで、コンテナ再起動するだけで都度/var/www/bin/migrations.sh
が実行されるので、プロジェクトメンバーの負担も軽減出来るかなという発想でした。
何が起こったのか
シェルスクリプト自体は正常に動作していましたが、Docker Desktop
でコンテナのログを見てるとシェルスクリプトの実行ログがループして出力されているような状態に陥りました。最初はシェルスクリプトが終了したら再度実行されている?と思ってシェルスクリプトにsleep 30d
とか乱暴なことを書いていましたが、よくよく調べてみるとどうも違いそうです。こんなのコミットしたらぶん殴られてる所でした。
半ギレしながら調査していた所、そうではなく、コンテナがひたすら再起動を繰り返しているというのが実際のようです。Docker Desktop
のコンテナステータスをよくよく見ていれば前述のようなわけのわからないことをしてなかった気もします。
何故起こったのか
- シェルスクリプトが終了するとフォアグラウンドで作動しているプロセスが不在になり、コンテナは終了する
というのが原因のようです。この原因に到達した時に、物凄いデジャヴュを感じました。多分以前の案件でもやっぱり同じことをやらかしていると思います。また、この時点で、解決策に至れていなかったのは完全に見落としだったと思います。
修正しましょう
先程も書いたように、フォアグラウンドで作動するプロセスがなくなったらコンテナが終了するわけですから、フォアグラウンドで何かを動かし続ければいいのでしょう。ということで、乱暴に修正してみます。出典を記録し損ねてしまったのですが、「bash
を対話モードで動作させればコンテナは終了しない」というのを見たのでやってみます。
- command: bash -c "sh /var/www/bin/migrations.sh"
+ command: bash -c "sh /var/www/bin/migrations.sh && /bin/bash"
Docker Desktop
のコンテナログを見ている限り、先程のようにログが繰り返し出力されなくなりました。コンテナのステータスもRUNNINGのままですので、上手くいったように思えます。試しにこの状態で、コンテナを起動しているlocalhost:8080
にアクセスしてみます。
すると、ERR_EMPTY_RESPONSE
と返されました。うんともすんともです。
修正がダメだった理由
ERR_CONNECTION_REFUSED
じゃなくてERR_EMPTY_RESPONSE
なのは想定していなかったので、一瞬頭が真っ白になりましたが、冒頭のdockerfile
を開いてみてようやく気づきました。
-
docker-compose.yml
でcommand
を定義すると、dockerfile
のCMD
は無視される- つまり
dockerfile
のCMD ["apache2-foreground"]
は実行されていない
- つまり
- そのため、ApacheのコンテナなのにApacheが起動していない状態になっている
そりゃ見れるはずもありませんね…。
修正後
Apacheのコンテナを起動時にcommand
でコマンドを渡す際にApacheの起動コマンドも一緒に渡すようにしました。
- command: bash -c "sh /var/www/bin/migrations.sh && /bin/bash"
+ command: bash -c "sh /var/www/bin/migrations.sh && apache2-foreground"
先程と同様にlocalhost:8080
にアクセスしてみると、見慣れた画面が帰ってきました。軽く確認した限りでは、概ね問題はなさそうです。これがベストプラクティスなのかはちょっと懐疑的ではあるんですが、ひとまずは期待していた動作を確認出来るようになったので今日の所はこれで勘弁してやろうと思います。