Docker のベストプラクティス: Dockerfile の ADD 命令と COPY 命令の違いを理解する

COPY と ADD tl;博士:

Dockerfile のベスト プラクティス」を検索すると、Docker イメージにファイルを追加するときに、常に ADD 命令ではなく COPY 命令を使用することが提案の 1 つに見つかります。

このブログ記事では、この 2 つの手順の機能についてさらに詳しく説明し、この提案が存在する理由を探ります。 これらの概念を理解すると、提案を無視して COPY コマンドの代わりに ADD コマンドを使用することでメリットが得られるシナリオが見つかる場合があります。

2400x1260 Dockerfiles の追加命令とコピー命令の違いを理解する

ファイル・システムのビルド・コンテキストの理解

ADDCOPY の違いを詳しく説明する前に、ビルド コンテキストの概念を理解することが重要です。ビルドコンテキストは、イメージのビルド時に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 がリモート・コンテキストでどのように動作するか

ADDCOPY はどちらも、リモート コンテキストで使用すると動作が若干異なることに注意してください。

リモート・コンテキストでの 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/srcsrc ディレクトリもコピーします。

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複雑さの増大と潜在的なセキュリティ リスクのコストに対して、柔軟性を高めることができます。

さらに詳しく