「Dockerfile のベスト プラクティス」を検索すると、Docker イメージにファイルを追加するときに、常に ADD
命令ではなく COPY
命令を使用することが提案の 1 つに見つかります。
このブログ記事では、この 2 つの手順の機能についてさらに詳しく説明し、この提案が存在する理由を探ります。 これらの概念を理解すると、提案を無視して COPY
コマンドの代わりに ADD
コマンドを使用することでメリットが得られるシナリオが見つかる場合があります。
ファイル・システムのビルド・コンテキストの理解
ADD
と COPY
の違いを詳しく説明する前に、ビルド コンテキストの概念を理解することが重要です。ビルドコンテキストは、イメージのビルド時にDockerエンジンからアクセスできるファイルとディレクトリのセットです。 docker build
コマンドを実行すると、Dockerは指定されたコンテキストディレクトリ(およびそのサブディレクトリ)の内容をDockerデーモンに送信します。このコンテキストは、 COPY
命令と ADD
命令が動作するスコープを形成します。
COPY命令
COPY
命令は単純で、その名前が示すとおり、ビルドコンテキスト内のソースからDockerイメージの宛先レイヤーにファイルとディレクトリをコピーします。この命令は、ファイルとディレクトリの両方をコピーするために使用でき、ホスト上のすべてのパスはビルドコンテキストのルートに対して相対的です。
構文:
COPY <src>... <dest>
<src>
: ホスト上のソースファイルまたはディレクトリ。<dest>
: Docker イメージ内の宛先パス。
キーポイント
- 基本機能:
COPY
は、ホストファイルシステムからのファイルとディレクトリのコピーのみをサポートします。 URL や圧縮ファイルの自動解凍はサポートしていません。 - セキュリティ:
COPY
はローカル ファイルのみを処理するため、ADD
ファイルよりも予測可能で安全である傾向があり、外部ソースからファイルを意図せずに導入するリスクが軽減されます。 - ユースケース: 追加の処理を行わずに、ローカルのビルドコンテキストから Docker イメージにファイルを含める必要がある場合に最適です。
例:
COPY ./app /usr/src/app
COPY requirements.txt /usr/src/app/
この例では、ローカル app
ディレクトリのコンテキストが、ビルド中の Docker イメージ内の /usr/src/app
ディレクトリにコピーされます。 2 番目のコマンドは、 requirements.txt
ファイルも /usr/src/app
ディレクトリにコピーします。
ADD命令
ADD
命令は、COPY
命令と同じ機能を提供しますが、誤解されると複雑さと潜在的なセキュリティ リスクをもたらす可能性のある追加の機能もあります。
構文:
ADD <src>... <dest>
<src>
: ソースファイル (ディレクトリまたは URL)。<dest>
: Docker イメージ内の宛先パス。
キーポイント
- 拡張機能: ビルド コンテキストからローカル ファイルとディレクトリをコピーするだけでなく、
ADD
には次の高度な機能が用意されています。- URL の処理: ソースとして指定すると、URL で参照されるファイルは、指定された宛先パスの現在の Docker イメージレイヤーにダウンロードされます。
- アーカイブの抽出: ソースとして指定すると、
ADD
は自動的にアーカイブを解凍し、指定された宛先パスの現在の Docker イメージレイヤーに展開します。
- 柔軟性とセキュリティ:
ADD
はより柔軟ですが、リスクも伴います。 ビルドプロセスに外部URLをダウンロードすると、悪意のあるコードやコンテンツがプロセスに取り込まれる可能性があります。 アーカイブでADD
を使用すると、アーカイブの処理方法を理解していないと、意図しない結果が生じる可能性があります。 - ユースケース:
ADD
は、提供する特定の機能が必要で、この使用から生じる潜在的なセキュリティ問題を管理する意思がある場合にのみ使用してください。
例:
ADD https://example.com/file.tar.gz /usr/src/app/
ADD my-archive.tar.gz /usr/src/app/
この例では、ビルド プロセスは最初に https://example.com/file.tar.gz
をダウンロードし、その内容を Docker イメージ レイヤーの /usr/src/app
に抽出します。 次の手順では、ローカル ファイルを my-archive.tar.gz
取得し、 /usr/src/app
の下の Docker イメージ レイヤーに抽出します。
COPY と ADD のどちらを使用するか
- ほとんどのユースケースでは、
COPY
はそのシンプルさとセキュリティのためにより良い選択です。 この手順を使用すると、ローカルコンテキストからビルドしているDockerイメージにファイルとディレクトリを転送できます。 ADD
は、提供される追加機能が必要な場合にのみ使用しますが、セキュリティへの影響の可能性に注意してください。
リモートコンテキスト
従来のファイルシステムコンテキストに加えて、Dockerは リモートコンテキストもサポートしており、クラウド環境やコードリポジトリから直接イメージを構築する場合に特に役立ちます。 これには、次のものが含まれます。
- Git リポジトリ: Git リポジトリの URL をビルド コンテキストとして指定すると、Docker はリポジトリをクローンし、そのコンテンツをコンテキストとして使用できます。
docker build https://github.com/username/repository.git#branch
- リモート URL: Docker は、ビルド コンテキストにリモート URL を使用できます。 これは、オンラインで入手できるアーカイブから直接イメージを作成する場合に便利です。
docker build http://example.com/context.tar.gz
- OCIイメージ: OCIイメージをビルド・コンテキストとして使用できるため、新しいビルドの開始点として事前構築済イメージを使用する場合に便利です。
docker build oci://registry.example.com/image:tag
ADD と COPY がリモート・コンテキストでどのように動作するか
ADD
と COPY
はどちらも、リモート コンテキストで使用すると動作が若干異なることに注意してください。
リモート・コンテキストでの COPY の使用
COPY
は、ビルドコンテキストのスコープ内で動作し、クローンされたリポジトリから Docker イメージにファイルとディレクトリをコピーできます。 たとえば、Git リポジトリをビルド コンテキストとして使用する場合、 COPY
クローンされたリポジトリから Docker イメージにファイルとディレクトリをコピーできます。 URL やその他のリモートソースからのファイルを直接コピーすることはできません。
Git リポジトリをビルドコンテキストとして使用する例:
# Using a Git repository as build context
COPY ./src /app/src
この場合、 COPY
は Git リポジトリ (ビルド コンテキスト) から src
ディレクトリを Docker イメージの /app/src
にコピーします。
URL ビルドコンテキストの例:
# Using an archive from a URL
COPY ./src /app/src
この場合、 COPY
は抽出されたアーカイブ (ビルド コンテキスト) から src
ディレクトリを Docker イメージの /app/src
にコピーします。
OCIイメージをビルドコンテキストとして使用する例:
# Using an OCI image as build context
COPY /path/in/oci/image /app/path
この場合、 COPY
は OCI イメージ内の指定されたパスから Docker イメージ内の指定された宛先パスに内容をコピーします。
リモート・コンテキストでの ADD の使用
ADD
命令は、ファイルのダウンロードやアーカイブの抽出、およびビルド コンテキストからのファイルのコピーに引き続き使用できます。上記の ADD
の指示について提供されたすべての注意点がここでも適用されることに注意してください。
Git リポジトリをビルドコンテキストとして使用する例:
# Using a Git repository as build context
ADD https://example.com/data.tar.gz /data
ADD ./src /app/src
この例では、ADD
は URL から Docker イメージの /data
ディレクトリに data.tar.gz
をダウンロードして抽出します。また、Git リポジトリ (ビルド コンテキスト) から Docker イメージの /app/src
に src
ディレクトリもコピーします。
URL ビルドコンテキストの例:
# Using an archive from a URL
ADD https://example.com/data.tar.gz /data
ADD ./src /app/src
この例では、ADD
は URL から Docker イメージの /data
ディレクトリに data.tar.gz
をダウンロードして抽出します。また、ダウンロード/解凍されたURL(ビルドコンテキスト)から src
ディレクトリをDockerイメージの /app/src
にコピーします。
OCIイメージをビルドコンテキストとして使用する例:
# Using an OCI image as build context
ADD https://example.com/data.tar.gz /data
ADD /path/in/oci/image /app/path
このシナリオでは、ADD
は URL から Docker イメージの /data
ディレクトリに data.tar.gz
をダウンロードして抽出します。また、OCIイメージ内の指定されたパスからDockerイメージ内の指定された宛先パスに内容がコピーされます。
COPY と ADD tl;博士:
COPY
を優先する: ほとんどのユースケースでは、そのシンプルさとセキュリティのために、COPY
の方が適しています。これを使用して、ローカルコンテキストまたはGitリポジトリなどのリモートコンテキストからDockerイメージにファイルとディレクトリを転送します。ADD
は注意して使用してください:ADD
は、URL からのファイルのダウンロードやアーカイブの自動抽出など、追加機能が必要な場合にのみ選択してください (図 1)。ADD
を使用するときは、セキュリティに影響する可能性があることに常に注意してください。
結論
Dockerfile の ADD
命令と COPY
命令の違いと、ビルド コンテキストによってそれらがどのように影響を受けるかを理解することは、より効率的で安全な Docker イメージを構築するのに役立ちます。 COPY
では、ローカル ファイルを簡単に含める方法を提供していますが、ADD
複雑さの増大と潜在的なセキュリティ リスクのコストに対して、柔軟性を高めることができます。
さらに詳しく
- Dockerfile リファレンス ドキュメントをお読みください。
- Docker Newsletter を購読してください。
- Docker デスクトップの最新リリースを入手します。
- 次のものに投票してください! 公開ロードマップをご覧ください。
- 質問がありますか? Docker コミュニティがお手伝いします。
- ドッカーは初めてですか? 始めましょう。