はじめに
Pythonを使った簡単なWEBページを公開したいので,Herokuというものを触ってみることにした.
公式チュートリアル「Getting Started on Heroku with Python | Heroku Dev Center」に従って作業を進める.基本的には自分用のメモ1.
作業前のローカル環境
- MacOSX 10.11.6
- Python 3.6.3
- Git 2.10.1
作業者について
- Pythonは多少使っているが,Rの方が得意
- PostgresもDjangoもよくわかってない(使ったことない)
- 実はGitも怪しい
- 英語を読むのは苦にならない
注意事項
- 表示されるメッセージは,ある程度編集した
- あと,何か気づいたら書く
作業概要
公式チュートリアルは次のような手順になっている.
- 導入
- セットアップ
- デモアプリを準備する
- デモアプリをデプロイする
- ログを確認する
- Procfileを定義する
- デモアプリをスケールする
- 依存関係を宣言する
- ローカルでデモアプリを動かす
- ローカルでの変更をpushする
- アドオンをプロビジョニングする
- コンソールを開く
- config varsを定義する
- データベースをプロビジョニングする
1. 導入
まずは下記の状態を目指す.
- Herokuの無料アカウントがある
- Python 3.6以上がローカルにインストールされている
- Pipenvがローカルにインストールされている
- Postgresがローカルにインストールされている
Python 3.6以上については,元々あるので作業しない.
1.1. Herokuの無料アカウントを作成する
メールアドレスがあればOK.さすがにつまづくところはない.
1.2. Pipenvをインストールする
$ pip install pipenv
1.3. Postgresをインストールする
ローカルでアプリを動かすのに必要.ちょっとだけ面倒くさい.
Postgres.app – the easiest way to get started with PostgreSQL on the Macを参照しながら実施してみる.
まず,Postgres.appからダウンロードして,Applicationにインストールする.起動したらInitializeボタンをクリックして,新しくサーバーを作成する.
次にパスを通す.
$ sudo mkdir -p /etc/paths.d &&
$ echo /Applications/Postgres.app/Contents/Versions/latest/bin | sudo tee /etc/paths.d/postgresapp
最後に,環境変数DATABASE_URL
を設定する.
$ export DATABASE_URL=postgres://($whoami)
2. セットアップ
Gitが無い場合は,まずGitをインストールしてセットアップする.あるのでこの作業はしない.
満を持してHeroku CLIをインストールする.インストーラーをダウンロードすることもできるが,面倒なのでHomebrewを使おう.
$ brew install heroku/brew/heroku
と思ったら何やらエラーが出たので,やっぱりインストーラーを使ってインストール.
その後,ターミナルからログインする.
$ heroku login
これで,Herokuの無料アカウント作成時に使ったメールアドレスとパスワードを入力すると,
Logged in as メールアドレス
と表示される.(もちろん,表示されるメールアドレスは実際のもの)
3. デモアプリを準備する
Herokuが用意しているサンプルアプリを適当なディレクトリでcloneする.
$ git clone https://github.com/heroku/python-getting-started.git
$ cd python-getting-started
ちなみに中身はこんな感じ.
$ ls
Pipfile Procfile.windows gettingstarted
Pipfile.lock README.md hello
Procfile app.json manage.py
4. デモアプリをデプロイする
まず,Heroku上にアプリを作成する.
$ heroku create
Creating app... done, ⬢ lit-bastion-5032
https://lit-bastion-5032.herokuapp.com/ | https://git.heroku.com/lit-bastion-5032.git
lit-bastion-5032
の部分はHerokuによってランダムに付けられる名前.自分でつけることもできるらしいけど,どうやるのかチュートリアルではわからない2.
で,pushする.
$ git push heroku master
Counting objects: 232, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (217/217), done.
Writing objects: 100% (232/232), 29.64 KiB | 0 bytes/s, done.
Total 232 (delta 118), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Python app detected
remote: -----> Installing python-3.6.0
remote: -----> Installing requirements with latest pipenv...
remote: Installing dependencies from Pipfile.lock...
remote: $ python manage.py collectstatic --noinput
remote: 58 static files copied to '/app/gettingstarted/staticfiles', 58 post-processed.
remote:
remote: -----> Discovering process types
remote: Procfile declares types -> web
remote:
remote: -----> Compressing...
remote: Done: 39.3M
remote: -----> Launching...
remote: Released v4
remote: http://lit-bastion-5032.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To git@heroku.com:lit-bastion-5032.git
* [new branch] master -> master
上のメッセージは実際のものではなくチュートリアルのコピーで,大体こんな感じで終わる.
次に,インスタンスを1つ動かす.
$ heroku ps:scale web=1
Scaling dynos... done, now running web at 1:Free
ブラウザでアプリのURLを直接開くか,ターミナルで
$ heroku open
5. ログを確認する
Herokuでは,全てのアプリとHerokuコンポーネントの出力を時系列のイベントにまとめて,1つのチャネルで確認することができる.
$ heroku logs --tail
とやると,ログが色々と表示される.WEBアプリを再表示すると,新たなイベントが追加表示される.ログの意味は今は気にしない.
Control+C
でストリーミングを中断する.
6. Procfileを定義する
Procfileは,アプリを実行する際にどのコマンドが実行されるかを明示するためのファイル.「定義する」と言いつつ,今は中身を見て,Procfileが何かを(ある程度)理解するだけ.
$ more Procfile
web: gunicorn gettingstarted.wsgi
チュートリアルでは末尾に--log-file -
が付いているが,気にしない.
先頭のweb
というのが重要で,これを宣言すると,このプロセスはHerokuのHTTP routing stacksにアタッチされ,デプロイされるとWebトラフィックを受け取る.
それ以降はコマンドで,ここではgunicornを起動している.
7. デモアプリをスケールする
「dyno」の数を変えるだけ.dynoは軽量のコンテナだと思えば良い.
7.1. dynoの数を確認する
現時点で,サンプルアプリは1つのdyno上で動いている.ps
コマンドで,dynoが幾つ動いているか確認できる.
$ heroku ps
Free dyno hours quota remaining this month: 550h 0m (100%)
For more information on dyno sleeping and how to upgrade, see:
https://devcenter.heroku.com/articles/dyno-sleeping
=== web (Free): gunicorn gettingstarted.wsgi (1)
web.1: up 2018/08/xx xx:xx:xx +0900 (~ xxm ago)
これは,dynoが1つということ.
デフォルトだと無料のdynoが使われる.無料のdynoは,30分間何のトラフィックも無いとスリープする.また,1ヶ月の時間割当があって,割当を使い果たすまでは動き続ける.
7.2. dynoの数を変える
スケールするとは,dynoの数を変えるということ.ただし,2つ以上のdynoを動かすにはアカウントのverificationが必要(クレジットカード登録が必要)なので,とりあえずチュートリアルでは数を1から0に変更する.
$ heroku ps:scale web=0
Scaling dynos... done, now running web at 0:Free
この状態でアプリにアクセスすると,エラーが表示される.
スケールアップするには,再び数を1にする.
$ heroku ps:scale web=1
Scaling dynos... done, now running web at 1:Free
もちろん,この状態ならアプリにアクセスしてもエラーは表示されない.
8. 依存関係を宣言する
ローカルでPipenvを使う話.
8.1. Heroku上の話(読むだけ)
Herokuは,rootに存在する「Pipfile」または「requirements.txt」によって,アプリがPythonアプリであることを認識する.
デモアプリのPipfileの中身はこんな感じ.
$ more Pipfile
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
[packages]
django = "*"
gunicorn = "*"
django-heroku = "*"
[requires]
python_version = "3.6"
Heroku上にアプリがデプロイされると,Herokuはこのファイルを読んで,pipenv install --system --skip-lock
コマンドを使い,適切な依存関係をインストールする,らしい.
8.2. ローカルで実施する
Pipenvを使ってvirtualenvを作り,依存関係をインストールする.これを行うためにはPostgresがちゃんとインストールされてないとダメなので注意3.
$ pipenv --three
$ pipenv install
問題なければ,virtualenvをアクティベートして,仮想環境を有効にする.
$ pipenv shell
9. ローカルでデモアプリを動かす
まずはDjangoのためにcollectstaticを走らせる.
$ python manage.py collectstatic
チュートリアルには「yesと答えろ」とか書いてあるけど何も聞かれない.気にしない.
次に,アプリを起動する.
$ heroku local web
ここでこんなウィンドウが表示された.「許可」をクリック.
ブラウザでhttp://localhost:5000を開くと,Heroku上と同じようにデモアプリが表示される.
ローカルでデモアプリが起動できたことになる.ターミナルでCtrl+C
を押すとプロセス中断.
10. ローカルでの変更をpushする
ここでは,ローカルでのデモアプリへの変更を,Heroku上に反映させる.
10.1. requestsをインストールする
requestsを新たに利用するために,ローカルにインストールしてみる.
$ pipenv install requests
そうすると,Pipfileの内容が変更され,requestsが追加されているのがわかる.
$ more Pipfile
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
[packages]
django = "*"
gunicorn = "*"
django-heroku = "*"
requests = "*"
[requires]
python_version = "3.6"
10.2. Pythonコードを変更する
requestsを使うようにPythonコードを変更する.変更するファイルはhello/views.py
.
先頭に以下を追加する.
import requests
さらに,indexメソッドの中身を,requestsを使う以下のものに書き換える.
def index(request):
r = requests.get('http://httpbin.org/status/418')
print(r.text)
return HttpResponse('<pre>' + r.text + '</pre>')
10.3. ローカルで起動する
views.pyを書き換えたら,ローカルでデモアプリを起動してみる.
$ heroku local
ファイルの確認や編集のためにディレクトリを移動していたら,python-getting-started
に戻ること.
先刻はheroku local
の後ろにweb
を付けたけど,この時点でProcfileにはwebが1つ定義されているだけなので,付けても付けなくても同じことのようだ.
再びブラウザでhttp://localhost:5000を開くと,http://httpbin.org/status/418の出力である,変なAAが表示される.
公式チュートリアルには「可愛いティーポット(a lovely teapot)」と書いてあるが,どうしても顔が見える.
10.4. デプロイする
ローカルでの変更を,Heroku上に反映させる.Herokuにおけるほとんど全てのデプロイは,同じ手順を取るらしい.
まずはローカルのgitレポジトリに修正されたファイルを追加する.
$ git add .
次に変更をコミットする.
$ git commit -m "Demo"
前に一度やったのと同じように,デプロイする.
$ git push heroku master
で,Heroku上のデモアプリを表示すると
$ heroku open
ローカルと同じく,変なAA……じゃなくて,可愛いティーポットが表示される.
ローカルでの変更が,Heroku上に反映されたことがわかる.
11. アドオンをプロビジョニングする
Herokuにはサードパーティのアドオンがある.ここでは,Papertrailと言うログ統合管理のアドオンをプロビジョニングする.
$ heroku addons:create papertrail
Creating papertrail on ⬢ lit-bastion-5032... !
▸ Please verify your account to install this add-on plan (please enter a
▸ credit card) For more information, see
▸ https://devcenter.heroku.com/categories/billing Verify now at
▸ https://heroku.com/verify
上にある通りアカウントのベリフィケーションが必要なので,ここはスキップしてしまおう.
ベリフィケーションが終わっていれば,このコマンドだけでアドオンのデプロイができていたらしい.
追加したアドオンをリストアップする.(未確認)
$ heroku addons
PapertrailのWEBコンソールを表示する.(未確認)
$ heroku addons:open papertrail
12. コンソールを開く
heroku run
コマンドを使うと,one-off dyno上でコマンドを走らせることができる.ここでの「one-off」とは,一回限りと言う意味.
12.1. Pythonの対話型インタプリタを開く
$ heroku run python manage.py shell
Running python manage.py shell on ⬢ lit-bastion-5032... up, run.1060 (Free)
/app/.heroku/python/lib/python3.6/site-packages/psycopg2/__init__.py:144: UserWarning: The psycopg2 wheel package will be renamed from release 2.8; in order to keep installing from binary please use "pip install psycopg2-binary" instead. For details see: <http://initd.org/psycopg/docs/install.html#binary-install-from-pypi>.
""")
Python 3.6.6 (default, Aug 1 2018, 21:10:27)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole) >>>
このPythonシェルは,デモアプリと同じ環境で動いている.例えば requestsを使って変なAA……じゃなくて可愛いティーポットを表示できる(しつこい).
>>> import requests
>>> print(requests.get('http://httpbin.org/status/418').text)
-=[ teapot ]=-
_...._
.' _ _ `.
| ."` ^ `". _,
\_;`"---"`|//
| ;/
\_ _/
`"""`
>>> exit()
12.2. bashもいける
$ heroku run bash
Running bash on ⬢ lit-bastion-5032... up, run.8093 (Free)
~ $ ls
app.json manage.py Procfile requirements.txt
gettingstarted Pipfile Procfile.windows runtime.txt
hello Pipfile.lock README.md staticfiles
~ $ exit
one-off dynoはそれぞれのephemeralな(一時的な)ファイルシステムを持ち,接続が切れると消える.よって,例えばここでファイルを削除したとしても,アプリに影響を及ぼすことはない.
最後にexitしてdynoを止めるのを忘れないように.
13. config varsを定義する
外部リソースのアドレスとか暗号化キーなど,永続的に保持しておきたい設定はconfig varsに保存できる.
config varsは,起動しているアプリに対して環境変数として示される.
13.1. Pythonコードを変更する
またもやhello/views.py
を変更する.先頭に下記を追加する.
import os
さらに(またもや)indexメソッドを書き換える.環境変数TIMES
を使っている.
def index(request):
times = int(os.environ.get('TIMES',3))
return HttpResponse('Hello! ' * times)
os.environ.get()
の第2引数(3)は,TIMES
がなかったときのデフォルト設定なので気にしない.
13.2. .envを確認する
デモアプリには「.env」というファイルが存在し,既にTIMES環境変数が定義されている.heroku local
コマンドは,このファイルを参照して環境を設定する.
$ ls .env
.env
$ more .env
TIMES=2
この状態でローカルでアプリを起動する.
$ heroku local
http://localhost:5000をブラウザで開くと,「Hello! Hello!」と2回出力されていることが確認できる.
13.3. Heroku上のconfig varを設定する
Heroku上のconfig varは,次のようにして設定することができる.公式チュートリアルだとTIMES=2
で.envと同じで面白くないので,TIMES=4
にしてみる.
$ heroku config:set TIMES=4
Setting TIMES and restarting ⬢ lit-bastion-5032... done, v7
TIMES: 4
設定されているconfig varは,次のようにして確認できる.
$ heroku config
=== lit-bastion-5032 Config Vars
DATABASE_URL: postgres://xxx
TIMES: 4
この環境変数がちゃんと取り込めるか,デプロイして確認してみる.
$ git add .
$ git commit -m "Demo"
$ git push heroku master
$ heroku open
ブラウザで,「Hello! Hello! Hello! Hello!」と4回表示される.
14. データベースをプロビジョニングする
Herokuではデータベースはアドオンで,RedisとかMongoDBとかMySQLとか色々あるけれど,アプリがデプロイされると,無料のHeroku Postgresが自動的にプロビジョニングされる.ここではこのPostgresについて学ぶ.
14.1. Postgresの情報を確認する
データベースはアドオンなので,次のコマンドで確認できる.
$ heroku addons
Add-on Plan Price State
───────────────────────────────────────────────── ───────── ───── ───────
heroku-postgresql (postgresql-asymmetrical-xxxxx) hobby-dev free created
└─ as DATABASE
The table above shows add-ons and the attachments to the current app (lit-bastion-5032) or other apps.
環境変数DATABASE_URL
には,URLが設定されている.次のコマンドで確認できる.
$ heroku config
=== lit-bastion-5032 Config Vars
DATABASE_URL: postgres://xxx
TIMES: 4
pg
コマンドでもっと詳細な情報を確認できる.
$ heroku pg
=== DATABASE_URL
Plan: Hobby-dev
Status: Available
Connections: 0/20
PG Version: 10.4
Created: 2018-08-xx xx:xx UTC
Data Size: 7.7 MB
Tables: 0
Rows: 0/10000 (In compliance)
Fork/Follow: Unsupported
Rollback: Unsupported
Continuous Protection: Off
Add-on: postgresql-asymmetrical-xxxxx
14.2. テーブルを作成する
デモアプリのURLの後ろに/db
を追加すると,データベースの機能にアクセスできるが,テーブルが無いのでエラーが表示される.
次のコマンドで標準的なDjangoを走らせてテーブルを作成する.
$ heroku run python manage.py migrate
チュートリアルには,もし,次のようなメッセージが表示されたら「no」と答えろと書いてあるが,聞かれなかった.
"You just installed Django’s auth system, which means you don’t have any superusers defined. Would you like to create one now?"
これでもう一度,/db
を付けたURLにアクセスすると,「Page View Report」が表示される.
データベースへアクセスするコードはhello/models.py
に書いてある.GreetingsというシンプルなDjangoモデルを使っている.読むだけ.
また,環境変数DATABASE_URL
に基づいてデータベースのセットアップを行うための設定は,gettingstarted/settings.py
に記述してある.中身を確認するだけ.
14.3. views.pyのdbメソッドを確認する
/db
を付けたURLにアクセスするとhello/views.py
のdbメソッドが呼ばれている.dbメソッドは,新たなGreetingを作成し,存在する全てのGreetingをrenderメソッドに渡す.
中身を確認する.
def db(request):
greeting = Greeting()
greeting.save()
greetings = Greeting.objects.all()
return render(request, 'db.html', {'greetings': greetings})
14.4. リモートのデータベースにアクセスする
ローカルにPostgresがインストールされていれば,次のコマンドでリモートのデータベースにアクセスできる.
$ heroku pg:psql
--> Connecting to postgresql-asymmetrical-xxxxx
psql (10.5, server 10.4 (Ubuntu 10.4-2.pgdg14.04+1))
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.
lit-bastion-5032::DATABASE=>
SQLを使ってみる.
lit-bastion-5032::DATABASE=> select * from hello_greeting;
id | when
----+-------------------------------
1 | 2018-08-xx xx:xx:xx.xxxxxx+00
2 | 2018-08-xx xx:xx:xx.xxxxxx+00
(2 rows)
/db
へのアクセスが表示される.
接続を切るには,
lit-bastion-5032::DATABASE=> \q
でOK.
おわりに
作業は以上で終了である.大きくつまづくところはなかったが,意味がわかっていない部分は多々ある.
チュートリアルは,Next Stepsとして,次の3つのページを紹介している.
ということで,勉強は続く.
-
チュートリアルをやった後に「heroku で python 動かすチュートリアルをやったメモ - Qiita」を読ませて頂いた.2016年1月の記事で,チュートリアルの流れは今も同じだが,細かいところが若干変更されているようである. ↩
-
heroku create myapp
で,名前が重複していなければ「myapp」というアプリができる. ↩ -
と書いてあるが,ここPostgres関係ある? ↩