ビルドコンテキスト - docker image build, COPY でディレクトリが見つからない - 

<!--

初心者OK！Docker入門＋応用：ゼロからでも実務で使えるスキルが身に付ける
https://www.udemy.com/course/ok-docker/?couponCode=ST19MT60324

- `--build-context` 修正
- https://chatgpt.com/c/a9056672-32d4-47b0-9a8b-55e272dd02cb
- https://www.docker.com/ja-jp/blog/dockerfiles-now-support-multiple-build-contexts/

-->

:::note warn

本記事で説明している親ディレクトリを参照するやり方よりも `--build-context` を使うほうが良さそうです...

* [Dockerfiles で複数のビルド コンテキストがサポートされるようになりました](https://www.docker.com/ja-jp/blog/dockerfiles-now-support-multiple-build-contexts/)

Docker Compose では `additional_contexts` プロパティを使用してください。

* https://docs.docker.com/compose/compose-file/build/#additional_contexts

:::


## 概要
### 1. 原因

Docker では兄弟ディレクトリを参照することはできないようになっているから

### 2. 対処

```
# 引数に

# カレントディレクトリ . ではなく
# docker image build .

# 親ディレクトリ .. を指定する
docker image build ..
```

https://x.com/beyon_231115/status/1786352008800403674



## 詳細
### 1. やりたいこと

```
$ # 親ディレクトリ .. を起点にして２階層目までを tree で表示
$ tree -L 2 ..
.
├── backend <-- ここから
│   └── Dockerfile
├── frontend
│   └── Dockerfile
└── storage <-- ここを参照したい
    └── scripts
$
$ # カレントディレクトリは backend ディレクトリにいるとします
$ pwd
/home/user/project/backend
$
```


### 2. 改善前

```Dockerfile:backend/Dockerfile
# 誤
#   これがエラーになる
#   Docker では兄弟ディレクトリを見ることはできない
COPY ../storage .
```
```
$ docker image build -t backend .
```

<details><summary>エラーになる...</summary>

```
=> ERROR [7/8] COPY ../storage .                                                                                             0.0s
------
 > [7/8] COPY ../storage .:
------
dockerfile:13
--------------------
  11 |     
  12 |     WORKDIR /storage
  13 | >>> COPY ../storage .
  14 |     
  15 |     WORKDIR /app
--------------------
ERROR: failed to solve: failed to compute cache key: failed to calculate checksum of ref b2b8bec0-7f16-4a4e-82ce-50cc6ea8ad78::olt6lm81xjn7ke9u319v7irsg: "/storage": not found
yaju@yaju-house:project$ docker image build -t backend -f backend/dockerfile .
[+] Building 4.2s (13/13) FINISHED         
```
</details>



### 3. 改善後

```Dockerfile:backend/Dockerfile
# 誤
# COPY ../storage .

# 正
#   storage への相対パスは親ディレクトリを起点にする
COPY storage .
```

```
$ # 誤
$ # docker image build -t backend .
$
$ # 正
$ #   ビルドコンテキストを起点に Docker ファイルへのパスが指定されてしまうので
$ #   -f オプションで Docker ファイルへのパスを明示する
$ #   -f オプションの相対パスの起点はビルドコンテキストではなくカレントディレクトリになります。
$ docker image build -t backend -f ./Dockerfile ..  
```


## 背景


### 1. 疑問

なんで兄弟ディレクトリを参照できないのか？不要なファイルをビルドコンテキストに含めてしまうと `docker image build` が重くなってしまうらしいです。`COPY` しなければ Docker image に含まれないのでは？🤔と思ったのですがそう単純ではないようです。翻訳サイトはみつかったのに英語の公式サイトでは記述が見当たらない...

> イメージのビルドには必要のないファイルを誤って含めてしまうと、ビルドコンテキストがそれだけ大きくなり、結果としてサイズの大きなイメージが生成されることになります。 こうしてしまうと、イメージビルドの時間、このイメージをプッシュしたりプルしたりする時間が、その分だけ要することとなり、コンテナーの実行時の容量も増えてしまいます。 ビルドコンテキストのサイズがどれだけになったかは、Dockerfileを使ってビルド処理を行った際の以下のようなメッセージを確認すればわかります。
> ```
> Sending build context to Docker daemon  187.8MB
> ```
> [Dockerfile 記述のベストプラクティス | Docker ドキュメント](https://matsuand.github.io/docs.docker.jp.onthefly/develop/develop-images/dockerfile_best-practices/)

### 2. 用語

- ビルドコンテキスト

Docker イメージを作成する際に使用するファイルの集まり。
> The build context is the set of files that your build can access.
> [Build context | Docker Docs](https://docs.docker.com/build/building/context/#what-is-a-build-context)

`docker image build` の位置引数、本記事で言うところの `.` や `..` によって、ファイルの集まり即ちビルドコンテキストが指定される。

`docker image build` コマンドにおいては「位置引数」でビルドコンテキストとなるファイルの集まりが存在するパスを指定し、「`-f` オプション」で Docker ファイルのパスを指定する。


- `.dockerignore`

`.dockerignore` ファイルで指定されたファイル、ディレクトリはビルドコンテキストから除外されます。


### 3. 問題

親ディレクトリ `..` をビルドコンテキストに設定して、`COPY ..` でなんでもかんでも放り込むのはよろしくないとのことなのでその点はご留意ください。

https://x.com/mattn_jp/status/1788404475637768576



### 4. 対応

大雑把に親ディレクトリを指定するのではなく、個別にビルドコンテクストのディレクトリを指定したい方は ChatGPT 先生に聞いてください。

> `docker build image` コマンドにおいて複数のビルドコンテキストを含めることはできますか？




## 参考

これを見て解決できました。ありがとうございます。

* [Dockerfileがあるディレクトリから親ディレクトリを参照する](https://tarosky.co.jp/tarog/1078)


<!--

1. dockerfile を書き換え
2. build context, ビルドコンテキストを親ディレクトリに変更する


親ディレクトリで `docker image build .` しなくても
子ディレクトリで `docker image build ..` すれば通るので記事にしました。
  -->