結論
- ボリュームマウントしているディレクトリ配下のDockerfileによる変更は全て消えるので、ディレクトリをホスト側で作成しておくか、ボリュームマウントに含まれないディレクトリに変更する。
現象
./docker/Dockerfile
FROM python:latest
RUN mkdir -p /app/data/hoge && echo "hello" > /app/data/hoge/sample.txt
./docker-compose.yaml
services:
web:
build:
context: ./
dockerfile: docker/Dockerfile
volumes:
- ./local_data:/app/data # hogeディレクトリの上位ディレクトリをマウント
- docker compose up -dで起動してexecでコンテナ内にログインすると/app/data内にhogeディレクトリがある想定だが見てみるとファイルどころかディレクトリも存在しない
原因
- ボリュームマウントされているディレクトリの中身はマウント元の内容に上書きされてしまうのが原因
- 処理の順番がdockerfileの処理→ボリュームマウントなのでdockerfile内で処理した内容が全て消える
- ボリュームマウントした後ならdocker内でmkdirした内容がマウントによってホスト側に反映されるが残念ながら順番が逆
- ファイルコピーなどの場合も同様の挙動になるので注意。
- Dockerfile内でマウントしているディレクトリ下にディレクトリを生成してその配下にファイルコピーすると直感的に考えてファイルが残りそうだが実際はマウント前なのでファイルが消えてしまい混乱しがち。
- マウント元に元々あるディレクトリにDockerfile内でファイルをコピーするとこちらはちゃんとコピーされるので余計混乱する
- Dockerfile内でマウントしているディレクトリ下にディレクトリを生成してその配下にファイルコピーすると直感的に考えてファイルが残りそうだが実際はマウント前なのでファイルが消えてしまい混乱しがち。
対応策
- Dockerfile内でmkdirせずにホスト側でディレクトリをあらかじめ作成しておく
- マウントボリューム外にディレクトリを作成する
- Dockerfile内にENTRYPOINT ["/entrypoint.sh"]の記述を追加し、entrypoint.sh内でディレクトリを生成する(未検証)
- entrypoint.shの実行タイミングはボリュームマウントの後らしい