herokuからdockerのmysqlに移行（メモ書き）

円安の影響でherokuの最安料金でさえ貧乏学生が支払う金額としてはキツくなってきたので移行を決意。この時の覚え書き。（MySQLスキーマ変更あたりは泥臭い処理をしてしまっている)

注意） 自分の操作より、もっと良いコマンド操作があると思います。


# herokuから PostgreSQLデータをダンプ
## dockerでPostgreSQLを起動
- pg_dumpのためだけにdbを生ダウンロードしたくなかったので、dockerでpostgresを作りました。


（参考リンク🔽）

https://qiita.com/kazokmr/items/48200cc2188d27d5d536


```bash:postgresのdocker コンテナ作成
docker run --name postgres -e POSTGRES_PASSWORD=617e330ed35242e6dca3dc8b0c5629efb0f9a90ecdec07ddc2e532d617ddd8e1 -e POSTGRES_INITDB_ARGS="--encoding=UTF8 --no-locale" -e TZ=Asia/Tokyo -p 5432:5432 -v $PWD:/my_data -d postgres
```

-- --

## herokuのPostgresSQLデータをローカルにダンプ

（参考リンク🔽）

https://www.letitride.jp/entry/2020/08/03/132128

https://www.postgresql.jp/document/8.2/html/app-pgdump.html

```bash:アプリ名検索 & herokuのデータベース情報を取得
heroku apps
heroku pg:credentials:url --app （アプリ名）
```

```bash:dockerのPostgreSQLに入る
docker exec -it postgres /bin/bash
```

```bash: データ & スキーマをダンプ
pg_dump --no-acl --no-owner -h （--.amazonaws.com) -U (ユーザ名) -v -a -（データベース名） > /my_data/postgres/（ダンプファイル名）
pg_dump --no-acl --no-owner -h （--.amazonaws.com) -U (ユーザ名) -v --schema-only -（データベース名） > /my_data/postgres/（ダンプファイル名）
```
- （）の部分は 適当な値を入れる
- コマンド実行ごとに パスワードを聞かれる
- 
- ダンプファイルをdocker外部に取り出したい場合、 『/my_data/欲しい場所』 にする。（PostgreSQLのコンテナ起動時に/my_dataをdocker外部のディレクトリに反映する設定をしているため）


# MySQLに移行

