HerokuとAWSのS3を使ってWebサービスを作るには

Herokuを使ってWebサービスを作るのは手軽にできると宣伝されていますが、実はかなり高度な知識が必要です。Herokuのアカウント自体は簡単に開けられるかもしれないけど、実際にサービスを公開するには、Linuxやデータベース、RubyやPythoなどの言語で一通りのコードがかけること、HTMLやCSS,JavaScripなど、広範囲の知識が必要です。これをさらに、iPhoneやAndroidなどの端末で使えるようにしようとすると、SwiftやAndroidなどの端末側のプログラミング言語の知識も必要になります。

さらに、Herokuの場合は、解説がほとんど英語なので、英語が結構得意でないと、解説を読むこと自体が億劫になってしまいます。もしくは、それを上回る熱意とか根性が必要でしょう。

最近、Herokuでは画像ファイルが保存できないことを発見したと書きましたが、Herokuでやることで、ソフトウェアが他の環境にデプロイしやすくなるなど、設計上のメリットがあることがわかったので、最近の定番っぽいAWSのS3(Amazon Web Serviceの中のストーレッジの機能)ではどうやるのかを調べてみました。

ジャジャーン。

A file is selected for upload by the user in their web browser;
JavaScript is then responsible for making a request to your web application on Heroku, which produces a temporary signature with which to sign the upload request;
The temporary signed request is returned to the browser in JSON format;
JavaScript then uploads the file directly to Amazon S3 using the signed request supplied by your Python application.

これはHerokuの中の、解説記事から拾ってきたものです。結構、レベルの高いことが書いてあって、気が遠くなります。
基本的には、(1)ブラウザーなどでアップロードする画像を洗濯した後、(2)JavaScriptでHerokuにログインして、(3)Heroku側から認証情報をJSONで取得し、(4)JavaScriptでその認証情報を使って、S3に画像をアップする、手順のようです。

これで、ソフトウェアのロジックと画像の保存をするストーレッジが疎結合になるので、ソフトウェアとしては設計がよくなるのでしょう。また、S3は普通のFTPとは違い、オブジェクト・ストーレッジという形式のようです。最近の雑誌でその単語自体は載っていたのですが、未知のものなので、これを機会に触ってみようかと思いました。

*************
S3を触ってみました。管理用のページがすごくよくできているので、とてもわかりやすかったです。

HerokuからAWS s3にファイルをアップロードするのは、さらに色々な知識が必要になります。
結構苦労することになると思いますが、とても勉強になります。とにかく色んなエラーが出るのでくじけそうになりますが、一つずつエラーを潰していけば、いつかたどり着けます。私も、6−7時間は使ったと思いますが、最終的にはブラウザーから、JavaScript経由でs3にアップロードが出来るようになりました。

Webサービスを提供するのに、ローカルのマシンとクラウドではどっちが有利か

Djangoでアプリを作りましたが、これを公開するのにローカルのマシンを使うか、クラウドを使うかで迷いました。

そこで、どちらが良いのかメリットとデメリットをそれぞれあげて、有利不利を検討してみようと思います。

まず、コスト

ローカルでやる場合には、開発と同じ環境の方が楽です。私はmacのノートで開発しているので、Mac Miniサーバーを考えています。ツールを入れる手順などが、開発環境と全部一緒にできるので、かなり楽だと思うのです。値段も、一番安いもので5万円くらい、CPUがいいものでも7万円ちょっとです。他のことにも使えますから、それほど高い買い物とは言えないと思います。

次に、クラウドです。今回のアプリは領収書の画像を保存するのでデータの保存量がだんだん大きくなっていきます。一枚の領収書のデータサイズを1MBとして、1000枚で1Gです。1年に1,000枚として、お客様1件で1GBという計算になります。

簡単な計算ですが、100件のお客様に使用していただくとすると、100ギガですが、アマゾンのS3の料金表を見ると最初の 最初の50TBまでは、1GBあたり月$0.025ドルだそうです。つまり、1件につき月3円、100件で300円、年間でも3,600円です。べらぼうに安いですね。

ソフトウェアの設計の良さ

次にソフトウェア自体の作り方ですが、クラウドを使うことによる大きなメリットがあります。このメリットはある文章を読むまで私も意識していませんでした。

Herokuでサービスを公開する場合、色々面倒くさい設定が必要になります。例えば、まず本番環境に展開する場合には、Githubを通してpushする必要があります。また、依存関係のあるモジュールをあらかじめリストアップして置く必要があります。また、Hrokuでは画像ファイルを保存することができないので、AmazonのS3などの外部ストーレッジを利用する必要があります。

かなり面倒くさいのですが、Herokuで展開する過程で、Herokuの提唱するソフトウェアを効率的に開発するための12の提言に自動的に準拠することになります。この12提言は12factors.netとサイトで公開されています。この12提言がいいのです。

