bottleとtweepyで作ったWEBアプリをherokuにデプロイしてみる

WEBアプリの完成イメージ

ILove NORANEKO
IloveNoraneko
崇拝するコスプレイヤー「@noraneko_skmz」さんの画像をtwitterから取得し、グリッド表示させるだけのWEBアプリです。
masonryレイアウトでインスタグラム風に画像を敷き詰めてレイアウトさせています。また、画像クリックで画像が拡大表示されるLightbox.jsを利用しています。
[簡単な概要] twitter apiをpythonで手軽にいじれるライブラリ「tweepy(3.5.0)」を使用。
ルーティングやリクエスト処理には、軽量WEBアプリケーションフレームワークのbottleを使用。
サーバー環境には、手軽に構築できるHerokuを使用しています。

 

[最終的なディレクトリ構成] app/
├ dist/
│ └ css/
│ └ js/
│ └ img/
├ node_modules/
├ src/
│ └ stylus/
│ └ js/
│ └ img/
├ views/
│ └ common/
│  └ header.html
│  └ footer.html
│ └ index_template.html
├ gulpfile.js
├ myapp.py
├ package.json
├ Procfile
├ requirements.txt
└ runtime.txt

bottleアプリをherokuにデプロイしてみる

このアプリはherokuにbottleアプリをデプロイしてみるテスト的なアレです。

Bottle は、シンプルで早い、軽量のWSGIインターフェイスによるpython製のWEBフレームワークです。

 

アプリ完成までのステップ

 

  1. 開発に必要なもの
  2. スクリプトを完成させる
  3. bottleアプリをherokuにデプロイする

開発に必要なもの

  • テキストエディター(何でも良い、筆者はAtom)
  • コマンドラインインターフェイス(macでいう、ターミナルとwindowsでいうコマンドプロンプト)
  • Python3
  • いくつかのライブラリ

 

python3のインストール

もしパソコン内にpyhonのver3がなければ、インストールを行ってください。
詳しくはPython websiteをご覧ください。
インストール方法については、こちらをご参照ください。

 

pipのインストール

pythonをインストールした後は、pipをインストールします。pipとは、pythonのパッケージやライブラリをインストールしたり管理するためのシンプルな標準ツールです。

 

[aside type=”normal”]もしpythonのバージョンが3.4以上の場合は、すでにpipが搭載されているので、こちらは飛ばしてください。[/aside]

 

1. 右のリンクを開きget-pip.py ダウンロードすることができます。
2. コマンドラインインターフェイスで、get-pip.pyファイルがある階層まで移動します。
3. 以下のコマンドを入力します。
$ python3 get-pip.py
[aside type=”normal”] Windowsでは、 $でなく、C:>となります。 [/aside] 何か問題がありましたらこちらをごらんください。 pip instructions

 

Bottleのインストール

pipをインストールしたら、以下のコマンドを入力し、Bottleをインストールします。
$ pip3 install bottle

もしPythonのバージョンが3.3日それ以前のバージョンで且つpipをすでにインストールされていたら、pipの代わりにpip3をコマンドラインで入力してあげてください。

もし何か問題があれば、公式ドキュメントをご覧ください。

スクリプトを完成させる

最終的なディレクトリ構成は以下のようになっています。
app/
├ dist/ — アセット関連(css, js)などの公開用にデプロイされた静的ファイル。
├ node_modules/ — gulpで使用するライブラリが入ったディレクトリ。
├ src/ — アセット関連(css, js)などのデプロイ前のスクリプトが入ったフォルダ。
├ views/ — HTML表示用のテンプレートが入ったディレクトリ。
├ gulpfile.js — タスクランナーgulp用の記述ファイル。
├ myapp.py — メインファイル。ここにガツガツ記述していく。
├ package.json — ラスクランナーgulpで使用するライブラリが記載されているファイル。
├ Procfile — herokuサーバー上でアプリを起動させるためのコマンドを記載するファイル。
├ requirements.txt — herokuで起動する際に必要となるライブラリを明示的に記載するファイル。
└ runtime.txt — pythonのバージョンを明示的に記載する。

以下に、最終的なmyapp.pyの内容をほぼコピペで記載します。

 


# 必要なライブラリの読み込み
import os
from bottle import route, run, template, request, static_file
import tweepy

# 定数管理
SITE_NAME = 'ILove NORANEKO' # サイト名
SITE_DESC = '崇拝するコスプレイヤー@noraneko_skmzさんの画像まとめです' # サイトのメタディスクリプション
SITE_URL = 'https://ilovenoraneko.herokuapp.com' # サイトのURL
TWEET_COUNT = 100 # 読み込むツイートの数
USER_ID = 'noraneko_skmz' # 読み込みたいユーザーのスクリーンネーム(@の右側)

# twitter 開発者情報(各々ご自身のコンシューマキーやシークレットキーを取得して記載してください。)
CONSUMER_KEY = 'XXXXXXXXXXXXXXXXXXXX'
CONSUMER_SECRET = 'XXXXXXXXXXXXXXXXXXXX'
ACCESS_TOKEN = 'XXXXXXXXXXXXXXXXXXXX'
ACCESS_TOKEN_SECRET = 'XXXXXXXXXXXXXXXXXXXX'


