RailsでDockerfile設定しながら、コマンド一つひとつ丁寧に読んでみた

## この記事の内容
Railsで新規プロジェクトを立ち上げることになりました。
`Docker`周りも一から設定するのは初めてだったため、[公式のRailsの設定ガイド](https://docs.docker.com/samples/rails/)を参考にしつつ、バージョン等を最新版（2021年8月時点）にアップデートして作成しました。

今後自分でカスタマイズしていくことが予想されたので、下記ガイドのコマンドも一つ一つ丁寧に読んで理解してみることにしました。

- [Quickstart: Compose and Rails](https://docs.docker.com/samples/rails/)

以下は、その時のノートです。
なお`Dockerfile`だけではなくRailsの環境構築全体を解説した記事には以下の素晴らしい記事があります。

- [DockerでRuby on Railsの環境構築を行うためのステップ【Rails 6対応】](https://qiita.com/kodai_0122/items/795438d738386c2c1966)

また、途中で出てくる`Dockerfile`のコマンドに関しては、全てこちらの[公式ガイドの日本語訳](http://docs.docker.jp/engine/articles/dockerfile_best-practice.html)の方が詳しいです。

- [Dockerfile のベストプラクティス](http://docs.docker.jp/engine/articles/dockerfile_best-practice.html)

この記事は、あくまでもRailsを立ち上げるための最低限の機能を細かく読み解きながら記載しているものになります。

**【追記：この記事の続きの環境構築を書きました！】**
- [DockerでRailsの環境構築を一つ一つ丁寧に読み解きながらやってみた（docker-compose.yml編）](https://qiita.com/tanutanu/items/95db52613f9b27bb03d2)

## Define the project （プロジェクトの定義）
### 序盤
下記のコードは、公式の[Define the project](https://docs.docker.com/samples/rails/#define-the-project)の最初の部分を最新版にアレンジしたものです。（以下、同じ）

```dockerfile
# syntax=docker/dockerfile:1
FROM ruby:3.0.2
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
```
1行ずつ読み解いていきます。

```dockerfile
FROM ruby:3.0.2
```
- `FROM` ... 使用するイメージを定義します。
- **`イメージ名：タグ`**の順に記載します。
- どんなタグが存在するかは、[dockerhubのrubyのページ](https://hub.docker.com/_/ruby)で調べます。

```dockerfile
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
```

- `RUN` ... 実行するコマンドを指定します。
- `apt-get update -qq` ... ライブラリをアップデートします。`-qq` はquietモードで実行。エラー以外を表示しないオプションです。
- `apt-get install -y nodejs postgresql-client` ... 全て承諾（`-y`オプション）で必要なライブラリを入れます

`postgresql-client`を入れると、[psqlコマンドが使えるようになる](https://ubuntu-perl-web.com/blog/20200603135100.html)んですね。へー。。。

```dockerfile
WORKDIR /myapp # アプリ名
```

- `WORKDIR` ... 作業ディレクトリの指定。ここで指定したディレクトリが、その後の[Dockerfile内でのRUN,COPYなどのあらゆる命令の起点となり](http://docs.docker.jp/engine/reference/builder.html#workdir)ます。

```dockerfile
COPY Gemfile /nanairo/Gemfile
COPY Gemfile.lock /nanairo/Gemfile.lock
RUN bundle install
```

ローカルの`Gemfile`及び`Gemfile.lock`をDockerコンテナ内にコピーして、`bundle install`します。

### 中盤

```Dockerfile
# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
```

```Dockerfile
COPY entrypoint.sh /usr/bin/
```
- `entrypoint.sh`をコンテナ内の`/usr/bin/`にコピーします。
- `entrypoint.sh`にはコンテナ立ち上げ時に実行するスクリプトを書きます。何を書けば良いかは、先に取り上げた[公式のRailsの設定ガイド](https://docs.docker.com/samples/rails/)の下方に書いてあります。

```Dockerfile
RUN chmod +x /usr/bin/entrypoint.sh
```
- ファイル所有者に`entrypoint.sh`の実行権限を付与します。

```Dockerfile
ENTRYPOINT ["entrypoint.sh"]
```
- `ENTRYPOINT` ... 最初に実行するコマンドを指します。文法やベストな使い方は[公式の以下のガイド（日本語訳）](http://docs.docker.jp/engine/reference/builder.html#entrypoint)に詳しかったです。
- [ENTRYPOINT](http://docs.docker.jp/engine/reference/builder.html#entrypoint)

```Dockerfile
EXPOSE 3000
```
- `EXPOSE` ... コンテナがリッスン（待機）するポート番号を指定します。

### 終盤

```Dockerfile
# Configure the main process to run when running the image
CMD ["rails", "server", "-b", "0.0.0.0"]
```

- `CMD` ... ソフトウェアを実行するコマンドです。`["実行ファイル","パラメータ1","パラメータ2", ...]`の形式で書かれています。
- こちらも[詳しい書き方やベストな使い方がガイドに紹介されていました](http://docs.docker.jp/engine/reference/builder.html#cmd)

## で、途中に出てきた `entrypoint.sh` って何よ？

コンテナ立ち上げ時に実行するコマンドをここでは `entrypoint.sh` というファイルに記していましたね。こちらのファイルを手動で作成したのち、以下のように記します。

```sh:entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
```
- `#!/bin/bash` ... bashを利用したシェルスクリプトであることを示しているそうです。へー。（[この記事の中盤](https://www.sejuku.net/blog/54333)に書いてありました）
- `set -e` ... エラーが出たらスクリプトを中断します。
- `rm -f /myapp/tmp/pids/server.pid` ... [pidファイルが既に存在するためサーバーが立ち上がらないエラー](https://blog.cloud-acct.com/posts/u-rails-serverpid-error/)を回避するため、`server.pid`ファイルが既にあった場合、それを削除します。
- `exec "$@"` ... Dockerfileの`CMD`の部分に書いてあるコマンドを実行する記述。`"$@"`自体は[シェルスクリプトらしい](https://taramonera.hatenadiary.jp/entry/20100715/1279177394)のだけど謎が多くて分からないので今回は呪文として覚える。


## 終了！
以上でした！シンプルなサンプルだったからかもしれませんが、意外と簡単でした＾＾；
実際に使うには、他`docker-compose.yml`の作成など色々必要ですが、そちらは作成し次第随時追記していきます。

**【シリーズの他の記事】**
- [DockerでRailsの環境構築を一つ一つ丁寧に読み解きながらやってみた（docker-compose.yml編）](https://qiita.com/tanutanu/items/95db52613f9b27bb03d2)