DockerでAPIサーバー(Flask)を立てる


Dockerのお勉強シリーズその2 

https://www.nogawanogawa.work/entry/backend_api

を参考にやってみたことのメモ。

[前回](https://qiita.com/kimisaki/items/c37aa5855cca4b7ca45b)の続き


## 実行環境

* Windows 10
* DockerDesktop for Windows

## ディレクトリ構成

```
├── backend
│   ├── Dockerfile
│   ├── app.py
│   └── requirements.txt
├── docker-compose.yml
└── mysql
    ├── conf.d
    │   └── my.cnf
    ├── initdb.d
    │   ├── schema.sql
    │   └── testdata.sql
    └── log
        └── ysql
```

## docker-compose.yml

flaskの定義を追加。

```yml:docker-compose.yml
version: '3.3'
services:
  db:
    image: mysql:latest
    restart: always
    volumes:
      - .\mysql\initdb.d:/docker-entrypoint-initdb.d
      - .\mysql\conf.d:/etc/mysql/conf.d
      - .\mysql\log\ysql:/var/log/mysql
    environment:
      MYSQL_DATABASE: sample_db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      MYSQL_ROOT_PASSWORD: rootpassword
    command: --default-authentication-plugin=mysql_native_password
    expose:
      - 3306

  flask:
    build: backend/
    volumes:
      - ./backend:/code
    environment:
      MYSQL_DATABASE: sample_db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      MYSQL_ROOT_PASSWORD: rootpassword
    ports:
      - "5000:5000"
    command: flask run --host 0.0.0.0 --port 5000
    links:
      - db
    depends_on:
      - db
```

## Flask

### Dockerfile

python3のイメージにrequirements.txtのパッケージをインストールするだけ。

```
FROM python:3
ENV PTYHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
```

### requirements.txt

なんとなくPyMySQLにしてみた。

```
flask
flask-cors
PyMySQL
cryptography
```

### app.py

```py:app.py
import os
import pymysql.cursors
from flask import Flask, request, jsonify
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

conn = pymysql.connect(
    host='db',
    port=3306,
    user=os.environ.get('MYSQL_USER'),
    password=os.environ.get('MYSQL_PASSWORD'),
    db=os.environ.get('MYSQL_DATABASE'),
    charset='utf8mb4',
    cursorclass=pymysql.cursors.DictCursor
)


@app.route('/', methods=['GET'])
def select_all():
    with conn.cursor() as cur:
        sql = "SELECT * FROM Comment"
        cur.execute(sql)
        results = cur.fetchall()
    return jsonify(results)
```


## コンテナ起動&確認

```
$ docker-compose build
$ docker-compose up -d
Starting webapp_db_1 ... done
Creating webapp_flask_1 ... done
```

curlでgetしてデータをとれることを確認。そのままだと見づらいのでjqに食わせると見やすくなる。

```
$ curl 'localhost:5000' | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   256  100   256    0     0   6400      0 --:--:-- --:--:-- --:--:--  6400
[
  {
    "category": "food",
    "content": "good",
    "id": 1,
    "title": "curry"
  },
  {
    "category": "vegitable",
    "content": "good",
    "id": 2,
    "title": "poteto"
  },
  {
    "category": "vegitable",
    "content": "bad",
    "id": 3,
    "title": "onion"
  },
  {
    "category": "meat",
    "content": "very good",
    "id": 4,
    "title": "poak"
  }
]
```


## 途中で発生した問題

```
$ docker-compose up -d
Starting webapp_db_1 ... done
Starting webapp_flask_1 ... done
$ docker-compose ps
     Name                   Command               State                  Ports
--------------------------------------------------------------------------------------------
webapp_db_1      docker-entrypoint.sh mysqld      Up       0.0.0.0:3306->3306/tcp, 33060/tcp
webapp_flask_1   flask run --host 0.0.0.0 - ...   Exit 1
$ docker-compose logs -t flask
Attaching to webapp_flask_1
 flask_1  | 2020-07-29T07:00:20.975201259Z RuntimeError: 'cryptography' package is required for sha256_password or caching_sha2_password auth methods
```

ここらへんを参考に

-> [【MySQL・Docker】cryptography is required for sha256_password or caching_sha2_password](https://qiita.com/nqyutq/items/63df920415ae27bb417c)を参考にmy.cnfを作成
-> [docker-compose python: RuntimeError: cryptography is required for sha256_password or caching_sha2_password](http://blog.livedoor.jp/kmiwa_project/archives/1073708294.html)