# oauth認証
def get_oauth():
    consumer_key = CONSUMER_KEY
    consumer_secret = CONSUMER_SECRET
    access_token = ACCESS_TOKEN
    access_token_secret = ACCESS_TOKEN_SECRET
    try:
        auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
        auth.set_access_token(access_token, access_token_secret)
        return auth
    except tweepy.TweepError:
        print('認証に失敗しました。')

# ツイートリストから画像のURLだけを抜き取ってリストに格納&出力
def get_images_from_statuses(statuses):
    images_list = []
    for status in statuses:
        if 'media' in status.entities:
            images_list.append(status.entities['media'][0]['media_url_https'])
        if hasattr(status, "extended_entities"):
            if status.extended_entities['media']:
                for media in status.extended_entities['media']:
                    images_list.append(media['media_url_https'])

    return set(images_list)


# ID[USER_ID]さんのメディアの画像URLを[TWEET_COUNT]件取得し、リストに加える
def get_images_list_from_user_id(auth, screen_name=USER_ID, count = TWEET_COUNT):
    try:
        api = tweepy.API(auth)
        statuses = tweepy.Cursor(api.user_timeline, screen_name=screen_name, count=count).items(count)
        images_list = get_images_from_statuses(statuses)
    except tweepy.error.TweepError:
        pass
    return images_list

# トップページのルーティング設定
@route('/')
def index():
    auth = get_oauth()
    images_list = get_images_list_from_user_id(auth, screen_name=USER_ID, count = TWEET_COUNT)
    return template('index_template', image_list = images_list, site_name=SITE_NAME, site_url=SITE_URL, site_desc=SITE_DESC)


# 静的ファイル(assets)のルーティング設定
@route("/dist/", name="static_file")
def static(filepath):
    return static_file(filepath, root="./dist")


# アプリケーションの起動
if os.environ.get('APP_LOCATION') == 'heroku':
    run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)))
else:
    run(host='localhost', port=8080, debug=True, reloader=True)

 

 

The file consist of routes that map HTTP requests to functions. The return value of each function is sent in the HTTP response. 詳細については、こちらRequest Routingをごらんください。

このルーティング機能により、リクエストに応じたレスポンスを返すことができます。

 

詳しくはBottle公式ドキュメントの Templates をご覧いただくとよいでしょう。

myapp.pyrun()メソッドを呼び寄せることでローカルサーバーないしは、Herokuサーバー上でアプリを起動します。


if os.environ.get('APP_LOCATION') == 'heroku':
    run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)))
else:
    # ローカル環境では、http://localhost:8080で表示。
    # debugをTrueにすることで、エラー内容などを画面に表示させることができる。
    # reloaderをTrueにすることで、いちいちサーバーを再起動させなくてもファイルの変更内容を反映させることができる。
    run(host='localhost', port=8080, debug=True, reloader=True)

このアプリでは、環境変数「APP_LOCATION」の値を読み込んで、分岐しています。これについては後ほど説明します。

 

Bottleフレームワークはビルトインサーバーを含んでいるので、リモートサーバーでいちいちデプロイして確認しなくてもローカルでテストすることができます。

 

以下のコマンドを入力することで、ローカル内でアプリを起動することができます。

 

  1. cd /User/scripts/myapp的な要領で、ファイル「myapp.py」含むディレクトリまで移動します。
  2. 移動したら以下のコマンドを入力します。
     $ python3 myapp.py
  3. そして、ブラウザを起動し、こちらのURLを開きます。 http://localhost:8080/home
  4. コマンドラインインターフェイスに切り替えて、Ctrl+Cを押すと、サーバーがシャットダウンします。

 

bottleアプリをherokuにデプロイする

Bottleアプリをでプロするにあたって、以下のステップが生じます。

 

 

まずはHerokuの無料アカウントを取得する。

もしアカウントを取得していなければ、無料で作成することができますので登録しましょう。
[aside type=”normal”]もしすでにHerokuのアカウントを持っていて、且つHerokuコマンドラインインターフェイス (CLI)がインストールされていたら、こちらは飛ばして構いません。[/aside]

 

  1. こちらをご覧ください。https://signup.heroku.com/dcprimary development languageに「Python」を選択してください。
    そして、Create Free Accountをクリックしてください。
  2. メールアドレスやパスワードなど必要な情報を入力し、管理画面へログインしてください。
  3. その後、Herokuコマンドライニンターフェイスをインストールします。インストール方法はこちらをご確認ください。Heroku CLI。ドキュメントに記載の通りに、Heroku CLIをインストールしたらすぐにコマンドラインでログインすると良いでしょう。

 

あなたのHeroku上にリモートリポジトリを作成します。

