2014年9月30日 (火)

DockerでLAMPサーバをつくる話

こんにちは。最近業務マシンがMac Book Airになって気を良くしているエンジニアの佐藤です。

世間ではDockerが注目を集めていますので、今回はこの話題をお届けしたいと思います。

Dockerとは

ものすごく簡単に言うと、従来(ハイパーバイザー型)より少ないリソース(CPU、メモリ、ストレージ)で同等のサービスをホストする仮想化技術です。 Linuxカーネルのコンテナと呼ばれる機能により、ある「おまじない」をして開始したプロセスはそれぞれ独立した以下の一式を受け取ります。

  • ファイルシステムルート
  • rootユーザ(およびその他のカーネルサービスID空間)
  • ネットワーク

したがってこのプロセス(およびその子プロセス)は、あたかも独立したホスト(「コンテナ」と呼ばれます)であるようにふるまうことができるのです。プロセスのカーネルメモリ空間は全コンテナで共有使用するので、CPUとメモリが節約でき、カーネルの初期化をスキップして高速起動できます。

Dockerの問題点

ただしこの仕組みが成立するためには、コンテナ内のプロセスが、Dockerの用意した上記の仮想リソースの範囲で「おとなしく」動作することが必要です。Dockerを飛び越えてのリソースアクセスはご法度となり、失敗するか、コンテナの動作障害につながる恐れがあります。

LAMPのすべてをコンテナに収容できるか

それではLinuxサーバの定番用途の一つであるLAMPサーバ(Liux Apache MySQL PHP)は、コンテナ上で動作するのでしょうか?もしこれが可能なら、サーバのポータビリティが飛躍的に向上し、便利です。そこで今回はこのテーマに挑戦してみることにしました。

LAMPサーバ「コンテナ」の作成

結果からお伝えすると、以下の手順でLAMPサーバ「コンテナ」が作成できました。

  1. Dockerのインストール
  2. CentOS 6イメージをDocker hubからpull
  3. /bin/bashでスタート
  4. あとは普通にセットアップ
  5. 最後に起動スクリプトを書く
  6. イメージを保存して、docker run

1. Dockerのインストールと開始

今どきのLinuxディストリビューションでは、コマンド一発です。筆者のUbuntu 14.04では以下のようにしました。

# apt-get install docker.io
# service docker.io start

2. CentOS 6イメージをDocker hubからpull

これもコマンド一発です。

# docker pull centos

3. /bin/bashでスタート

次に「bash」コマンドを指定してコンテナをスタートします。この時「-i -t」オプションを指定し、コンテナ内で起動したbashの標準入力と標準出力を、今まさにdockerコマンドを打っているターミナルに接続します。

# docker images | grep centos6  <-- CentOS 6 のイメージIDを確認
centos              centos6             68eb857ffb51        2 weeks ago         212.7 MB 
# docker run -i -t 68eb /bin/bash <-- bashを指定してコンテナを起動。イメージIDは前方一致で指定できる。
bash-4.1# whoami <-- コンテナ内のbashのプロンプト
root

4. あとは普通にセットアップ

ここまできたら後はapt-getとかyumとかを用いて通常のサーバと同じように設定していきます。

# apt-get install httpd openssh-server mysql-server php
...

5. 最後に起動スクリプトを書く

ここがちょっと難しい部分です。 Dockerは「docker run」で開始されたプロセスに特別なリソースを割り当てる仕掛けですので、このプロセスが終了すると、コンテナ全体が終了となります。これではサーバとして常駐するサービスとして使えません。このため「docker run」で開始するプロセスは以下の役割を担う必要があります。

  • 開始したら他の常駐プロセス(httpdなど)を起動し、シグナル(docker killコマンドで送信)を受信するまで終了待機する。
  • シグナルを受信したら、常駐プロセスを終了し、自身も終了する。

方法はいろいろあるのですが、一番簡単だと思うのは以下のようなシェルスクリプトです。

#! /bin/bash
service rsyslog start
service sshd    start
service mysqld  start
service httpd   start

term() {
     service httpd   stop
     service mysqld  stop
     service sshd    stop
     service rsyslog stop 
}

trap "term; exit" SIGHUP SIGINT SIGTERM

while true; do
     sleep 1
done 

このスクリプトを/root/start.shなどのパスに保存し、次回からdocker runするときはこのスクリプトを実行するようにします。

6.イメージを保存して、docker run

まずセットアップ作業が終わったコンテナを終了します

bash-4.1# exit  <-- コンテナを終了
exit

この段階でコンテナは、「イメージ+変更差分」の形で保存されています。

# docker ps -l <-- コンテナのIDを確認
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES 
ad8596fad31e        centos:centos6      "/bin/bash"         51 minutes ago      Exited (1) 3 seconds ago

docker runするためにはイメージにする必要がありますので、「イメージ+変更差分」を一本のイメージにします。

# docker commit ad85 server01 <-- イメージを作成

いよいよ起動です。このときコンテナホスト(dockerを実行しているマシン)の80番ポートを、コンテナの80番ポートに接続します。(この設定により、外部からコンテナにHTTPリクエスを送信できるようになります。)

# docker run –d –p 80:80 mybasket01 /root/start.sh
5cf98b694ceb5d62f7fa01d4ff5fc7130eb98ab4ea5c04a3df37c090c7b4595f

この状態でコンテナホストの80番ポートにアクセスすると、コンテナサーバからのレスポンスが返るはずです。

7. コンテナ終了は docker kill

コンテナを終了するときは、シグナルを送信して起動スクリプトの終了処理を実行します。ここではTERMシグナルを送信しています。

# docker kill -s="SIGTERM" 5cf9

いくつかのハマりポイント

Dockerコンテナでサーバをつくろうとした時にいくつかハマったポイントがあったので、ご紹介します。

1. CentOS 7 コンテナが使えない

Cent OS 7では常駐プロセス制御にsystemdが使用されていますが、Dockerコンテナ内ではsystemdが動きません。またApacheのインストールも失敗します。残念ですがリビジョンアップで改善されることを期待です。

2. SSHサーバにログインできない

SSHサーバの初期処理が実行されていない可能性がありますので、コンテナ内でSSHサーバを一旦起動して初期処理を実行します。

bash-4.1# service sshd start

また、既定のPAM(Praggable Authentication Module、Linuxの認証拡張モジュール)設定がDockerとぶつかる場合もあります。/etc/ssh/sshd_configを編集し、「UsePAM no」に設定します。

3. ファイル共有が使えない

NFSサーバはカーネル機能ですので、Dockerでは使えません。更に、Sambaも何故か動作しませんでした(調査中です…)。ファイル共有については、現在WebDAV + davfsでやっています。

まとめ

Dockerはまだ新しい技術で、心配な部分が多いというのが率直な印象です。しかしコンテナ仮想化のリソース効率の高さはまちがいなく、ポータビリティの恩恵も大きいと感じています。主要企業は一斉にサポートを表明しており、今後広まっていくのではないでしょうか。

2014年8月22日 (金)

サブディレクトリ型の複数サイトでtwitter cardを設定した

こころです。番外編ネタですが、フレクトで運営しているブログにtwitter cardを設定してみました。

1.twitter cardって?

twitter cardとは自分のサイトにmetaタグを数行埋め込むと、twitterのタイムラインにメディア(カード)を添付できるサービスです。

20140822_113413_2

こんな感じ。

カードは7種類。
Summary Card・・・標準のカード(タイトル、ディスクリプション、サムネイル、サイトのTwitterアカウント)
Summary Large Image Card・・・標準カードの画像大きめ
Photo Card・・・写真を表示するカード
Gallery Card・・・写真の収集を目立たせるカード
Player Card・・・Youtube動画や音楽プレーヤーを埋め込むカード
App Card・・・アプリケーションを紹介するカード
Product Card・・・商品を見せるカード

