Google App Engine への移行

2008/05/20 7:39am

ここ数日というもの、Mac の前に座ってやっていたことといえば、Twitter か RSS フィードの消化か、でなければブログの移行作業だ。

もともと、このブログは Wordpress で運営していたのだが、色々と不満もたまってきたので、いつの日かつくりなおしたい、と思っていた。おりしも Django の勉強をはじめたばかりである。ちょうどよい。教材代わりに簡単なブログシステムを細々とつくっていた。

それを更に、Google App Engine に移植しましたよ、というのが今回のお話。

Google App Engine に移植した理由

まずは、Google App Engine(以下、GAE)に移植した理由から説明させてほしい。いままで Wordpress を動かしていたサーバでそのまま新しいブログシステムを動かすこともできた。

それでも、わざわざ時間を割いてまで GAE に移植したのは、GAE が話題になってるとか、Django が使えるらしい、というのも重要だったが、自宅サーバの管理から解放されたい 、という理由が実は一番大きい。

うん、自宅サーバの、しかも個人ブログの管理の手間なんて、たかがしれている(そりゃ、セキュリティとかは神経使うけどさ)。それよりは今後、もし、転居や契約している回線業者を変更する場合を考えると、そのあいだは自宅サーバは停めなきゃならないわけで、いまのうちに GAE に移植しておけば、あとあと困らないだろう、というわけである。

実際の移植作業には 4 日程度を要した。

GAE のオンラインドキュメント を参考に、ほとんど単純作業による変換だったが、細かい変更や思わぬ問題などもあったので、開発中にとったメモを片手につらつらと書いてみる。

Django

Django は Running Django on Google App Engine を参考に、開発版のものを動かしている。

GAE では Django の Database API和訳)は動作せず、GAE の Datastore API を使う必要があるが、当然の帰結として、Database API に依存した機能やアドオンも使えない。Django の売りのひとつである Admin Interface も、サイトマップを手軽に生成できる Sitemap framework も、Generic View でさえ使えない。また、Sites も RequestSite オブジェクトで代替してやらなくてはいけない。

ただ、Generic View は簡単な変更で動きそうだ。実際、Pagination の処理では django.core.QuerySetPaginator に GAE の Query オブジェクトをそのまま渡して動作していた(GAE の Query オブジェクトも [] アクセスを適切な fetch() に変換してくれる)。

Akismet

スパムコメント対策として HashcashAkismet を使っているのだが、外部リソースへのアクセスは GAE の URL Fetch API に変更が必要だ。Akismet への問い合わせ処理は、外部リソースへのアクセスなので URL Fetch API を使うように変更が必要だった。

docutils, pygments

reStructuredText でブログを書くために docutils を、そして、ソースコードのハイライトするために pygments をソースコードに含めるようにした(トップレベルだと邪魔なので、lib というディレクトリにパスを通して、そこに必要なライブラリを置くようにした)。

また、docutils はそのままだと、一部 GAE で禁止されているファイルシステム関連の API を使っている。docutils/frontend.py

if read_config_files and not self.defaults['_disable_config']:
    try:
        config_settings = self.get_standard_config_settings()
    except ValueError, error:
        self.error(error)
    self.set_defaults(**config_settings.__dict__)

この部分は潔くコメントアウトした。

検索機能

モデルクラスで db.Model ではなく、そのサブクラスである google.appengine.ext.search.SearchableModel を継承することで、モデルの検索ができるようになるようだ(Indexing Large Chunks of Text for Search - Google App Engine | Google グループ を参照)。「検索機能を備えたクラスを継承する」というだけでもダサいのに、日本語での使用とか不安なので、検索機能はとりあえず見送った。

デプロイして直面した問題

Web アプリケーションの宿命で、最大の問題はデプロイ後にやってくる。

デプロイ直後はすぐに CPU 制限にひっかかってしまう 理由は分からないが、デプロイ直後は GAE の CPU 制限によるエラーが頻発した。これくらいの処理でもういっぱいなのか、と萎えかけたが、しばらくすると正常に動作するようになった。なので、これからもし、同じ現象に遭われた方は、静かな心で見守るのがよいと思う。

データベースの制限でデータ移行ができない 以前のブログからのデータ移行は、dump したデータベースからデータを投入する Python スクリプトを生成する移行スクリプトを用意していた(CSV を使う手段もあるようだが、こっちの方がオブジェクト間の関連を再現するのも楽だ)。

しかし、これが動かない。一度に保存するデータが多すぎると制限にひっかかってエラーになるらしい。

解決策としては、移行処理を機械的に関数に分割して、一度のリクエストでひとつの関数を呼ぶように変更、外部からスクリプトで順番にアクセスさせるようにした。現実の素晴らしき泥臭さ。

favicon.ico と robots.txt の設定 些細なことかもしれないが、favicon.ico と robots.txt の設定をしていなかったせいで、404 エラーが大量に発生してしまった。Google App Engineでfaviconを設定するを参考に app.yaml を設定した。

- url: /favicon.ico
  static_files: public/favicon.ico
  upload: public/favicon\.ico
- url: (.*?)/robots.txt
  static_files: public/robots.txt
  upload: public/robots\.txt

GAE にしてよかったこと・不満

最後に感想でも。

最後の点について補足。必要なライブラリはバンドルしなければならないが、それ以外の部分(サーバ管理とか、ミドルウェアとか、ログとか)は無視してアプリケーションの開発に集中できる、という意味で「ひとつの閉じた世界をいじくってる楽しさ」を感じた。そういうこと。

あと 2 つアプリケーション作れるらしいので、何かネタを思いついたら挑戦してみたいですね。