LoginSignup
42
53

More than 5 years have passed since last update.

Pythonで始めるHeroku 2018

Last updated at Posted at 2018-08-18

はじめに

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も怪しい
  • 英語を読むのは苦にならない

注意事項

  • 表示されるメッセージは,ある程度編集した
  • あと,何か気づいたら書く

作業概要

公式チュートリアルは次のような手順になっている.

  1. 導入
  2. セットアップ
  3. デモアプリを準備する
  4. デモアプリをデプロイする
  5. ログを確認する
  6. Procfileを定義する
  7. デモアプリをスケールする
  8. 依存関係を宣言する
  9. ローカルでデモアプリを動かす
  10. ローカルでの変更をpushする
  11. アドオンをプロビジョニングする
  12. コンソールを開く
  13. config varsを定義する
  14. データベースをプロビジョニングする

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

とやると,アプリが表示される.
20180816_HerokuSampleApp.png
デプロイ成功!

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

この状態でアプリにアクセスすると,エラーが表示される.

20180816_HerokuSampleError.png

スケールアップするには,再び数を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

ここでこんなウィンドウが表示された.「許可」をクリック.
20180817_warning.png
ブラウザでhttp://localhost:5000を開くと,Heroku上と同じようにデモアプリが表示される.
20180816_HerokuSampleApp.png
ローカルでデモアプリが起動できたことになる.ターミナルで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

先頭に以下を追加する.

views.py
import requests

さらに,indexメソッドの中身を,requestsを使う以下のものに書き換える.

views.py
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が表示される.

20180817_teapot.png

公式チュートリアルには「可愛いティーポット(a lovely teapot)」と書いてあるが,どうしても顔が見える.

10.4. デプロイする

ローカルでの変更を,Heroku上に反映させる.Herokuにおけるほとんど全てのデプロイは,同じ手順を取るらしい.

まずはローカルのgitレポジトリに修正されたファイルを追加する.

$ git add .

次に変更をコミットする.

$ git commit -m "Demo"

前に一度やったのと同じように,デプロイする.

$ git push heroku master

で,Heroku上のデモアプリを表示すると

$ heroku open

ローカルと同じく,変なAA……じゃなくて,可愛いティーポットが表示される.
20180817_teapot.png
ローカルでの変更が,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を変更する.先頭に下記を追加する.

views.py
import os

さらに(またもや)indexメソッドを書き換える.環境変数TIMESを使っている.

views.py
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つのページを紹介している.

ということで,勉強は続く.


  1. チュートリアルをやった後に「heroku で python 動かすチュートリアルをやったメモ - Qiita」を読ませて頂いた.2016年1月の記事で,チュートリアルの流れは今も同じだが,細かいところが若干変更されているようである. 

  2. heroku create myappで,名前が重複していなければ「myapp」というアプリができる. 

  3. と書いてあるが,ここPostgres関係ある? 

42
53
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
42
53