今回はよく見かけるSummary Large Image Card(標準のカードの画像大きめ)を設定してみます。

2.準備

用意するもの

  1. WebKitを用いたブラウザ(GoogleChromeかSafari)
  2. twitterアカウント
  3. カードを埋め込むWebサイト

twitter cardのプレビュー機能がWebKitを用いたブラウザでしか動作しないのです。
また、今回はサブディレクトリで複数サイトを運用している場合に対応しました。

フレクトでは、

フレクトのクラウドブログ> http://blog.flect.co.jp/cloud/
セールスフォースの豆知識> http://blog.flect.co.jp/salesforce/
フレクトのHeroku Lab> http://blog.flect.co.jp/labo/

と3つのブログをサブディレクトリ型で運用してるのです。

http://blog.flect.co.jp/***/を切り分けるときにちょっと詰まったので、あまり居ないと思いますが同じ様なサイト運用してる人のために書いてみようと思います。

3.設定

https://dev.twitter.com/docs/cards/validation/validator

から、作成したいカードのタイプを選択します。

20140822_120236今回はSummary Large Imageを選択

次のCard Validator画面では、サイトに貼付けるmetaタグを生成するためのオプションを入力します。

20140822_134800

赤枠・・・入力必須
黄色枠・・・任意項目(スマートフォン画面に最適化するためのオプション項目です)

必須プロパティについて

twitter:card・・・cardの種類
twitter:site・・・twitter cardを作成するサイトオーナーのユーザ名
twitter:title・・・カードのタイトル
twitter:description・・・カードのメッセージ(200文字以内)
twitter:creator・・・ページのコンテンツ作成者のTwitterアカウント(twitter:siteと同じでもOK)

twitter:image:src・・・画像のURL (Summary Large Image)の場合は最低280×150px必要です。

twitter:domain・・・サイトのドメイン ※サブディレクトリ型の場合は注意が必要で、http://blog.flect.co.jp/labo/* と、ワイルドカードを設定するのがポイントです。
Update Previewボタンを押すとmetaタグが生成されるので、サイトの共通headerに追加します。

4.確認方法
Card ValidatorのValidate&Applyタブに、追加したサイトのURLを入力し、Goボタンを押します。

20140822_113310

<Your domain name> approved と表示されます。

20140822_112750

以上で設定完了ですが、設定しようとするとけっこう細かいエラーが出るので、こちらのFAQを参考にしてください。特に、Twitterのクローラーはおよそ週1回の割合でサイトのメタデータを再度取得するので、twitter cardに修正を加えた場合は反映されるまで時間がかかるようです。

2014年7月16日 (水)

Chef の database cookbook でハマった話

こんにちは、エンジニアの小笠原です。

最近は Chef で開発環境の構築なんかやってるわけですが、database cookbook の利用でハマったので小ネタ的に。
結論からいうと、rubyのコードくらい読めるようになっておこうね、という話でしかないんですが。。

前提

  • Heroku を使うことが多いので、RDBMS は基本 PostgreSQL
  • 開発環境もできるだけ構成を本番環境に合わせて構築したい
  • ローカル開発環境構築は基本 VirtualBox + Vagrant + Chef + Test-kitchen
  • DB のユーザ作ったりデータベース作ったりは database cookbook で出来る
  • 筆者は Ruby 経験ほぼなし

ハマったこと

postgresql cookbook での PostgreSQL の設定、database cookbook 使って稼働してる PostgreSQL への CREATE USER/GRANT, CREATE DATABASE 共に、それぞれ単体では問題なくできました。
が、双方を一緒に実行させようとするとエラーを吐いて止まります。

.kitchen.yml にはこう記述してる状態。

suites:
  - name: default
    run_list:
      - recipe[postgresql::server]
      - recipe[init_db]

init_db cookbook のレシピで、include_recipe database::postgresql して DB ユーザの生成なんかを記述してるわけですね。
で、kitchen setup すると、

(前略)
[2014-07-16T01:09:18+00:00] ERROR: Exception handlers complete
[2014-07-16T01:09:18+00:00] FATAL: Stacktrace dumped to /tmp/kitchen/cache/chef-stacktrace.out
Chef Client failed. 15 resources updated in 711.501939185 seconds
[2014-07-16T01:09:18+00:00] ERROR: execute[generate pg gem Makefile] (postgresql::ruby line 89) had an error: Mixlib::ShellOut::ShellCommandFailed: Expected process to exit with [0], but received '1'
---- Begin output of PATH=$PATH:/usr/pgsql-9.3/bin /opt/chef/embedded/bin/ruby extconf.rb ----
STDOUT: checking for pg_config... no
checking for libpq-fe.h... no
STDERR: No pg_config... trying anyway. If building fails, please try again with
 --with-pg-config=/path/to/pg_config
Can't find the 'libpq-fe.h header
       *** extconf.rb failed ***
(後略)

と怒られました。

なんで単体で動いたものが組み合わせると動かなくなるん? Chef って記述した順にシーケンシャルに実行してくれるんじゃないの?とまったく Chef を理解してない感丸出しで調査スタート。

単体で動いてたものが組み合わせると動かなくなった謎については、Engine Yardさんのブログが紐解いてくれました。
単体で database cookbook 動かしてた時は既に postgresql cookbook のおかげでインストールされてた libpq が、組み合わせた場合はコンパイル(か run_action 実行)時にはまだインストールされてない為エラーになった、と。

