LoginSignup
3
4

More than 1 year has passed since last update.

Visual Studioで作ったFlaskアプリをGitHub経由でHerokuにデプロイする方法

Last updated at Posted at 2021-07-08

タイトルの環境でのデプロイではまったので注意すべき点を記事にします。正直試行錯誤の末ようやくうまくいったという感じなので、理屈がわかっていない部分は結構ありますが参考になればと思います。もしも間違っている箇所があれば教えて頂けると大変助かります。

動機

Pythonで作った簡単なWebアプリケーションをHerokuにデプロイしたかったのですが、Visual Studioならテンプレートを選ぶだけでFlaskアプリが作れるし、GUIでGitHubと連携できる!さらにGitHubとHerokuも連携できるので、この組み合わせが楽なのでは?と思いやってみました(が、冒頭の通り思いのほか苦戦しました)

前提

  • HerokuやGitHubのアカウントは作成済
  • Visual Studioインストール済(今回はVisual Studio Community 2019 Version 16.9.5を利用しました)

Herokuにデプロイするまでの手順

1. Visual StudioでFlask Web プロジェクトを作る

特に難しいことはなくFlask Web プロジェクトを選択するだけです。
image.png
image.png

2. Herokuへのデプロイに必要なファイルの作成

HerokuにデプロイするためにはProcfile、requirements.txt、runtime.txtの3ファイルが必要になります。作り方は以下の通りです。

2-1. Procfileの作成

ProcfileはHerokuに起動時に実行するコマンドを指定するためのもので必ず必要なファイルです。また、ルートディレクトリに配置しないと動きません!(これではまった人は多そう)詳細は公式を参照下さい。

色々なサイトを見ていると、

web: gunicorn FlaskOnHeroku.views:app --log-file -

とgunicornコマンドを利用するパターンと、

web: python FlaskOnHeroku/views.py

とpythonコマンドを利用するパターンのどちらも書かれていましたが、今回は前者でないとうまく動きませんでした(エラー詳細はこちら)。理由はよくわかりません・・・(ご存じの方がいれば教えて下さい)。
もうひとつの注意点ですが、gunicornコマンドを利用する場合、ディレクトリの区切りはピリオドになります!(この情報はなかなか見つけられずはまりました)上の例だとFlaskOnHerokuがディレクトリ名、viewsがviews.pyの拡張子を取ったものになります(拡張子は含めず書くようです)。ちなみにappは__init__.pyの中のapp = Flask(__name__)と対応しているはずなので、もしも別の変数名を使っていればそれに合わせて下さい。

2-2. requirements.txtの変更

このファイルに必要なパッケージを記述することで、デプロイ時にHerokuがこれらをインストールしてくれます。おそらくVisual Studioがrequirements.txtを初めから作ってくれていると思いますが(下の例の一行目のみ書かれている)、これにgunicornを追加します。

requirements.txt
Flask~=1.1
gunicorn

他のサイトを見ていると、以下のようにローカルで利用しているパッケージと同じものをHerokuに導入しようとしていました。今回のサンプルアプリはHello Worldに近いものなので、これをスキップしても問題なかったのですが、今後本格的なアプリを作る際には必要になりそうです。

$ pip freeze > requirements.txt

2-3. runtime.txtの作成

ここに実行環境のバージョンを指定します。今回は以下のように書きましたが、各自の環境に応じて変更下さい。

runtime.txt
python-3.7.8

2-4. 最終的なディレクトリ構成

次のようになります。Procfile、requirements.txt、runtime.txtがプロジェクトの直下にあり、動かしたいviews.pyはFlaskOnHerokuディレクトリ下にあります。
image.png

3. GitHubにプッシュ

Visual Studioのソリューションエクスプローラーの右側のGitのタブから、コミット、GitHubへプッシュします。特に難しくないと思いますので詳細割愛します。
image.png

4. Herokuアプリケーションの追加

4-1. GitHubとの連携

HerokuのWebページからCreate new appを選択し、アプリ名を決めます。
image.png

次にDeployment methodをGitHubに変更し、連携するGitHubのリポジトリ名を入力します。
image.png

Automatic deploysのEnable Automatic deploysをクリックし、GitHubのコードに変更がある都度自動デプロイするよう設定します。
image.png

4-2. Setting変更

ここもはまったポイントなのですが、GitHubのルートディレクトリは次のようになっているはずです。ただ、Herokuにデプロイしたいのは、FlaskOnHerokuディレクトリ以下です。ProcfileなどはHerokuのルートディレクトリ下にないとダメなため、このまま全体をデプロイしてもエラーになります。
image.png

こういったサブディレクトリをデプロイ対象として選択するためには、heroku-buildpack-monorepoというbuildpackを使うことになります。これをSettingタブから導入します。BuildpacksのAdd buildpackを押し、https://github.com/lstoll/heroku-buildpack-monorepoを入力します。
image.png

次にheroku/pythonも追加します。これは下のpythonを押せばOKです。
image.png

また、Config VarsのReveal Config Varsを押し、KEYにAPP_BASEを、VALUEにFlaskOnHeroku(サブディレクトリ名)を入力します。これによりデプロイ対象ディレクトリを指定しています。

最終的には以下のようになります。heroku-buildpack-monorepoとheroku/pythonの順番はこの通りでないとダメですので注意下さい。
image.png

