docker cpコマンドの使い方(実例で解説)

docker cpコマンド解説

 本記事はDocker ver24.0.7の環境で確認しています。

 このコマンドは、Dockerホスト内のファイルやディレクトリを、コンテナ内にコピーすることができます。

 コンテナ内のファイルやディレクトリをDockerホストにコピーすることもできます。

※DockerホストとはDocker本体が稼働しているコンピュータを指します。

 ハイパーバイザ型の仮想環境では、仮想マシン環境内にftpデーモンなどのサービスを起動して、ホストマシンとのファイルの受け渡しを行うことが多いと思います。

 しかし、必要最低限のプロセスしか起動させたくないコンテナ型仮想環境では、ftpデーモンなどは起動せず、docker cpコマンドを使用してファイルのやり取りを行います。

docker cpコマンドのフォーマットとオプション

フォーマット

docker cp [オプション] [(コピー元)コンテナ:パス ] [(コピー先)ローカルパス | - ]
docker cp [オプション] [(コピー元)ローカルパス | - ] [(コピー先)コンテナ:パス ]

主なオプション一覧

オプション概説
-aコピー元のファイルオーナ情報をコピー先のファイルに引き継ぎます。
-Lコピー元内のシンボリックリンクをフォローします。
つまり、リンク先の実ファイルがコピー対象となります。
-q NEWコピー中の進行状況の出力を抑制します。(デフォルトは進行状況が出力される)
端末が接続されていない場合、進行状況の出力は自動的に抑制されます。
)Docker公式情報と実際の挙動が異なっています。表内の記載内容はDocker公式情報の内容です

コマンド例

$ 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コマンドの使い方

 以下で実例をまじえたコマンドの使い方を解説していきたいと思います。

実例では、Ubuntuの公式イメージにより起動したコンテナ(testvm)を使用します。

コンテナは「docker run -dit --init --name testvm ubuntu」で起動します。

※「--rm」オプションを付けておりませんので、ご利用後はコンテナ削除をお忘れなく。

基本事項の解説

 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コマンドの一覧(オリジナルな実例付き)」をご参照ください。

 ご訪問ありがとうございました!

コメント