例えばですが、以下の通りです。

1.) セットアップ自動化のために 宣言的な フォーマットを使い、プロジェクトに新しく加わった開発者が要する時間とコストを最小化する。

2.) 下層のOSへの 依存関係を明確化し、実行環境間での 移植性を最大化する。

3.) モダンな クラウドプラットフォーム 上への デプロイ に適しており、サーバー管理やシステム管理を不要なものにする。

4.) 開発環境と本番環境の 差異を最小限 にし、アジリティを最大化する 継続的デプロイを可能にする。

5.) ツール、アーキテクチャ、開発プラクティスを大幅に変更することなく スケールアップできる。

この観点からはクラウドでやる方が圧倒的によさそうです。

簡単さ

短期的にはローカルの方が簡単かもしれません。ディレクトリ構造は自由に変更できるし、DBなどのインストールも自由です。開発と本番環境も、例えばサーバーでmac miniを使えば同じになります。使い慣れている環境の方が、学習コストも少ないのでツールなどは使いこなしやすいです。

上記の比較からは、クラウドの方がよほど有利に見えます。私は、新しいサービスは、とりあえずローカルではなく、クラウドで始めてみようと思いました。

ウェブサービスをPythonで作る理由

PythonでWebサービスを作るために色々な事に遭遇したり、調べたりしたので、それをシェアするためのポストです。色々とやってみないとわからない事があり、知ってれば無駄な時間を大量に使う必要のなかった落とし穴があるので、それをシェアしようという趣旨です。

貴重な時間を浪費するのを避けるためにも、次にやる人のかたの参考になれば幸いです。

どの言語を使うか

まず言語選びです。ウェブサービスを作る場合には、言語を選ぶ必要があります。可能性としては、C#、Java、Ruby、PHP、Pythonなどがあると思います。最近はサーバーサイドのJavaScriptやLinuxで走るSwiftなどもあります。色々ありますし、どれを使っても一緒と思いそうですが、ライセンスや言語の性質でその後に大きく影響するので、実はとても重要です。

まず、C#はLINQもあり非常に使いやすいのですが、WEBサービスとして公開する際にはライセンスの問題が発生するので注意が必要です。最初からユーザーにライセンスのコストを転嫁できる立場の強いWEBサービスなら別ですが、最初は無料でユーザー数の獲得に力点を置いているような場合には(特に最初は)コスト割れになると思われるので、使わない方が無難です。ちなみに私は簡単便利なLINQは大好きです。社内システムなどで使うようでしたら問題なさそうです。

Javaは開発が重たすぎるので、やめた方がいいという意見も多いです。また、世の中で活躍している有名なWEBサービスはスクリプト言語またはライトウェイト言語と呼ばれているRubyやPHPを使っているところが多いようです。Moneyforwardとかfreeeとか。実際に調べてみると、良いフレームワークやデータベースとの接続を楽にするOR Mappingは随分改良されているようで、Javaも選択肢の一つなのではないかと思いました。

C#やJavaなどは静的型付け言語と呼ばれていますが、静的型付け言語の良いところは、コンパイルする時に型に関するエラーを見つけてくれるので、バグが入りにくいというのがあると思います。実際にiPhoneなどの開発に使われる言語はSwiftですが、これは静的型付け言語です。AppleがSwiftを静的型付け言語にしたのは(統計的にバグが少なくなるなどの)理由があるはずです。

ライトウェイト言語(LL)では、RubyやPython、PHPなどがあります。私は一応全部試してみて、今回はPythonで行こうと決めました。Rubyは日本では大手のWebサービスにも使われておりメジャーなのですが、Googleの検索件数などから逆算した割合だと、世界ではPythonの方が圧倒的に使われています。私の調べた範囲なだけですが、使っているプログラマーの数が多いからかライブラリーの数も豊富です。画像を使ったWebサービスでは必ず必要なPILLOWや、CSVの読み込みや書き出しの処理をするcsv、エクセルやPDFの処理など多数のライブラリーが存在します。きっとRubyやPHPにもあるのでしょうが、海外でのシェアはPythonの方が圧倒的です。

PHPも多くのサイトで使われているし候補ではあったのですが、他の言語では関数やプロパティをA.Bというふうに書きますが、PHPではA->Bという風に書きます。2文字で打ちづらいキーで書かなくてはいけないのと、見た目が何となく好きになれなかったのでやめました。ちょっと本質的な理由ではないですね。

動的型付け言語はバグが多くなり、メンテが大変か?

