[備忘録]自作アプリへの理解を深める

### 注意）この記事について
この記事は、私自身が作成したWebアプリについて自身で振り返り、理解を深めるためのものです。基本的には個人的な備忘録として執筆したものですので、ご了承ください。

作成したwebアプリ

https://topic-board.jp/

# 備忘録 Docker#1
### Dockerfile

```
FROM ruby:3.2.2
ENV TZ Asia/Tokyo
RUN mkdir -p /etc/apt/keyrings \
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
&& NODE_MAJOR=20 \
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \
&& curl -fsSL https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor -o /etc/apt/keyrings/yarn.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs yarn vim imagemagick libvips42

WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

CMD [ "rails","server","-b","0.0.0.0" ]
```

### 解説
```
FROM ruby:3.2.2
```
`FROM`
ベースとなるDockerイメージを指定する。

```
ENV TZ Asia/Tokyo
```
`ENV`
環境変数を指定する。ここでは`TZ`(タイムゾーン)を`Asia/Tokyo`(日本時間)に指定している。

```
RUN mkdir -p /etc/apt/keyrings \
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
&& NODE_MAJOR=20 \
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \
&& curl -fsSL https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor -o /etc/apt/keyrings/yarn.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
```
ここでは必要なパッケージ(Node.js, yarn)をインストールしている

`mkdir -p /etc/apt/keyrings`
 
 - gpgキーを保存するためのディレクトリを作成する。パッケージの署名を確認するためのキーを格納する場所。公開鍵を格納する。
 - `pオプション`：複数階層のディレクトリを１回で作成できる。

`curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \`

- `fsSLオプション`：curlのオプション
** `fオプション（fail）`；curlコマンドによるHTTPリクエストでサーバーエラーによってリスエストが失敗した際、通常返されるhtmlを返さず、22というエラーコードを返す。
** `sオプション（silent）`：進行状況やエラーメッセージを表示しないサイレントモードで実行する。ただし、後述する`Sオプション`と一緒に用いると、エラーメッセージは表示するようになる。
** `Sオプション（show error）`：エラーメッセージを表示する。
** `Lオプション（location）`：HTTPリクエストを投げた際に、要求したページが移動していることをサーバーが伝えてきた場合、移動した新しいページにリクエストを投げ直してくれる。
=>つまり`fsSLオプション`は、
**HTTPリクエストがサーバーエラーにより失敗した場合に、22というエラーコードを返し、**
**進行状況を表示せず、エラーメッセージを表示し、**
**アクセスしたページが移動していた場合にば、その移動さきにもう一度リクエストし直す、**
というオプションになる。

`https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key`
- 公開鍵を取得

` | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg `
- `|（パイプ）`：前のコマンド（左）の出力を次のコマンド（右）の入力として渡す。ここでは、取得した公開鍵をgpgコマンドに渡している。
- `--dearmorオプション`：キーの形式を、ASCII Armor形式からバイナリ形式に変換する。
- `-oオプション`: ダウンロードしたデータをファイル名を指定してファイルとして保存する。ここでは、curlで取得した公開鍵を`~.gpg.key`というファイルに保存している。

`&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \
`

- ここではリポジトリと公開鍵を紐づけている
- `https://deb.nodesource.com/node_$NODE_MAJOR.x `：NodeSourceのNode.jsパッケージが置かれているURL。環境変数でバージョンを指定している。
- `nodistroオプション`：特定のディストリビューションに依存せず、パッケージをインストールする。以前はDebianなどの指定が必要だったが、NodeSourceアップデートによりこのように変更された。

>Package Changes: DEB and RPM packages are now available under the nodistro codename. We no longer package the installer coupled to specific versions. This means you can install Node.js on almost any distro that meets the minimum requirements.

https://github.com/nodesource/distributions


`| tee /etc/apt/sources.list.d/nodesource.list `
- `tee`：パイプで受け取ったデータを標準出力に表示すると同時に、指定したファイルに書き込む
- ここでは、直前のコマンドで、`echo`で生成されたリポジトリ情報を標準出力に表示し、その内容を指定したファイルに書き込んでいる。
- `/etc/apt/sources.list.d/nodesource.list`に指定したリポジトリを追加することで、apt経由でNode.jsパッケージをインストールできる。

