Docker-compose にてAPI(Flask)とDB(MongoDB)とクライアントソフト(MongoExpress)の開発環境作成

## はじまり
研究室の後輩に対してPython講習会を持ち回りで行っているんですが、自分の出番でAPI通信を勉強したくなりました。

少しだけDockerを作っていることから、DockerでDBとAPIサーバーが作れるようになったら便利かなと思い、トライしてみました。

Docker環境さえあれば、手軽にWebアプリの開発環境としても利用できます。

## 手に入る環境

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520701/d51f9262-8a83-36d9-d2f4-bdc3904af296.png)

わざわざ説明するまでもないかもしれませんが、構成と環境を書きました。

APIアクセスの場合、`localhost:5000`にいけば、APIへフォワーディングされ、

DBへの直接接続の場合、`localhost:27018`にいけばフォワーディングされます。

また`localhost:10081`をブラウザ上で開けば、クライアントソフトであるMongo－Expressが立ち上がります。

なんか微妙にポートを変えている理由は、研究室のサーバーで既に使っているポートがあったためです。

あまり他の記事でも、ポート変更をしてなかったので、備忘録としても書いておきます。

## フォルダ構成

```
├── Dockerfile
├── configdb
├── docker-compose.yml
└── src
    ├── app.py
    ├── mongo.py
    └── requirements.txt
``` 
なんか自動的に生成されるフォルダとかは省いています。

`DockerFile`はFlaskによるAPIサーバーの内容を記述、composeには、mongoとmongo-expressを書いています。

## 実際のコード

長々と失礼しました。ここからはコードの共有＋説明です。

```dockerfile:DockerFile
FROM python:3.6

ARG project_dir=/projects/

ADD src/requirements.txt $project_dir

WORKDIR $project_dir

RUN pip install -r requirements.txt
```
なんてことないPythonのイメージです。

composeにてVolumeなどを行っていきます。


```yml:docker-compose.yml
version: '3.1'
services:
  flask:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - "./src:/projects"
    tty: true
    environment:
      TZ: Asia/Tokyo
  api_mongo:
    image: mongo:3.6.5
    restart: always
    ports:
      - 27018:27017
    volumes:
      - /var/lib/mongo_data:/data/db
      - ./configdb:/data/configdb
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: password
  api_mongo-express:
    image: mongo-express
    restart: always
    links:
      - 'api_mongo:mongo'
    ports:
      - 10081:8081
    environment:
      ME_CONFIG_MONGODB_AUTH_DATABASE: admin
      ME_CONFIG_MONGODB_ADMINUSERNAME: root
      ME_CONFIG_MONGODB_ADMINPASSWORD: password
      ME_CONFIG_BASICAUTH_USERNAME: admin
      ME_CONFIG_BASICAUTH_PASSWORD: password
    depends_on:
      - api_mongo

```
個人的にミソだと思ったところはmongo-expressの場所の以下の記述です

```
links:
  - 'api_mongo:mongo'
```
ここでDocker-compose内のMongodbの名前を入れてあげないと、expressが立ち上がりません。





```python:app.py
from flask import Flask, jsonify, request
from mongo import get_mongo

app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False

@app.route('/')
def index():
  return jsonify({
    "message": "API立ち上がってまーす！"})

@app.route('/test')
def mongo_test():
  conf = get_mongo()
  col = conf['test']['test_col']
  data = col.find_one()
  return jsonify(data)
　
if __name__ == '__main__':
  app.run(host='0.0.0.0', port=5000)
```
一応、APIが立ち上がっているかだけ確認する`localhost:5000/`と
APIにアクセスした上でMongoのコレクションを参照する`localhost:5000/test`を実装しています。


```python:mongo.py
from pymongo import MongoCliant

def get_mongo():
    mongo_client = MongoClient('api_mongo', 27017)
    mongo_client['admin'].authenticate("root","password")
    return mongo_client
```
こちらはmongoのコネクションを獲得するための関数になります。

これのポイントとしては

```python
mongo_client = MongoClient('api_mongo', 27017)
```

の`api_mongo`です。ここを自分は`localhost`にしていたんですが、なかなかつながらなくて苦労しました。

なぜかというと、こちらのPythonファイルが動く`flask`コンテナにおいての`localhost`という意味合いになってしまうためですね。

ゆえにDocker-compose時に出来上がるDockerNetWorkで名前解決のできる、docker-compose時につけた名前を書く必要があるというわけです。



```:requirements.txt
flask
pymongo
```
flask と pymongoのpip をインストールします


## 早速起動

```
docker-compose up -d
```

後でflaskのコンテナに入りたいので、-dオプションを追加します。

コンテナが3つ立ち上がり、停止していないことを確認します

```
docker ps
```

次に、APIサーバーの起動を実際に行います。

そのために`flask`コンテナに入り、app.py を実行します。

```
docker-compose exec flask bash
## コンテナ内にて
python3 app.py
```

こうするとAPIサーバーが立ち上がります。

もしコードにタイポや間違いがあったら、上手く立ち上がらないと思います。

あとは、mongo-expressでも直接DBでもいいので、`test`DBに対して`test_col`コレクションを作り、適当に値を入れ、

APIサーバーを実際叩いてみましょう！

```
curl localhost:5000/
curl localhost:5000/hello
```

問題なくちゃんと帰ってくれば、開発環境完成です。


## 終わりに

どこにも所属してないですが、アドベントカレンダー代わりに投稿しました。

今回はlocalで作りましたが、外部に公開したサーバとかと疎通させてみます。