🫠

[Docker]外部データの注入は都度で、コンテナ内で生成したデータは必要なときに引っ張ってきたい

2023/11/17に公開

https://github.com/lll-lll-lll-lll/sample-docker-cp-cli
タイトルがやりたいことだが、背景も含めて改めて説明する。
PythonのFireを使ったCLIを作ろうとしていて、外部との共有もあったのでDockerを使おうとしていた。
外部データは都度変化するので、コンテナ生成時にbindマウントし、volumeにマウントされたデータはどうにかこうにかしてローカルに持ってきたい。GUIはやだ
コマンド一発よろ。って感じで任されたので、解決策をメモる。

imageをビルドする

dockerのイメージ名をcli_imageで指定。

docker build -f . -t cli_image --rm .

containerを作成

  • --namecli_containerでコンテナ名を指定
  • --mountでホストマシンの./dataディレクトリを対象に、コンテナ上の/src/dataディレクトリにマウントする
  • -vでcli-volを作成し、コンテナ上の/src/outputにマウントする。このマウント先が後にホスト上に保存するときに必要
  • 後はコンテナ止めたらコンテナを随時削除する--rm
docker run -it --name cli_container --mount type=bind,source=$(realpath ./data),target=/src/data -v cli-vol:/src/output   --rm cli 

コンテナ内のvolumeのコンテンツをホストに保存

  • 先ほど作成したcli-volvolumeをcontainer-volvolumeにマウントしする
  • ホストカレントディレクトリをマウントし、コンテナ内のcontainer-volをホストのcontainer-volディレクトリにコピー
docker run --rm -v cli-vol:/container-vol -v `pwd`/:$(realpath ./) cli_image sh -c 'cp -r /container-vol $(realpath ./)'

サンプルコードを用意した。
簡単な説明をしておくと、data/ディレクトリが外部データの保存先。
コンテナを立ち上げて、python main.py helloでコンテナ内でファイルを生成。
container-volがコンテナコンテンツの保存先。

ファイル構造
.
├── Dockerfile
├── Makefile
├── container-vol
│   └── test.txt
├── data
│   └── a.txt
├── main.py
└── requirements.txt
main.py
import fire
import os

class Main:
    def __init__(self) -> None:
        pass

    def hello(self):
        output_directory = 'output/'
        os.makedirs(output_directory, exist_ok=True)
        with open(os.path.join(output_directory, 'test.txt'), 'w') as file:
            file.write('Hello')

if __name__  == "__main__":
    fire.Fire(Main)

Dockerfile
FROM python:3.11

WORKDIR /src

COPY . .
RUN python -m pip install --upgrade pip
RUN pip install --no-cache-dir -r requirements.txt

CMD ["bash"]

追記

volumeからというより、コンテナからデータを引っ張ってくるだけならdocker cpで問題ない。
たったこれだけで良いんだ
コンテナ名:コンテナのファイルの出力先 出力先

docker cp cli_container:/src/output $(realpath ./)

Discussion