3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

docker-composeでApacheコンテナ起動時にcommandを実行する

Last updated at Posted at 2021-02-26

昨年の2月くらいからリモートで業務するようになってから、1ヶ月くらいの出社期間を挟んでそろそろ1年近くになってきました。リモートでの業務自体は過去にフルリモートで数年勤務してたこともあるので問題はなかったのですが、最近テレカンの際に自分でも引くくらい話すのが下手になっているのを実感します。結構真面目に危機感を覚えました。

それはさておき掲題の件ですが、ぐーぐる先生に聞いても全然解決策が見つけられず、結構久々に苦戦しました。何かこれ、以前にも同じようなことでハマっていたような記憶があるので、備忘録として残しておきます。長くなってしまったので、お急ぎの方は「修正後」をご参照ください。

何がしたかったのか

php:7.4.12-apacheをベースに作成したApacheのコンテナ時に、シェルスクリプトを走らせたかったという所から始まりました。実際にはwp-cliを使ってWordPressを入れていて、固定ページなどの実装をgit管理出来るように擬似的なマイグレーションの仕組みを作ったのですが、いちいちコンテナに入ってコマンド実行というのがイケてない気がしたのでこれならばdocker-compose upするだけで勝手に適用されるかなというのが発端です。

何をしたのか

一部抜粋の形ですが、docker-compose.ymldockerfileはこんな感じです。

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かと思います。

docker-compose.yml

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を対話モードで動作させればコンテナは終了しない」というのを見たのでやってみます。

docker-compose.yml

-   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.ymlcommandを定義すると、dockerfileCMDは無視される
    • つまりdockerfileCMD ["apache2-foreground"]は実行されていない
  • そのため、ApacheのコンテナなのにApacheが起動していない状態になっている

そりゃ見れるはずもありませんね…。

修正後

Apacheのコンテナを起動時にcommandでコマンドを渡す際にApacheの起動コマンドも一緒に渡すようにしました。

docker-compose.yml

-   command: bash -c "sh /var/www/bin/migrations.sh && /bin/bash"
+   command: bash -c "sh /var/www/bin/migrations.sh && apache2-foreground"

先程と同様にlocalhost:8080にアクセスしてみると、見慣れた画面が帰ってきました。軽く確認した限りでは、概ね問題はなさそうです。これがベストプラクティスなのかはちょっと懐疑的ではあるんですが、ひとまずは期待していた動作を確認出来るようになったので今日の所はこれで勘弁してやろうと思います。

3
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?