`curl -fsSL https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor -o /etc/apt/keyrings/yarn.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list`
- nodeと同様なので省略。

注意）
もしも`signed-by`で指定した公開鍵が存在しない、誤っていた場合、以下のようなエラーが発生します。
```
W: GPG error: https://dl.yarnpkg.com/debian stable InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 23E7166788B63E1E
```
- APTが https://dl.yarnpkg.com/debian stable のリポジトリを認証しようとした際に、署名を検証できなかった（= 公開鍵が見つからなかった） ことを示しているようです。

```
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs yarn vim imagemagick libvips42

```
ここまででnodeとyarnをインストールするための準備ができたので、ここでインストールしています。

`apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs yarn vim imagemagick libvips42`
- パーケージリストの更新とインストールを実行している。
- なお、`apt-get update`と`apt-get install`は常に同時に実行する必要がある。
- `yオプション`：ユーザーの確認なしでyesとして処理を進める。
>RUN apt-get updaate と apt-get install は常に同じ RUN 命令文で連結します。

https://docs.docker.jp/engine/articles/dockerfile_best-practice.html#run:~:text=RUN%20apt%2Dget%20updaate%20%E3%81%A8%20apt%2Dget%20install%20%E3%81%AF%E5%B8%B8%E3%81%AB%E5%90%8C%E3%81%98%20RUN%20%E5%91%BD%E4%BB%A4%E6%96%87%E3%81%A7%E9%80%A3%E7%B5%90%E3%81%97%E3%81%BE%E3%81%99%E3%80%82

※ここで、curl、wgetのインストールは必要ないのかと疑問を持ちましたが、ruby3.2.2の公式イメージには以下のようなパッケージが標準搭載されているため、明示的にcurl、wgetのインストールは不要なものと思われます。
`deb / debian/curl / 7.88.1-10+deb12u1`
`deb / debian/wget / 1.21.3-1+b2`

https://hub.docker.com/layers/library/ruby/3.2.2/images/sha256-914abde21560cba7817b55bddb6a371b8ff78c88197c2db27f2fc8c9aaeed3a1?context=explore#:~:text=3.2.2-,ruby%3A3.2.2,-MULTI%2DPLATFORM

```
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

CMD [ "rails","server","-b","0.0.0.0" ]
```
`WORKDIR /myapp`
- 作業ディレクトリを設定している。
- なお、指定したディレクトリがDockerコンテナ内に存在しない場合、自動的に作成される。

`COPY Gemfile /myapp/Gemfile`
`COPY Gemfile.lock /myapp/Gemfile.lock`
- ローカルにあるGemfile、Gemfile.lockというファイルをDockerの指定したディレクトリ内のファイルにコピーしている。

`RUN bundle install`
- gemファイル内に記述されたgemをインストールしている。

`COPY . /myapp`
- ローカルのカレントディレクトリをDocker内の/myappディレクトリにコピーしてい

`COPY entrypoint.sh /usr/bin/`
- ローカルのentrypoint.shというファイルを指定したディレクトリにコピーしている。
- entrypoint.shは、アプリの起動前に実行したいシェルスクリプトを記述するファイル。

`RUN chmod +x /usr/bin/entrypoint.sh`
- `/usr/bin/entrypoint.sh`の実行権限を付与する。これがなければ実行できずエラーとなる。

`ENTRYPOINT ["entrypoint.sh"]`
- `ENTRYPOINT`には実行したいシェルスクリプトを指定する。ここでは`entrypoint.sh`フィイルを指定し、ファイル内のスクリプトを実行するように指定している。

`EXPOSE 3000`
- 3000番ポートに接続することを指定している。
- なお、このコマンドは実際の動作には影響しないが、ドキュメント的に書かれている場合が多い。
- 実際にポートを指定するためには`docker-compose.yml`にて指定することが必要。

`CMD [ "rails","server","-b","0.0.0.0" ]`
- railsサーバーを起動している。
- なお、CMDは`docker-compose.yml`の`services.web.command`内の記述によって上書きされるため実際には不要。