Dockerfile付きのAngularアプリ作成する

#概要
DockerfileでAngularの環境を構築し、gitのサブモジュールとして使えるような状態のアプリケーションを作成していきます。
自環境にnode.jsやangular/cliを入れずにDockerのコンテナ上で作成します。
Docker習得前の自分に向けて各ファイルやコードの解説も随所に入れていきます。

#環境
- Windows10 pro (Homeでも可)
- Visual Studio Code
- Docker version 20.10.8
- Docker Compose version v2.0.0

以下、Visual Studio Codeの拡張機能
- Docker v1.17.0
- Remote - Containers v0.202.5

#構成
コンテナの構築に必要なファイルです。
構築後はcilent-appフォルダ内にAngular関連のファイルが追加されます。

```
.
├── docker-compose.yml
└── client-app
    ├── Dockerfile
    └── .dockerignore
```

#コンテナ構築に必要なファイルの作成
上記のdocker-compose.yml、Dockerfile、.dockerignoreをそれぞれ作成していきます。
##1.Dockerfile作成
###概要
まずはじめにDockerfileを作成します。
Dockerfileがコンテナ構築の基本となるファイルです。

```:Dockerfile
FROM node:12-slim

WORKDIR /usr/src/client-app

RUN apt-get update
RUN echo y | apt-get install git
RUN npm install -g @angular/cli

COPY ./ ./

EXPOSE 4200
```
###コード解説
- 【FROM】
docker hubから基盤となるイメージを取ってくるための命令です。 
：の後にバージョン等を指定します。今回はslimで構築してみます。



- 【WORKDIR】
コンテナに入った際にいる場所を指定します。 
今回のclient-appのような存在しないディレクトリの場合は自動で生成してくれます。


- 【RUN】
コンテナを構築する際に一度だけ流れるコマンドのことです。上から順に処理されるので順番に注意してください。 
今回はangular-cliでアプリを生成する際にgitが必要なのでupdateを行ったうえでgitをインストールしています。

- 【COPY】
これは以下のように、一方的な命令です。コンテナ側でファイルを作成（"ng new hoge"など）してもホスト側に同期はされません。同期については以下のdocker-compose.ymlの章で紹介します。
【ホスト側】今回はWindows側　→(COPY)→　【ゲスト側】コンテナ側


- 【EXPOSE】
コンテナ外に開放するポート番号を指定します。

##2.docker-compose.yml作成
###概要
次にdocker-compose.ymlファイルを作成します。インデントも記述ルールに関係してくるので注意してください。
本来はコンテナの起動順序だったり、コンテナ同士の依存関係等をも記述しますが、今回はコンテナ側で作成されたファイルをホスト側に同期するためだけのコードに留めます。
後々サーバーサイドのアプリやDBなどのコンテナを追加した際はこのファイルに追記するようになります。

```:docker-compose.yml
version: '3.9'
services:
  client-app:
    build: ./client-app
    ports:
      - "4200:4200"
    volumes:
      - ./client-app:/usr/src/client-app
      - /usr/src/client-app/node_modules
    tty: true
```
###コード解説
- 【client-app】
ここには好きな名前を付けられます。今回はAngularのアプリなのでclient-appとしました。


- 【build】
Dockerfileがある場所を指定します。このdocker-compose.ymlファイルがある場所からの相対パスで記述してください。


- 【volumes】
ここが今回のこのファイルの肝となる箇所です。:の左側にホスト側、右側にコンテナ側のディレクトリを記述することで左右の箇所以下のファイルを同期することができます。
以下の.dockerignoreファイルの章で解説しますが、node_modulesを除外する用に絶対パスを個別に明記します。


※ちなみにファイル名はdocker-compose.ymlでもdocker-compose.yamlでも良いそうです。

##3. .dockerignore作成
###概要
docker-compose.ymlのvolumesの箇所でファイルの同期をするように記述しましたが、node_modulesまで同期してしまうと重くなってしまいます。
なので.gitignoreのように除外対象のファイルを指定することでnode_modulesのファイルがホスト側に流れ込んでくるのを防ぎます。

