DockerfileのCOPY
コマンドとADD
コマンドの違いは何ですか?また、どちらを使用するのですか?
COPY <src> <dest>
COPY命令は
<src>
から新しいファイルをコピーし、それらをパス<dest>
でコンテナのファイルシステムに追加します。
ADD <src> <dest>
ADD命令は
<src>
から新しいファイルをコピーし、それらをパス<dest>
でコンテナのファイルシステムに追加します。
あなたは ADD
と COPY
のドキュメントでそれらの振る舞いの徹底的な説明をチェックするべきですが、一言で言えばADD
はCOPY
以上のことができるということです:
ADD
は<src>
をURLにすることを可能にしますADD
の<src>
パラメータが認識された圧縮形式のアーカイブである場合、それは解凍されますDockerfilesを書くためのベストプラクティス は、COPY
の魔法が必要ではない場合にADD
を使うことを示唆していることに注意してください。さもなければあなたは(あなたがこの答えを調べなければならなかったので)あなたがkeep_this_archive_intact.tar.gz
をあなたのコンテナにコピーしようとするときいつか驚くかもしれませんが、代わりにあなたはあなたのファイルシステムに内容をスプレーします。
その点に関する公式の文書がいくつかあります: Dockerfilesを書くためのベストプラクティス
画像サイズが重要であるため、
ADD
を使用してリモートURLからパッケージを取得することは強くお勧めできません。代わりにcurl
またはwget
を使用してください。そうすれば、不要になったファイルを抽出した後で削除でき、イメージに別のレイヤーを追加する必要がなくなります。
RUN mkdir -p /usr/src/things \
&& curl -SL http://example.com/big.tar.gz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all
ADD
のtar自動抽出機能を必要としない他の項目(ファイル、ディレクトリ)については、常にCOPY
を使うべきです。
Dockerのドキュメントから:
追加またはコピー
ADDとCOPYは機能的に似ていますが、一般的に言って、COPYが好ましいです。それはADDよりも透明度が高いからです。 COPYはローカルファイルのコンテナへの基本的なコピーのみをサポートしていますが、ADDには(ローカルのみのtar抽出やリモートURLサポートなどの)すぐには明らかではない機能があります。したがって、ADDの最善の使用方法は、ADD rootfs.tar.xz /のように、イメージへのローカルtarファイルの自動抽出です。
Xx.tar.gzをコンテナ内の/usr/local
に追加する場合は、それを解凍してから、不要な圧縮パッケージを削除します。
COPYの場合:
COPY resources/jdk-7u79-linux-x64.tar.gz /tmp/
RUN tar -zxvf /tmp/jdk-7u79-linux-x64.tar.gz -C /usr/local
RUN rm /tmp/jdk-7u79-linux-x64.tar.gz
追加の場合:
ADD resources/jdk-7u79-linux-x64.tar.gz /usr/local/
ADDはローカルのみのtar抽出をサポートしています。それに加えて、COPYは3つのレイヤーを使いますが、ADDは1つのレイヤーしか使いません。
Dockerのドキュメントから: https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#add-or-copy
「ADDとCOPYは機能的には似ていますが、一般的に言って、COPYが好ましいのです。これは、ADDよりも透過的であるためです。そのため、ADDの最善の使用方法は、ADD rootfs.tar.xz /のように、ローカルのtarファイルをイメージに自動抽出することです。
コンテキストとは異なるファイルを使用するDockerfileステップが複数ある場合は、それらをまとめてコピーするのではなく、個別にコピーします。これにより、特に必要なファイルが変更された場合にのみ、各ステップのビルドキャッシュが無効化されます(強制的にステップが再実行されます)。
例えば:
COPY requirements.txt /tmp/
RUN pip install --requirement /tmp/requirements.txt
COPY . /tmp/
COPYを入力した場合よりも、RUNステップのキャッシュ無効化が少なくなります。それの前に/ tmp /。
画像サイズが重要なので、リモートURLからパッケージを取得するためにADDを使用することは強くお勧めできません。代わりにcurlかwgetを使うべきです。これにより、不要になったファイルを抽出した後に削除でき、イメージに別のレイヤーを追加する必要がなくなります。たとえば、次のようなことは避けてください。
ADD http://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
RUN make -C /usr/src/things all
代わりに、次のようにします。
RUN mkdir -p /usr/src/things \
&& curl -SL htt,p://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all
ADDのtar自動抽出機能を必要としない他の項目(ファイル、ディレクトリ)については、常にCOPYを使用するべきです。」
COPY
はファイル/ディレクトリをあなたのホストからあなたのイメージにコピーします。
ADD
はあなたのホストからあなたのイメージにファイル/ディレクトリをコピーしますが、リモートURLの取得、TARファイルの抽出などもできます。
単純にファイルやディレクトリをビルドコンテキストにコピーするには、COPY
を使用します。
ADD
を使ってリモートリソースをダウンロードしたり、TARファイルを展開したりします。
_コピー_
これにより、1つ以上のローカルファイルまたはフォルダがDockerイメージ内の保存先にコピーされます。
COPY < src> < dest >
COPY ["< source >",... "< destination >"]
(この形式は空白を含むパスに必要です)
COPY
を使用するDockerfileの例これはRubyアプリケーションのDockerfileでCOPY
を使用する方法です。
FROM Ruby:2.5.1
WORKDIR /usr/src/app
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .
CMD ["./your-daemon-or-script.rb"]
これは、FROMを使用して定義された親イメージRuby:2.5.1から始めて、レイヤーでイメージを構築します。
Docker命令のWORKDIR
は、それに続くCOPY
またはADD
命令の作業ディレクトリを定義します。
Gemfiles
の後にRUN bundle install
をコピーすることで、インストールされたRuby Gemsを使ってイメージレイヤーが作成されます。最後の2つのDocker命令は、アプリのファイルをイメージにコピーし、CMD
を使用してデフォルトのコマンドを設定します。
つまり、アプリのファイルを変更した場合は、キャッシュされた親レイヤーと中間レイヤーを使用してDockerイメージを再構築できます。これは、すべてをゼロから構築するよりもはるかに効率的です。
_追加_
この命令はCOPY
と似た構文をしています。
ADD < src> < dest >
ADD ["< source >",... "< destination >"] (this form is required for paths containing whitespace)
ローカルファイルやディレクトリをDockerイメージ内のコピー先にコピーするだけでなく、いくつかの追加機能があります。
<source>
が認識された圧縮形式のローカルのtarアーカイブである場合、それはDockerイメージへのディレクトリとして自動的に解凍されます。例えば、次のとおりです。ADD rootfs.tar.xz /
<source>
がURLの場合は、ファイルをダウンロードしてDockerイメージ内の保存先にコピーします。しかし、Dockerはこの目的のためにADDを使用することを勧めません。
URLからコピーするためのDockerfileのベストプラクティス
Dockerは、ADDを使用してURLからコピーするのは効率的ではないことが多く、必要なリモートファイルを含めるために他の方法を使用することをお勧めします。
画像サイズが重要なので、リモートURLからパッケージを取得するためにADDを使用することは強くお勧めできません。代わりにcurlかwgetを使うべきです。これにより、不要になったファイルを抽出した後に削除することができ、画像に別のレイヤーを追加する必要がなくなります。 - Dockerfileのベストプラクティス
たとえば、次のようなことは避けてください。
ADD http://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
RUN make -C /usr/src/things all
代わりに、次のようにします。
RUN mkdir -p /usr/src/things \
&& curl -SL http://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all
ADD
のtar自動抽出機能を必要としない他の項目(ファイル、ディレクトリ)については、常にCOPY
を使うべきです。
ソース: https://nickjanetakis.com/blog/docker-tip-2-the-difference-between-copy-and-add-in-a-dockerile :
COPYとADDは、どちらもDockerfileの命令であり、同様の目的で使用されます。特定の場所からDockerイメージにファイルをコピーできます。
COPYはsrcとdestinationを取り込みます。ローカルファイルまたはディレクトリをホスト(Dockerイメージを構築しているマシン)からDockerイメージ自体にコピーインすることだけが可能です。
ADDでもこれを実行できますが、他の2つのソースもサポートされています。まず、ローカルのファイル/ディレクトリの代わりにURLを使うことができます。次に、ソースから直接tarファイルを宛先に抽出することができます。
ADDの有効な使用例は、ローカルのtarファイルをDockerイメージの特定のディレクトリに抽出したい場合です。
ローカルファイルをDockerイメージにコピーインする場合は、明示的なので常にCOPYを使用してください。
私は自分のdockerイメージの中でJavaパッケージをCOPY
そしてuntarしなければなりませんでした。 ADDを使用して作成されたdockerイメージのサイズを、COPYを使用して作成されたものと比べて180MB大きくなっています。
つまり、ADDはtarファイルを削除しますが、それはまだどこかに保存されています。そしてそれはイメージをより大きくしています!
Docker 17.05のCOPY
が multi-stage builds の--from
フラグと一緒に使用されるため、前のビルドステージから現在のビルドステージにアーティファクトをコピーします。
ドキュメント から
オプションで、COPYは、ソースロケーションをユーザーが送信したビルドコンテキストの代わりに使用される前のビルドステージ(FROM .. ASで作成)に設定するために使用できるフラグ
--from=<name|index>
を受け入れます。
docker build -t {image name} -v {Host directory}:{temp build directory} .
これはファイルを画像にコピーするもう一つの方法です。 -vオプションは、ビルドプロセス中に使用したボリュームを一時的に作成します。
ビルド専用のホストディレクトリをマウントするため、これは他のボリュームとは異なります。ファイルは標準のcpコマンドを使用してコピーできます。
また、curlやwgetのように、コマンドスタック内で(単一のコンテナ内で)実行することができ、イメージサイズを増やすことはできません。 ADDとCOPYはスタンドアロンのコンテナで実行されるためスタックできません。追加のコンテナで実行されるこれらのファイルに対する後続のコマンドはイメージサイズを倍増します。
このように設定されたオプションで:
-v /opt/mysql-staging:/tvol
次は1つのコンテナ内で実行されます。
RUN cp -r /tvol/mysql-5.7.15-linux-glibc2.5-x86_64 /u1 && \
mv /u1/mysql-5.7.15-linux-glibc2.5-x86_64 /u1/mysql && \
mkdir /u1/mysql/mysql-files && \
mkdir /u1/mysql/innodb && \
mkdir /u1/mysql/innodb/libdata && \
mkdir /u1/mysql/innodb/innologs && \
mkdir /u1/mysql/tmp && \
chmod 750 /u1/mysql/mysql-files && \
chown -R mysql /u1/mysql && \
chgrp -R mysql /u1/mysql