ジャコ Lab

プログラミング関連のメモ帳的ブログです

Docker コンテナ起動時に前処理を実行したい

例えば、DB や Redis など特定のリソースが起動するまで待ってからメインのアプリケーションを起動したいときなどです。

前提

前提として、Dockerfile と docker-compose.yml の定義をします。
ここでは、簡単な Dockerfile を用意します。

Dockerfile & docker-compose.yml

FROM python:3.11.10-slim-bullseye

RUN apt update -y

COPY ./app ./app

ENTRYPOINT ["python", "app/main.py"]
services:
  app:
    build:
      context: .
    container_name: app

この程度の簡単な Docker ファイルがあったとします。

起動コマンドである python app/main.py が実行される前に何か処理を入れたいです。

一応 main.py は以下のような適当なものになっています。

def main():
    print("START : main()")

if __name__ == '__main__':
    main()

entrypoint のスクリプトを用意する

ここでは、10秒間のウェイト処理をしようと思います。
[docker-entrypoint.sh]

# このブロックに本当にやりたい処理を入れる
for i in {1..10}; do
  echo "Waiting... count: $i"
  sleep 1
done

exec $@

Dockerfile を変更する

  FROM python:3.11.10-slim-bullseye

  RUN apt update -y

  COPY ./app ./app
+ COPY ./docker-entrypoint.sh ./docker-entrypoint.sh

- ENTRYPOINT ["python", "app/main.py"]
+ ENTRYPOINT ["bash", "docker-entrypoint.sh"]
+ CMD ["python", "app/main.py"]

ENTRYPOINTbash docker-entrypoint.sh を実行するようにして、
CMDpython app/main.py を渡すようにします。

これで、10秒のカウントの後、main() の print 文が出力されれば成功です。

試す

$ docker compose up
[+] Building 2.8s (11/11) FINISHED  docker:default
~省略~
[+] Running 2/2
 ✔ Network my_app_default  Created  0.4s 
 ✔ Container app           Created  0.2s 
Attaching to app
app  | Waiting... count: 1
app  | Waiting... count: 2
app  | Waiting... count: 3
app  | Waiting... count: 4
app  | Waiting... count: 5
app  | Waiting... count: 6
app  | Waiting... count: 7
app  | Waiting... count: 8
app  | Waiting... count: 9
app  | Waiting... count: 10
app  | START : main()
app exited with code 0
成功!

exec $@ が重要

exec は、Bash や他のシェルスクリプトで使われるコマンドで、現在のシェルプロセスを指定したコマンドに置き換える ために使用されます。通常のコマンド実行とは異なり、exec で実行すると、元のシェルプロセスが終了し、新しいプロセスがその場で置き換わる点が特徴 です。


$@ は、Bash スクリプトで使われる特殊な変数で、スクリプトに渡された全ての引数 を表すものです。複数の引数を処理する際に便利な機能を提供してくれます。

ということで、

ENTRYPOINT として docker-entrypoint.sh を実行していたものが、
CMD で渡された python app/main.py で実行していることになった。ということでしょうか?

まとめ

起動前に何かしておきたいケースってありますよね。例えばどこからかファイルをダウンロードしておく。とか。そんなときに使う感じです!