docker cpコマンドの使い方(実例付)CE対応


 docker cpコマンドの使い方を解説します。Docker CE ver18.06.0に対応してます。

 このコマンドは、Dockerホスト内のファイル/ディレクトリをコンテナ内にコピー、もしくはコンテナ内のファイル/ディレクトリをDockerホストにコピーすることが出来ます。

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

 コピーは、起動しているコンテナだけで無く、停止しているコンテナでも可能です。

 ハイパーバイザ型の仮想環境では、仮想マシン環境内にftpデーモンなどのサービスを起動して、ホストマシンとのファイルの受け渡しを行うことが多いと思います。しかし、必要最低限のプロセスしか起動させたくないコンテナ型仮想環境では、ftpデーモンなどは起動せず、docker cpコマンドを使用してファイルのやり取りを行います。

 それでは以下で詳細に解説いたします。

 

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

フォーマット

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

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

 

主なオプション一覧

-a
コピー元のファイルオーナ情報をコピー先のファイルに引き継ぎます。(バグ確認

-L
コピー元内のシンボリックリンクをフォローします。つまり、リンク先の実ファイルがコピー対象となります。

■ 本記事の目次に戻る ■

docker cpコマンドの主な使い方

 以下の実例は、CentOSの公式イメージにより起動したコンテナ(testvm)を使用します。コンテナは「docker run -d --name testvm centos init」で起動します。

Dockerホスト内のファイルをコンテナ内にコピーする

 Dockerホスト内のファイル(例えばfile01.txt)をコンテナ内の/opt下にコピーします。

$ docker cp file01.txt testvm:/opt

 以下のコマンドでコンテナ内のファイルを確認できます。

$ docker exec testvm ls -l /opt
total 4
-rw-r--r-- 1 root root 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 root root 9 Oct 3 06:51 file01.txt
-rw-r--r-- 1 root root 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ホスト内にディレクトリ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 root root 23 Oct 3 06:51 dir2
$ docker exec testvm ls -l /opt/dir2
total 4
-rw-rw-r-- 1 root root 13 Jan 24 02:20 file02.txt

■ 本記事の目次に戻る ■

コンテナ内のディレクトリをDockerホスト内にコピーする

 コンテナtestvm内に/var/logディレクトリがあります。事前に、そのディレクトリの中身を確認しておきます。

$ docker exec testvm ls -l /var/log

 いくつかファイルとディレクトリが入っていることが確認できます。

total 32
-rw-------. 1 root utmp 0 May 31 18:02 btmp
-rw-r--r--. 1 root root 193 May 31 18:02 grubby_prune_debug
-rw-r--r--. 1 root root 23944 May 31 18:02 lastlog
-rw-------. 1 root root 0 May 31 18:02 tallylog
-rw-rw-r--. 1 root utmp 0 May 31 18:02 wtmp
-rw-------. 1 root root 1368 May 31 18:03 yum.log

 このコンテナtestvm内の/var/logディレクトリを、Dockerホストのカレントディレクトリにコピーしてみます。

$ docker cp testvm:/var/log .

 確認してみます。

$ ls -l
 合計 0
 drwxr-xr-x 3 test01 users 43 11月 2 21:47 log
$ ls -l log
合計 32
-rw-------. 1 test01 users 0 6月 1 03:02 btmp
-rw-r--r--. 1 test01 users 193 6月 1 03:02 grubby_prune_debug
-rw-r--r--. 1 test01 users 23944 6月 1 03:02 lastlog
-rw-------. 1 test01 users 0 6月 1 03:02 tallylog
-rw-rw-r--. 1 test01 users 0 6月 1 03:02 wtmp
-rw-------. 1 test01 users 1368 6月 1 03:03 yum.log

 Dockerホストのカレントディレクトリにlogディレクトリがコピーされて、そのディレクトリ内にコンテナ内にあったファイルとディレクトリがコピーされていることが確認できました。

 コピーされたファイルとディレクトリのオーナーに関しましては後述しております。

■ 本記事の目次に戻る ■

ファイルのパーミッションは引き継がれる

 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 root root 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 root root 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

■ 本記事の目次に戻る ■

コピーしたファイルのオーナとグループについて 更新

 docker cpコマンドのヘルプ(docker cp --helpを実行すると表示される)を見たところ、新しく「-a」が追加されていました。

 Docker公式ドキュメント(18.03版)を確認したところ、以下の表記がありました。

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コマンドのように動作します。可能であれば、ディレクトリは再帰的にコピーされ、パーミッションは保存されます。 所有権は、宛先のユーザーおよびプライマリグループに設定されます。 たとえば、コンテナにコピーされたファイルは、ルートユーザーの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」を付けても付けなくてもオーナ情報は引き継がれませんでした。

※「docker-ce 17.12.1」に引き続き「docker-ce 18.06.0」でも状況は変わっていませんでした

■ 本記事の目次に戻る ■

シンボリックリンク用のオプション-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 root root 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 root root 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 root root 23 Oct 5 02:09 opt
$ docker exec testvm ls -l /tmp/opt
total 4
-rw-r--r-- 1 root root 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 root root 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

 

 以上でdocker cpコマンドの紹介を終わります。

 ご指摘、ご要望などが御座いましたらコメントいただけるとうれしいです。

 他のDockerコマンドの実例付紹介記事は、本サイト内の別記事「Dockerのコマンドの一覧(ver1.12対応版)(オリジナルな実例付き)」をご参照ください。

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


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください