Pythonを定期実行したかったので、Herokuの使い方を勉強してみました!
具体的には、Herokuの公式チュートリアル
「Getting Started on Heroku with Python(PythonでHerokuをはじめよう)」
を日本語に翻訳しつつ、勉強した内容をまとめました。
#①Herokuの公式チュートリアルを勉強する
Herokuの公式チュートリアルは、「HerokuでPythonプログラムの定期実行」する方法ではないです。
しかし、まず公式チュートリアルをやるとHerokuの使い方がなんとなく分かります。
そして、その後にPythonプログラムの定期実行をやってみるとスムーズに理解できた気がします。
したがって、この記事では「①Herokuの公式チュートリアル」→「②Pythonプログラムの定期実行」の順で書いています。
##セットアップ
###Gitを使えるようにする。
まず、Heroku CLIを使うには、バージョン管理システムであるGitが必要です。
まだインストールしていない場合は、インストールして設定をします。
###Heroku Command Line Interface (CLI)をインストールする。
Herokuのインストーラーは**こちら**のページから入手できます。
僕はWindowsを使っているので、Windows用のインストーラーの表示に従ってインストールしました。
インストールが完了すると、コマンドシェルからherokuコマンドを使用可能になります。
###Herokuへログインする。
僕はWindowsなので、PowerShellにheroku login
コマンド
$ heroku login
を入力します。
すると、ブラウザが起動して「Herokuにログインしますか?」的な確認画面が出てくるので、受け入れます。
##アプリを準備する
https://devcenter.heroku.com/articles/getting-started-with-python#prepare-the-app
Heroku側が、勉強用サンプルアプリ↓を作ってくれているので
これを自分のローカル環境にclone
(コピー)します。
具体的には、まずサンプルアプリを保存したい任意の場所(デスクトップとか)に移動させます。
PowerShellにcd
コマンドを入力して移動します。
※例
$ cd 任意の場所
その後
$ git clone https://github.com/heroku/python-getting-started.git
を実行して、ローカル環境にサンプルアプリのクローンを作成します。
「python-getting-started」というサンプルアプリのディレクトリ(フォルダ)が作成されるはずです。
「python-getting-started」内には、いろいろなファイルが生成されているはずです。
主なファイルの役割↓
-
.env
環境変数を書いておくファイル。
「env」は、「environment(環境)」の略。 -
.gitignore
「.env」などGitの管理に含めたくないファイルを指定するためのファイル。
(「ignore」の意味は「無視」) -
app.json
Herokuでアプリを実行するために必要な環境変数、アドオン、その他の情報を宣言するファイル。 -
manage.py
Django プロジェクトの設定ファイル。 -
README.md
説明書的なファイル。 -
Procfile(プロクファイル)
Heroku上で動かしたいコマンドの一覧を指定するファイル。(拡張子は無し) -
Procfile.windows
Windowsでローカル開発を行うためのProcfile(プロクファイル)。 -
README.md
説明書的なファイル。 -
requirements.txt
ローカルにインストールしてあるPythonのライブラリを書いておくファイル。
(Herokuへデプロイ時に指定したPythonのライブラリがインストールされる。) -
runtime.txt
インストールするPythonのバージョンを書いておくファイル。
(Herokuへデプロイ時に指定したバージョンのPythonがインストールされる。)
##アプリをデプロイする
https://devcenter.heroku.com/articles/getting-started-with-python#deploy-the-app
続いて、そのままcd
コマンドでディレクトリ(フォルダ)の中へ移動します。
$ cd python-getting-started
そこでheroku create
コマンドを実行すると…
$ cd heroku create
Creating app... done, ⬢ serene-caverns-82714
https://serene-caverns-82714.herokuapp.com/ | https://git.heroku.com/serene-caverns-82714.git
みたいな感じで、gitリモート(herokuと呼ばれる)も作成され、ローカルのgitリポジトリに関連付けられます。
アプリにランダムな名前(ここではseren-caverns-82714)になります。
ちなみに
$ heroku create アプリ名
とすると任意のアプリ名を指定できます。
(しかし、数字や大文字始まりのアプリ名や、既に他のユーザー使用されているアプリ名と被っているのはダメっぽいです。)
###コードをデプロイする
そのままpush heroku main
コマンドを実行すると、コードをデプロイしてくれます。
$ git push heroku main
実行が終わったらheroku ps:scale web=1
コマンドで
$ heroku ps:scale web=1
アプリのインスタンスが、少なくとも1つ実行されているかを確認します。
「now running」みたいなメッセージが返ってきたら成功だと思います。
###実際に確認する
次に、先ほどアプリ名で生成されたURL
例
https://serene-caverns-82714.herokuapp.com/
でアプリにアクセスします。
ショートカットとして、heroku open
コマンドでもWebサイトを開けます。
$ heroku open
###ログの表示方法を知る
https://devcenter.heroku.com/articles/getting-started-with-python#view-logs
公式チュートリアルによると
「Herokuはログを、すべてのアプリとHerokuコンポーネントの出力ストリームから集約された、時間順に並べられたイベントのストリームとして扱い、すべてのイベントに対して単一のチャンネルを提供します。」
とのこと。
…正直、ちょっと何言ってるかよく分からない。笑
「アプリを複数作っても、ログはまとめて時系列順で表示されるよ。」ってことでしょうか。
とりあえずheroku logs --tail
コマンド
$ heroku logs --tail
で直近の実行中アプリのログが見れるっぽいです。
###Procfile(プロクファイル)を定義する
先ほども紹介した「python-getting-started」の中にある「Procfile(プロクファイル)」。
Heroku 上で動かしたいコマンドの一覧を指定するファイルみたいです。(拡張子は無し)
※Procfileは必ずルートディレクトリに置く。
##アプリの拡張
ここまで確認してきたアプリは、"Dyno(仮想サーバー)"上で動作しているみたいです。
いくつの"Dyno"が稼働しているかは、ps
コマンドで確認できます。
$ heroku ps
"Dyno"は複数使えるので、アプリの負荷が高くなってきたら"Dyno"を増して対応します。
(スケールアウトって手法だと思います。)
※"Dyno"の数は、こんな感じ↓で設定・変更する。
$ heroku ps:scale web=1
###無料用Dynoと課金について
デフォルトでは、アプリは**"無料用Dyno"**にデプロイされます。
"無料用Dyno"は、30分ほど活動しないと(トラフィックを受け取らないと)スリープします。
そして、スリープ解除後の最初のリクエストに遅延が生じます。
「そうならない"Dyno"を使いたい場合は課金してね」ってわけです。
※"無料用Dyno"でも使用時間が1000時間/月以上使いたい場合は、課金が必要みたいです。
###アプリの依存関係を宣言する
先ほども紹介した「python-getting-started」の中にある「requirements.txt」。
ローカルにインストールしてあるPythonのライブラリを書いておくファイル。
サンプルアプリには
django
gunicorn
django-heroku
が記述されています。
Herokuへデプロイ時に指定したPythonのライブラリがインストールされるみたいです。
ローカル環境にも同じライブラリをインストールしたい場合は
$ pip install -r requirements.txt
で実行できるみたいです。
(上手くいかない場合、Postgresを正しくインストールしてある必要があるみたいです。)
###アプリをローカルで実行する
ここらへんは、HerokuというよりDjangoの使い方です。
まず、collectstatic を実行します。
$ python manage.py collectstatic
Djangoの使い方詳しくないので分かりませんけど、必要なファイルを生成するコマンドだと思います。
そして、以下のコマンドを実行します。
heroku local web -f Procfile.windows
(この時に、Windowsでローカル開発を行うためのProcfileである「Procfile.windows」を使うわけですね。)
しばらくすると、ローカルサーバーが立ち上がって「localhost:5000」から先ほどと同じページが閲覧できます。
ローカルサーバーの停止はCtrl+C
で行えます。
##ローカル環境での変更をHerokuに反映させる方法
###試しに変更してみる
まず、公式チュートリアル通りにローカルにpythonのライブラリ「requests」をインストールします。
(僕は既に入れてありました。)
$ pip install requests
次に、requirements.txtに「requests」を書き加えます。
そして、hello/views.pyを書き換えます。
ここにある↑ファイルですね。
requestsをインポートして、関数「index」を指定通りに書き換えます。
from django.shortcuts import render
from django.http import HttpResponse
from .models import Greeting
import requests # ← 「requests」をインポートする!!!!
# Create your views here.
# def index(request):
# # return HttpResponse('Hello from Python!')
# return render(request, "index.html")
# ↓関数「index」を書き換える!!!!!
def index(request):
r = requests.get('http://httpbin.org/status/418')
print(r.text)
return HttpResponse('<pre>' + r.text + '</pre>')
再びローカルサーバーを立ち上げて、localhost:5000 にアクセスすると…
ページの表示がティーポットのアスキーアートになっています。
###変更をHerokuへデプロイ
この状態をHerokuへデプロイします。
まず、変更した全てのファイルをローカルの git リポジトリに追加します。
$ git add .
次に、変更内容をリポジトリにコミットします。
コミットメッセージは「Demo」とします。
$ git commit -m "Demo"
Herokuへデプロイします。
$ git push heroku main
Herokuへデプロイが完了したら、確認します。
$ heroku open
で、アプリのURLへアクセスできましたよね。
アクセスすると…
ちゃんとティーポットになっていたら成功!
##git cloneしない場合
ここまで公式チュートリアル通りにサンプルアプリをgit cloneして進めてきました。
任意のフォルダ内のアプリをHerokuへデプロイしたい場合は
$ heroku create アプリ名
で新規アプリを作った後、
自分でruntime.txt と requirements.txtを用意して
$ git init
$ git remote add heroku https://git.heroku.com/アプリ名.git
$ git add .
$ git commit -m "コミットメッセージ"
$ git push heroku master
でいけるはずです。
#②ファイルの定期実行がしたい
さて。なんとなくHerokuの概念は理解できてきた気がします。
しかし、今回はDjangoで作ったWebアプリをデプロイしたいのではなく、Pythonファイルを定期実行したいわけです。
いよいよ、定期実行をするための設定をしていきたいと思います。
##定期実行するファイルを用意する
僕は自分にLINEメッセージを送るプログラムを定期実行させてみます。
import requests
import datetime
TOKEN = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' #アクセストークン
# APIのURL(エンドポイント)を変数に代入。
api_url = 'https://notify-api.line.me/api/notify'
# -------------------------------------------
# メッセージを送信する関数
def send_message(send_text, token):
# 情報を辞書型にする
TOKEN_dic = {'Authorization': 'Bearer' + ' ' + token}
# 送りたいコンテンツ
send_contents = f'{send_text}'
send_dic = {'message': send_contents}
# LINE通知を送る(200: 成功時、400: リクエストが不正、401: アクセストークンが無効:公式より)
requests.post(api_url, headers=TOKEN_dic, data=send_dic)
# 現在時刻を取得
time = datetime.datetime.now()
time = time.strftime('%Y年%m月%d日 %H:%M:%S')
# 送りたいテキスト
send_text = f'\n{time}\nテスト送信'
# メッセージを送信する
send_message(send_contents, TOKEN)
※アクセストークンを発行するためには、LINE Notifyに登録する必要があります。
↓詳しくは、こちらの動画が参考になると思います。
アクセストークンはスクリプトにベタ打ちするのではなく、環境変数に設定した方が良いと思います。
##Herokuへデプロイする
先ほどと同じ要領で、用意したpyファイルをHerokuへデプロイします。
(もう一度新たに定期実行用のフォルダを作ってHerokuの設定をしても良いですけど…
とりあえず、練習ならそのまま「python-getting-started」の中に入れると手っ取り早そうです。)
##アドオン(拡張機能)を設置する方法
Herokuへデプロイしたファイルの定期実行をするには、「スケジューラ」のアドオンを使います。
まず、スケジューラーを使うには、クレジットカード情報の登録が必要です。
HerokuのAccount settings→Billingタブを開いてクレジットカード情報を登録します。
(※登録したからといってプランを変えない限り、勝手には課金されないみたいです。)
コマンドを使って「スケジューラ」のアドオンを追加します。
$ heroku addons:add scheduler:standard
コマンドを実行して、「Created scheduler-アプリ名」みたいなのが出てきたらOKだと思います。
##スケジューラのジョブを設定をする
スケジューラのアドオンを追加したら、ジョブを設定するページへ移動します。
$ heroku addons:open scheduler
を実行すると、ブラウザで設定ページが開かれます。
Create jobボタンを押して、ジョブを作成します。
ここに実行する間隔と、実行したいpyファイルを設定するわけですね。
設定時は、dyno sizeの「Free」が選択肢に出てこなくて、「え?これ有料のDynoじゃね?」と思いつつ「Standard-1X」にしてみました。
しかし、1度でも実行すると管理画面で「Free」に表示に変わりました。
どうやら、スケジューラで使うdynoは「One-off dyno」というものらしいです。
Free または Hobby dyno タイプを使用するアプリでは、対応する Free または Hobby タイプが One-off dyno で使用されます。その他の dyno タイプは使用できません。
つまり、自分の使用プランに合わせて勝手にOne-off dynoの種類が選択される(?)みたいです。ややこしい…。
最後に、時刻を**UTC(協定世界時)**で指定します。
(日本標準時から9時間マイナスした時刻になります。)
これで指定通りにプログラムが実行されれば成功です!
(微妙に実行時間がズレるのは仕様のようです。)
今回の場合は、LINEメッセージが来れば成功だと分かりますけど、チュートリアルでやったheroku logs
でも情報を確認できます。
#参考にさせていただいたページ