4-3. 手動デプロイ、確認

最後に初回デプロイのためDeployタブに戻り、Manual deployのDeploy Branchをクリックします。デプロイが終わればViewボタンが表示されますので、これをクリックし(右上のOpen appボタンでも可)デプロイされたアプリを確認し終了です。

【補足】heroku-buildpack-monorepoを使わない方法

今回、heroku-buildpack-monorepoを使うことになったのは、プロジェクトの上のディレクトリ階層にソリューションファイルがあったためです。そのため、Visual Studioで新しくプロジェクトを作るときに次のようにソリューションとプロジェクトを同じディレクトリに配置することでheroku-buildpack-monorepoを使う必要はなくなります。Buildpacksにheroku/pythonを追加する必要もないので、こちらの方が楽かもしれません(背反は不明ですが、1ソリューションで複数のプロジェクトを管理する場合には困るかもしれません)。
image.png

はまったときには?

今回、数多くはまった経験より、はまったときにはログを確認するのがいいと思いました(当たり前ですが)。BuildログはActivityタブから確認できます。また、より詳細なログを確認するには、コマンドプロンプトから以下のコマンドを打つといいです
(事前にHeroku CLIのインストールが必要なはず)。flask-on-herokuはHerokuのアプリ名なため適宜変更下さい。ログは全リリースつながった内容になっているので、関係のある部分(基本的には最新のリリース)のみ参照するようにして下さい。

heroku logs -a=flask-on-heroku

コード

以下に公開しています。
* https://github.com/shoji9x9/FlaskOnHeroku
* https://github.com/shoji9x9/FlaskOnHeroku2 :ソリューションとプロジェクトを同じディレクトリに配置したバージョン

Tips:Herokuアプリケーションの停止

無料でHerokuを使っている場合、30分でスリープするそうですが、手動で停止したい場合はResourcesタブから停止できます。同じ要領で再開もできます(つまみを右にすると動き、左にすると止まります)。
image.png

Procfileにpythonコマンドを書いたときのエラー

Procfileにpythonコマンドを書いた場合、ログに以下のエラーが出ていました。views.pyの中の@app.route('/home')がまずいようです。__init__.pyの中のapp = Flask(__name__)をviews.pyに移植することで改善しそうな気もしたのですがうまくはいかず、それ以上の調査は断念しました。

2021-07-08T00:29:42.084171+00:00 heroku[web.1]: Restarting
2021-07-08T00:29:42.148384+00:00 heroku[web.1]: State changed from up to starting
2021-07-08T00:29:44.404543+00:00 heroku[web.1]: Stopping all processes with SIGTERM
2021-07-08T00:29:44.523881+00:00 app[web.1]: [2021-07-08 00:29:44 +0000] [9] [INFO] Worker exiting (pid: 9)
2021-07-08T00:29:44.525208+00:00 app[web.1]: [2021-07-08 00:29:44 +0000] [10] [INFO] Worker exiting (pid: 10)
2021-07-08T00:29:44.525880+00:00 app[web.1]: [2021-07-08 00:29:44 +0000] [4] [INFO] Handling signal: term
2021-07-08T00:29:44.532266+00:00 app[web.1]: [2021-07-08 00:29:44 +0000] [4] [WARNING] Worker with pid 9 was terminated due to signal 15
2021-07-08T00:29:44.535449+00:00 app[web.1]: [2021-07-08 00:29:44 +0000] [4] [WARNING] Worker with pid 10 was terminated due to signal 15
2021-07-08T00:29:44.627895+00:00 app[web.1]: [2021-07-08 00:29:44 +0000] [4] [INFO] Shutting down: Master
2021-07-08T00:29:44.740145+00:00 heroku[web.1]: Process exited with status 0
2021-07-08T00:29:45.711143+00:00 heroku[web.1]: Starting process with command `python FlaskOnHeroku2/views.py`
2021-07-08T00:29:48.566986+00:00 app[web.1]: Traceback (most recent call last):
2021-07-08T00:29:48.567009+00:00 app[web.1]: File "FlaskOnHeroku2/views.py", line 10, in <module>
2021-07-08T00:29:48.567325+00:00 app[web.1]: @app.route('/home')
2021-07-08T00:29:48.567359+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 1315, in decorator
2021-07-08T00:29:48.568276+00:00 app[web.1]: self.add_url_rule(rule, endpoint, f, **options)
2021-07-08T00:29:48.568319+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 98, in wrapper_func
2021-07-08T00:29:48.568537+00:00 app[web.1]: return f(self, *args, **kwargs)
2021-07-08T00:29:48.568567+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 1284, in add_url_rule
2021-07-08T00:29:48.569459+00:00 app[web.1]: "existing endpoint function: %s" % endpoint
2021-07-08T00:29:48.569584+00:00 app[web.1]: AssertionError: View function mapping is overwriting an existing endpoint function: home
2021-07-08T00:29:48.647837+00:00 heroku[web.1]: Process exited with status 1
2021-07-08T00:29:48.802550+00:00 heroku[web.1]: State changed from starting to crashed
2021-07-08T00:29:48.854986+00:00 heroku[web.1]: State changed from crashed to starting

参考にさせて頂いたサイト

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4