さてじゃぁ、どうやってあらかじめ libpq をインストールすれば良いんだろう?と考えてもわからなかったので、仕方なくソースコードを読みます。
エラーの発生した箇所は、出力されてるログからわかります。

       Cookbook Trace:
       ---------------

         /tmp/kitchen/cookbooks/postgresql/recipes/ruby.rb:95:in `rescue in rescue in from_file'
         /tmp/kitchen/cookbooks/postgresql/recipes/ruby.rb:57:in `rescue in from_file'
         /tmp/kitchen/cookbooks/postgresql/recipes/ruby.rb:24:in `from_file'
         /tmp/kitchen/cookbooks/database/recipes/postgresql.rb:20:in `from_file'
         /tmp/kitchen/cookbooks/init_prj/recipes/default.rb:13:in `from_file'

ん? database cookbook って実際の DB の cookbook を呼び出してるのね。
まぁともかく追っていくと、postgresql/recipes/ruby.rb は、どうやら pg gem をビルドしてインストールするレシピのようですね。
で、95行目でエラーになってると。

    lib_builder = execute 'generate pg gem Makefile' do
      # [COOK-3490] pg gem install requires full path on RHEL
      command "PATH=$PATH:/usr/pgsql-#{node['postgresql']['version']}/bin #{RbConfig.ruby} extconf.rb"
      cwd ext_dir
      action :nothing
    end
    lib_builder.run_action(:run)

lib_builder.run_action(:run) が 95行目です。
んー、ということは、ここまでに libpq がインストールされれば良いと。
コードを遡って行くと、

  node['postgresql']['client']['packages'].each do |pg_pack|
    resources("package[#{pg_pack}]").run_action(:install)
  end

という記述を見つけました。
こいつは postgresql::client レシピでインストールするパッケージを指定する attribute じゃないですか。
というわけで、 .kitchen.yml に以下のように libpq-dev パッケージ(Ubuntu14.04)のインストール指定を追加したところ、無事エラーなく動いてくれました。

    attributes:
      postgresql:
        client:
            packages: ["libpq-dev", "postgresql-client-9.3"]

まとめ

  • Chefのレシピは上から下にシーケンシャルに実行されるわけじゃない
  • 困ったらソースコード読もう

続きを読む "Chef の database cookbook でハマった話" »

2012年1月22日 (日)

Panda Streamを使ってWEBサイトに動画アップロード&エンコード&再生機能を作る

こんにちは、大橋です。
ひさしぶりの記事投稿になります。

今日はPanda Streamという動画アップロード、エンコード(変換)および再生機能を自分のサイトに組み込めるサービスを使ってみたので記事にしてみます。Panda Streamの公式サイトは以下です、あわせて見てみてください。

http://www.pandastream.com/


<Panda Stream概要&特徴>

Panda Streamを使うと、Youtubeみたいに動画ファイルをブラウザからアップロードして、アップロードしたファイルをブラウザ上で再生できる機能を簡単に既存Webサイトに組み込むことができます。特徴は以下です。

  1. すべての機能がREST API形式で提供されていて、Ruby, Python, PHPなどAPIを簡単にコールするライブラリも用意されている
  2. ブラウザからのアップロードはpandaのサーバ側に直接送信されるので、自前のサーバで動画アップ用にインフラ/ミドルなど構築をしなくてよい
  3. データのストア先はAmazon S3を使うので、ストレージを自前で用意する必要なし
  4. アップロード、再生するときのJavaScript, HTML,などサンプルが一通り用意されている。
  5. 多様なInputフォーマットからFLV, MP4(H.264), WebMなど主要な再生環境向けへの変化に対応。

名前はなんだかかわいいですが、できることはけっこうすごいですね。なにかと難しい、動画アップ、変換、が簡単にできちゃいます。HerokuのAdd-onにもなっているので、Herokuを使うときにも便利(←一部の人だけの恩恵かもですが・・・)。

<動画機能を利用するための流れ>

早速使っている前に、大まかな手順を確認しましょう。Panda Streamを使ってWebサイトに動画アップロード&再生機能を埋め込む手順は以下のようになります。

  1. Amazon Web Services(AWS)にサインアップしてAmazon S3を利用できるようにしておきます。
  2. PandaにSign Upします。
  3. CloudというS3のバケットに1対1で対応したエンコーディングした動画を管理するグループを作成。
  4. Panda StreamのAPI Access用のキーとCloud IDを取得。
  5. ここから本番。実際にWebサイトに組み込むためのプログラミングをします。


<実際にWebサイトに組み込むための前準備>

手順(1)〜(4)のCloud作成までは簡単なのでさらっと説明します。

まず、Amazon S3を用意しましょう。AWSのアカウントがなければ以下から申し込んで、Amazon S3を使えるようにしましょう。アップロードした動画やエンコード後の動画、および動画から抽出されたサムネイル画像はAmazon S3上に保存されます。

http://aws.amazon.com/jp/

次にPanda Streamのサイトへいってサインアップしましょう。

http://www.pandastream.com/

サインアップしたら、Home画面のメニューに「API Access」という項目があるので、そのリンクをたどると以下のような画面になります。

Pandaapikey

ここで、
 ・Access Key
 ・Secret Key
 ・API URL(api.pandastream.com)

があることを確認しましょう。これはPanda StreamのAPIを使うときに必要になります。

次にメニューの「Clouds」というメニューがありますのでここをたどり、「Create new cloud」をクリックし、Cloudを作成します。Cloudの名前とパーミッションおよびS3のバケット、Access Key、Secret Keyを設定します。すると、以下の画面のようにCloudが作成されるので、作成後に左上に表示されているIDがCloud IDというもので、この後、APIアクセスで使うので控えておきましょう。

Cloud_id

いろいろサインアップするものがあって大変ですが、これで準備完了です。


<WEBサイトに動画アップロード機能を埋め込む>

Panda Streamのサイトにサンプルコードがアップされているので、それを見たり、動かしたりするのが入門にはちょうどよいです。

http://www.pandastream.com/docs/sample_apps

ここでは、その中のエッセンスだけ抜き出して、アップロードから再生までどんなコードを書けばよいか解説していきます。

まず、アップロード画面のHTML/JavaScript側を準備します。
HTMLは以下のように記述します。actionの遷移先は適当に変えてください。
最初のhiddenはこのあと説明するJavaScriptによりアップロードに成功後に動画のIDが埋め込まれ、次の画面に遷移するときのパラメータになります。

 

   

   

 

JavaScriptはPandaが提供しているJavaScriptライブラリ、jquery.panda-uploaderを使います。jQuery本体を先に読み込んで、Pandaのアップローダーライブラリを読み込みます。

  
  

  


アップローダーの読み込み後、前準備で取得したPanda Stream用のaccess_key、cloud_idなどともにsignatureを書く必要があります。これはサーバサイドで値を作成します。サーバサイド用にはいろいろな言語用にクライアントライブラリがあるので、言語ごとのPandaライブラリを使うことで、signatureを取得できます。ライブラリは以下にあります。

http://www.pandastream.com/docs/client_libs

Ruby, PHP, Pythonなどのライブラリがあります。環境が整っていてよいですが、Java版やPerl版がなかったりもします。
たとえば、Pythonならば以下のような処理でJSON形式でsignatureなど取得できますので、JavaScriptに埋めてください。

panda = Panda(
    api_host='api.pandastream.com',
    cloud_id='Cloud ID',
    access_key='Panda API用のAccess Key',
    secret_key='Panda API用のSecret Key',
    )
python_access_details = panda.signed_params('POST', '/videos.json')
# 以下のようなJSONが取得できます。
#{'access_key': 'xxxxxxxxxxxxxxx', 'timestamp': '2012-01-19T15:01:43.268760+00:00', 'cloud_id': 'xxxxxxxxxxxxxxxxxxxx', 'signature': 'U8OOrnBlYekV3FjyyAIZj1H0kVZlAATn8O/uI07mEMI='}

ここまでのHTML, JavaScript, サーバサイドの処理を組み合わせて、アップロード処理が作れます。説明したパーツを組み合わせると以下のようにプログレスバーが出てくる動画アップロード機能が作れます。

Upload_progress

 アップロードが終わるとコンテンツはS3に登録され、Panda Streamのサーバ側でエンコーディング処理が始まります。同時に、HTMLにhiddenでpanda_video_idとしたところに、動画再生のためのIDがセットされ、フォームのアクション先にpanda_video_idがパラメータとなり画面遷移します。

アップロードされた動画はPanda Streamの画面でも以下のように作成したCloudのDashboardでエンコード中の動画が確認できます。

Dashboard


<WEBサイトで動画を再生する>

さて、アップロードされた動画はエンコードに多少時間がかかります。エンコードのフォーマットはPandaに作成したCloudごとにプロファイルを作成できます。デフォルトはmp4/h.264です。PandaのAPIを使ってエンコードの進捗が何パーセントかも取得できますが、それについては今日は省きます。

動画のエンコードが終わったら、PandaStreamのDashboard上でも再生できますが、アップロード時に取得できたpanda_video_idをパラメータにencodings APIを呼び出し、エンコードされたS3上のファイルパスを取得します。エンコーディングのプロファイルごとにファイルパスや拡張子、スクリーンショットのパスが取得できます。Pythonだと以下のようなコードで取得できます。

    # panda_video_idはアップロード時に取得したID。pandaはPandaクラスのインスタンス
    panda_encodings = json.loads(panda.get("/videos/%s/encodings.json" % panda_video_id))

    encoding = None
 
 # エンコーディングのプロファイルごとに取得できる
    for panda_encoding in panda_encodings:
        if panda_encoding['extname'] == '.mp4' and panda_encoding['status'] == 'success':
            encoding = {
                'id'     : panda_encoding['id'],
                'width'  : panda_encoding['width'],
                'height' : panda_encoding['height'],
                # 以下のようにすると動画のURLやスクリーンショットのjpegのURLが取得できる
                'url'    : "http://%s.s3.amazonaws.com/%s%s" % (’S3のバケット名', panda_encoding['id'], panda_encoding['extname']),
                'screenshot_url' : "http://%s.s3.amazonaws.com/%s_4.jpg" % ('S3のバケット名', panda_encoding['id']),
            }

取得したurlやscreenshot_urlをHTML上で以下のように埋め込みます。ここではHTML5で再生する例を示します。

サーバ側で取得したスクリーンショットのURLや動画ファイルのURLをそれぞれ埋め込めば再生できると思います。もちろん、エンコードが終わってからですが。

かんたんな使い方は以上になります。Panda StreamのDocumentにいろいろな情報があるので、ここから先はそちらを見るようお願いします。


<気になる価格体系>

そういえば、価格について触れないといけないですね。以下のページに記載がありますが、同時に処理できるエンコーダの数により価格が決まります。

http://www.pandastream.com/pricing_and_signup

フリー版はエンコーダは他の人とシェア、ファイルサイズの上限が10MBです。有料版は1つの専用のエンコーダ(dedicated encoder)あたり月間99ドルです。たとえば、3つのエンコーダならば397ドルです。エンコーダの数は同時にエンコードできる動画の数と考えてください。実際には占有できるCPU coreのようです。あと有料版はファイルサイズの上限が5GBのファイルの動画までエンコードできます。


<PaaS上でのプログラミング>

今回はPanda Streamという動画アップロード、エンコード、再生を実現するためのサービスの紹介をしましたが、こういった特定の機能を提供するサービスは動画のエンコードだけでもZencoder(http://zencoder.com/ )など他のサービスがあります。他にも画像変換、メール、PDF生成など、スクラッチで作ると手がかかる機能の実現が最近は外部サービスを使うことで可能になってきているようですね。

Heroku、DotCloudなどのPaaSにより、簡単にアプリケーションをクラウド上にデプロイできるようになりましたが、動画処理やサムネイル生成など特別な機能の実現をしようというときにこれまでと同じやり方ではできないものもあり、少し頭を悩ます部分です。

そういった問題への解決策がPanda Streamのようにアプリケーションの特定の機能を提供するサービス群なのかな、と思います。

クラウド環境でのプログラミングは主にWEB、アプリケーションサーバ用のCPU/DBを提供するHerokuなどのPaaSとその周辺を補強するサービス群を使いこなすことがポイントになるんだろうと思い始めています。

PaaSを使ったアプリケーション構築スタイルをこれから追求しないといけない分野ですね。


<まとめ>

Panda Streamという動画アップロード、エンコード、再生機能を簡単にWebサイトに組み込めます。

こういったサービスは他にもたくさんあるので、今後もたくさん試してみてこのブログ上で共有していきたいと思います。

2011年9月 1日 (木)

Dreamforce'11 参加レポートと感想(2) ~第1のデバイスとしてのモバイル~

前回に引き続き、参加レポートその2。

モバイルデバイスの増加と、それに対してのDreamforce'11内で自分が拾った情報と感想を簡単にまとめてみます。Salesforceな部分が少ない記事になっていますが、ご容赦を。


■ モバイルデバイスの利用増

モバイルデバイスについて基調講演にてその成長についてグラフが示されていました。

Mobile_as_first_device

Employees_have_tablets


コンシューマや企業の従業員がモバイルデバイスでWEBアクセスをするだけでなく、企業においては従業員がタブレットデバイスを使うようになっていて、その勢いがすごく大きいということです。

たしかに、自分のお取引させていただいているお客様でもiPadを持っている方が増えています。スマートフォンを含めたスマートモバイルデバイスの利用というのは加速度的に増えていて、その結果、PCからのアクセスというのが主流ではなくなる(なくなった)ということのようです。

自分は大学時代からずっとPCなので、今でもPCメインですが、もう1まわり下の世代以下になるとスマートモバイルデバイスでのWEBアクセスが普段から主流になっていたりするのかな、と思います。

■ 第1のデバイスとしてのスマートモバイルデバイス

そういったスマートモバイルデバイスの増加を考えると、これからは第1のデバイスとして考えなくてはいけないのだと認識しました。

基調講演でモバイルすごいな、と思ってその後のSocial Enterprice Applicationのアーキテクチャについてのセッションに参加したら、これからアプリケーションを作るときにはモバイルデバイスをfirst deviceとして扱おうといった話を聞きました。

そのセッションでは90年代はクラサバ、2000年代はRIAやサーバサイドが中心だったが、これからはハイスペックなモバイル端末のパワーを活かしたアプリケーションアーキテクチャになるという話がありました。Database.comの話をしたうえで、従来はアプリケーションサーバを介してモバイルデバイスはWEBなどにアクセスしたけど、次のアーキテクチャとしてDatabase.comに直接、つなげるようにするという例の紹介がありました。

われわれはWEB開発では今まではPCを第1のデバイスとして考えることが多かったですが、今後は徐々にスマートモバイルデバイスを第1のデバイスとして考えるようにシフトしていかないとまずいなぁ、と認識。そのときにはアプリケーションアーキテクチャ設計、実装、サービス開発のロードマップなども、順序や発想が違うので、今からそういった順序で開発するときの考え方を築いていかないとならないときと実感しました。

■ HTML5で対応するtouch.salesforce.com

Salesforceの毎回の新機能、製品の発表を見ると、基本的には企業向けであるSalesforceの製品であってもコンシューマ向けのサービスで必要とされるレベルのユーザエクスペリエンスをちゃんと提供していきたい、という意志のようなものを感じます。

スマートモバイルデバイスの増加に対してもtouch.salesforce.comとして基調講演で解がひとつ発表されていました。

Touch


touch.salesforce.comはHTML5でできていて、タブレット型、スマートフォン型など問わず、タッチUIを持つスマートモバイルデバイスでSalesforceの機能が使えるようになるということです。Visual Forceでガリガリに書き換えた画面等はできないかもですが、カスタムオブジェクトなどユーザがカスタマイズした部分についても対応しているとのことで、Salesforceのプロダクト群もスマートモバイルデバイスからより使いやすくなるのかと思います。

ソーシャルの波に引き続き、モバイルについてもきっちり対応していっていることが分かる発表でした。

■ まとめ

モバイルが大事だ、は最近ずっと言われていることで、当たり前といえば当たり前なのかもですが、より強く実感をしましたし、帰国したら社内でのモバイル対応の既存の動きについてもっと加速度をつけたい、と思います。

次回はHerokuやSiteforceについてセッションやブースで見聞きしたことを書いてみたいと思います。

Dreamforce'11 参加レポートと感想(1) ~企業のソーシャル化について~

8/30からDreamforce参加にしています。社長の黒川と私とで2人で参加しています。

Salesforce_plus_you_2


8/31まで終わったのでその分について忘れないうちにまとめておきたいと思います。
われわれはSalesforce関連のインテグレーション開発を主力している会社なので、そういった視点になります。

レポートは何回かに分かれます。Salesforce.comはビジネスユーザー向けのアプリケーションサービスの会社であるとともに開発者向けプラットフォームの会社でもあり、視点はいろいろあります。まずは前者のサービス観点から気になったこととして、「企業のソーシャル化」についてのレポート、感想です。

■ 従来のWEBと企業のソーシャル化

従来のWEBと企業のソーシャル化について基調講演での発表内容についてはPublickeyさんの以下の記事に正確な情報があるのでそちらを参照してもらえるとよいかと思います。

http://www.publickey1.jp/blog/11/chatterhtml5ui.html

ここではフレクトの担当者としての追加の感想を書きます。

基調講演では最初の方にデータとしてインターネットの利用が従来の検索から始まるWEBではなく、Facebookなどのソーシャルメディアを中心としたものに変遷してきていることが示されていました。日本ではどうかは正確にはわからないのですが、そんなに使われているんだぁ、と思いました。

Fb_eat_web


その上で、ネットサービス、コンシューマ向けサービスがソーシャル化する中、「企業のソーシャル化ができているか?」と問いかけ、それに対するSalesforce.comのアプローチがChatterをベースにした各種機能の発表がありました。

ChatterでIMができる、顧客とプライベートグループを作ってコミュニケーションができる、Contact(取引先責任者)にSocial Media上でのコミュニケーション情報が記録されるなどソーシャル化を示す機能が次々と発表されました。次々と発表されるのでメモが追いつかないくらいでした。

Chatter_now


ポイントは、(1)フィードやチャットなどChatterを基本としてFacebookのようにエンタープライズシステムが使える、(2)従来のWebではなく、ソーシャルなインターネットを前提とした顧客とのリレーションづくりができる、という2点だと思います。

(1)についてはChatterが出てきたときからそういった発想がありましたし、新しくはないかもですが、大事なことと考えています。Salesforceはコンシューマサービスの中でも特にユーザへのサービス、UIが進んでいるところと同じようにエンタープライズシステムを使えるようにしたい、というのが強い会社なので今はFacebookと同じようにユーザエクスペリエンスを提供していくということなのかと。(昔はAmazonのように、将来はわかりません)。

(2)は特に今回強調されたことで、ソーシャルメディアの情報をSalesforceに統合することで、新しい顧客との関係づくり、をイメージさせるようなデモが多く見られました。(2)については以下の感想でもう少し詳細を。

■ ソーシャルメディアの情報を使っている現場から感想

一緒に参加した社長とともに、企業のソーシャル化、Chatterを中心としたソーシャルメディアとの連携には強い興味を持ちました。(ほかの参加者さんも同じと思いますが)

私どもも社内では営業管理にSalesforceを使っています。顧客や顧客の担当者情報についてFacebookやTwitterのURLが分かっていれば、取引先責任者(Contact)のフィールド(カスタムで追加)に入れるよう"手動運用"していて「顧客がどんなことに関心を持っているのか」についてわれわれも強く関心を持って営業活動をしています。

運用してみると、実際に初めてお会いする方でも、ソーシャルメディア上で関心事などがあらかじめ分かっていると、より強く相手に関心を持った状態で人とお会いしてよりよいコミュニケーションがとれるようになったと思います。また、お客様との双方向の関係においてもソーシャルメディア上でのつながりが何かしらある方が、より深いリレーションが築けています。

そういった現場にいる担当として、顧客管理をするシステムとしてのSalesforceが次にChatterを基点に外部のソーシャルメディアと連動して情報も含めて顧客とよいリレーションを築けるようにしよう、という方向のは単純に私どもの手動運用を減らしてくれるだけでなく、顧客とのよりより関係づくりの新しい手段を提供してくれる可能性を持っているのではと思いました。

ただ、システムの機能としては充実したとしても、機能だけではなく、まだ成熟していないソーシャルメディアを使った業務、運用に耐えられる同時にベターなやり方、自分たちなりのプラクティスを同時に蓄積していく必要があると思いました。ぼくらも顧客のソーシャルメディア情報を登録していますが、活用については人によってまだばらつきがある感じです。

Social Divideという言葉が基調講演でありましたが、ITリテラシーという言葉があるように、ソーシャルメディアと使った顧客とのリレーション構築には、何かしらのリテラシーが必要で、企業としてはそれができる集団になっていかないと、効果を上げられないだろうなぁ、と思いました。

■ まとめと次回

ソーシャルメディアをつかった企業活動については今回の発表にある機能によい運用がかけ合わさればより新しいレベルでのリレーションづくりができると思いました。

まだ運用プラクティスが少ない分野ですが、自分たちでも機能のあるなしにかかわらず、引き続き実践して、機能の理解だけでなく、より使いこなせるようになるよう、がんばってみます。

次のレポートはモバイル関連を書いて、その次はHerokuとかSiteforceのことを書こうかと思います。

2011年8月26日 (金)

Heroku for Javaとセールスフォース

HerokuがJavaをサポートするとのことです。

http://blog.heroku.com/archives/2011/8/25/java/

昨年、2010年のDreamforceでセールスフォース・ドットコム(以下、セールスフォース)がHerokuを買収したというニュースが出たあと、Node.jsなどがサポートされ、RubyまつもとゆきひろさんがHerokuに参加され、といろいろな注目すべきニュースがありましたが、Javaのサポートもすごく大きなニュースです。

また、フレクトはJavaによるWEB開発を得意領域のひとつにしているので、当社としては待ち望んでいたニュースでもありました。

以下、さーっと、Herokuのブログ記事やDev Centerのドキュメントを読んだかぎりでのHeroku for Javaについての自分なりの理解をまとめておこうと思います。(さーっと読んだ結果なので、間違いあるかもです)

■ HerokuっぽくJavaを使う

Herokuは小さいチームがスピード感を持ってインフラ/ミドル管理などのストレスなく高い生産性でアプリケーションをシンプルに構築できるプラットフォームを作るという思想でサービスの拡張等を進めているとぼくは理解しています。ビジネスマンというよりはDeveloperの立ち位置にすごく近い感じ。Rubyが最初の言語として選択されているのは、そういう思想のもとにサービスを展開しているからと理解していました。

したがって、個人的(フレクト的にも)Javaをサポートしてほしいな、と思いながら、ちょっと文化が違うかも、とも思っていました。Herokuっぽい部分とJavaっぽい部分が合わない部分があるのではと(あいまいな表現ですみません)。

これについて、Herokuはブログ記事によると、Javaにはやはりいくつか問題があると認識していたようです。特にJ2EE(JEE)とJ2EEアプリケーションコンテナを使った開発、デプロイが問題であることを認識していたようです。

これに対して、Heroku for JavaではJ2EE的なアプリケーションコンテナを使わないでJettyをアプリケーション内に埋め込むというアプローチをとっています。そのうえで、J2EE的なアプリケーションコンテナが提供しているデプロイ、ロギング、クラスタリング等の機能をHerokuのプラットフォームが提供するということのようです。

こういったアプローチをとることにより、JavaにおいてもRubyでHerokuを使うのと同じようにソースを書いて、gitにコミットして、pushするというRubyの場合と同じステップで簡単にアプリケーション構築・デプロイができるようになっています。実際にブログ記事中の「Heroku for Java in 2 minutes」を見ても、Rubyでのソース書く→Deployのステップとまったく同じように見えます。すごくシンプルですね。

Javaのサポートってどうなるのかな、Herokuと合うのかな、とちょっとだけ心配していましたが、杞憂のようでした。Herokuが大事にしている生産性、シンプルにストレスのないことをJavaでもとなってますね。Java的な文化にあわせるのではなく、JavaをHerokuっぽく使えるようにされています。すごくよいと思いました。社内でもいいねと話しています。早急に社内のエンジニア達でキャッチアップしようと思います。

■ セールスフォース風味な部分やVMforceな部分が少し入っている

あと、今回のJavaサポート関連のドキュメントを読んでいると、セールスフォースとの関連がちらほら見え隠れします。

たとえば、Force.com、Database.comとHerokuとのインテグレーションはどうするの?といったFAQが入っています。

http://devcenter.heroku.com/articles/java-faq#how_do_i_build_forcecom_and_databasecom_java_applications_on_heroku

買収後、あまりセールスフォース的な要素が見られなかったHerokuですが、少しずつ相乗効果が出せる部分が見えてきそうです。セールスフォースを使ってインテグレーション事業に取り組んでいる我々としてはこういったことは大歓迎です。

VMForce風なところは、tutorialにSpringをつかったものがあったり、ブログ記事中の「Why Java?」に対して「600万人のDeveloperがいるから」みたいな記述がある部分です。VMForceはSpringという業界でよく使われているのフレームワークで、なおかつ世界中の600万人のJava Developerにクラウドを提供できる、という触れ込みだったので、その辺の文言やら雰囲気がちょっとだけHeroku for Javaに混ざっていると感じました。VMForceは今後、Heroku for Javaとどう違いを出すのでしょうか。いろいろ気になることはありますが、Dreamforce等、今後のニュースを確かめたいです。

■ まとめ

Heroku for Javaについて今ある情報だけからの感想を簡単にまとめました。Herokuのよさを最大限に活かしてJavaが使えるというのがすごくうれしいですね。

セールスフォースのプロダクト群とも、Database.comなど相乗効果が高そうなものはどんどん連携しやすくなるのだと思います。その辺も要ウォッチですね。

今後は実際に使ってみた記事など技術的なことも書いていきたいと思います。

■ ちょっとだけ当社のことと中途採用のこと

フレクトはWEBサイトとSalesforceとの連携開発を1つの強みとしており、WEB開発についはJavaがメインです。そういった我々にとってHeroku for Javaの発表は待ちに待った発表でした。今後、Heroku for Javaと他のSalesforceプロダクト群連携ソリューションをもっと充実させていきたいと思います。

また、それを担ってくれるエンジニアも引き続き募集しています。Herokuなどクラウドプラットフォームでの開発を行いたい方、ぜひ以下からご連絡をいただければと思います。

http://www.flect.co.jp/recruit/index.html

2011年8月18日 (木)

Amazon SESをbotoを使ってPythonで操作する

前回の記事に引き続き、Amazon SESについてです。

今回はPythonでbotoを使って実際にAmazon SESを使ってメールを送信したり、メール送信結果の統計情報を取得してみようと思います。


■ botoを利用する

botoはAmazon SESなどAmazon Web Servicesのプロダクト群のAPIを操作できるPython用のライブラリです。

インストール方法については以前、Amazon S3を操作する方法の記事で書いたので、以下を参照してください。

http://blog.flect.co.jp/cto/2011/08/pythonamazon-s3-d36b.html


■ Amazon SESを使えるようにする

botoを使う前にAmazon SESのページへ行き、サービス利用を申し込んでおいてください。

申し込んだ直後に利用できる環境はサンドボックス環境と呼ばれる環境です。1日に200通までの送信、および認証されたメールアドレスにしか送受信できない、という制限があります。サンドボックス環境で十分に検証をしたら、以下からプロダクション環境利用の申請をします。

https://aws-portal.amazon.com/gp/aws/html-forms-controller/contactus/SESAccessRequest


■ SESへの接続

では、これから実際に使ってみます。
環境変数としてAWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEYをあらかじめセットしておけばプログラム中にアクセスキー、秘密キーを記述する必要はありません。以下のような感じで接続できます。

from boto.ses.connection import SESConnection
conn = SESConnection()

ホストの指定も以下のように一応できますが、現状では東海岸しかホストされていないので、あまり指定する意味はないです。

# SESへの接続用オブジェクト作成。現在は東海岸しかホストされていない。
conn = SESConnection(host='email.us-east-1.amazonaws.com')

■ メールアドレスの認証

先ほども記載した通り、Amazon SESでは認証されたメールアドレスしか、送受信できません。
Amazon SESにはVerifyEmailAddressというAPIが用意されていて、これを使うことでメールアドレスの認証ができます。以下のようにして呼び出します。

conn = SESConnection()
conn.verify_email_address('o-masaoki@flect.co.jp')

このAPIを呼び出すと、対象のメールアドレスに認証確認のメールが届き、メール本文内のURLをクリックすると認証成功となります。ListVefiriedEmailAddressesというAPIを呼び出すことで認証済みのメールアドレスのリストを取得できます。たとえば、以下のようにすると呼び出せます。

# 認証済みアドレスの取得(細かいチェック省いています)
response = conn.list_verified_email_addresses()
result = response['ListVerifiedEmailAddressesResponse']['ListVerifiedEmailAddressesResult']
addresses = result['VerifiedEmailAddresses']

for address in addresses:
   print address


■ メールの送信

メールの送信はSendEmail APIを使います。使い方は以下のような感じです。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from boto.ses.connection import SESConnection

# SESへの接続用オブジェクト作成。
conn = SESConnection()

# 送信先のtoのアドレスリスト
to_addresses = [
   'o-masaoki+sestest01@flect.co.jp',
   'o-masaoki+sestest02@flect.co.jp',
   'o-masaoki+sestest03@flect.co.jp',
   ]

# reply to headerにセットするアドレス
reply_addresses = ['o-masaoki@flect.co.jp']

# SendMail APIを呼び出す
conn.send_email('o-masaoki@flect.co.jp' # from
               ,u'テスト'               # subject
               ,u'本文のテスト'          # body
               ,to_addresses           # toのアドレスリスト
               ,cc_addresses=[]        # ccのアドレスリスト
               ,bcc_addresses=[]       # bccのアドレスリスト
               ,reply_addresses=reply_addresses        # Reply-toヘッダの設定
               ,return_path='masaoki.ohashi@gmail.com' # bounceメールを返す場所
               )

上記のサンプルは日本語が書かれていますが、送信元のプログラムがMac OS
X、受信側のメーラーがGMailという環境では日本語がUTF-8で表示されました。他の環境ではダメかもしれません。SendEmail APIのリファレンスは以下ですが、主要なパラメータについて上記サンプル中のコメントに説明を記載しておきました。

http://docs.amazonwebservices.com/ses/latest/APIReferene/index.html?API_SendEmail.html

SendEmail APIはパラメータにReply-toやbounceメールを指定すると、自動的にメールのヘッダに付与してくれます。文字コードのエンコードの指定やヘッダの細かい制御等を行うにはSendRawEmailというAPIがあります。これについてはまたの機会に書きたいと思います。


■ 統計情報の取得

前回の記事で、ユーザはバウンスメール数などの統計情報のフィードバックを見られる旨を記載しましたが、それが次に説明するGetSendStatistics APIです。この機能と次に説明するQuotaの機能が、Amazon SESのすごく特徴的なところで、Amazon SESの配信性能の仕組みを支えている部分のひとつになります。

まず、GetSendStatistics APIです。このAPIでは15分インターバルで集計される送信メールの統計情報(15分ごとの統計情報のグループをDataPointと言うようです)を取得できます。サンプルは以下の通りです。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from boto.ses.connection import SESConnection

# SESへの接続用オブジェクト作成。現在は東海岸しかホストされていない。
conn = SESConnection(host='email.us-east-1.amazonaws.com')

# 15分間隔ポイントで統計情報を作成している
response = conn.get_send_statistics()

result = response['GetSendStatisticsResponse']['GetSendStatisticsResult']
points = result['SendDataPoints']

for p in points:
   print '----------------------'
   print 'time of data point : %s' % p['Timestamp']

   # 配信を試みたメール数(配信数)
   print 'delivery attempts : %s' % p['DeliveryAttempts']

   # 何かしらの原因で不達になったバウンスメール数
   print 'bounces : %s' % p['Bounces']

   # 苦情として連絡されたメール数(受信者から拒否されたメール数)
   print 'complaints : %s' % p['Complaints']

   # Amazon SESサービスにより拒否されたメール数。SESのフィルタリングにひっかかったものと思われる。
   print 'rejects : %s' % p['Rejects']

print '----------------------'

取得できるのは配信試行数(DeliveryAttempts)、バウンスメール数(Bounces)、受信側から拒否された数(Complaints)、Amazon SESのフィルタリングにより送信拒否となった数(Rejects)の4つの数値とDataPointのタイムスタンプが取得できます。上記のサンプルプログラムだと以下のように出力されます。

----------------------
time of data point : 2011-08-15T02:38:00Z
delivery attempts : 17
bounces : 0
complaints : 0
rejects : 0
----------------------
time of data point : 2011-08-11T15:23:00Z
delivery attempts : 1
bounces : 0
complaints : 0
rejects : 0
----------------------
time of data point : 2011-08-17T15:38:00Z
delivery attempts : 3
bounces : 0
complaints : 0
rejects : 0
----------------------

ユーザはこれを見て、bounces、complaints, rejectsを減らすことによって配信メールの品質を向上させていく必要があります。Amazon SESにはじかれたメールはAPI経由で、バウンスメールはReturn-Pathのメールから判断できるので、それらの内容をよく確認し、配信リストの修正、品質向上に取り組むといいと思います。


■ 配信割当量(Quota)情報の取得

サンドボックス環境だと固定の数値、プロダクション環境だと、送信したメール数、品質によって徐々にアップしていきます。取得できるAPIはGetSendQuotaで、以下のように使います。

# SESへの接続まではGetSendStatisticsのサンプルと同じです。
response = conn.get_send_quota()
result = response['GetSendQuotaResponse']['GetSendQuotaResult']

# 24時間以内に送信できるメール数
print 'max 24 hour send : %s' % result['Max24HourSend']

# 24時間以内に送信したメール数
print 'sent last hour send : %s' % result['SentLast24Hours']

# 1秒間に送信できるメール数
print 'max send rate : %s' % result['MaxSendRate']

上記のサンプルの通り、24時間以内に送信できるメール数、実際に24時間以内に送信したメール数、それと1秒間に何通送信できるか、という割当情報が取得できます。GetSendStatistics APIで品質チェックをして、品質向上と配信数の向上に努めたら、徐々にこの割当がアップしていくようです。なんだか、レベル上げみたいですね。

 

■ まとめ

前回の記事に引き続き、今回はAmazon SESのAPIをbotoライブラリを使ってPythonでプログラミングする場合の使い方をまとめました。ただ送信するだけではなく、SESからフィードバックをもらい、より高品質なメール配信ができるようにしてもらいたい、というAWS側からの意思みたいなものを感じるAPIですね。

AWSはまだまだ使っていないプロダクトも多いので、今後もいろいろいじってみて実運用につなげていきたいと思います。

■ おまけ ~中途採用のお知らせ~

フレクトではAWSやSalesforceを使ったソリューション事業の拡大をしております。クラウド環境を使った開発に興味がある人はぜひご連絡いただければと思います。以下、採用ページです。

http://www.flect.co.jp/recruit/index.html

2011年8月17日 (水)

Amazon SESとメール配信の難しさについて調べたこと

Amazon SESについて簡単に調査、試用してみたので記事にしてみます。
記事は2回構成で、今回はAmazon SESの特徴をドキュメントベースに調査したものをまとめました。次回、実際にAmazon SESでプログラミングした記事をアップします。

■ 動機と調べたことの概要

メール配信のソリューションはいろいろなベンダーが、魅力的なサービスを展開していますが、初期費用が高かったり、ランニングも場合によってはけっこう高かったりと、やや高価な感が否めません。(そうではないものもあると思いますが)

そう思っていたところでAmazon SESを見つけたので調べてみました。(前からAmazon SES自体は知ってましたが、調べるのが今になってしましまいした・・・)

Amazon SESは初期費用はいらず従量課金の低コストで提供されるメール送信サービスです。1000通あたり0.1ドルと非常にリーズナブルです。

費用以外では、確実にメールを届ける配信性能を売りとしています。メールを送信すれば届くというのは意外と当たり前のようなことですが、大量にメールを送るときに確実にすべての受信者に届けるのはかなり難しいです。

なので、どの辺が難しいか、Amazon SESは何を配信性能とはどういうことなのかメール配信について初心者の自分の理解するのためにまとめてみました。

■ 確実にメール配信するために必要なこと

Eメールを使わないネットサービス、業務システムは少ないと思います。特にコンシューマ向けのPC、モバイル向けのWebサイトではメールマガジンなど大量にメールを送信しなければいけないケースが少なくないです。

メールを送る処理は1通の送信ならばそんなに難しくないですが、マーケティング要素が強い大量メールの配信というのはかなり難しいです。たとえば、以下のような要件をクリアしないといけません。

 ・バウンスメールの処理をきちんとしてISP等でブロックされないようにする
   例)存在しないメールアドレスに対してISPにメールを大量に送るとブロックされたりする

 ・送信できなかった場合の再送処理
   例)IPベースでISPでブロックされた場合、別のIPから送りなおすなど

 ・送信量の制御をしてISPの制御にひっかからないようにする
   例)モバイルのキャリア(ドコモ)などに短い時間で大量に送信すると
      送信ブロックをされることがあるなど

 ・複数台構成で信頼性の高いメール配信サーバを容易する

 ・SPF/Sender IDなどの設定

もう、なんかこれだけで大変そうです。おなかいっぱいですね。

■ スパムフィルタがメール配信を難しくする大きな原因

次に、なぜこんなにメール配信がこんな難しい要件になっているか、についてです。

その原因はどうやらISPのスパムフィルタにあるようです。つまり、届くべきメールまでスパム扱いされているということが原因のようです。

たとえば、情報ソースはやや古いですが、以下のような記事があります。

・メールの0.71~1.02%は「ただ消えて無くなる」~Microsoft研究者らが論文
 

上の記事では以下のような原因でメールは届かなくなるケースが多いとあります。

  •  ISPにて送信元のIPアドレスをフィルタリングしてホワイトリストにないか、ブラックリストに入っていたら、メールを除去
  •  (一か所から)一定量以上(おそらく大量)のメールが送信されている場合
  •  HTMLメールかつ特定の文面が含まれている場合

また、モバイルサイトを開発した人ならば見たことがある人も多いドコモの以下のページも参考になります。

http://www.nttdocomo.co.jp/service/communication/imode_mail/notice/mass_send/index.html

これによると、ドコモ側としては主として

  •  過剰なSMTPセッション数
  •  1セッション(短時間)の送信数
  •  大量の宛先不明を含むメール

などが検知されると、迷惑なメール配信業者という扱いをするようですね。

 

まとめると、

  •  メール不達の原因の大きなものはISPなどにスパム扱いされてしまいブロックされている
  •  短時間に大量のメール送信、宛先不明のアドレスに大量送信、をするとスパム扱いされやすい(下手するとブラックリストに入ってしまう)

ということのようですね。

■ Amazon SESの配信の信頼性を向上させる仕組み

ここで、やっとAmazon SESについて調べたことに入ります。(前置きが長いですね、すみません)

Amazon SESにはメール配信の信頼性を向上させるためにAmazon SES自体を外部ISPからの信頼性を損ねないよう、ISPのスパムフィルタにひっかからないようにする仕組みがあるとのことです。

具体的には、主に以下の手段で配信されるメールを高品質であるよう保ちます。

  1.  Amazon SESのフィルタリングによりスパムメールの可能性が高いメールは外部へ配信しない。
  2.  ユーザにメール品質向上のためのフィードバック情報を提供し、品質向上できるようにする。
  3.  ユーザには急激なメール送信の増加をさせず、段階的にユーザのメール送信量を増やすようにし、継続的に高品質なメールを配信するユーザのみ大量メール配信できるようにする。

まず(1)ですが、スパムメールやその他低品質なメールはAmazon SES自体がそれらのメールを外部に送信しないばかりか、ひどい場合はアカウントの停止もあるとのことで、徹底して低品質なメールを外部に出さないようにしています。

次に(2)では、ユーザに対してバウンスメールの数、苦情メールの数など統計情報を提供し、ユーザ自身がそれらの統計情報を元にメールの品質を向上できるようにします。(具体的なAPIは次の記事で紹介します)

最後の(3)ですが、たとえば、プロダクション環境では最初は24時間に1000通のみの配信ができますが、高品質なメール配信を続けるとその制限が徐々に緩和され、10日間かけて10,000通程度メールが送れるようになります。その間、Amazon SESはそのユーザから送られるメールについて高品質なメールを送りつづけているか評価し、制限の緩和を判断するようです。
(参考:http://docs.amazonwebservices.com/ses/latest/DeveloperGuide/)

これらのことを実施することにより、Amazon SES自体から発信されるメールが各ISPのブロックにかからないようになり、高い配信性能が保たれるということのようです。

■ 他サービスとの比較や気になる点

Amazon SESは「開発者のみなさんも品質向上に協力してね!」という姿勢が他社のサービスと比較すると強く感じます。セルフサービス要素が強い感じ。

国内にある他のメール配信サービス業者などでは、基本的には法人による契約なので、Amazon SESと同様の取り組みなどは必要ないのだと思います。

他のメール配信業者はより高価ですが、配信性能だけではなく、開封情報の取得や不達の管理や、ドコモ等キャリアへのメール配信など、Amazon SESにはない機能も備えているので、実は単純には価格では比較できるものではなく、それぞれの用途によって使い分けましょう、という話になるのかと思います。当たり前ですが。

実運用を見据えると、やはり国内用途ではドコモ、au、ソフトバンクの携帯メールへの配信は大丈夫かな、というのが気になります。たとえば、配信性能は満たしたとしても、配信の高速化(並列化)などはどれくらいできるのだろうか、、、など。機会があったら調べてみたいと思います。

■ まとめと次回

Amazon SES自体はまだベータ版で、導入例などもどれくらいあるかわからないので、当社でも実戦投入はまだ先なのかなとは思いますが、初期費用なく、ランニングも少ない、そして簡単なAPIで使え、配信性能もよい、ということでいつか実戦投入を模索したいな、と思います。

次回は実際にAmazon SESのAPIを使ってプログラミングをしてみたまとめなどを書きたいと思います。

■ おまけ ~中途採用のお知らせ~

フレクトではAWSやSalesforceを使ったソリューション事業の拡大をしております。クラウド環境を使った開発に興味がある人はぜひご連絡いただければと思います。以下、採用ページです。

http://www.flect.co.jp/recruit/index.html

2011年8月10日 (水)

PythonでのAmazon S3プログラミング

ちょっとした事情があり、PythonでAmazon Web Servicesを操作するプログラムを作ることになりました。PythonでAWSを操作するにはbotoがよさそうです。

PythonでAWSプログラミングの手始めにメジャーなサービスであるAmazon S3でbotoの使い方を学習してみました。

■ botoについて

botoはAWSの公式SDKではありませんが、以下のAWSのAPIに対応したライブラリです。

  • Simple Storage Service (S3)
  • SimpleQueue Service (SQS)
  • Elastic Compute Cloud (EC2)
  • Mechanical Turk
  • SimpleDB
  • CloudFront
  • CloudWatch
  • AutoScale
  • Elastic Load Balancer (ELB)
  • Virtual Private Cloud (VPC)
  • Elastic Map Reduce (EMR)
  • Relational Data Service (RDS)
  • Simple Notification Server (SNS)
  • Identity and Access Management (IAM)
  • Route53 DNS Service (route53)

公式SDKに迫るような対応サービスの多さですね。
それだけではなく、Google Storageにも対応しています。PythonとGoogle関連サービスとの相性がよいからでしょうか...。単純にS3とインタフェースが近しいからというのもありそうですが。

まあ、とにかくしっかりAWSプログラミングができそうなライブラリです。

■ botoインストール

Linux、Mac OS Xなどではeasy_installがあれば以下のような感じで簡単インストールです。オススメです。

% sudo easy_install boto

あるいは、ここからダウンロードして、展開して
以下のような感じでインストールでもよいかと。(easy_installつかったほうが簡単だと思いますが・・・)

% wget http://boto.googlecode.com/files/boto-2.0.tar.gz
% cd boto-2.0
% sudo python setup.py install

■ S3への接続とアクセスキー、秘密キーについて

環境変数としてAWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEYをあらかじめセットしておけばプログラム中にアクセスキー、秘密キーを記述する必要はありません。以下のような感じで接続できます。

from boto.s3.connection import S3Connection
conn = S3Connection() # プログラム中にキー情報は書かない

もし、プログラム中に記述する場合は以下のようにAWSとのAWSAuthConnectionを継承したクラス(この場合S3Connection)のインスタンスを作成するのですが、そこで引数にキー情報を入れます。

from boto.s3.connection import S3Connection
conn = S3Connection('アクセスキー', '秘密キー')

■ バケット情報取得とバケット作成

すべてのバケット情報を取得して、バケット名を出力すると以下のような感じになります。簡単ですね。

from boto.s3.connection import S3Connection

conn = S3Connection()

# すべてのバケットを取得する。
buckets = conn.get_all_buckets()

# バケット名出力
for bucket in buckets:
    print bucket.name

続いて、バケットの有無を判定して、あればバケットオブジェクト取得、なければバケットオブジェクトを作成する、というのは以下のようにすれば動きます。ちなみにバケットのリージョンは東京リージョンを指定しています。

bucket_name = 'flect-bucket-tokyo'

# バケットがあるかどうかを調べる、なければ作成する。
if bucket_name in conn:
    bucket = conn.get_bucket(bucket_name)
else:
    bucket =  conn.create_bucket(bucket_name, location=Location.APNortheast) # 東京リージョン指定

補足ですが、リージョン情報を取得するのは以下のように書けばできます。

from boto.s3.connection import Location
print dir(Location)
# 出力例→ ['APNortheast', 'APSoutheast', 'DEFAULT', 'EU', 'USWest', '__doc__', '__module__']

■ オブジェクトの作成と削除

続いて、先ほど作成したバケットにオブジェクトを出し入れしてみます。
まずは単純なテキストから。以下のように出し入れできます。

# キーからオブジェクトの取得/保存操作には以下のインポートが必要
from boto.s3.key import Key

# 中略

k = Key(bucket)
k.key = 'text_content' # キー指定
k.set_contents_from_string('text content') # テキストをオブジェクトとして保存
text_content = k.get_contents_as_string()  # 保存したオブジェクトのテキスト取得

また、ファイルとしてアップロード/ダウンロードも簡単です。
以下はローカルの画像ファイルをアップし、別名でダウンロードする例です。
(bucketはバケットオブジェクトが取得されているものとします)

# ファイルをS3に保存する
k = Key(bucket)
k.key = 'sample_image.jpg'
k.set_contents_from_filename('./sample.jpg')

# ファイルをS3から取得して、指定したファイル名に保存
k.get_contents_to_filename('./download.jpg')

■ まとめと次の課題

内容が著しく浅い、という感はぬぐえないですが、今回はPythonでAWSを触る感触を学習してみたかった、ということでS3を操作するプログラムを通してbotoの使い方になじんでみました。

よく使っているからという理由でS3から学習してみたのですが、今回はAmazon SESなどほかに動かしたいサービスのウォーミングアップなので次回以降いろいろなサービスを動かしてみたいと思います。

採用情報

株式会社フレクトでは、事業拡大のため、
・Salesforce/Force.comのアプリケーション開発
・HerokuやAWSなどのクラウドプラットフォーム上での
Webアプリケーション開発
エンジニア、マネージャーを募集中です。

未経験でも、これからクラウドをやってみたい方、
是非ご応募下さい。

フレクト採用ページへ

会社紹介

株式会社フレクトは、
認定コンサルタント
認定上級デベロッパー
認定デベロッパー
が在籍している、セールスフォースパートナーです。
また、heroku partnersにも登録されています。
herokuパートナー
株式会社フレクトのSalesforce/Force.com
導入支援サービス
弊社の認定プロフェッショナルが支援致します。
・Visualforce/Apexによるアプリ開発
・Salesforceと連携するWebアプリ開発
も承っております。
セールスフォースご検討の際は、
お気軽にお問合せください。

2024年3月

          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
ブログ powered by TypePad