Docker初心者がnginxの学習環境を整えるまでにやったこと

## この記事に書くこと
フロントエンドエンジニアたるもの、コーディングだけでなくWebサーバーに対しても理解があるべきと思いnginxをいじりながら勉強したいと思いました。
とはいえ手元のMacパソコンにWebサーバーをインストールして設定をガチャガチャいじるのは気が引けたので、この機会にDockerも一緒に入門することにしました。
Dockerの基礎を身につけつつ、nginxの学習環境を構築する時にやったことを記録しています。

## 公式サイトに登録　Dockerダウンロード
[Docker公式のGet Started][3]からDocker Desktopをダウンロードしてインストールします。
特に難しいところはありません。

## Dockerのチュートリアルを実施
ダウンロードしたDockerを起動するとチュートリアル画面が起動しました。
![Docker_tutorial.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601155/5c14a007-f56c-4da6-1e56-654dd50c79f7.png)

チュートリアル用のリポジトリをクローンし、docker imageをビルドしてdocker hubにシェアするところまでを体験させてくれます。
コマンドが書いてある青いボタンを押すと画面右側にあるコンソールで実行されます。
知らずに押したらHomeディレクトリにリポジトリをクローンし始めた　あとで掃除しなきゃ。

最後までやっても５分もかからない　少し解説読んで４回ボタン押したらおしまい。
とはいえ、まだDockerについてはほとんどわからないまま。

## docker/getting-startedを読む
チュートリアルがあっさり終わったと思ったら、このコンテナ自体がドキュメントになっていた。
docker-tutorialのコンテナが起動していて、http://localhost でアクセスできる。

色々書いてあるので読んでいく
![スクリーンショット 2020-08-24 13.25.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601155/79f92e26-837f-645c-3d01-81496738b0e0.png)

それなりに文量があるのでちょっと面倒に感じたが、かなり有益な情報が書いてあリます。
わざとエラーを発生させて対処を教えてくれるような項目もあり、初心者が陥りがちな問題の解決法も教えてくれるので面倒くさがらずに頭から読んでいきましょう。

### Getting Startedから学べること
- コンテナの起動/停止の仕方
- シンプルなwebアプリケーションをdocker image化する方法
- docker hubのとplay with dockerの使い方
- Volumeの使い方（Named Volumes, Bind Mounts)
- networkの作成
- Node.jsとmysqlをdocker上で利用するサンプル
- Docker Composeの利用
- docker-compose.ymlの記述
- build cacheを使った最適化
- Multi-Stage Buildsによる最適化

全部ちゃんと読んで休日を２日費やしましたが、読む価値は十分にありました。
ぜひ読むだけでなく、実際にコマンドを実行しながら進めていくのをお勧めします。

## 実際にnginx学習環境を構築する
Getting Startedを最後まで終えたので、ここで実戦に入ります。

### nginxのイメージを落とす
Docker Hubから[nginx][1]のイメージをダウンロード
nginxイメージのページの下部にクイック起動コマンドがあります。/some/contentの部分がいわゆるhthomeになるので、適当なディレクトリを作成して/some/contentをそのパスに置き換えてテストします。
ホストマシンのポートと紐づけるための-pオプションと 8080:80を追加した以下のコマンドを実行

```
docker run --name some-nginx -v /some/content:/usr/share/nginx/html:ro -dp 8080:80 nginx
```
ブラウザを立ち上げてhttp://localhost:8080 にアクセスすると403 Forbiddenになるが、nginxは無事起動できることが確認できます。
403は後ほど解決します。

### docker-composeから起動
上記のような長いコマンドを毎回打ち込むのは大変ですし、将来的には他のコンテナとの連携も行いたいのでdocker-composeから起動できるようにします。
下記のような構成のPJディレクトリを作成

ProjectRoot/
┣ docker-compose.yml
┗ static-html-directory/

Getting Startedの内容を思い出しながらdocker-compose.ymlを記述します。

```yml
version: "1.0"

services:
  nginx:
    image: nginx
    ports: 
      - "8080:80"
    volumes:
      - ./static-html-directory:/usr/share/nginx/html
```
で、docker-compose upを叩くと下記エラー

```
ERROR: Version "1.0" in "./docker-compose.yml" is invalid.
```
versionは自分のシステムのバージョンかと思って1.0にしちゃったけど、getting startedにdocker-composeのschema versionだったことを思い出してVersionを3.8に書き換えると無事に起動完了

ブラウザを立ち上げてhttp://localhost:8080 にアクセスすると再び403 Forbiddenになり、コンソールに下記のエラーが出ています。

```
nginx_1  | 2020/08/27 06:59:58 [error] 23#23: *5 directory index of "/usr/share/nginx/html/" is forbidden, client: 172.20.0.1, server: localhost, request: "GET / HTTP/1.1", host: "localhost:8080"
```

