概要
DjangoとDockerを使ってローカル環境でコンテナを立ち上げ、スクリプトでpython manage.py runserver 0.0.0.0:8000
を実行していたら、このコマンドが原因で次のコマンドに進まないことがあることがわかりましたので解説します。
コマンドの順番によって次に進まないことがある
以下はサンプルのシェルスクリプト。
docker-compose
のcommand:
セクションで実行させます。
## 略 ##
web:
build:
context: .
dockerfile: Dockerfile
command: ["./sample-script.sh""]
volumes:
- ./myprojects:/code
ports:
- "8000:8000"
#!/bin/bash
echo "Hi, this is sample command"
# Djangoのサーバーを起動
python manage.py runserver 0.0.0.0:8000
上記のように、後でDjangoのサーバーを起動するコマンドを持ってくれば、echo
コマンドはdocker logに出力されます。
しかし、以下のように逆にすると、echo
コマンドは出力されません。
#!/bin/bash
# Djangoのサーバーを起動
python manage.py runserver 0.0.0.0:8000
echo "Hi, this is sample command"
これは、シェルスクリプトの実行がpython manage.py runserver 0.0.0.0:8000
でブロックされ、このコマンドが終了するまで次のコマンドに進まないためです。python manage.py runserver
は、サーバーが終了するまで実行を続けるため、その行以降のコマンドは実行されません。
解決策:バックグラウンド起動&コンテナ永続化
このような場合、&
によってDjangoのサーバーをバックグラウンドで起動させ、また、その後にコンテナが終了しないようにしてあげれば、順番通り出力されるようになります。
#!/bin/bash
# Djangoのサーバーをバックグラウンドで起動
python manage.py runserver 0.0.0.0:8000 &
echo "Hi, this is sample command"
# コンテナが終了しないようにする
tail -f /dev/null
tail -f /dev/null
とは?
/dev/null
は、読み込むと即座にEOF(End of File)を返し、書き込みを行っても何も保持せずに破棄されるという、特殊なファイルです。英語圏では“black hole”
と呼ばれているとか。まぁその通りですね。
シェルスクリプトやコンテナは、実行されたコマンドが終了すると通常終了します。では終わらせないためにどうすればいいか?というと、tail -f /dev/null
のように永遠に終了しないプロセスを起動させてあげれば、コンテナが終了せずに動き続けることができる、というわけです。
記事「永遠に終了せず何もしないDockerコンテナを立ち上げる方法」に他にも方法が記載あるので気になる方はご参考まで。
その他エラー:シバン記載漏れによるexec format error
パッと使うサンプル用にシェルスクリプトを作った気でいたら、シバン(シェバン)の書き漏れがありました。
echo "Hi, this is sample command"
# Djangoのサーバーを起動
python manage.py runserver 0.0.0.0:8000
#!/bin/bash
のようなシバンがない場合、以下のエラーになりました。
standard_init_linux.go:228: exec user process caused: exec format error
#!/bin/bash
とは?
#!/bin/bash
とは、シェルスクリプトがどのシェルで実行されるべきかを示す特殊なコメント行(宣言)。シバン(shebang、シェバンライン)と呼ばれます。
これがないと、システムはスクリプトをどのシェルで実行すれば良いかわかりません。
スクリプトがデフォルトのシェルで実行されようとしますが、そのシェルがバイナリ形式ではない場合に"exec format error"
というエラーが発生しているんですね。
#!/bin/bash
をスクリプトの先頭に追加することで、スクリプトがbash
で実行されることが明示されるので、エラーは無くなりました。