DockerでRailsの環境構築をした



## はじめに

DockerでRailsとMysqlが載った環境を用意してその上で何かを作ろうと思います。

手始めとして、以下の事を行っていきたいと思います。

1. Docker上でRailsとMySQLを動かす

## キーワード

Rails, Docker, make, Mysql

## 目次

1. 環境
2. 宣言
3. やる
4. まとめ
5. 参考

## 環境

- docker desktop: 20.10.22

でこいつらを動かせるようにしたい

- rails: 7.0.4
- ruby: 3.2
- mysql: 8.0.3

## 宣言

公式が出している情報のみ引用します(エラー時は別)

## 使ってみる

Dockerについては前に自分がメモしていた。見返してもあんまり役に立たないですw

[https://qiita.com/kajiyai/items/3e55844b9b39cb177128](https://qiita.com/kajiyai/items/3e55844b9b39cb177128)

公式がdockerにrailsをセットアップする方法を出しているが、postgresql版なので適宜読み替えつつ、追っていきます。

[https://github.com/docker/awesome-compose/tree/master/official-documentation-samples/rails/](https://github.com/docker/awesome-compose/tree/master/official-documentation-samples/rails/)

#### Dockerfileの定義

Dockerfileは環境の依存関係などを定義するときに呼び出すファイルです。rubyのバージョンだけ変更しました。

```ruby
# syntax=docker/dockerfile:1
FROM ruby:3.2
RUN apt-get update -qq && apt-get install -y nodejs mysql-client
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install

# 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

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

`FROM`,`RUN`,`WORKDIR`,`COPY`等の命令が何をしているかはだいたいわかりますが、`ENTRYPOINT`, `EXPOSE`, `CMD`等のコマンドが何をしているかよくわからないので調べました。

##### ENTRYPOINTについて

そもそもエントリーポイントの意味が分かってなかったです。

> エントリーポイントとは、プログラムを実行するうえで、プログラムやサブルーチンの実行を開始する場所のこと。プログラム全体のエントリーポイントとなる場所を含むルーチンがメインルーチンである。
> 

[https://ja.wikipedia.org/wiki/エントリーポイント#:~:text=エントリーポイントとは、プログラム,がメインルーチンである。](https://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3%E3%83%88%E3%83%AA%E3%83%BC%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88#:~:text=%E3%82%A8%E3%83%B3%E3%83%88%E3%83%AA%E3%83%BC%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88%E3%81%A8%E3%81%AF%E3%80%81%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0,%E3%81%8C%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%AB%E3%83%BC%E3%83%81%E3%83%B3%E3%81%A7%E3%81%82%E3%82%8B%E3%80%82)

一番初めに処理されるプログラムを指定しているという事ですね。

##### EXPOSEについて

トランスポート層の設定のドキュメントとして機能するみたいです。実際にポートを開けるには`docker run`コマンドを叩こうとかいてあります。

プロトコルのデフォルトはTCPだけど、オプションでUDPも選べるよと書いてあります。

> The `EXPOSE` instruction informs Docker that the container listens on the specified network ports at runtime. You can specify whether the port listens on TCP or UDP, and the default is TCP if the protocol is not specified.
> 
> 
> The `EXPOSE` instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published. To actually publish the port when running the container, use the `-p` flag on `docker run` to publish and map one or more ports, or the `-P` flag to publish all exposed ports and map them to high-order ports.
> 

[https://docs.docker.com/engine/reference/builder/#expose](https://docs.docker.com/engine/reference/builder/#expose)

##### CMDについて

どうやらCMDとENTRYPOINTは奥が深そうです。

ココでは、IPアドレスを明示してrails serverコマンドを実行したいのね、と理解しておきます。

```ruby
$ rails server -b '0.0.0.0'
```

[https://railsdoc.com/page/rails_server](https://railsdoc.com/page/rails_server)

#### Dockerfileのための準備色々

##### Gemfileの作成

`rails new`　を後のステップで実行するとすぐに更新されますが、vscodeを開き、Gemfileを一時的に作成します。

```ruby
source 'https://rubygems.org'
gem 'rails', '~>7'
```

##### Gemfile.lockの作成

```ruby
$ touch Gemfile.lock
```

##### docker-compose.ymlの作成

posgresql→mysqlに変更してます。

```ruby
services:
  db:
    image: mysql:latest
    ports:
      - "13306:3306"
    volumes:
      - ./.data/db:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
```

参考

[https://hub.docker.com/_/mysql/](https://hub.docker.com/_/mysql/)

#### コンテナの実行

```ruby
$ docker compose run --no-deps web rails new . --force --database=mysql
```

このコマンドを実行した所、次のようなエラーが生じた

```ruby
ERROR [7/8] COPY entrypoint.sh /usr/bin/

failed to solve: failed to compute cache key: failed to calculate checksum of ref moby::****: "/entrypoint.sh": not found
```

entrypoint.shファイルをentorypoint.shと名付けていたゆえのエラーだった

再度エラーが

```ruby
E: Package 'mysql-client' has no installation candidate
```

Dockerfileの3行目、mysql-clientをdefualt-mysql-clientに変更

```ruby
RUN apt-get update -qq && apt-get install -y nodejs default-mysql-client
```

またまたエラーが

```ruby
exec /usr/bin/entrypoint.sh: no such file or directory
```

そんなファイル無いよ

stackoverflowのスレ

[https://stackoverflow.com/questions/38905135/why-wont-my-docker-entrypoint-sh-execute](https://stackoverflow.com/questions/38905135/why-wont-my-docker-entrypoint-sh-execute)

改行コードが原因?

[https://kakiblo.com/docker-windows/](https://kakiblo.com/docker-windows/)

試したこと

- entrypoint.shファイルの改行コードをLFに変更した
- entrypoint.shファイルの先頭行を#!bin/shに変更した
- Dockerfileの10,11行目の/usr/binを/usr/local/binに変更した

動いた

参考: [https://www.baeldung.com/docker-cant-connect-local-mysql](https://www.baeldung.com/docker-cant-connect-local-mysql)

こちらのコマンドで`—no-deps`を指定しているのでコマンド実行後はファイルが作成されるだけ、が正しい挙動だと思われます

docker compose run はアドホックなタスクに使用するみたいです

```ruby
$ docker compose run --no-deps web rails new . --force --database=mysql
```

なにはともあれGemfileが更新されたのでビルドします

```ruby
$ docker compose build
```

rails仕様のディレクトリ構成が完成しました

#### DBを接続

何も変更せずに`docker compose up `したらエラー

```ruby
Can't connect to local MySQL server through socket '/run/mysqld/mysqld.sock' (2)
```

ローカルのMySQLサーバーと繋げないよ～と言ってそう

database.ymlのhostをlocalhostからdbに変更してみた

またエラー。今度はユーザ名とPWが違うと言ってそう

```ruby
ActiveRecord::DatabaseConnectionError
There is an issue connecting to your database with your username/password, username: root.
Please check your database configuration to ensure the username/password are valid.
```

docker desktopのterminalから `mysql -u root -p`でも入れない

docker-compose.ymlファイルのdb:enfironment:にMYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORDを入力して、再ビルドしてみる

```ruby
services:
  db:
    image: mysql:latest
    ports:
      - "13306:3306"
    volumes:
      - ./.data/db:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
```

エラーが解決できないので質問を投げた。

[https://qiita.com/kajiyai/questions/6bb978839a2b78c8ae03](https://qiita.com/kajiyai/questions/6bb978839a2b78c8ae03)

Postgresqlに変更したらwelcomeページは動いた

## まとめ

MySQLで動かそうとしましたが、動きませんでした

Postgresqlでは動きました

MySQLでなければならない理由はないのでPostgresqlで作っていこうかと思いますが、何が問題なのかはっきりせず、もやもやします。お詳しい方、コメントで教えて頂けると幸いです。

次は、以下の記事を元にmakeツールでdockerコマンドを整理してみたいと思います

[https://beyondjapan.com/blog/2020/10/makefile-docker/](https://beyondjapan.com/blog/2020/10/makefile-docker/)

ではまた。

## 参考

- [https://github.com/docker/awesome-compose/tree/master/official-documentation-samples/rails/](https://github.com/docker/awesome-compose/tree/master/official-documentation-samples/rails/)