.dockerignoreが効かない？.gitignoreとは書き方が違うよ！

# この記事は
.dockerignoreと.gitignore、名前が似ているし書き方も似ているので同じように書けばよいと思っていましたが、違いました。この記事では違いを紹介します。

# 対象読者
.gitignoreは書いたことがあるけれど、.dockerignoreはあまり書いたことがない人

# ポイント
.gitignoreの仕様は [公式ページのgitignoreのページ](https://git-scm.com/docs/gitignore) に記載されています。
日本語だとQiitaの [.gitignoreの仕様詳解](https://qiita.com/anqooqie/items/110957797b3d5280c44f) が分かりやすいです。

.dockerignoreの仕様は [公式ページのdocker build#dockerignore](https://docs.docker.jp/engine/reference/builder.html#dockerignore) に記載されています。

主なルールは3つです。

> - パターンマッチングには Go 言語の [filepath.Match](https://golang.org/pkg/path/filepath/#Match) ルールが用いられています。 
> - 特別なワイルドカード文字列 `**` をサポートしています。 これは複数のディレクトリ（ゼロ個を含む）にマッチします。
> - 行頭を感嘆符 `!` で書き始めると、それは除外に対しての例外を指定するものとなります。

# .dockerignoreとは

.dockerignoreと.gitignoreの違いを説明する前に、docker build時のファイル転送と.dockerignoreの役割を説明します。

## docker build時のファイル転送

Dockerfileをビルドする際、dockerはビルドコンテキスト以下をtarでまとめています。これは対象のディレクトリをdockerデーモンに転送するためです。
このtarの中には、COPYやADDされないファイルも含まれます。ビルドコンテキスト以下の全てのファイルが含まれるのです。

![build_context.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288329/9d32eb9e-8059-b717-bff3-6c543af505fd.png)


## .dockerignore

dockerビルドに必要ない(tarの中に入れたくない)ファイルは.dockerignoreに記載します。
.dockerignoreを作成することで、ビルド時間の短縮、docker imageサイズの最適化、機密情報(パスワードなど)の不本意な漏洩の防止、等の効果があります。

## ビルドコンテキストルート

ビルドコンテキストルートは、docker buildで使用するパスです。(Dockerfileの場所ではありません)

```bash
docker build -f path/to/Dockerfile myprj
                                   -----
                              ↑ docker buildの引数に指定しているパスがビルドコンテキストルート ↑
```

上の例だと、`myprj`がビルドコンテキストルートです。上記の例の場合、.dockerignoreは`myprj`ディレクトリに配置します。

# .dockerignoreと.gitignoreの違い

さて本題です。.dockerignoreと.gitignore、目的も書き方も似ていますが、実装は同じではありません。仕様も違っています。


## パスの指定の仕方

### .gitignore

.gitignoreでは書かれたファイルorディレクトリ名は.gitignoreファイル以下の階層であれば、どの階層であっても無視されます。

例えば、

```plaintext:.gitignore
target
```

と記載すると、

```plaintext
target
src/target
path/a/b/target
```

などが無視されます。

###.dockerignore

.dockerignoreでは、パスはすべて.dockerignoreが置かれているパスからの相対パスで記載します。[^dockerignore_path]

[^dockerignore_path]: .gitignoreと同様にパスの先頭に `/` を付けることも可能です。

例えば、

```plaintext:.dockerignore
target
```

と記載すると、

```plaintext
target
```

のみが無視され、

```plaintext
src/target
path/a/b/target
```

は無視されません。

.gitignoreのように任意の階層を対象にしたい場合は

```plaintext:dockerignore
**/target
```

と記載します。

## サブディレクトリにあるignorefile

### .gitignore

.gitignoreの場合、.gitignoreをサブディレクトリにも配置することができます。その場合は対象ファイルに近い方のルールが優先されます。

![gitignore_directory.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288329/2f74eb81-a563-e997-e1c0-a029d1b20a3f.png)



###.dockerignore

.dockerignoreはビルドコンテキストルートにある.dockerignoreしか読み込まれません。サブディレクトリにある.dcokerignoreファイルは読み込まれません。

![dockerignore_directory_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288329/81a2ed1e-0dff-340e-8150-156da1f6ad53.png)


Dockerfileのディレクトリとビルドコンテキストが異なる場合に注意が必要です。Dockerfileと同じ場所に.gitignoreを置くのではなく、ビルドコンテキストに.dockerignoreを配置します。

# あとがき

もしかしてもう少し違いがあるかもしれませんが、今のところ見つけた違いはこのくらいでした。
快適なdockerライフを。

# 環境
- Docker: 19.03.12
- Docker for Mac: 2.3.0.5

# 参考資料リンク

- [Dockerfile リファレンス — Docker-docs-ja 17.06 ドキュメント#dockerignore-file](https://docs.docker.jp/engine/reference/builder.html#dockerignore-file)
- [build — Docker-docs-ja 17.06 ドキュメント#dockerignor](https://docs.docker.jp/engine/reference/commandline/build.html#dockerignore)
- [Dockerfile 記述のベストプラクティス | Docker ドキュメント#ビルドコンテキストの理解](https://matsuand.github.io/docs.docker.jp.onthefly/develop/develop-images/dockerfile_best-practices/#%E3%83%93%E3%83%AB%E3%83%89%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%AE%E7%90%86%E8%A7%A3)
- [Docker Buildにおけるリードタイム短縮のための3つの改善ポイント | PLAID engineer blog](https://tech.plaid.co.jp/improve_docker_build_efficiency/)
- [docker-compose で一向にビルドがはじまらない、もしくは起動しない。はたまた忘れたころに起動する。 - Qiita](https://qiita.com/KEINOS/items/42aae92d00675c8b0b78)