Bash関数: DockerVolumeでのCopy
Intro
意外なことに、DockerのVolumeと単体でファイルをやりとりする方法がない。
幸い、これはいとも簡単に解決される。
TL; DR
DockerおよびDocker Volumeの紹介を行う。
さらに、Docker Volume (名前付きVolume) へのファイルコピーを行うBash関数を作成する。
Docker
まず、Dockerの簡単な紹介を軽くしておこう。
- Dockerは、コンテナ型の仮想化技術を提供するプラットフォームである。
- これにより、アプリケーションを環境から切り離して実行できる。
- 新規の環境準備の手間も、既存の環境への汚染も、両方の懸念がなくなる。
- 移行や導入、カスタマイズが非常に容易になる。
- 単体のソフトだけではなく、複数のソフトを組み合わせた環境も簡単に構築できる。
- Dockerfileやdocker-compose.ymlというテキストファイルで管理できるので、環境のカスタマイズも容易で見通しがいい。管理や移行も簡単だ。
- 複雑なアプリケーションに限らず、さっと新しい言語に触れたり、異なる環境を試すのにも便利。
- AWSやAzure、GCPなどのクラウドサービスでもDockerをサポートしている。
Docker利用ケース
実際に筆者がDockerを利用している/していたケースを紹介する。
導入・運用の手間軽減
- Minecraftサーバー
ボットおよびスクリプト関連
- 複数環境でのDiscord Botの安定運用
- 複数環境でのScript実行
開発およびコンパイル環境
- 簡単にLaTeXのコンパイル環境を構築
- Go, Rust, Juliaなどに触れるための環境
動作確認および検証
- 新規のUbuntuでの動作確認
- アプリケーションで不具合が生じた際、環境由来の影響を排除するため
Webアプリケーション導入
- GrowiやCodimdなどのWebアプリケーション導入
- もともとOnlineで動かしてるphpmyadminのlocal動作検証
一時的な利用環境
- 研修で一瞬だけ入れたJava環境
Docker Volume
実は、Dockerのコンテナ(VMみたいなもの)は、データの非保持が原則だ。
コンテナを閉じるまではデータが保持されるが、再度コンテナを立ち上げるとデータは消える (Imageの状態に初期化される)。
それに対する解決策は、以下の通り。
- DockerコンテナのImageを都度、再作成する
- 内部データ永続化のためのイメージ作成はおすすめしない。
- Dockerは処理ごとに差分バックアップをとっているので、この手法を続けると、容量が膨れ上がる。
- なにより、DockerのImageの利用方法として不適切だ。
- 内部データ永続化のためのイメージ作成はおすすめしない。
- ホストOSのディレクトリをマウントする (Bind Mount)
- この方法は、コンテナ内のデータをホストOSのディレクトリと同期することで、データの永続化を実現する。
- 常にホストOS側でデータにアクセスできるので、管理も簡単。
- ただ、この処理はDockerコンテナの動作を非常に低速化する。
- 少数のファイルや簡単な処理の場合は問題ない
- LaTeXのコンパイルや、簡単なスクリプトの実行など
- Docker Volume (正確には名前付きVolume) を利用する
- 一般的なVMにおけるStorageとしてとらえるとよい
- コンテナにattachされる形で、コンテナのデータを保持する
- 一般的なVMにおけるStorageとしてとらえるとよい
Docker Volume in script
docker runの際に、-vまたは--mountオプションを利用することで、Docker Volumeを利用できる。docker docsより引用。
1 | |
Docker Volume in docker-compose.yml
今回はあまり触れていないが、Docker ComposeというDockerの拡張を利用すると、複数のDockerサービスや実行時のオプションを一つのYAMLファイルで管理できる。
以下はMincecraft Bedrock Serverを立ち上げるdocker-compose.ymlの例。
1 | |
Docker Composeの説明 by ChatGPT
Docker Composeの説明 by ChatGPT
Docker Composeは、複数のDockerコンテナを定義・管理し、まとめて起動・停止するためのツールです。docker-compose.ymlという設定ファイルを用いて、アプリケーションの各サービスを記述し、一括して管理します。これにより、複雑なアプリケーションの環境を簡単に設定し、再現することができます。
Docker Composeのメリット
簡単な設定管理:
docker-compose.ymlファイルにより、複数のコンテナ設定を一つのファイルで管理可能。
一括操作:
- 複数のコンテナを一度に起動・停止・再起動できるため、操作が効率的。
開発環境の再現性:
- 同じ設定ファイルを使用することで、開発環境やテスト環境を簡単に再現可能。
依存関係の管理:
- サービス間の依存関係を明確に定義でき、起動順序の制御が容易。
ネットワーキングの簡素化:
- 複数のコンテナ間のネットワーク設定が自動で行われ、手動でのネットワーキング設定が不要。
これらのメリットにより、Docker Composeは開発者や運用担当者にとって非常に有用なツールとなっています。
不満点: 単体でCopyができない
で、DockerやDocker Volumeのすばらしさが伝わったところで、何が不満なのか。
Docker Volume単体へのCopyができない。
かみ砕いて説明しよう。
いかにもcopyをしそうなdocker cpは、コンテナとホストOS間のファイルコピーを行うコマンドだ。通常のcpと似た感覚で利用できる。
1 | |
これはコンテナとのファイルコピーであり、Docker Volumeとのファイルコピーではない。
当然、Docker Volumeがコンテナにマウントされている場合は、コンテナ内のファイルをDocker Volumeにコピーすることができるが、いつでもDocker Volumeがマウントされているわけではない。
たとえば、MinecraftサーバーのためのVolumeの場合、サーバー本体立ち上げ前にVolumeにワールドデータをコピーしておきたいものだろう。
解決策
情報元
さて、すべてを簡単に解決してしまう情報元はGitHub Issueである。
1 | |
あるいは、日本語のこちらのBlogを閲覧した人も多いだろう。(情報元は同じ)
つまり一度コンテナを作ってしまえばdocker cpが使えるので解決できるわけです。
コンテナを作って削除すれば、volumeだけ残るので結果的にやりたいことが実現できるわけですね。
またホストからコピーしたvolumeを作るだけなのでdocker runでわざわざ起動せずとも、docker container createで済みます。
作成されたScript
さて、すでに問題は解決しているのだが、これをScript化することで、より簡単にファイルのコピーを行うことができる。
1 | |
実際の使用例
1 | |
今回のScriptの技術的な解説 by ChatGPT
今回のScriptの技術的な解説 by ChatGPT
以下のスクリプトは、Dockerボリュームとホスト間でファイルをコピーするためのものです。新しいスクリプトでは、ファイルのコピー方向(ホストからボリューム、またはボリュームからホスト)を判断するためにmode変数を追加しています。これにより、どちらの方向にもファイルをコピーできるようになります。
スクリプトの解説
エイリアスの設定
1
alias dockerVolCp="_DockerVolume_Copy"dockerVolCpというエイリアスを設定し、このエイリアスが呼ばれると_DockerVolume_Copy関数が実行されます。
関数の定義
1
function _DockerVolume_Copy(){dockerVolCpコマンドが実行されると、この関数が動作します。
一時的なコンテナ名の作成
1
container_name="tmp_volcp"$(date +%s)- 現在の時刻を使ってユニークなコンテナ名を作成します。
引数の解析とコピー方向の判断
1
2
3
4
5
6
7
8
9if [[ "$1" == *":"* ]]; then
mode="from"
virtual_path="$1"
host_path="$2"
else
mode="to"
host_path="$1"
virtual_path="$2"
fi- 最初の引数に「:(コロン)」が含まれている場合、Dockerボリュームからホストへコピーする(
mode="from")。 - コロンが含まれていない場合、ホストからDockerボリュームへコピーする(
mode="to")。
- 最初の引数に「:(コロン)」が含まれている場合、Dockerボリュームからホストへコピーする(
ボリューム名とパスの設定
1
2volume_name=$(echo $virtual_path | cut -d: -f1)
virtual_dest=$(echo $virtual_path | cut -d: -f2)virtual_pathからボリューム名と、ボリューム内のパスを分割して取得します。
一時的なコンテナの作成
1
docker container create --name $container_name -v $volume_name:/root hello-world- Dockerボリュームをマウントした一時的なコンテナを作成します。
ファイルのコピー
1
2
3
4
5if [[ $mode == "from" ]]; then
docker cp $host_path $container_name:/root/$virtual_dest
else
docker cp $container_name:/root/$virtual_dest $host_path
fimode変数に基づいて、適切な方向にファイルをコピーします。mode="from"の場合、ホストからコンテナへコピーします。mode="to"の場合、コンテナからホストへコピーします。
一時的なコンテナの削除
1
docker rm $container_name- コピーが終わったら、一時的なコンテナを削除します。
使い方の例
ホストからDockerボリュームへコピー
1
dockerVolCp /path/to/local/file volume_name:/path/in/volumeDockerボリュームからホストへコピー
1
dockerVolCp volume_name:/path/in/volume /path/to/local/file
このスクリプトを使うことで、Dockerボリュームとホスト間のファイルコピーが簡単に行えるようになります。
まとめ
Docker Volumeは、DockerコンテナとホストOS間でデータを共有するための便利な機能である。しかし、DockerコマンドにはDocker Volume単体へのファイルコピー機能がないため、スクリプトを作成することでこの問題を解決した。