/usr/share/nginxは./static-html-directoryにBind Mountしている領域なので、static-html-directoryの権限を確認します。

```
kontam> ls -l
total 16
-rw-r--r--  1 kontam  staff  150  8 27 16:48 docker-compose.yml
drwxr-xr-x  3 kontam  staff   96  8 27 15:56 static-html-directory
```
read権限は全ユーザーにあるので問題なさそう。
もしやと思い、下記ファイルをtest.htmlと名付けてstatic-html-directory配下に格納しました。

```html
<html>
  <body>
    <h1>kontam added this</h1>
  </body>
</html>
```
その後ブラウザでhttp://localhost:8080/test.html にアクセスすると無事にHTMLが返されて「kontam added this」と表示されます。
static-html-directoryの配下にindex.htmlがなかったためルートにアクセスするとファイルリストを表示することになりますが、デフォルトではリストは未許可になっているため403になっていたようです。

### nginxのコンテナに接続して設定変更の練習をする
nginxの学習も兼ねてこのファイルリスト表示を許可する設定変更をしてみることにしました。
ググった結果、nginxの基本設定ファイルは/etc/nginx/nginx.confとのこと。
早速vimで設定ファイルを開いてみよう。

```
root@d46b1cf2dadf:/etc/nginx# vim /etc/nginx/nginx.conf
bash: vim: command not found
```
vimが無い...だと？ 無いなら入れるしかありません。
/etc配下にdebian_versionがあったのdebian系なことがわかったので、apt-getでインストールします。

```bash
apt-get update
apt-get install vim
```
これで無事にVimが使えるようになりました。

##### nginx.confの設定変更
ファイルリストことautoindexの設定については[nginx公式ドキュメント][4]を見れば指定方法がわかります。
nginxでファイルリストの表示を許可するには設定ファイルのlocationブロックにautoindex onを指定すれば良いとのこと。
vimでnginx.confを開くとhttpブロックの中にこんな記述がありました。

```
http {
    ...
    include /etc/nginx/conf.d/*.conf;
}
```
他のconfファイルをincludeしています。　serverブロックはそちらにあるのでは？と思い、探してみます。
/etc/nginx/conf.d配下にdefault.confという設定ファイルがあるのでこれを開いてみます。
すると、思った通りserverブロックはこちらに丸ごと書いてありhthomeのパス指定なども書かれていました。
ここに下記１行を追加

```
autoindex on;
```
これでnginxのコンテナを再起動

```
docker-compose down
docker-compose up
```

再びhttp://localhost:3000 にアクセスしてみると思った通りファイルリストが表示されました。
![スクリーンショット 2020-08-27 18.06.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601155/ec44ed68-a8e4-c7e8-2f99-020de302f144.png)

無事にnginxの設定をいじりながら変化を確認できる学習環境が整ったと言えるでしょう。

## 設定ファイルをBind Mountsでコンテナの外で管理する
nginxの学習環境はできましたが、コンテナ内の設定ファイルを書き換えるだけではコンテナを作り直した時に全て設定が戻ってしまいます。
壊すつもりで学習するなら使い捨てできて便利ですが、システムを構築するような練習ではコンテナが壊れた時にそれまでの作業が全て失われかねないしgit管理しにくいのも大変です。
設定ファイルはホストマシンのファイルシステム上で管理できるようにすべきと思います。

nginxの設定ファイルを格納するnginxディレクトリを作成し、その中に各configファイルのコピーを格納しました。
PJディレクトリは以下のような構成になります。

ProjectRoot/
┣ docker-compose.yml
┣ static-html-directory/
　┗ test.html
┗ nginx/
　┣ nginx.conf
　┗ conf.d/
　　┗ default.conf

このnginxディレクトリをvolumeとして指定すればコンテナを作り直したとしても変更した設定は保持できます。
docker-compose.ymlのvolumesの部分を追記します。

```yml
version: "3.8"

services:
  nginx:
    image: nginx
    ports: 
      - "8080:80"
    volumes:
      - ./static-html-directory:/usr/share/nginx/html
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
```
ホストマシンのconfを参照するので、設定変更する際にいちいちdockerコンテナに接続しなくて済むので楽です。
あとは好きなように設定を変えたり壊したりしながら勉強を進めれば良いでしょう。


## まとめ
- Docker初心者はまず[docker/getting-started][1]をやるのがお勧め
- getting-startedの知識を生かせばnginx環境を立ち上げるのは簡単

以上です。誤り、改善ポイントなどありましたらコメントお願いします。

[1]:https://hub.docker.com/_/nginx
[2]:https://github.com/docker/getting-started
[3]:https://www.docker.com/get-started
[4]:https://nginx.org/en/docs/http/ngx_http_autoindex_module.html