爆速で幼稚園児並みのFlaskアプリをHerokuにデプロイしていくぅ！↑↑↑


## はじめに

本記事は爆速（1日）でHerokuに幼稚園児並みのアプリをデプロイしていくまでの軌跡である。
Herokuへのデプロイの仕方が主で、Flaskについては幼稚園児並みにしか触れないので注意されたい。

## 環境

動作OS：Windows10 home
ターミナル：Powershell
言語：Python 3

## 実施手順

1. [venvでの環境構築](#venvでの環境構築)
2. [Herokuへのデプロイ](#herokuへのデプロイ)
3. [パイプラインの実装](#パイプラインの実装)

## venvでの環境構築

任意のディレクトリに任意名のフォルダを作成する。
kindergartenというのは**幼稚園**という意味である。
幼稚園児でも理解できる記事にしていきたいと思う。

```
$ mkdir flask_kindergarten
$ cd flask_kindergarten
```

pythonでvenvを実行しアクティベートしていく。
WindowsやMac、Linuxでコマンドに差分があるので注意。
ターミナルがPowershellかCOMかでも差分があるので注意。
今回はWindows-Powershellでの実行だが環境差分がある人は、当該環境でvenvアクティベートの仕方を調べると良いだろう。

```
$ python3 -m venv venv
$ Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force
$ venv/Scripts/Activate.ps1
```

Flaskのインストール。

```
$ python3 -m pip install Flask==1.1.2
```

herokuへデプロイする用のrequirements.txtを作成。venvは仮想環境ごとにpipのスコープを持つので仮想環境下でインストールしたものだけがテキストファイルに出力される。

```
$ python3 -m pip freeze > requirements.txt
```

次に、お待ちかねFlaskのメインのコードを書いていく。
[MVCモデル](https://qiita.com/s_emoto/items/975cc38a3e0de462966a)で言うところのC=Controllerにあたり、アプリの背骨の部分である。

現在のディレクトリにapp.pyを作成。

```
$ type nul > app.py
```

今のディレクトリ構成はこんな感じ。

```
flask_kindergerten/
│
├── venv/
│
├── app.py
└── requirements.txt
```

では、app.pyを記述して一度Flaskを立ち上げていこう。

```python:app.py
from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "お前、どこ園だ、バブゥ！？"
```

```
$ flask run
```

ローカルで立ち上がったWebサーバを覗きに行く。デフォルトでは127.0.0.1:5000/であった。

![flask_kinder01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208060/1d483bb2-7d57-c385-c4c9-b8121244fbe4.png)

ブラウザに遷移して「お前、どこ園だ、バブゥ！？」と表示されていたら勝ちである。
これは不良中学生の「お前、どこ中だ、オラァ！？」のオマージュである。

コードに変更があった場合にいちいちWebサーバを落として再起動しなくても済むように以下のコマンドを打っておく。
例によって、環境差分があるので注意。

```
$ $env:FLASK_ENV = 'development'
```

次に、herokuにデプロイするためにgitの設定をしていく。
'git init'でレポジトリの初期化を行ったあとに'.gitignore'でコミットしないファイルを指定する。.gitignoreはvenvや\_\_pycache\_\_のほかにSECRET KEYを書いたconfigファイルとかを指定する場合があると思う。
また、'>'
この大なりの記号は出力リダイレクトといって出力結果をリダイレクト先に書き込むことができる。
'>>'で追記となる。


```
$ git init
$ echo venv > .gitignore
$ echo __pycache__ >> .gitignore
$ git add .gitignore app.py requirements.txt
$ git commit -m "my first commit"
```

## Herokuへのデプロイ

まず、Herokuに未登録の人は[こちら](https://signup.heroku.com/)から登録しよう。

次に、CLIを使うために[こちら](https://devcenter.heroku.com/articles/heroku-cli)からインストールしよう。

ここまでできたらHerokuにログインしよう。

```
$ heroku login
```

次に、Herokuにデプロイする準備をする。
まずはHerokuの設定ファイル'Procfile'を作成していく。
このProcfileだが、間違えると痛手になる。
具体的には以下２つには気をつけて欲しい。私はこれに2時間くらい足踏みし、結果として爆速味が失われてしまった。

- 最初のPは必ず大文字にすること
- UTF-8でエンコードしていること

以下のようにProcfileを作成する。


```:Procfile
web: gunicorn app:app
```

次に、PythonのWSGIであるgunicornをインストールする。
[WSGI](https://ja.wikipedia.org/wiki/Web_Server_Gateway_Interface)とはWeb Server Gateway Interfaceの略であり、アプリとサーバの差分をなくして標準化するようなインターフェースだそうだ。

```
$ python3 -m pip install gunicorn==20.0.4
$ python3 -m pip freeze > requirements.txt
```

gunicornをインストールしたので、requirements.txtを更新した。
では、追加分をgitに反映する。

```
$ git add Procfile requirements.txt
$ git commit -m "Add Heroku deployment files"
```

Herokuにリポジトリを作成して、git pushしていく。
いつもは'origin'でpushしてるところは'heroku'に変更になるから注意だ。
あと、Herokuはアンダーバーが使用不能なのでリポジトリ名をハイフンで代用する。

```
$ heroku create flask-kindergarten
$ git push heroku master
```

がんばってクラウド上のサーバでデプロイしてまっせ、みたいなメッセージ群が流れ終わったら完了だ。
では、実際に確認してみよう。

```
$ heroku open
```

Herokuのドメインで先の幼稚園児アプリが確認できたらOKだ！

![flask_kinder01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208060/9bac874e-f83d-4c31-0fb4-fe14fec06a9d.png)

## パイプラインの実装

Herokuへのデプロイまでなら前項で終了なのだが、それだとあまりに幼稚園児すぎるので、せめて小学生に顔向けできるように最後にパイプラインを構築する。

パイプラインというのは複数の環境をワークフローで結んだグループのことである。
複数の環境というのは、主に開発環境・ステージング環境・本番環境のことである。
ここまでで使用した環境はローカルの開発環境とHerokuの本番環境だけだが、これだと実運用では困るだろう。
例えば、往々にして開発環境と本番環境には環境差がある。
開発環境ではうまく作動した機能が本番環境でもうまく作動するかわからない。なんなら、機能追加してしまったせいで本番環境がうまく動作しなくなるなんてこともあるだろう。
そんな時に役立つのが**ステージング環境**である。
ステージング環境は本番環境と同様の環境をつくり、ここで新機能などのテストを行うのだ。
各環境のイメージは以下。
これらを結ぶものがワークフローであり、ワークフローによってグループ化されたものがパイプラインだ。

![flask_kinder02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208060/a8f414e5-c373-7a15-1066-b3f82cc75572.png)

それでは、早速ステージング環境をHerokuに構築していこう。

```
$ heroku create flask-kindergarten-staging --remote staging
$ git push staging master
```

https://flask-kindergarten-staging.herokuapp.com/
みたいな名前で本番環境と同じものが確認できればOKだ！

では、次にパイプラインを作成していく。
flask-pipelineというパイプラインに本番環境としてflask-kindergartenのアプリを登録する。

```
$ heroku pipelines:create --app flask-kindergarten `
    --stage production `
    flask-pipeline
```

次に、gitを反映させる。
gitでの名前はprodとする。

```
$ heroku git:remote --app flask-kindergarten --remote prod
```

そして、ステージング環境としてflask-kindergarten-stagingのアプリをパイプラインに加えていく。

```
$ heroku pipelines:add flask-pipeline \
  --app flask-kindergarten-staging \
  --stage staging
```

では、先ほどのapp.pyの中身を少し変更し、ステージング環境だけに反映してみよう。

```python:app.py

from flask import Flask

# make app instance
app = Flask(__name__)

# routing
@app.route('/')
def index():
    return 'あなた様はどこ園かしら？'
```

なんとなく女子にしてみた。

それでは、ステージング環境にファイルをcommitしていく。

```
$ git add app.py
$ git commit -m "changed"
$ git push staging master
```

![flask_kinder03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208060/ab5a71c0-a90e-60d1-dea9-f7b82acb3db2.png)

ブラウザでステージング環境と本番環境のURLを叩いて、別々の表示になっていればOKだ。

最後に、ステージング環境の変更を本番環境へパイプラインを用いて反映させる。

```
$ heroku pipelines:promote --remote staging
```

本番環境にも変更が反映されていれば完了だ！

## おわりに

今回は爆速でFlaskアプリをHerokuにデプロイしたわけだが、Flaskアプリ部分があまりにも幼並完（幼稚園児並みの完成度）であった。

今度はちゃんとHTMLなりを実装し、まともなFlaskアプリを構築してみようと思う。

ではまた！


## 参考

1. [Deploying a Python Flask Example Application Using Heroku](https://realpython.com/flask-by-example-part-1-project-setup/)