静的型付け言語の方がバグが発生しにくいと思われるので、システムが大きくなる予定だったら、メンテナンスのことを考えてJavaを使った方が結局効率がいいのではとは思いました。RubyやPythonなどの動的型付け言語は最初は楽ですが、あとでバグ取り地獄に入ってしまうのだったら、開発の後半でシステムが大きくなっていくほど長い時間がかかりそうに思えました。最初が急坂でだんだん傾斜が緩くなっていくか、最初がゆるいけど、あとで段々きつくなっていくかのどちらにするかのイメージです。

ただ、現状を見回すと急成長しているWebサービスは動的型付け言語でやっているっぽいです。私の見えていない何かがあるのかもしれないと思い、とりあえずその流れに合わせてみることにしました。

エディタ、IDE、開発ツール

最初はATOMを使っていたのですが、開発が本格的になってからPycharmに変えました。
ATOMは無料ですし、入力補助のモジュールもあるのでテキストエディタとしては大変優秀です。ですが、変数のスペルミスなどは事前に見つけてくれないので、実際に走らせてみるまでわかりません。

ATOMに限りませんが、テキストエディタで開発すると、なんでもテキストエディタとターミナルからコマンドを使ってやらなくてはいけないので、プログラムが走るまでの環境をどうやって作るかとか、ツールのインストールの仕方とかとてもよくわかるようになります。私も、ATOMで開発を始めたおかげで、Linux(やMaxOS)がどうなっているかだいぶ勉強になりました。

最初は無料でいいのですが、本格的にやることがわかったら無料でも有料でもIDEを使った方がいいと思います。私の場合はPycharmを個人ライセンスで買ったので89ドルでしたが、スペルチェックのミスを見つけるのやリファクタリングはエディタではできないので、それだけでも十分に元が取れます。

まだ試していない機能がたくさんあるのですが、デバッグでブレークポイントも設定できるようですし、IDEにお金を出す価値は十分すぎるほどあります。

フレームワーク

フレームワークはPythonでは一番機能が充実していると言われるDjangoにしました。PythonではそのほかにもFlaskやPyramidなど色々なフレームワークがあるようですが、Djangoが一番機能が充実しているようです。実際、ORMや画面遷移など、とても便利です。

ORMは何を使ったらよいか。

ただ、DjangoのデフォルトのORMは書き方も直感的で便利ではあるのですが、データベースを動的に複数作りたい場合に、構造的にうまくできなさそうなのでやめました。DjangoではDBへの接続を設定ファイルに書いておかなくてはいけないのですが、私が作ろうとしているのは、新しいユーザーがウェブサイトから登録した場合に、個別に新しいDBを作る設計にしたかったので、接続文字列をログインのたびに動的に変更できない(ように少なくともOfficialのTutorialではそう見えた)Django ORMはやめて、sqlalchemyというものを使いました。

sqlalchemyはFlaskやPyramidなどのPyrhonの他のフレームワークで使われているORMなのですが、Djangoでもインポートして使えます。

データベースは何を使うか。

Djangoのデフォルトはsqlite3なのですが、使おうと思ったプラットホームのサービスのHerokuでは、sqlite3は使えなくて、Postgresqlです。その他にMySQLという選択肢もありますが、私にはMySQLでもPostgresqlでもどちらを使っても得られる機能は同じに見えました。sqlite3はデータがファイルなので管理するにしてもわかりやすいのですが、パスワードをつけることができないのでユーザー認証ができず、やめました。

プラットフォームは何を使うか

Windowsサーバーはライセンス料が発生するので論外でしょう。
次に、Linuxを使うかMacを使うかですが、普通はLinuxのどれかのバージョンを使うのでしょうが、私は開発をMacでやっているので、WebサーバーもMacにしました。やっぱり環境の構築とか色々覚えるより、使い慣れている環境を使った方が一々調べる手間も減ると思ったので、ハード代くらいは浮くと思ったのです。ハード代といってもmac miniなら5万円くらいで買えるので、Linuxのハードを買ってもそれくらは普通にかかりそうです。

サーバーをローカルで立てるか、クラウドにするかも考えたのですが、今の所は、事務所に実際のサーバーを置いて運用する予定です。最初はHerokuを使おうと思っていたのですが、色々試したところで、動的にアップロードした画像ファイルをHerokuには保存できないということがわかったのでやめました。画像ファイルが保存できないなんて、領収書の保管が必要な私のサービスでは致命的でした。

ちなみにアップロードした画像ファイルはAWSに保存するようにするのが一般的なようなのですが、それだったら最初からAWSを使った方がよくないですか?

以上、色々と言語の選定から、フレームワーク、データベース、環境構築などに渡りつらつらと書きました。新しくWebサービスを立ち上げる際に沢山の選択肢がありますが、その中からどれを選ぶかなどの参考になれば幸いです。

DjangoをApacheで動かすまでの話

