Heroku で Flask + SQLAlchemy + Amazon RDS をやってみる。

Heroku で Pythonが動かせるらしいという情報をいち早くキャッチ(大分遅い) したのでやってみる事にした。Flaskのチュートリアルで作るアプリ「Flaskr」を Heroku + Amazon RDS(MySQL5.5) で動かします。

Heroku標準のPostgresとかの連携手順とかは、既に良くまとまってるブログがあるので、一番最後の参考URL群を参照してください。ここではせっかちな人のために、一気にHerokuアプリと、RDSインスタンスを作るスクリプトを晒しておきます。手順をシェルスクリプト化しただけともいいます。

環境

MacOSX (Lion) での作業を前提としています。

前提

以下のものが使えるようになっている必要があります。

  • AWS アカウント
  • Heroku アカウント
  • heroku(ruby gems)
  • bash
  • git
  • virtualenv
  • pip
  • rds-command-line-tools

「rds-command-line-tools」は、あんま情報がなかったので、自分がインストールした方法を書いておきます。簡単にいうと、CLIAmazon RDSを操作するツール群です。それ以外は、結構検索に引っかかると思います。

rds-command-line-toolsのインストール

SDKs and Programming Toolkits for AWS から自分でダウンロードして、手動でセットアップしてもよいですが、Macであればhomebrew でインストールができます。

brew install rds-command-line-tools

インストールが終わると、環境変数を設定するように求められるので、.bashrcとか設定してください。

export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Home"
export EC2_PRIVATE_KEY="$(/bin/ls $HOME/.ec2/pk-*.pem)"
export EC2_CERT="$(/bin/ls $HOME/.ec2/cert-*.pem)"
export AWS_RDS_HOME="/usr/local/Cellar/rds-command-line-tools/1.3.003/jars"

「EC2_PRIVATE_KEY」と「EC2_CERT」に設定されている「*.pem」とかいう証明書は、https://aws-portal.amazon.com/gp/aws/developer/account/index.html?action=access-key にアクセスして、「X.509証明書」から「新しい証明書を作成する」とかやれば入手できます。入手したら、~/.ec2 の下に置いてください。

これで「rds-describe-db-instances」とかいうコマンドを打ってみて反応があればインストール完了です。

注意事項

スクリプトは下記のような操作をやるので、その辺を了解した上で実行してください。いかなる責任にも対処しかねますので、不安な人は、スクリプトの中身をのぞいてから実行するか否かを決めてください。

  • Herokuアプリを新規に作成・起動します。
  • AWS RDS に新規インスタンス(最小構成)を作成・起動します。
  • AWS RDS の 「us-east-1」 のデフォルトのセキュリティグループに、「ローカルマシンからのグローバルIPアクセス」と、「Heroku のEC2セキュリティグループからのアクセス」を許可するように設定を追加します。
  • AWS RDS にアプリ用のDB Parameter Groupを追加します。
  • Flask のシークレットキーは勝手にランダム値で決めてます。

スクリプト

gistにしておいたので、実行は簡単です。[ ]で囲まれた部分は自分で決めて引数として渡してあげてください。

curl -O https://raw.github.com/gist/1342640/083822585c1321a47ad8f193ea37e8c9eb26fadb/setup_flaskr_on_heroku.sh
sh setup_flaskr_on_heroku.sh [app_name] [username] [password]

#app_name => アプリケーションの名前
#username => Flaskrのログインユーザー名 & RDSインスタンスのログインユーザー名
#password => Flaskrのパスワード & RDSインスタンスのパスワード

スクリプトを実行すれば、後はひたすら待つのみです。結構時間かかります。20〜30分位かかります。時間がかかってるのは、RDSのインスタンスを新規作成したときに、インスタンスが起動し終わるまで、スクリプトは待ってるからですw

インスタンスを作成してから使えるようになるまで結構時間かかるんですよ。

セットアップが完了すれば、ブラウザ上にFlaskrが表示されると思います。スクリプト実行時に引数として渡した[username] と [password]でログイン可能です。

今回作ったヤツのファイルレイアウトはこんな感じに出来てると思います。カレントパスに引数として指定した[app_name]というディレクトリが出来きていると思います。

[app_name]
│
├── Procfile
├── apps
│        ├── __init__.py
│        ├── flaskr.py
│        ├── manage.py
│        ├── static
│        │        └── style.css
│        └── templates
│                   ├── layout.html
│                   ├── login.html
│                   └── show_entries.html
└── requirements.txt

メモ

Amazon RDS周りは、いくつかはまった所があるのでメモしておきます。

Heroku が連携できる RDS のリージョンは 「us-east」 のみ

Heroku -> RDS のアクセスを許可するためにRDS側で「HerokuのEC2セキュリティグループ」を設定しているが、それが「us-east」だかららしい。なので、ap-north-eastとかでRDSを作ってもHerokuからアクセスさせる設定ができないので注意。

RDSの utf8 の設定

RDS のDBインスタンスを作るときに、DB Paramter Group で「character_set_database」を「utf8」に変更しても、実際にDBが新規作成された時に、「character_set_database」が「 latin1」になってしまって日本語が文字化けする。

ParamterGroupでは自分がやった限りでは、どうしようもなかったので、SQLAlchemyでDBを新規作成する時に、下記のようにして逃げた。

@manager.command
def syncdb():
    db.engine.execute('alter database default character set utf8;')
    db.create_all()

最後に

とりあえず、herokuはそのままでも大丈夫だと思いますが、RDSはインスタンスが起動したままだとお金がかかるので、必要がなくなったら管理画面上で削除する事をおすすめします。