FlaskをIBM Cloud(PaaS)上で動かす時の注意点メモ

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/ede33dfd-f02d-8c72-e6a7-b424957a344e.png)
# はじめに
こんにちわ！遅まきながらPython/Flask勉強中の石田です。FlaskをIBM CloudのPaaS(旧名Bluemix)で動かす際にいくつか注意点があったので、同じようなことをやろうとされる方のためにメモしておきます。

- ネット上に良記事が多数ありますので、Flask自身の説明は割愛します
- 記事執筆時点は2018/01です。将来的に変更があるかもしれません
- IBM CloudにデプロイするためのMinimalなHello World一式を[ここ](https://github.com/ishida330/flask-ibmcloud-starter)に置いておきますので、よろしければcloneしてご利用ください。(名前変更してbx cf pushすれば動きます)

# FlaskをIBM Cloud(PaaS)上で動かす時の注意点・気が付いた点

① Cloudランタイムの作成 
② ローカル環境(コード)の準備 
③ Cloudへのデプロイ 

の流れに沿って注意点や気が付いた点を記載します

## 1. Cloudランタイムの作成
### ボイラープレートとランタイム
IBM CloudではPython FlaskのボイラープレートとPythonランタイムの2種類のメニューを提供しています。
![image](https://qiita-image-store.s3.amazonaws.com/0/108535/d6c44681-fab4-69d1-e2ed-768ecd205272.png)
最終的にはどちらでもいいのですが、Python Flaskのボイラープレートは

- ライトプランの対象なので、**無料で使う分にはお勧め**です
- Starter Codeのプログラム中では、Cloudantを利用していますが不要なら除去してしまいましょう
- 記事執筆時点、日本語コンソール(ブラウザーの言語設定が日本語)からはアプリの作成ができません。( Planの選択でエラーになり「作成」ボタンが押せない) この事象は英語コンソール(ブラウザーの言語設定を英語に変更)すれば解消します。( バグとして報告済なのですぐ直るでしょう）

デプロイされるStarter Codeは[IBM-Cloud/get-started-python](https://github.com/IBM-Cloud/get-started-python)からダウンロードできます。

### ランタイムのPythonバージョン
参考文献: [Python](https://console.bluemix.net/docs/runtimes/python/index.html#python_runtime)

- Pythonのランタイムは**デフォルトでバージョン 2.7.13** が選択されます。Python3を使いたい場合はruntime.txtにバージョンを記載します(後述)


## 2.ローカル環境での開発
### コード
以下がIBM Cloud(cf)上にFlaskをデプロイするための最小限のhello worldコードです。

```py3:hello.py
from flask import Flask
import os
import metrics_tracker_client

app = Flask(__name__)
metrics_tracker_client.track() # Trackingするなら必要

@app.route('/')
def index():
    return '<h1>Hello World!</h1>'
port = os.getenv('PORT', '5000') # portはIBM Cloud環境から割り当てられたものを利用

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=int(port), debug=True) # Procfile内でpython hello.pyで起動
```
以下の考慮点があります。

1. ポートはIBM Cloud(PaaS)環境から与えられる
世間一般のFlaskの入門記事などではappがListenするポート番号を明示指定したりデフォルト(5000)を使ったりしていますが、IBM Cloud/PaaS環境では、アプリは**環境変数「PORT」から与えられるポート番号をListen**する必要があります。インターネットなど外部からアプリにアクセスする場合は、PaaS側で標準の80/443ポートからアプリのListenしているポートへ自動的にルーティングしてくれますので、アクセスのURLにポート番号の指定は不要です。(逆に言うと上記の仕組みなので「勝手に使いたいポートを指定する」ことは基本、できません）

2. Metrics Trackerのコードの追加
これは必須ではなく推奨オプションですが、アプリにMetrics Trackerを組み込んでおくとコンソール上の「monitoring」メニューで様々なモニタリングを行えるようになります。(逆に言うと、これを漏らすとモニタリングできません）
![image](https://qiita-image-store.s3.amazonaws.com/0/108535/8c4283c5-072d-daaa-8dc7-1fa08e58e2bd.png)

無料ですし、かなり色々な監視ができますので、IBM Cloud上で動かすなら使わない手はないでしょう。そのためにはコードに下記２行、追加しておいてください。

```py:
import metrics_tracker_client
metrics_tracker_client.track()　
```

:warning: 前述のPythonのStarter Codeではモニタリングのためにcf-deployment-trackerが使われていますが、これは2018年早々にも利用が停止されます([Deployment Tracker Service status](https://github.com/IBM-Cloud/cf-deployment-tracker-service/wiki/Deployment-Tracker-Service-status))。モニタリングをするなら新しい[metrics-collector-service](https://github.com/IBM/metrics-collector-service)を使うようにしましょう。なお、これはPythonだけの話ではなくJavaやNodeなど他の言語でも同様です。(「[Deployment Tracker Service status](https://github.com/IBM-Cloud/cf-deployment-tracker-service/wiki/Deployment-Tracker-Service-status)」の文書に移行の方針などが記載されています)

### IBM Cloudにデプロイするためのファイル群
Pythonのコード(以下ではhello.py)以外に以下のファイルを用意します。

```text:files                          
│  .cfignore         ...① cf pushで除外したいディレクトリーやファイル                
│  .gitignore                 
│  hello.py                   
│  manifest.yml   ...② アプリ名やメモリ量の指定
│  Procfile          ...③ 始動コマンド
│  README.md                  
│  requirements.txt　...④ Flaskなど利用するモジュールとバージョンを指定           
│  runtime.txt          ...⑤ 利用するPythonのバージョンを指定                
│                             
└─__pycache__                 
        hello.cpython-35.pyc  
```

以下、指定例です。（Starter Codeにも含まれています)

```text:.cfignore
.gitignore
```

```yaml:manifest.yml
---
applications:
 - name: <<change-your-name>>
   random-route: true
   memory: 128M
```

```text:Procfile
web: python hello.py
```

```text:requirements.txt
Flask==0.12.2
metrics-tracker-client
```

```text:runtime.txt 
python-3.6.2
```

## 3.IBM Cloudへのデプロイ
### bx cf pushコマンド

ランタイムを定義して、上記のファイル群を準備したらあとは`bx login`して
`bx cf push` するだけで簡単にデプロイできます。実行中のメッセージは長いので掲載しませんが、途中でmanifest.ymlを選択してPythonのバージョンを選んでrequirements.txtを反映して、、という流れが見られます。デプロイのサーバー側の状況は別ウインドウで `bx cf logs <アプリ名>`で見られます。

## ご参考) Flaskアプリケーションの起動コマンドについて
Flaskアプリケーションを起動するコマンドは以下の2通りの方法があります
a) メインにしたいプログラムを直接指定する

```bash
python xxxx.py
```

b) **環境変数 FLASK_APP**をセットしてからflask runコマンドを使用する

```bash
export FLASK_APP=xxxx.py
export FLASK_DEBUG=1
flask run
```

a) が昔からの方法でStarter Codeでも採用している/今までご紹介してきたものです。b) は最近の方法で、この場合は①環境変数を設定する②flask runコマンドを発行する　など若干の変更を加える必要があります。以下、IBM Cloud上でflask runで起動する場合の方法を記載します。

【1】 flask runで起動する場合はプログラムの末尾のportの設定や__main__判定、app.runの部分は不要です。(書いても無視されます）flask runの場合のミニマムなコードは以下のようになります。

```py3:hello.py
from flask import Flask
import os
import metrics_tracker_client

app = Flask(__name__)
metrics_tracker_client.track() # Trackingするなら必要

@app.route('/')
def index():
    return '<h1>Hello World!</h1>'
```

【2】manifest.ymlで環境変数 **FLASK_APP**をセットします(開発中はFLASK_DEBUGもセットするとよいでしょう)

```yaml:manifest.yml
---
applications:
 - name: <<change-your-name>>
   random-route: true
   memory: 128M
   env:
    FLASK_APP: hello.py
    FLASK_DEBUG: 1   
```

【3】Procfileでflask runコマンドを実行します。--host 0.0.0.0で外部からのリクエストを受け付けます。ポート番号はOSの環境変数 $PORTをそのまま書けばよく、プログラム内で指定する必要は無くなります。(私の環境で試した際は8080が割り当てられていましたが、保証はありません）flask run --helpで他の設定可能なパラメータも見られます。

```text:Procfile
web: flask run --host 0.0.0.0 --port $PORT;
```

最終的には`python xxx.py`でも `flask run`でもそれなりの設定をすれば動くので問題ではありませんが、ネット上の記事やチュートリアルを見ていると、特に言及無くいずれかの方法で行っているものが多いです。IBM Cloudにデプロイする際は、前述のようにプログラムや設定に少し違いが出ますので、念のため両方の方法をお示ししました。

以上です。