フルスタックエンジニアへの道 part 2 ~Rails 7 × Dockerの環境構築 2

### 前回: 個人開発をやる目的とか、何をするかなどはこちらから

[https://qiita.com/Terao-Takumi/items/f33393f7e99d40d7e4bb](https://qiita.com/Terao-Takumi/items/f33393f7e99d40d7e4bb)

### 今回のゴール： Docker上に起動したMySQLとRailsを接続し、rails sする。

# dockerまわりの設定

Dockerfile: 最後にこれを足す

```bash
$ CMD ["mysqld"] # mysqlを起動
```

docker-compose.yml

```bash
db-sloth:
    image: mysql:5.7
    platform: linux/x86_64 # M1 Macだと動かないのでplatformを指定
    volumes:
      - ./db/development/tools:/docker-entrypoint-initdb.d # 初回データ実行
      - ./db/development/db:/var/lib/mysql # データ永続化
    environment:
      MYSQL_ROOT_PASSWORD: root
      TZ: Asia/Tokyo
    hostname: db-sloth
    ports:
      - "3306:3306"
    command: mysqld --sql_mode="NO_ENGINE_SUBSTITUTION" --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci --innodb-flush-log-at-trx-commit=0 --default-authentication-plugin=mysql_native_password --innodb-ft-enable-stopword=0
    networks:
      - shared-network
```

だいたいこの記事に書いてくださっているので、これ読めばわかります(笑)

[https://qiita.com/leafeon00000/items/e190cf92af3a487cc749](https://qiita.com/leafeon00000/items/e190cf92af3a487cc749)

ここで重要なのが、volumeという概念。これは、コンテナを削除したとしてもデータが残り続けるもの。

参考:

[https://zenn.dev/ajapa/articles/fc1205d4bcbfe7](https://zenn.dev/ajapa/articles/fc1205d4bcbfe7)

今回は、、、

```bash
./db/development/tools:/docker-entrypoint-initdb.d
```

これで`:`の左のディレクトリ配下のファイル(ローカルファイル)を右のディレクトリ配下(docker側ファイル)にマウントするということを記述している。1つめのこれは、

docker-entrypoint-initdb.d ディレクトリにsqlファイルを入れておくことで、コンテナ作成時にsqlを実行してDBとかテーブルを初期セットしておくというギミック。

```bash
- ./db/development/db:/var/lib/mysql # データ永続化
```

これは、mysqlのデータをずっと残しておくためにdb/development/db 配下においておくよ~ということ。コマンドは、なんか、魔法です(笑)。色々設定をここで変更している感じ。

initialize_db.sql

```sql
DROP DATABASE IF EXISTS sloth;
CREATE DATABASE sloth;

USE sloth;

DROP TABLE IF EXISTS `memo`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `memo`
(
    `memo_id`      int(11) NOT NULL AUTO_INCREMENT COMMENT 'メモID',
    `memo_title`   varchar(255) NOT NULL COMMENT 'メモタイトル',
    `memo_content` text COMMENT 'メモ内容',
    PRIMARY KEY (`memo_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
/*!40101 SET character_set_client = @saved_cs_client */;
```

くっそかんたんなメモテーブルだけを入れておいた。スピーディーにRails sするため、ここは手を抜こう…。後からテーブル追加したり、ガンガンalter tableしていく。テーブル変更を恐れない。それがアジャイル。

注意点は、先にローカルでdb作っていたり、間違えて変なファイルができてしまったりしたときに、docker-entrypoint-init.d配下のsqlだったりshだったりが起動しないということ(これに気づかず1時間くらい格闘していた)

[https://zenn.dev/re24_1986/articles/978801ae092498](https://zenn.dev/re24_1986/articles/978801ae092498)

> 実行スクリプト作成での補足
docker-entrypoint-initdb.d 内に複数のスクリプトが存在する場合、名前順で実行
**実行タイミングは、/var/lib/mysqlがない場合に実行される**
> 

### database.ymlの編集

```sql
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: root
  host: db-sloth # docker-compose.ymlで設定した名前

development:
  <<: *default
  port: 3306
  database: sloth
```

ま、ポート番号あわせて、host-name合わせることくらい。何も難しいことはない。

# docker composeして確認

```bash
$ docker ps
CONTAINER ID   IMAGE                 COMMAND                  CREATED          STATUS          PORTS                               NAMES
dac9ad924d5f   sloth-web_web-sloth   "entrypoint.sh tail …"   22 seconds ago   Up 20 seconds   0.0.0.0:3002->3002/tcp              sloth-web_web-sloth_1
b74377851690   mysql:5.7             "docker-entrypoint.s…"   22 seconds ago   Up 21 seconds   0.0.0.0:3306->3306/tcp, 33060/tcp   sloth-web_db-sloth_1
4ee6c1526f2f   redis:6.2-alpine      "docker-entrypoint.s…"   22 seconds ago   Up 21 seconds   0.0.0.0:6382->6379/tcp              sloth-web_redis-sloth_1
```

→無事 image = mysql:5.7 のコンテナができていて、、、

mysql入って…

```bash
$ docker exec -it 6b1d61e42d35 bash
$ mysql -uroot -proot # -uはユーザー、-pはパスワードを予め入力できるオプション
```

```sql
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sloth              |
| sys                |
+--------------------+
5 rows in set (0.01 sec)
```

→できてる。

いざ、、、

# Rails s!!!!!!!

![スクリーンショット 2022-05-25 1.12.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2496677/9964872f-7e86-6534-9fd1-7f20d705b6c1.png)


これで、Rials 7 × Docker × MySQLの環境構築が無事できましたとさ。

次回はメモ帳のUIを作っていこうかしら。ひとまずXDでデザインこしらえて、vue.jsとか使ってSPAを実装してみたい。

# 補遺: shared-networkについて

ちょっと物足りないので、今回docker-composeでコンテナのネットワークにshared-networkを使ったのを少しだけ解説したい。

### Shared-networkとは?

docker-compose.ymlで定義された**複数の環境間で通信を行うことができる**ネットワーク環境のこと。今回使う必要性はまったくないが、やってみたかったのでやってみたという経緯。

例えば、

・アプリケーション A

・アプリケーション B

・それを紐付けるAPI

と3つのプロジェクトがあったときに、それらを全部つなげたい…ってな場合に便利なんじゃないかと思われる。社内システムとか作っているとよくあることなのかな?

### デフォルト設定ではどうなる?

dockerを実行状態にしておくと、3つのnetworkが立ち上がっている。

```bash
$ docker network ls

NETWORK ID     NAME                  DRIVER    SCOPE
997b7bca7af9   bridge                bridge    local
eda438fe48a8   host                  host      local
3548002f655e   none                  null      local
```

そこから(一般的な方法で)docker-composeをすると、、、

```bash
$ docker network ls

NETWORK ID     NAME                  DRIVER    SCOPE
997b7bca7af9   bridge                bridge    local
eda438fe48a8   host                  host      local
3548002f655e   none                  null      local
82cded1a198f   sloth-web_app_net   bridge    local
```

sloth-web_app_netが増える。これは、docker-composeのnetworksで

```yaml
networks:
    app_net: # ネットワークの名前
        driver: bridge
        ipam: # IP Address Management
            driver: default
            config:
                - subnet: 172.20.101.0/24 # 0~24までの幅で使うと言っておく
```

こんなふうに定義されている。そして、作られたネットワークの中身を見てみると、、、

```bash
$ docker inspect [ネットワークID]

[
    {
        "Name": "sloth-web_app_net",
        "Id": ここにID,
        "Created": "2022-05-23T05:28:59.372943095Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.20.101.0/24"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "28012fe2c27a1c9293d13f5470a3d1161f021b48db0f940eb51709f324ef39f0": {
                "Name": "コンテナの名前1",
                "EndpointID": "cc4016f7f64dcab24053248e0e97b902f569c82a72b62acc48087ee673c63aa3",
                "MacAddress": "02:42:ac:14:65:04",
                "IPv4Address": "172.20.101.4/24",
                "IPv6Address": ""
            },
            "2cb70ccca32edc27ba31343abfc6c85e918441abf1075b3aa05ac7474a4e1435": {
                "Name": "コンテナの名前2",
                "EndpointID": "5bb65c62eb476d2c60c5785ed90034fc64ffd1e5e7de130ac233f2dc4b8e3443",
                "MacAddress": "02:42:ac:14:65:03",
                "IPv4Address": "172.20.101.3/24",
                "IPv6Address": ""
            },
            "f093c59b62c5e151071bdcf2a40d81e1d4f15b0d9ce196e341b3215a3822bc8c": {
                "Name": "コンテナの名前3",
                "EndpointID": "4b9c39201f21e22f632b545aac52da5b9d59b2ed4cdff87013e837470abe5bba",
                "MacAddress": "02:42:ac:14:65:02",
                "IPv4Address": "172.20.101.2/24",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "app_net",
            "com.docker.compose.project": "sloth-web",
            "com.docker.compose.version": "1.29.2"
        }
    }
]
```

つまり、app_netという名前のネットワークに3つのコンテナが紐付いていて、それぞれのコンテナ間で通信が可能になっている。

### なぜデフォルトのネットワークではなく、自前のネットワークを使うのか?

→多分、IPアドレスを固定したいから。だが、なぜ固定させたいのかがまだきちんとわかっていない。IPアドレスが変わったらめんどくさい環境設定がどこかにあるはず…。

参考記事: 複数のdocker-compose間で通信する

[https://tech.anti-pattern.co.jp/docker-compose/](https://tech.anti-pattern.co.jp/docker-compose/)

参考: 参考訳：Docker コンテナ・ネットワークの理解

[https://qiita.com/zembutsu/items/1da05cb6a60e1c5acc25](https://qiita.com/zembutsu/items/1da05cb6a60e1c5acc25)

参考: networksキー

[https://docs.docker.jp/compose/networking.html](https://docs.docker.jp/compose/networking.html)

参考: なぜIPアドレスを固定させるのか?

[https://qiita.com/takara@github/items/2349fff473474d7fcf47](https://qiita.com/takara@github/items/2349fff473474d7fcf47)