はじめに
PythonのWebフレームワークBottleのトップページには以下のサンプルが載っています。
from bottle import route, run, template
@route('/hello/<name>')
def index(name):
return template('<b>Hello {{name}}</b>!', name=name)
run(host='localhost', port=8080)
これをHerokuに置くときは、色々と調べると、最終行のrun(host='localhost', port=8080)
を
run(host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
に書き換えるようです。
これで動作するので問題ないのですが「どうして?」と思ったので調べました。
host
はリッスンするインタフェースの指定
一番わかりやすいのはDeploymentのページだと思います。
The bottle run() function, when called without any parameters, starts a local development server on port 8080. You can access and test your application via http://localhost:8080/ if you are on the same host.
To get your application available to the outside world, specify the IP of the interface the server should listen to (e.g. run(host='192.168.0.1')) or let the server listen to all interfaces at once (e.g. run(host='0.0.0.0')).
bottleのrun()関数は、パラメータなしで呼び出されると、8080番ポートでローカルの開発サーバーを起動します。同一ホスト上からなら、http://localhsot:8080/ で、アプリケーションにアクセスしてテストできます。
アプリケーションを同一ホストだけでなく外部からも利用できるようにするには、サーバがリッスンするインタフェースのIPを指定するか(例えば
run(host = '192.168.0.1')
)、全てのインタフェースをリッスンするかします(run(host =(0.0.0.0)
。)
run(host="localhost")
だとlocalhost
インタフェースへのリクエストだけをリッスンします。このインタフェースにリクエストを出せるのは同一ホストからだけなので、bottleを起動したホストからしかアクセスできません。
bottleを起動したホストに振られているIPアドレス(例えば192.168.0.1
)を指定すれば、外部のホストからもアクセスできるようになります。
0.0.0.0
を指定すれば、全てのインタフェースをリッスンしてくれます。
Herokuに置いたときに振られるIPアドレスは解らないので、全てのインタフェースをリッスンする0.0.0.0
を指定します。
Herokuのport
は動的に決まる
os.environ
は公式ページによると環境変数を表すマップ型オブジェクトを返します。
os.environ
A mapping object representing the string environment.
マップ型オブジェクトなのでget()
が使えます。
get("PORT", 8080))
で、環境変数PORT
が存在する場合はその値を、存在しない場合はデフォルト値として8080
を返します。
Herokuでは、どのポート番号でリッスンするかは動的に決まり、そのポート番号は環境変数PORT
に格納されます。
そのためos.environ.get("PORT", 8080))
でポート番号を指定します。
Herokuでは、PORT
に必ず値が設定されるので、デフォルト値の8080
を記載する必要はありません。os.environ.get("PORT")
で十分です。
しかしそうすると、ローカルで試験する際に、必ずPORT
に値を設定しなければならず面倒です。デフォルト値の8080
も記載しておいたほうが便利でしょう。
残る謎
heroku config:get PORT
としても、値が返ってこないのはなんで?