リポジトリにアプリをプッシュすると、Herokuが受け取ります。

 

  1. もしまだログインが済んでいなければ、以下のコマンドを入力しコマンドラインからHerokuにログインしましょう。
     $ heroku login
  2. ログイン後、以下のコマンドを実行して下さい。
     $ heroku create your-app-name

    “your-app-name”の部分はご自身の好きなように変更してください。“my-app” や “tutorial” などはすでに使われているかと思われるので、唯一無二のものを選択すると良いでしょう。
    以下のように空欄でも作成することが可能です。その場合は、ランダムなアプリ名をHerokuで自動生成してくれます。

     $ heroku create

    すると例えば以下のようにレスポンスが返ってくると思います。

     Creating app... done, ⬢ fast-sierra-15737
        https://fast-sierra-15737.herokuapp.com/ | https://git.heroku.com/fast-sierra-15737.git
        

これは最初だけ必要となるアクションです。Herokuがリモートリポジトリを生成してくれますが、
この設定を行うことによって、pushコマンドで簡単にherokuサーバーにアプリをデプロイしてくれるようになります。

 

ローカルリポジトリを作成する

始める前に、「Git」がインストールされていることを確認してください。インストールされていなければ、Gitをインストールしましょう。

 

  1. コマンドラインインターフェイス上で、Bottleアプリのディレクトリまで移動しましょう。今回の例では、myapp.pyファイルが含まれているディレクトリになります。
  2. ローカルリポジトリを作成するために以下のコマンドを実行しましょう。
     $ git init
             $ git add .
             $ git commit -m "my first commit"
            

    これによりローカルGitリポジトリが作成されます。

  3. この時、$ heroku loginでheroku上にログインしていることを確認してください。それから以下のコマンドを入力することでこのローカルリポジトリとHerokuのリポートリポジトリをリンクさせます。
     $ heroku git:remote -a your-app-name
    [aside type=”normal”] “your-app-name”の部分は、先ほどheroku createした時のアプリ名を入力してください。[/aside]
     $ heroku git:remote -a fast-sierra-15737
  4. リモートリポジトリを確認したい場合は以下のコマンドです。
    $ git remote -v

 

デプロイのための準備

Herokuでデプロイする際は、以下のファイル群がアプリのルート直下に入っている必要があります。

 

  • Procfile
  • runtime.txt
  • requirements.txt

 

Procfileにはアプリの起動プロセスを記載したいので、以下のような記述をしてください。

web: python myapp.py

Bottleアプリはシングルプロセスモードでアプリを起動します。
シングルプロセスモードでは、サーバーは Web クライアントからの要求を単一のプロセスを使って受信します。

 

runtime.txtが必要となってきます。あなたの開発環境のpythonのバージョンに合わせて記述する必要があります。(筆者の場合は今回pythonの3.6.1を使用しているため以下の記述になりました。)

 

 python-3.6.1

 

runtime.txtファイルでは、このアプリで使用するpythonのバージョンをHerokuに伝えます。
この記述設定により、ローカルで開発した時と同じ開発環境を保証することができます。

 

ご自身のローカルで使用してるpythonのバージョンを調べるには以下のコマンドを入力します。

 $ python3 --version

requirements.txtというファイルを作成し、以下のテキストを入力します。

bottle==0.12.13
requests==2.12.4
tweepy==3.5.0

このファイルには、WEBアプリを起動するのに必要な外部ライブラリを記載します。正しいバージョンは入力されていることを確認してください。
現在のバージョンを確認するには以下のコマンドを入力すれば表示されます。

 $ pip3 show bottle

or

 $ pip3 show requests

Herokuにアプリをプッシュ

このステップでは、ようやくherokuにWEBアプリをデプロイすることになります。

  1. もしまだ完了していなければ、herokuにログインし、メールアドレス及びパスワードを入力します。
     $ heroku login
  2. そして以下のコマンドを入力すればherokuにプッシュされます。
     $ git push heroku master

    これにより、今まで作成したファイルをディレクトリごとHeroku上のgitリポジトリにアップしてくれます。

  3. ただし、これで完了ではありません。heroku上で、環境変数を設定する必要があります。コマンドライン上で以下のコマンドを入力してください。※ もしくはHerokuの管理画面上からでも環境変数を設定することができます。
     $ heroku config:set APP_LOCATION=heroku

    これを入力・設定するのは最初だけです。
    以下のコードでは、起動時にAPP_LOCATIONという環境変数を読み込んで、その環境変数に応じて、条件分岐しています。1つは、ローカルサーバー上のもの、もう一つはherokuサーバー上で起動するためのコードです。

     if os.environ.get('APP_LOCATION') == 'heroku':
             run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)))
         else:
             run(host='localhost', port=8080, debug=True)
  4. そして最後に以下のコマンドを入力して、実際にブラウザでWEBアプリを開きます。
     $ heroku open

 

もし上手く行かないようであれば、コマンドライン上でheroku logs --tailと入力してみてください。そのログを確認していけば原因を調査すると良いかと思われます。
そして最後にURLをブックマークするなどして覚えておくと良いでしょう。