【Docker】rebuildする時に不必要なCOPYを避ける方法 no.10

![パンプキン カフェ (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/c0e9639d-32ed-fe5e-77ed-56aca6fc9d91.png)


こんにちは、まゆみです。

Dockerについての記事をシリーズで書いています。

今回は

>ビルドコンテキスト内のファイルをアップデートしたい時、アップデートする必要のないファイルがある時はどうしたら良いのか？

ということについて書いていきます。

<font color="OrangeRed">抽象的で少しわかりにくいので、具体的に言いますね。</font>

[第8回目の記事](https://qiita.com/Mayumi_Pythonista/items/483173ee900035a9f59b)で、ビルドコンテキスト内に『Dockerfile』『index.js』『package.json』を用意してbuild する方法をお伝えしました。


上記のような状況である時、仮に、<font color="Red">index.jsファイルの中身のみを書き換えて、package.jsonは一番最初にbuild した時のキャッシュを利用したい</font>という時のDockerfile の書き方を書いていきます


![Dockerfile (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/df1dbc8c-4dd8-cc0a-a9c6-7b7afc92a042.png)

DockerfileからImageを作るには下記のように書く場合が多いと思います。

```
FROM　ベースのイメージ
WORKDIR ワーキングディレクトリを指定する
COPY Containerにコピーしたいファイルを指定
RUN 
```


このような書き方だと、<font color="Red">その後もファイルを書き換えることはないという時は良い</font>と思います。

ただ

>①index.jsの中身を書き換えて
②<font color="Red">再び</font>『docker build .』する時
③Dockerfileの『COPY ./ ./』で不要なpackage.jsonまでCOPYされ、キャッシュが活用できないという事態になり、


再buildに余分な時間がかかってしまいます。

では、今回の記事の概要を伝えたところでさっそく具体的に解説していきます

#今回使うファイル

![2021-06-05_8-10-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/8d93a514-83dd-b62a-52c2-efbf4ce962e6.png)

![2021-06-05_8-10-38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/7e476eda-4c93-d9fe-feed-eb5b49fc981d.png)


![2021-06-05_8-10-59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/b507f3ac-b528-6e8c-cd64-1e6c373104f8.png)

ポートマッピングをして、localhost:8080にアクセスすると、『こんにちは』と表示してくれるアプリを作りました。


![2021-06-05_8-15-22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/c0059b6b-bce9-60d4-5f33-e0bdb3e68647.png)

![2021-06-05_8-16-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/9620ad51-9212-bfdb-7394-994fc209e6c8.png)

うまく行っています。

ではindex.jsの中の『こんにちは』というテキストを『さようなら』に変えてみます


![2021-06-05_8-19-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/b486343d-d7ac-a2d7-28c8-d99da2fbec60.png)

index.jsを保存し、localhost:8080をリロードしましたが、ファイルの変更は反映されず、表示は『こんにちは』のままです


![2021-06-05_8-16-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/2b237d52-1243-b286-5512-bdd2f4dfbb08.png)

これは、<font color="Red">Imageを再び作りなおす必要</font>があります

このまま<font color="Red">Dockerfile を書き換えないで</font>、一からbuild してみました。

localhost:8080をリロードすると、『さようなら』に書き換えられましたが、『COPY ./ ./』の時点で、COPYする必要のないpackage.jsonまでCOPYされ、step 3 以降のプロセスもキャッシュが活用されず、全て一から作りなおされているのが分かると思います


![2021-06-05_8-24-22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/8f9764d7-83ca-300c-b088-7ee2096b1693.png)



![package.jsonは最初にbuildした時のキャッシュを利用して、書き換えたindex.jsのみCOPYしたい.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/4541aefe-4066-fb95-6c6a-ae6cdaf3f2df.png)
index.jsのたった1行を書き換えただけなのに、最初にbuildした時のキャッシュを活用できないのは、嫌ですよね。

#解決方法
では、やっと本題に入ります。

rebuildした時に、書き換えた部分のみ上書きして他の部分は最初にbuildした時のキャッシュを活用するようにDockerfileを書き換えてみます

```
FROM node:alpine
WORKDIR /usr/app
COPY ./package.json ./
RUN npm install
COPY ./ ./
CMD ["npm", "start"]
```
上記のコードを解説します

まず

3行目に

```
COPY ./package.json ./
```
とありますが、4行目でnpmをインストールするとき、package.jsonは必要なファイルなので『そのファイルのみ』は最初にCOPYしておきます

そして

```
RUN　npm install
```

でnpmをインストールした後、package.json以外にも必要なファイルも『含めてすべて』COPYします。

ただその後、ファイルを書き換えてImageをrebuildする必要が出てきた場合も、

```
FROM node:alpine
WORKDIR /usr/app
COPY ./package.json ./
RUN npm install
```

上記のプロセスは、前回にbuildをした時のキャッシュが活用できるようになるのです。

```
COPY ./ ./
CMD ["npm", "start"]
```
<font color="Red">上記の2行分のみのプロセスが作り替えられることになります</font>

この解決法のDockerfileを使って、Imageをbuildして、index.jsの一行を書き換え、再びbuildしてみましょう


![2021-06-05_9-16-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/1fc75bd6-1792-4ca7-db0e-c912fdbda6f4.png)

実行結果は上記のようになります。

step 5 の『COPY ./ ./』までは全て

>Using cache

と書かれていて、キャッシュが活用されているのが分かります

#今回わかったこと

![Container (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/bed6426a-b203-eb15-520e-016a6828e2eb.png)

Docker Image が作られる時、stepごとにベースイメージに変更が加えられながら作られていきます

その後ファイルに変更が加えられ、rebuildする時、例えばstep 4で変更があれば、それ以降のプロセスは全て新しく作り直されることになります

Dockerfileの書き方によっては、rebuildの際、本来ならキャッシュを活用すべきところも、新しく作りなおされる場合もあるので、最初にDockerfile を書く時点で、あとのことも考慮に入れながら書くと良いと思います。

今回の記事は、ここで締めくくらせていただきますね。

お役に立てれば嬉しいです。