2012-01-30
■[heroku][cron][gae]herokuのcronを使わず、定期的にmydnsにIPアドレスを通知する。
どうも。
テストが一段落し、heroku とGAE をいじっています。
題名だけではちょっとわけがわからないよ、ということで今開発しているherokuで動作するWebサービスとサーバー構成を。
なぜheroku上で動作しているアプリケーションからmydns(Dynamic DNSサービス)にIPアドレスを通知しないといけないのか。
現段階ではWebサービスをリリースしていないので、ここでは仮にドメインをexsample.comと定義します。
私がやりたいことはこのexsample.comで、herokuで動作するアプリと、自宅のサーバーの2つを同じドメインで、
なおかつサブドメインで振り分けたいわけです。しかも自宅のサーバーは動的なIPで。
まず、自宅サーバーではwebサーバーが稼働しており、プロバイダから配布されているグローバルIPが動的なのでmydnsにIPアドレスを通知し、
IPアドレスが変動しても、ドメインとIPアドレスの結びつきが離れないようになっています。
ドメインを取得したレジストラではmydnsのネームサーバーを指定しており、*exsample.com にリクエストが飛ぶと、
mydnsのネームサーバーに通知してある自宅のサーバーのIPが返って来るようになっています。
まーここまでは普通のDDNSの使い方ですね。
開発しているサービスはheroku上で動作しているので、サブドメインごとにIPを振り分ける必要があります。
hoge.exsample.comはherokuのサーバー、その他は自宅のサーバー、のような感じ。
herokuで独自ドメインを使うには、Aレコードでherokuから指定されたIPアドレスを設定する必要があります。
ところが、mydnsでできる設定がちょっとアレ。
Aレコードは、その通知してきたIPアドレスでしか設定できない模様。多分。
つまり、サブドメインで違うIPにAレコードでは振り分けられない。
そこで、mydnsに用意されているDELEGATE機能を使う。
DELEGATEは、子idを作成し、その子idに通知してきたIPアドレスをAレコードに設定することができる。
つまり、herokuで動作しているアプリケーションからmydnsに設定している子idに対してIPアドレスの通知をしなければいけない。(herokuのね
ということで通知するスクリプトなどを書いた。
まー、こんな事をしなくても*exsample.comはすべて自宅のサーバーに行くので、HTTPのHOSTを見て、hoge.exsample.comだったらherokuのアプリケーションにリダイレクト
させるみたいなこともできますが、一旦自宅のサーバーの経由するので嫌ですね無駄ですね、ってことです。
で、本題。
mydnsにIPアドレスを通知するのは超簡単です。mydnsではPOP3,FTP,HTTP-BASICなどでIPを通知できます。
今回はHTTP-BASICでheroku側から通知させます。urllibを使えば一発。
問題なのは、どのタイミングで通知させるのよってことです。
herokuは固定IPですので、その固定IPをmydnsに設定していればいちいち通知する必要ないんじゃないの?って思うと思います。
しかし、mydnsの制約上、10日(だったかな?)通知がないと、IPアドレスがリフレッシュされてしまうので、接続できなくなります。
ということで、少なくとも10日に一回はheroku側からmydnsにIPアドレスを通知しなければなりません。
となると、やっぱcronかなーってなるわけです。herokuでもcronは使えます。1日一回までは無料で、それ以降は課金。
アドオンを追加するだけなので、簡単ですがクレジットカードの登録が必要です。(無料版でもね!
ですが、今回はherokuのcronは使いません。
調べてみるとherokuのcronはRubyのRakefileが云々..
Ruby?
ああ、Rubyですかそうですか
RubyでもIP通知するくらいなら簡単です。
ですが、できれば開発しているサービスでは1日に2回はcronを動かしたい...、しかし1日1回以上は有料、私は学生お金が無い
じゃどうやって定期的に通知させるの?ってことですが
今回はGAEとherokuを組み合わせて無料で定期的にタスクを実行させるようにします。
GAEのcronは制限はそんなになかったような気がします(よく調べてない
仕組み
とすれば無料で、なおかつpythonで処理が書ける!
Flask側(heroku側)
@app.route("/dns/hogehogehugahugapiyopiyo") #URLはハッシュ化とかしたほうが良いでしょう def dns(): user = "mydns0123456" passwd ="hugahuga" url = "http://%s:%s@www.mydns.jp/login.html" % (user, passwd) urllib.urlopen(url).close() return str("OK")
これで通知側はおわり。
http://hoge.exsample.com/dns/hogehogehugahugapiyopiyo
にアクセスがくると通知する。(hogehogeとか使いすぎて見難いけど
GAEのcron.yaml
cron: - description: cron jobs url:/cron/ schedule: every 12 hours
これで、GAE側の/cron/が12時間起きに実行される。
/cron/には一般ユーザがアクセスできないよう、app.yamlにlogin:adminなどとしておいたほうが良い。
GAEのmain.py
def fetch_url(url, max_times=3, sleep_sec=5): retry_count = 0 success_flag = False while True: f = urlfetch.fetch(url) if f.status_code == 200 or retry_count >= max_times: success_flag = True break else: retry_count += 1 time.sleep(sleep_sec) if success_flag: return "success" else: return "failed"
こんな関数を適当に作って、あとはhttp://hoge.exsample.com/dns/hogehogehugahugapiyopiyoを渡せばいいですね。
まとめ終わり!
なんか頭いい方法あったら優しく教えて下さい。
2012-01-08
2011-12-06
■[セキュリティ]mixi scrap challenge 2011に参加してきました
株式会社mixiさんが主催している mixi Scrap & Buid challenge 2011に参加してきました。
当日の様子→Togetter
どんなイベントか
あまり詳しくは"アレ"なので"アレ"ですが、XSSを主体とした問題が多かったです。
たしか10問くらいの問題があって、時間の都合と技術力の問題で3,4問くらいしか解けなかった。
回答を聞くと「あ〜・・・」ってなったので、頭が硬いんですかね..
まぁ、いずれにせよこれからも勉強を続けたいと思います。
ちょっとした裏話みたいなのも聞けて楽しいイベントでした。
来年、再来年と続くことを期待しています。
mixiさん、参加者皆さんありがとうございました。
※ピザ美味しかったです
2011-11-23
■[python]サーバーでSSHのログイン等があった場合にGrowlに通知を飛ばす
中国からSSHのブルートフォースアタックを受けていたので、なにか通知するようなプログラムを書いてみた。
構成として、サーバーはubuntu,Growlで通知が飛んでくるのはiMacとする。
こんな感じで、iMac側のGrowlには外から通知を受けれる設定にしておく。
SSHサーバーで稼働させるスクリプト
#!/usr/bin/env python import os import re import time import Growl INTER_VAL = 1.0 def get_new_log_file(): p = re.compile("^auth.log") log_path = "/var/log/" log_list = os.listdir(log_path) #get time stamp time_stamp = {} for ll in log_list: #re match if p.match(ll): time_stamp.update({os.stat(os.path.join(log_path, ll)).st_atime:ll}) new_time_stamp = time_stamp[time_stamp.keys()[0]] for ts in time_stamp: if new_time_stamp < ts: new_time_stamp = ts return os.path.join(log_path, new_time_stamp) def check_log(log_file): fp = open(log_file) stat = os.stat(log_file) fp.seek(stat[6]) try: while True: where = fp.tell() line = fp.readline() if not line: time.sleep(INTER_VAL) fp.seek(where) else: yield line except: raise finally: fp.close() class SSHGrowl(object): def __init__(self,message): self.g = Growl.GrowlNotifier( applicationName = 'GrowlPython', notifications = [ 'Demo' ], defaultNotifications = [ 0 ], hostname = 'ip address', password = 'port') self.g.register() self.message = message def run(self): for i in range(3): self.g.notify(noteType = 'Demo', title = '!! WARNING !!', description = self.message, sticky = False) time.sleep(0.25) if __name__ == "__main__": log_file = get_new_log_file() for line in check_log(log_file): i = SSHGrowl(line).run()
- /var/log/から正規表現でauth.logから始まるファイルを取得
- タイムスタンプをみて、最新っぽいauth.logのファイル名を取得
- ジェネレータでそのファイルが更新されたらその内容を出力
- Growlに通知
手抜きで、auth.logが更新されると通知されるので、ログイン、ログアウト、scpとか、なにかSSHで動きがあったときに通知される。
パースして云々すればへんなアクセスが来たときにだけ通知する、ってこともできるけどメンドイのでやってない。
ちなみにiMacに通知が飛んできた時の画像
かっこいいっすね!!!!!1
2011-11-20
■[Webサービス]「この人誰ったー」というWebサービスを作りました。
この人誰ったー
Google App Engine + Pythonで作成しました。
webapp というか、先日作成した自作のフレームワークっぽいのを利用しました。
どんなサービスなのか完結に言うと、ツイッターを利用したクイズゲームです。
一番苦戦したのはTwitterのAPIを利用して、問題を作成する部分でした。
9月の下旬ごろからちまちま作って、11月19日に公開しました。
11月20日(現在)では約1万5000のユーザの方が遊んでくれたみたいで、予想していたよりも多くて嬉しい限りです。
反省点
- 1、「Google App Engineの無料枠で済むだろww」なんて思ってたら1時間で使いきってしまい、1時間ほどサービスがダウンしてしまった。
- 2、memcache を使ってデータストアのアクセスなどを節約した「つもり」でしたが、甘かった。データストアのReadが一番最初に上限を越してしまった。
- 3、静的コンテンツもGoogle App Engineの同じサーバーで配信していた。
一気にリクエストが発生して、ピーク時ではGoogle App Engineのインスタンス数が70近く生成されてましたので、
Google App Engineでやってなかったら普通に落ちてたのかなー...
そろそろ値上げされるみたいなので、負荷分散とかその辺の知識を増やしてVPSかなんかでまたサービス作りたいですね。
