本記事はDocker ver24.0.7の環境で確認しています。
このコマンドは、Dockerホスト内のファイルやディレクトリを、コンテナ内にコピーすることができます。
コンテナ内のファイルやディレクトリをDockerホストにコピーすることもできます。
※DockerホストとはDocker本体が稼働しているコンピュータを指します。
ハイパーバイザ型の仮想環境では、仮想マシン環境内にftpデーモンなどのサービスを起動して、ホストマシンとのファイルの受け渡しを行うことが多いと思います。
しかし、必要最低限のプロセスしか起動させたくないコンテナ型仮想環境では、ftpデーモンなどは起動せず、docker cpコマンドを使用してファイルのやり取りを行います。
- docker cpコマンドのフォーマットとオプション
- docker cpコマンドの使い方
- 基本事項の解説
- Dockerホスト内のファイルをコンテナ内にコピーする
- コンテナ内のファイルをDockerホストにコピーする
- Dockerホスト内のディレクトリをコンテナ内にコピーする
- コンテナ内のディレクトリをDockerホスト内にコピーする
- ファイルのパーミッションは引き継がれる
- コピーしたファイルのオーナとグループの引継ぎ(「-a」オプション)について
- シンボリックリンク用の「-L」オプションについて
- tarファイルの中身をコンテナ内に展開、またはコンテナ内のファイルやディレクトリをtarファイルに格納する
- コピー先に同名のファイルが存在する場合の動作について
- 停止中のコンテナにDockerホストのファイルをコピーする
- 「-q」オプションについて
- おわりに
docker cpコマンドのフォーマットとオプション
フォーマット
docker cp [オプション] [(コピー元)コンテナ:パス ] [(コピー先)ローカルパス | - ]
docker cp [オプション] [(コピー元)ローカルパス | - ] [(コピー先)コンテナ:パス ]
主なオプション一覧
オプション | 概説 |
---|---|
-a | コピー元のファイルオーナ情報をコピー先のファイルに引き継ぎます。 (注) |
-L | コピー元内のシンボリックリンクをフォローします。 つまり、リンク先の実ファイルがコピー対象となります。 |
-q NEW | コピー中の進行状況の出力を抑制します。(デフォルトは進行状況が出力される) 端末が接続されていない場合、進行状況の出力は自動的に抑制されます。 |
コマンド例
$ docker cp file01.txt testvm:/opt
$ docker cp testvm:/etc/hosts hosts.tmp
$ docker cp dir2 testvm:/opt
$ docker cp testvm:/var/log .
docker cpコマンドの使い方
以下で実例をまじえたコマンドの使い方を解説していきたいと思います。
基本事項の解説
docker cpコマンドは、Dockerホストとコンテナ間でファイルやディレクトリの受け渡しを行うことができます。
具体的には以下の2つです。
- Dockerホスト上のファイルやディレクトリをコンテナ内にコピーする
- コンテナ内のファイルやディレクトリをDockerホスト上にコピーする
コピーはコンテナが停止している場合でも可能です。
DB関連のファイルはサービスが停止してからコピーすれば安心ですね。
以下で実例をまじえて具体的に解説します。
Dockerホスト内のファイルをコンテナ内にコピーする
Dockerホスト内のファイル(例えばfile01.txt)をコンテナ内の/opt下にコピーします。
$ docker cp file01.txt testvm:/opt
コンテナ内にコピーできているか確認します。
$ docker exec testvm ls -l /opt
total 4
-rw-r--r-- 1 test01 users 9 Oct 3 06:51 file01.txt
Dockerホスト内のファイルをコンテナ内に別名でコピーもできます。
$ docker cp file01.txt testvm:/opt/file99.txt
確認です。
$ docker exec testvm ls -l /opt
total 8
-rw-r--r-- 1 test01 users 9 Oct 3 06:51 file01.txt
-rw-r--r-- 1 test01 users 9 Oct 3 06:51 file99.txt
コンテナ内のファイルをDockerホストにコピーする
コンテナ内のファイル(下の例では/etc/hosts)をDockerホスト内のカレントディレクトリにコピーします。
$ docker cp testvm:/etc/hosts .
別名でのコピーも可能です。
$ docker cp testvm:/etc/hosts hosts.tmp
Dockerホスト内のディレクトリをコンテナ内にコピーする
Dockerホスト内にあるディレクトリをコンテナにコピーします。ディレクトリ内にはフィルが格納されています。
Dockerホスト内にディレクトリdir2を作成し、更にそのディレクトリdir2内にファイルを作成します。
$ ls -l
drwxr-xr-x 2 test01 users 23 10月 3 15:51 dir2
$ touch dir2/file02.txt
$ ls -l dir2
合計 0
-rw-rw-r-- 1 test01 users 0 1月 24 11:38 file02.txt
ディレクトリdir2をコンテナ内のoptディレクトリにコピーします。
$ docker cp dir2 testvm:/opt
確認します。
$ docker exec testvm ls -l /opt
total 8
drwxr-xr-x 2 test01 users 23 Oct 3 06:51 dir2
$ docker exec testvm ls -l /opt/dir2
total 4
-rw-rw-r-- 1 test01 users 13 Jan 24 02:20 file02.txt
コンテナ内のディレクトリをDockerホスト内にコピーする
コンテナ内にあるディレクトリを、ディレクトリ配下のファイルも一緒にコピーします。
以下は、コンテナtestvm内にあります/var/logディレクトリをDockerホストにコピーする例です。
事前に、そのディレクトリの中身を確認しておきます。
$ docker exec testvm ls -l /var/log
いくつかファイルとディレクトリが入っていることが確認できます。
total 232
-rw-r--r-- 1 root root 3189 Apr 23 11:09 alternatives.log
drwxr-xr-x 2 root root 4096 Apr 23 11:09 apt
-rw-r--r-- 1 root root 58592 Apr 23 11:06 bootstrap.log
-rw-rw---- 1 root utmp 0 Apr 23 11:06 btmp
-rw-r--r-- 1 root root 130326 Apr 23 11:09 dpkg.log
-rw-r--r-- 1 root root 3232 Apr 23 11:06 faillog
-rw-rw-r-- 1 root utmp 29492 Apr 23 11:06 lastlog
-rw-rw-r-- 1 root utmp 0 Apr 23 11:06 wtmp
このコンテナtestvm内の/var/logディレクトリを、Dockerホストのカレントディレクトリにコピーしてみます。
$ docker cp testvm:/var/log .
確認してみます。
$ ls -l
total 8
drwxr-xr-x 3 test01 users 4096 Apr 23 20:06 log
$ ls -l log
total 232
-rw-r--r-- 1 test01 users 3189 Apr 23 20:09 alternatives.log
drwxr-xr-x 2 test01 users 4096 Apr 23 20:09 apt
-rw-r--r-- 1 test01 users 58592 Apr 23 20:06 bootstrap.log
-rw-rw---- 1 test01 users 0 Apr 23 20:06 btmp
-rw-r--r-- 1 test01 users 130326 Apr 23 20:09 dpkg.log
-rw-r--r-- 1 test01 users 3232 Apr 23 20:06 faillog
-rw-rw-r-- 1 test01 users 29492 Apr 23 20:06 lastlog
-rw-rw-r-- 1 test01 users 0 Apr 23 20:06 wtmp
Dockerホストのカレントディレクトリにlogディレクトリがコピーされて、そのディレクトリ内にコンテナ内にあったファイルとディレクトリがコピーされていることが確認できました。
コピーされたファイルとディレクトリのオーナーに関しましては後述しております。
ファイルのパーミッションは引き継がれる
docker cpコマンドでコピーしたファイルのパーミッションは、コピー元の情報が引き継がれます。
実際に確認してみましょう。
Dockerホスト内にパーミッションが664のファイルを作成しました。
$ ls -l
-rw-rw-r-- 1 test01 users 8 10月 3 15:52 file03.txt
このDockerホスト内のファイルfile03.txtをコンテナ内にコピーします。
$ docker cp file03.txt testvm:/opt
コンテナ内のfile03.txtのパーミッションを確認します。
$ docker exec testvm ls -l /opt
-rw-rw-r-- 1 1001 users 8 Oct 3 06:52 file03.txt
コンテナ内のファイルもパーミッションが664になってます。
次に、コンテナ内のfile03.txtのパーミッションを666に変更後、Dockerホストにコピーします。
$ docker exec testvm chmod 666 /opt/file03.txt
$ docker exec testvm ls -l /opt
-rw-rw-rw- 1 1001 users 8 Oct 3 06:52 file03.txt
コンテナ内のfile03.txt(パーミッションは666)をDockerホストにfile10.txtとしてコピーします。
$ docker cp testvm:/opt/file03.txt file10.txt
コピーしたファイルのパーミッションが666であることを確認します。
$ ls -l
-rw-rw-rw- 1 test01 users 8 10月 3 15:52 file10.txt
コピーしたファイルのオーナとグループの引継ぎ(「-a」オプション)について
docker cpコマンドのヘルプ(docker cp --helpを実行すると表示される)を見ましたら、「-a」が追加されていました。
Docker公式ドキュメント(Reference documentation)を確認したところ、以下の表記がありました。
The cp command behaves like the Unix cp -a command in that directories are copied recursively with permissions preserved if possible. Ownership is set to the user and primary group at the destination. For example, files copied to a container are created with UID:GID of the root user. Files copied to the local machine are created with the UID:GID of the user which invoked the docker cp command. However, if you specify the -a option, docker cp sets the ownership to the user and primary group at the source.
Docker公式サイトより引用
「Google翻訳」
cpコマンドはUnixのcp -aコマンドと同じように動作します。この場合、ディレクトリは再帰的にコピーされ、可能であればアクセス権が保持されます。所有権は、宛先のユーザーおよび1次グループに設定されます。たとえば、コンテナにコピーされたファイルは、rootユーザーのUID:GIDで作成されます。ローカルマシンにコピーされたファイルは、docker cpコマンドを呼び出したユーザーのUID:GIDで作成されます。ただし、-aオプションを指定した場合、docker cpはソースのユーザーとプライマリグループに所有権を設定します。
デフォルトではファイルのオーナ情報は引き継がないが、「-a」オプションを付けることでオーナを引き継ぐそうです。
実際に試してみました。
Dockerホスト上にファイルを作成します。
$ touch file03.txt
オーナ情報を確認します。
$ ls -l file03.txt
-rw-rw-r--. 1 test01 users 0 3月 22 10:04 file03.txt
コンテナtestvm内にコピーします。
$ docker cp -a file03.txt testvm:/root
コンテナtestvm内のfile03.txtファイルを確認します。
$ docker exec testvm ls -l /root
-rw-rw-r--. 1 2000 users 0 Mar 22 01:04 file03.txt
コンテナtestvm内にtest01ユーザが存在していませんでしたので、Dockerホスト上のtest01ユーザのuidである2000が表示されています。
$ id test01
uid=2000(test01) gid=100(users) groups=100(users)
※Dockerホスト上のtest01ユーザの情報
確かにコピー元のオーナ情報がコピー先に引き継がれています。
念のため、「-a」オプション無しでコピーしてみました。
まずコンテナtestvm内のファイルを削除します。
$ docker exec testvm rm /root/file03.txt
$ docker exec testvm ls -l /root
コピーしてみます。
$ docker cp file03.txt testvm:/root
コンテナtestvm内のfile03.txtファイルの確認です。
$ docker exec testvm ls -l /root
-rw-rw-r--. 1 2000 users 0 Mar 22 01:04 file03.txt
オーナは引き継がれています・・・。
コピー対象がディレクトリの場合もファイルと同様の動作内容でした。
ちなみに、コンテナ内のファイルをDockerホスト上にコピーしてみたのですが、こちらの方は「-a」を付けても付けなくてもオーナ情報は引き継がれませんでした。
rootユーザでも試しましたが状況は変わりません。
※「docker-ce 19.03.10」に引き続き「docker 24.0.7」でも状況は変わっていませんでした
SEの方でしたら、コピー前と後のファイルやディレクトリの状態は確認されると思いますのでトラブルにつながりにくいかもしれませんが、お気を付けください。
シンボリックリンク用の「-L」オプションについて
シンボリックリンクを「-L」オプション付きでコピーしますと、リンク先のファイルがコピーされます。コピー先のファイル名は、コピー元のシンボリックリンク名になります。
オプションを付けない場合は、シンボリックリンクそのものがコピーされます。
Dockerホスト上で、まずディレクトリdir5内にファイルfile05.txtを作成します。そのfile05.txtにシンボリックリンクlnfile05.txtを設定します。
$ mkdir dir5
$ touch dir5/file05.txt
$ echo file05 > dir5/file05.txt
$ ln -s dir5/file05.txt lnfile05.txt
$ ls -l
合計 24
drwxrwxr-x 2 test01 users 23 1月 24 11:27 dir5
lrwxrwxrwx 1 test01 users 15 1月 24 11:27 lnfile05.txt -> dir5/file05.txt
$ cat lnfile05.txt
file05
dir5内のfile05.txtには「file05」と書き込みました。
では、このDockerホスト内のシンボリックリンクのファイルをコンテナ内の/optにコピーしてみます。
まずはオプション無しでやってみます。
$ docker cp lnfile05.txt testvm:/opt
コピー先のファイルを確認してみます。
$ docker exec testvm ls -l /opt
total 0
lrwxrwxrwx 1 test01 users 15 Oct 5 01:33 lnfile05.txt -> dir5/file05.txt
シンボリックリンクそのものがコピーされてます。
内容を表示してみます。
$ docker exec testvm cat /opt/lnfile05.txt
cat: /opt/lnfile05.txt: No such file or directory
リンク先のファイルが存在しないので当然の結果ですね。
コピーしたコンテナ内のシンボリックリンクを削除します。
$ docker exec testvm rm /opt/lnfile05.txt
今度は-Lオプションを付けて試してみます。
$ docker cp -L lnfile05.txt testvm:/opt
コピー先のファイルを確認してみます。
$ docker exec testvm ls -l /opt
total 4
-rw-r--r-- 1 test01 users 7 Oct 5 01:33 lnfile05.txt
コンテナ内にlnfile05.txtが作成されましたが、シンボリックリンクではありません。内容を表示してみましょう。
$ docker exec testvm cat /opt/lnfile05.txt
file05
コピー元のシンボリックリンクのリンク先のファイルfile05.txtの内容になっています。
コンテナ内のシンボリックリンクをDockerホスト内にコピーする場合も、同じ動作になります。
実例は省略します。
tarファイルの中身をコンテナ内に展開、またはコンテナ内のファイルやディレクトリをtarファイルに格納する
コンテナ内の/optディレクトリ下のファイルをDockerホスト上のtarファイルに格納します。
$ docker cp testvm:/opt - > test.tar
コピー先として「-」を指定してますが、これはDockerホストの標準出力を意味します。コピー先に「-」を指定することによって、docker cpコマンドは、コピー元の内容をtar形式で標準出力に出力します。
上記コマンドは、その出力内容をtest.tarにリダイレクトで出力してます。(- >は矢印ではありません)
ファイルの存在確認後、「tar tvf」コマンドでtarファイルの内容を確認してみます。
$ ls -l
合計 24
-rw-r--r-- 1 test01 users 2560 10月 5 13:11 test.tar
$ tar tvf test.tar
drwxr-xr-x 0/0 0 2016-10-05 11:09 opt/
-rw-r--r-- 0/0 22 2016-10-05 11:06 opt/test06.txt
確かにコンテナ内の/opt下のファイルが格納されてます。
今度は、このtarファイルの内容を、コンテナ内の/tmp下に展開してみます。
$ docker cp - testvm:/tmp < test.tar
コピー元として「-」を指定してますが、これはDockerホストの標準入力を意味します。コピー元に「-」を指定することによって、docker cpコマンドは、標準入力から入力された内容をtar形式として受け取り、コピー先に展開します。上記コマンドは、test.tarからリダイレクトで、そのファイルの内容を入力してます。
コンテナ内のコピー先を確認してみます。
$ docker exec testvm ls -l /tmp
total 4
drwxr-xr-x 2 test01 users 23 Oct 5 02:09 opt
$ docker exec testvm ls -l /tmp/opt
total 4
-rw-r--r-- 1 test01 users 22 Oct 5 02:06 test06.txt
コピー先/tmpにoptディレクトリが作成されており、optディレクトリ内にtest06.txtファイルが展開されていることが確認できます。
コピー先に同名のファイルが存在する場合の動作について
コピー先に同名のファイルが存在する場合は、確認無く上書きされます。
ご注意ください。
コンテナ内の/optにファイルtest06.txtがあります。
$ docker exec testvm ls -l /opt
total 4
-rw-r--r-- 1 test01 users 37 Oct 5 02:02 test06.txt
$ docker exec testvm cat /opt/test06.txt
aaaaaaaaaaa
bbbbbbbbbbb
ccccccccccc
以下のDockerホスト内のファイルtest06.txtを準備しました。
$ ls -l
$ cat test06.txt
zzzzzz
yyyyyy
xxxxxx
このファイルをコンテナ内の/optにコピーしてみます。
$ docker cp test06.txt testvm:/opt
コピーしたファイルの内容を確認してみます。
$ docker exec testvm cat /opt/test06.txt
zzzzzz
yyyyyy
xxxxxx
上書きされました。
停止中のコンテナにDockerホストのファイルをコピーする
まず、コンテナtestvmを停止します。
$ docker stop testvm
コンテナ内の/etc/hostsファイルを、Dockerホスト内のカレントディレクトリにコピーします。
$ docker cp testvm:/etc/hosts hosts.tmp2
もちろん逆に、Dockerホスト内のファイルをコンテナ内にコピーも出来ます。
$ docker cp file01.txt testvm:/opt/file99.txt
「-q」オプションについて
以前はdocker cpコマンドを実行しても特にメッセージは表示されなかったのですが、コピー処理の実行状況に関するメッセージが出力されるようになりました。(たぶんバージョン23.xからと思われます)
$ docker cp file01.txt testvm:/opt
Successfully copied 2.05kB to testvm:/opt
$
「Successfully …」の部分です。
小さいファイルのコピーは一瞬で終わってしまいますので、ターミナルのログを採取してメッセージの出力を確認してみました。
その結果、以下のメッセージが出力されていました。
Preparing to copy...
Copying from container - 0B
Successfully copied 2.05kB to testvm:/opt
その他にも出力されるメッセージがあるかもしれませんので、必要に応じてご確認ください。
「-q」オプションを付けますと、実行状況のメッセージが出力されなくなります。
$ docker cp -q file01.txt testvm:/opt
$
余計なメッセージが出力されますとシェルスクリプトなどで不具合が発生するかもしれませんので、メッセージが不要な場合は「-q」オプションをご利用ください。
なお、「-q」オプションを付けても、エラーメッセージは出力されます。
$ docker cp -q file.txt testvm:/opt
lstat /home/test01/file.txt: no such file or directory
$
おわりに
以上でdocker cpコマンドの紹介を終わります。
ご指摘、ご要望などが御座いましたらコメントいただけるとうれしいです。
他のDockerコマンドの実例付紹介記事は、本サイト内の別記事「Dockerコマンドの一覧(オリジナルな実例付き)」をご参照ください。
ご訪問ありがとうございました!
コメント