LoginSignup
137
91

More than 3 years have passed since last update.

DockerfileにてなぜADDよりCOPYが望ましいのか

Last updated at Posted at 2019-05-04

はじめに

Docker公式のBest practices for writing Dockerfiles
ADDよりもCOPYが望ましい(ADDは使わない方が良い)との記述があるのを見つけたのでその理由を確認してみました。

TL;DR

理由は以下の2つに分けることができます。

① Imageサイズの観点
② セキュリティの観点

そもそもCOPYとADDはどう違うのか

こちらの記事にて端的にまとめられていたので日本語訳してしまいます。

COPY - 明示的なコピー元とコピー先のファイルまたはディレクトリを指定して、ローカルファイルを再帰的にコピーします。 COPYでは、場所を宣言する必要があります。

ADD - ローカルファイルを再帰的にコピーし、存在しない場合は暗黙的にコピー先ディレクトリを作成し、アーカイブをコピー元としてローカルURLまたはリモートURLとして受け入れます。アーカイブはそれぞれコピー先ディレクトリに展開またはダウンロードされます。

COPYはソース側のマシンにあるものをImageへコピーするだけというシンプルな機能であるのに対し、ADDは対象が圧縮ファイルであればそれを展開してImageへ移し、リモート上のリソースも引っ張ってくる機能がついています。このCOPYに付与されたADDの機能自体が望ましくない原因になっています。

Imageサイズの観点

上記の公式ドキュメントに記載の内容です。

ADDを使ってしまっているアンチパターンが以下になります。

ダメな例
FROM alpine:3.4
RUN apk --update add curl

ADD https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/Python-3.7.3.tar.xz -C /usr/src/things

これの何がいけないかというと、ADD https://...tar.xz /usr/src/thingsの記述により結果的に不要なダウンロードされたディレクトリを持つImageレイヤーができてしまっている点です。

そうではなく、このようにしましょうということです。

改良
FROM alpine:3.4
RUN apk --update add curl

RUN mkdir -p /usr/src/things \
    && curl -SL https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tar.xz \
    | tar -xJC /usr/src/things

それぞれをビルドしてdocker imagesdocker historyで比較してみましょう。

ダメな例
$ docker images ng-sample
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ng-sample           latest              6f486d575040        15 minutes ago      103MB

$ docker history ng-sample
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
6f486d575040        15 minutes ago      /bin/sh -c tar -xJf /usr/src/things/Python-3…   79.3MB
7640da035c96        15 minutes ago      /bin/sh -c #(nop) ADD da2574b8e3fb62fc8442c4…   17.1MB
15a01069edfd        26 minutes ago      /bin/sh -c apk --update add curl                2.19MB
b7c5ffe56db7        3 months ago        /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>           3 months ago        /bin/sh -c #(nop) ADD file:bcde2f5c6cea41907…   4.82MB
改良
$ docker images ok-sample
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ok-sample           latest              c88218b0c0cf        28 minutes ago      86.3MB

$ docker history ok-sample
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
c88218b0c0cf        28 minutes ago      /bin/sh -c mkdir -p /usr/src/things     && c…   79.3MB
15a01069edfd        29 minutes ago      /bin/sh -c apk --update add curl                2.19MB
b7c5ffe56db7        3 months ago        /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>           3 months ago        /bin/sh -c #(nop) ADD file:bcde2f5c6cea41907…   4.82MB

ダメな方ではADDで追加された圧縮ファイルを持ったレイヤー分サイズが大きくなってしまっています。改良版ではcurlした圧縮ファイルをパイプでtarへつなげているのでImageには残りません。

セキュリティの観点

こちらの記事の内容の紹介になります。

上記のADDの機能を利用者が知らずに使っている場合、ADDはセキュリティのリスクが生じてしまいます。

  • リモート上のリソースを自動で取りに行くのでダウンロード中、中間者攻撃の対象となりえる
  • 圧縮ファイルを自動で展開するので、ZIP爆弾ZIP SLIP脆弱性攻撃の対象となりえる

ここで注意するべきは、上記のセキュリティリスクはCOPYを使っている場合でも起こりえます。ただ、COPYを使っていれば、

  • 明示的にリモートリソースからダウンロード(wget, curlなど)をする
  • 圧縮ファイルを展開(tarなど)する

ので対象リソースが安全かを検証する仕組みを組み込みやすいということです。

おまけ COPYのコツ

これも上記公式ドキュメントに記載の話です。

Imageキャッシュをできるだけ利用できるようにすることを意識してDockerfileを記述しましょう。

ダメな例
COPY . /tmp/
RUN pip install --requirement /tmp/requirements.txt
改良
COPY requirements.txt /tmp/
RUN pip install --requirement /tmp/requirements.txt
COPY . /tmp/

2つの違いがImageキャッシュ利用にどう関わるか理解しておく必要があります。
RUN pip install --requirement /tmp/requirements.txtrequirements.txtの差分のみに影響されて実行されるべきです。
ダメな方はそれ以外の.以下の何かが変更されるたび、COPY . /tmp/のレイヤーのImageコミットが変わるので、RUN pip installは以前のキャッシュを利用することができず毎回ダウンロードしてインストールすることになってしまいます。

参考

137
91
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
137
91