#### ファイル内容
自分はMySQLに接続する側も dockerで連携させた。以下が dockerの例
```yml:docker-compose.yml
services:
  db:
    build:
      dockerfile: ./Dockerfile_sql
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_USER: user
      DB_USERNAME: user
      MYSQL_PASSWORD: user
      MYSQL_DATABASE: user
    ports:
      - 3306:3306
    volumes:
      - ./mysql:/var/lib/mysql
      - ./postgres:/my_data #移行用データ保存元
    

  api:
    build:
      content: .
      dockerfile: ./Dockerfile
    ports:
      - 8000:8000
    volumes:
      - .:/mysite
    tty: true # コンテナの永続（必要か分からないけど)

    depends_on:
      - db

```
```dockerfile:Dockerfile
FROM python
ENV PYTHONUNBUFFERED 1
RUN mkdir /mysite
# docker内部で実行スタート場所を mysiteディレクトリに
WORKDIR /mysite
#現在のディレクトリ構成を dockerのmysiteフォルダに反映
Add . /mysite 
```
```dockerfile:Dockerfile_sql
FROM mysql:5.7

RUN mkdir /my_data
# postgresに入れた シェルファイルでmysql設定を変更
Add /postgres/change_mysql_utf.sh /my_data/

RUN sh my_data/change_mysql_utf.sh 
```
```sh:change_mysql_utf.sh
#! /bin/sh

## utf8に変更 

sed -i -e "s/\[mysqld\]/\[mysqld\]\ncharacter-set-server=utf8\n/g" ../etc/my.cnf
sed -i -e "s/\[client\]/\[client\]\ndefault-character-set=utf8\n/g" ../etc/my.cnf
```
[utf8に変更する理由](https://qiita.com/YusukeHigaki/items/2cab311d2a559a543e3a)


## dockerのMySQL起動

- apiを起動することで、db側も同時に立ち上げる
- mysqlコンテナIDは `docker ps`で 『（現在フォルダ名）-db-』 と書かれた左側

```bash:
docker-compose run api
docker exec -it mysqlのコンテナID /bin/bash
```

#### (+a)エラー時など？
参考

https://www.teenytinybot.dev/articledetail/5/



```bash: mysqlフォルダの初期化
rm -r ./mysql
mkdir ./mysql
docker compose up --build -d
```
- --buildで docker image生成から行う(しなくて大丈夫かも？)

https://stackoverflow.com/questions/73948802/strconv-atoi-parsing-invalid-syntax

```bash:buildしすぎた時の 実行停止 & キャッシュ削除？(良いのか分からないけどメモ)
docker-compose down --remove-orphans
```

- upと runの違いがわかってないので用調べ ↑

## Postgresのデータを微調整

以下、ひっかかった時に参考にしたサイト。これを利用し自作ファイルで微調整した。


##### 基本処理
- 自分はめんどくさくなって、schemaのtable宣言以外（ALTER TABLE関係）も徹底削除した。DB定義をよく変更していた方には良くないかも...

https://qiita.com/artifactsauce/items/f9fdee98a258b349dc06

https://www.rectus.co.jp/archives/7079

##### publicについて

https://www.miracleave.co.jp/contents/217/db-table-schema/

##### timestamp関係

https://filline.hatenadiary.org/entry/20120614/1339663646

https://yudai-stadium.com/blog/mysql5-7-error-1067-42000-invalid-default-value-for-xxx%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%8C%E3%81%A7%E3%81%9F%E3%81%8A%E8%A9%B1/


##### まとめサイト的

 https://nagoyanofes.hatenadiary.jp/entry/2022/09/02/081426#%E9%80%A3%E7%95%AA%E3%82%92%E4%BB%98%E3%81%91%E3%82%8B---dump%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E4%BF%AE%E6%AD%A3%E6%99%82%E3%81%AB%E7%9F%A5%E3%81%A3%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84%E3%81%93%E3%81%A8


###### おまけ?（自作の変換コード）
- [schema変更](https://gist.github.com/kabokawakabo/651d36d7a454d2bb8525dc36bae39a92)
- [tableデータ挿入用](https://gist.github.com/kabokawakabo/e47ae591c7858cd556e12bbf564f4f9b)


## MySQL操作
- mysqlコンテナ内部でmysqlにログイン
    - `mysql -u root -proot -h 127.0.0.1 -P 3306`
    - rootユーザでしかログインできなかった
    - パスワード、ポート番号などはdocker-compose参考



##### その他のポイント？
- djangoの runserverなどは 0.0.0.0を利用して動かさないとダメ
    - 例
    - `python manage.py runserver 0.0.0.0:8000`
    - `uvicorn main:app --reload --host 0.0.0.0 --port 8000`

https://qiita.com/taichikanaya_1989/items/5f60b55e847a33f8db41

- fastAPIの場合、URLは `"mysql://root:root@db:3306/user?charset=utf8"`
    - host名は docker-composeで作成した場合、サービス名で接続可能らしい？

https://qiita.com/satto_sann/items/4fbc1a4e2b33fa2237d2


-- --

##### 自分のディレクトリ構成
- docker-compose.yml
- Dockerfile
- Dockerfile_sql
- ＊ SQL変更pythonファイル
- postgres
    - change_mysql_utf.sh
    - ＊ ダンプデータ
    - data
        - ＊　SQLのテーブル別tsvファイル


（自分の実際の環境設定と変更している面もあるので、エラーが見つかった場合質問していただけると誤りに気付けて助かります。）