```:.dockerignore
node_modules
```
###コード解説
基本的にはDockerfileのWORKDIRの箇所からの相対パスで記述します。今回はdocker-compose.ymlファイルで個別に指定しているのでnode_modulesだけで十分です。
.dockerignoreは基本的にDockerfileのCOPY命令等に適用されます。しかし、docker-compose.ymlのvolumesでディレクトリを記述してしまうと除外の設定を無視して同期されてしまうので、除外するディレクトリorファイルは個別に明記する必要があるようです。（[参考3つ目](#参考)：Volume Trickと言うようです。）

#構築
構築に必要なファイルの準備ができたので、構築に入っていきます。
docker-compose.ymlファイルがある場所で以下のコマンドを実行。

```
$ docker-compose up -d
```
公式ドキュメントを見るのが一番ですが、簡単に解説すると、このコマンドはコンテナのビルドと実行を行うものです。
-dはバックグラウンドで実行するオプションです。

きちんとビルド＆ランができたかどうかはDocker Desktopアプリで確認できます。
<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2169561/20363dd3-3e11-d10f-7679-7d683c908338.png">

VSCode拡張機能のdockerからでも確認できます。
<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2169561/e95935e2-9d17-a871-e940-4f51ecd5274d.png">

#Angularアプリ作成
コンテナが起動していることを確認できたら、コンテナの中に入り、angullar-cliでアプリを生成します。
コンテナに入る方法は主に３つあります。お好きな方法でアクセスしてください。

- "docker exec"コマンドからコンテナに入る
- VSCode上のdockerから、CONTAINERS欄で該当するコンテナを右クリックして"Attach shell"もしくは"Attach Visual Studio Code"を選択する
- VSCode上のRemote - Containers（拡張機能。追加するとVSCodeの左下にリモートのマークが追加される）から接続する

DockerfileのWORKDIRで指定したのでcliend-appがカレントディレクトリになっています。
まだアプリを作成していないので以下のようにDockerfileと.dockerignore、空のnode_modulesフォルダだけです。
※.dockerignoreなど、"."で始まるファイルは隠しファイルになるので-aオプションを付けます。

```bash
$ ls -a
.  ..  .dockerignore  Dockerfile  node_modules
```

階層を１つ上に移動してからangular-cliでアプリを生成します。
--routingと--styleオプションは付けなくても作成できますが、オプションなしで作成した際に結局聞かれる項目です。
※お試しで作成したい場合は--minimalオプションを付けるとテスト関連のインストールがスキップされるので少し時短になります。

```bash
$ cd ..
$ ng new client-app --routing --style css
```


#同期されたファイルの確認

アプリが作成されたらホスト側にファイルが同期されているか確認してみましょう。

```bash
// windows側
$dir /b
.browserslistrc
.dockerignore
.git
.gitignore
angular.json
Dockerfile
node_modules
package-lock.json
package.json
README.md
src
tsconfig.app.json
tsconfig.json
```

angular関連ファイルに加えてDockerfileと.dockerignoreの存在が確認できました。
node_modulesフォルダは空の状態であることも確認してください。
後はWindows側で自分のgithub等へあげてしまえば終了です。

#まとめ
以上で環境付きの配布可能なAngularアプリを作成することができました。
開発する際はコンテナを実行している状態で[VSCodeからコンテナに入れば](#angularアプリ作成)、windowsのローカル環境と同じようになります。
他の環境・人がgitからpullしてもDockerfileだけでイメージとコンテナのビルドができます。必要に応じてdocker-compose.ymlファイルを作成すれば良いのでモビリティの高い状態だと思います。
ただ、この状態だとホットリロードが使えない状態なので注意してください（できるようにする方法はあるようです）

※追記
アプリビルド時にオプションを追加するだけでできました！（[別記事](https://qiita.com/theG/items/44d1b372c74a6c94c4ed)）

初めての記事投稿だったので分かりづらい・情報がまとまっていないような箇所があったと思います。今後も継続してアウトプットしていきながらレベルアップしていきたいと思います。

#参考
- [Docker公式ドキュメント](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/builder/)
- [Docker × Angular環境簡単構築](https://qiita.com/A-Kira/items/8693a78873ca9cab0738)
- [VSCode&Docker Volumeにおけるnode_modules問題を解決する](https://zenn.dev/foolishell/articles/3d327557af3554)