PythonにはDjangoという有名なフレームワークがあります。Djangoには簡易サーバーが付いているので、自分のMacで開発するときは、特にApacheやnginxなどのWebサーバーをインストールする必要はありません。開発用の段階ではこれで十分です。

しかし、いざ、iPhoneやAndroidなどの端末からサーバーにアクセスするアプリを開発しようとすると、外側から自分のMacにアクセスできるようになることが必要になります。iPhoneなどの端末から自分のMacにアクセスできないと、ちゃんと動いているかどうかもわかりません。ここで壁となるのが、Djangoに付属して付いてくるこのウェブサーバーでは外側からアクセスできないのです。

私は、今、iPhoneからサーバーに領収書の写真を送って、サーバー側で私たち会計事務所のスタッフが会計データに変換するサービスの開発をやっています。人間が写真のデータを会計データに直すサービスなので、AIなどのかっこいい技術を使うわけではありません。そこはいけていないのですが、そこはちょっと脇に置いておきます。

そのようなわけで、いろいろ調べてみた結果、昔からあるApacheと比較的最近のnginx(エンジンXと読む)が選択肢になったのですが、前にも触ったこともあって馴染みにあるApacheを入れてみることにしました。

具体的なステップ

ApacheをDjangoで使えるようにするのには、ほぼ一日仕事でした。速い人は数時間でできるのかもしれませんが、初めての方には、色々とひっかりやすいポイントがあり、結構時間がかかります。

私の環境は、Apache2.4、Python3.6です。

順番に、
Apacheのインストールと起動、
mod_wsgiをインストールしてApacheからPaythonのプログラムファイルを処理できるようにする、
MaxOS/Linuxのファイル権限を変更して、外部からのアクセスでも必要なファイルを読み書きできるようにする、

という順番でやっていきます。

一気にやろうとすると、色々なところでハマるので問題の切り分けができにくくなります。順番にやっていくのがいいと思います。

(1) まず、最初はApacheです。

Apacheは、とりあえず動くようにして、「It works!」の既定のメッセージが見れるようになることが目標です。
まずはターミナルを開けて、appachectl startとコマンドを打ち込みます。問題がなければ、次の行に移動して入力ができるようになります。

そして、Safariか Chromeを開けて、アドレスバーのところに127.0.0.1と打ち込みます。「It works!」と表示されれば、Apacheはちゃんと動いています。

(2) 次に、mod_wsgiをインストールします。

これが、Webでは様々な記事が交錯していて、一番わかりにくく苦労しました。しかし、一度出来てしまえばちゃんと動きます。ポイントはmod_wsgi.soというファイルをApacheの設定ファイルにちゃんと書いて、ApacheへのリクエストがきちんとPythonの処理として認識されるようにすることです。私は、最初、Pythonのプログラムのファイル(例:hello.pyなど)がただのテキストファイルとしか認識してもらえず苦労しました。

手順としては、
ターミナルからpip3を使って、pip3 install mod_wsgiを実行する。ー>mod_wsgiがインストールされる。

Apacheの設定ファイルであるhttpd.confのファイルを編集する。httpd.confファイルはprivate/etc/apache2という場所にある。これをATOMなどのエディターで開いて、以下のテキストを追加する。場所はどこでもいいようです。

ポイントは、ネットに色々書いてあるような単純なファイル名ではないので、ちゃんとそのsoファイルの場所と名前を発見して、その通りに記述することです。私の場合は、発見したネット情報のPythonバージョンが3.5と少し違っていたので、修正したらちゃんと動きました。

また、Directoryタグの中の記述の仕方もちょっと変わっているようなので、下記のようにすることが重要です。

LoadModule wsgi_module /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mod_wsgi/server/mod_wsgi-py36.cpython-36m-darwin.so
WSGIScriptAlias / /users/ichirok/Documents/python_projects/firstDjango/firstDjango/wsgi.py


Require all granted

この設定がちゃんとできるようになると、Apacheがちゃんと動いて、返ってくるエラーもInternal Server Errorなどになります。それまでは、そもそもPythonのファイルをプログラムファイルとして認識してくれません。

(3) ファイルのアクセス権(Mac OS/Linux)の設定

Permission Deniedなどのエラーが返ってきます。
chmod 755 directoryName コマンドを使って、Apacheがちゃんとファイルを読めるようにしなければなりません。

どこに問題があるか、問題の特定は、Apacheのエラーログを見ると速いです。エラーログは

/private/var/log/apache2

で見ることが出来ます。

Linuxのファイル設定については、色んな本に書いてあるので、ここでは細かくは書きません。ただ、ファイルやディレクトリのアクセス権限でハマることが多いのでここに書いておきました。

以上、DjangoがApacheで動くようになるまでには結構苦労すると思いますが、皆様の参考になればと思います。