VPSからAmazon S3とGoogle Apps for Businessに移行しました
さくらのVPSで運用していたkatahirado.jp(VALUE DOMAINで取得)を、WebサイトはAmazon S3に、メールはGoogle Apps for Businessにそれぞれ移行しました。
Webサイト、メールサーバの他に、redmine、git、Railsのデモアプリが動いていましたが、
git,redmineはgithubやPivotal Tracker等を使用することにして、既存のデータはとりあえずローカル(MBP)に。
Railsアプリのデモは動かすならHerokuかなと思っていますが、一旦保留としました。
S3とRoute 53,Google Appsでの作業をメモ。
Amazon S3
katahirado.jpはルートドメインでの静的なWebサイトなので、Amazon Route 53を使ってホストする必要がありました。
Amazon S3でのWebサイトですが、基本こちらの通りで。
- http://gatespace.jp/2013/03/05/aws-s3-static-site/
- http://aws.typepad.com/aws_japan/2012/12/root-domain-website-hosting-for-amazon-s3.html
www.katahirado.jpと、karahido.jpのバケットを作成しました。
なのですが、バケットポリシーを追加する時に、AWS Sample Bucket PolicyのWebページが丁度なくなっていたので、AWS Policy Generatorを利用してバケットポリシーを作成しました。*1
Sample Bucket Policiesをクリックするとページがなくなってました。
AWS Policy Generatorをクリック。
Select Type of PolicyをS3 Bucket Policyにして、Principalを*に。
ActionsでGetObjectにチェック。
Amazon Resource Name (ARN)のところはご丁寧に formatが乗っているので、それに合わせて入力しました。
arn:aws:s3:::<bucket_name>/<key_name>
↓
arn:aws:s3:::www.katahirado.jp/*
Add StatementしてGenerate Policyして表示されたものをコピーして貼り付ければOK
Amazon Route 53
Amazon Route 53でDNSの設定をします。ここいらを参考に。
- http://www.keygoal.jp/?p=399
- http://pocketstudio.jp/log3/2012/03/31/migrationg_an_existing_domain_to_route53/
Create Hosted Zoneして出来たNS,SOA以外にkatahirado.jpのA,www.katahirado.jpのCNAMEを追加。
MXレコードはGoogle Apps for Businessがまだ処理し終わっていないので、まだ登録しません。
というか出来ません。
VALUE DOMAINの管理コンソールにいってNSのValueをネームサーバとして登録。
なお、メール等のダウンタイムを極力なくすという意味ではAmazon Route 53→Google Apps for Business→S3とかの流れの方が良かった気がします。
ちなみにGoogle Apps for Businessでの処理で若干手間取って、30分ぐらいメールサーバー的にアレになってたかと。
Google Apps for Business
次、Google Apps for Businessを独自ドメインで設定。
以下が大変丁寧。
Google Apps for Businessのドメイン所有権の確認、MXレコード登録の流れで、Google AppsとAmazonを行ったり来たりして若干混乱したので流れを整理。
Google Apps for Businessの無料トライアル申し込み
↓
ドメイン所有権の確認(Google Apps for Business)
↓
Google Appsの管理コンソールからTXTレコードに設定する値を取得する
↓
Amazon Route53のコンソールで取得したTXTレコードを登録
↓
ドメインの所有権確認終了(Google Apps for Business)
↓
Google Appsの管理コンソールからMXレコードに設定する値を取得する
http://angelndxp.wordpress.com/2012/05/27/amazon-route53%E3%82%92google-apps%E3%81%AEdns%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%A8%E3%81%97%E3%81%A6%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B-%EF%BD%9E%E7%8B%AC%E8%87%AA%E3%83%89%E3%83%A1%E3%82%A4/
↓
Amazon Route53のコンソールでMXレコードの設定を行う
http://angelndxp.wordpress.com/2012/05/28/amazon-route53%E3%82%92google-apps%E3%81%AEdns%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%A8%E3%81%97%E3%81%A6%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B-%EF%BD%9E%E3%83%A1%E3%83%BC%E3%83%AB%E8%BB%A2%E9%80%81/
↓
MXレコードの設定反映完了(Google Apps for Business)
感想
若干手間取りましたが、がっちりサーバを構築するのに比べるとだいぶお手軽。
クラウドもずいぶん環境整ったなとしみじみ。
サーバ運用を自宅サーバ→VPSで長いこと続けてきましたが、もうクラウドでいいですね。
追記: 料金はさくらのVPSが年間一括払いだったので、月924円(4/18現在)。
Google Apps for Businessが年払いで一人利用なので、月500円、AWSは運用してみないとわかりませんが、Route 53は1ゾーンで、S3も大したアクセスでもないので両方で多分200円以内、合わせてもVPSより安くなるかなと想定しています。
*1:一時的な問題だったようで作業翌日には復活していました
WebViewに動的にJSを読み込みした後の評価(実行)タイミングではまった
11/20日追記:SafariとChromeでも試して見たところ、JSでbodyに複数appendChildすると順番は一定しない事を確認。そうだったのか。
http://blog.setunai.net/20120317/javascript%E3%81%AE%E5%AE%9F%E8%A1%8C%E9%A0%86%E5%BA%8F%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/
備忘録。
WebViewは、JSファイルを並列に読み込む。
で、動的に4つくらいJSファイルをbodyの末尾に読み込んでいるが、コードが追加順番に依存しているので、追加した順番に評価してほしいがどうも一定しない。
LABjsやRequireJS等を使うのが良いのだろうが、手っ取り早く、Railsライクに全部のJavaScriptファイルを順番に結合したファイルを作成、読み込むことで解決した。
ただこれをやると開発時に面倒くさくなるので、各JSファイルをちょっと手直しして結合する書き捨てスクリプトをRubyで書いた。
こういった処理は、GoogleのClosure Compilerや、RailsのAsset Pipelineなどを利用するのが標準的か。
しかし今回の場合は、Objective-C側から呼び出している為JS側では呼び出されていないメソッドや、Objective-C側から動的に挿入されているはずのネームスペースのメソッドをJS側から呼ぶといった、変則的なコードが散らばっていたりするという事情があるので、自前の結合スクリプトを用意した。圧縮も勝手にされるとちと困るので。
ファイルのアイコンを取得する
一つ前のエントリーでは端折っていたが、ファイルのアイコンを取得するのが目的で、pathをあれこれやってあれってなったのであんなエントリーを残した。
せっかくなのでアイコン取得もメモ。
pathをStringでアイコン取得する場合。
//_fullPath はこんなのが来てる。 @"file://localhost/directory/index.html"; NSString *filePath = [[_fullPath stringByReplacingOccurrencesOfString:@"file:/localhost" withString:@""] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; return [[NSWorkspace sharedWorkspace] iconForFile:filePath];
とかやる。前のエントリーのは、このケースでいうとfile://localhostを置換しようとしているのに、実際にはここに渡って来る前の文字列生成処理で、file:/localhostが渡ってきてた&decodeも抜けてたという話。
NSURLでアイコンを取得
//_fullPath はこんなのが来てる。 @"file://localhost/directory/index.html"; NSURL *fileUrl = [NSURL URLWithString:_fullPath]; NSImage *image=nil; [fileUrl getResourceValue:&image forKey:NSURLEffectiveIconKey error:NULL]; return image;
file:/localhost状態の文字列をNSURLにして、アイコン取得できなくて、StringでもNSURLでもアイコンが取得出来ないなあと調べたら、file:/localhostになっちゃってるじゃないかというのが、前回のエントリの真相でした。
file://localhost/...を使っているのは、アプリがWebViewメインのものなので、このほうが都合がいいため。
file://localhost/directory/といったURL文字列にstringByAppendingPathComponent:を使うと・・・
やっちゃ駄目って書いてあるからやるほうが悪いんですが・・
stringByAppendingPathComponent:のリファレンスには下記のように書いてあります。
Note that this method only works with file paths (not, for example, string representations of URLs).
file pathsでだけ動くと書いてありますが、表題のようにfile://localhost/....となっている文字列で実行してみると・・・
NSString *baseURLString = @"file://localhost/directory/"; NSString *fullPath = [baseURLString stringByAppendingPathComponent:@"index.html"]; NSLog(@"%@",fullPath); // file:/localhost/directory/index.html
file:/localhost/... というように、file:の後の//が/に削られてしまいます。
stringByAppendingPathComponent:は使用せず、stringByAppendingString:を使うとか、
NSString *baseURLString = @"file://localhost/directory/"; NSString *fullPath = [baseURLString stringByAppendingString:@"index.html"]; NSLog(@"%@",fullPath); // file://localhost/directory/index.html
ただ、stringByAppendingString:を使った場合だと、当然ながらpathを考慮されているわけではないです。
例えばpathComponentsを格納した配列から取り出して、個別に連結するといった場合には"/"を自前処理する必要があります。
文字列に%20であるとかが含まれれば、stringByReplacingPercentEscapesUsingEncoding:も必要です。
NSURLのインスタンスにして処理したほうがいいでしょう。
NSString *baseURLString = @"file://localhost/directory/"; NSURL *baseURL = [NSURL URLWithString:baseURLString]; NSString *fullPath = [[baseURL URLByAppendingPathComponent:@"index.html"] absoluteString]; NSLog(@"%@",fullPath); // file://localhost/directory/index.html
WebViewでsetFrameをアニメーションさせようとしたら記述量が多かった
NSAnimatablePropertyContainer プロトコルのanimatorを使えば下記のような感じに書ける↓
https://developer.apple.com/library/mac/#samplecode/BasicCocoaAnimations/Listings/MainWindowController_m.html
しかしWebViewでanimatorメソッドを使ってみたら、エラーでproxyオブジェクトがselectorを呼べなかった。
ので、下記サイトのようにNSViewAnimationを明示的に生成して処理した。
http://xcatsan.blogspot.jp/2008/12/window_28.html
animatorメソッド使用で、setFrame:display:とか呼ぶ場合は、暗黙的に処理してくれるので、変更前のNSRectとかいらないが、NSViewAnimationでsetFrameをアニメーションさせる場合は、変更前のNSRect,変更後のNSRectをNSValueに変換したやつを用意して,NSViewAnimationStartFrameKey,NSViewAnimationEndFrameKeyをKeyにもつNSDictionaryを生成する必要がある。
記述量がいきなり増えますね。
jQuery の複数バージョンを同時使用する
http://stacktrace.jp/jquery/with_other_lib.html#other_version
noConflictの引数にtrue渡せばいいと。
<html> <head> <script type="text/javascript" src="jquery-1.2.6.js"></script> <script type="text/javascript" src="jquery-1.4.2.js"></script> <script type="text/javascript"> // $ 関数および jQuery関数の上書きを元に戻します。 var $j = jQuery.noConflict(true); // $ は jQuery ver1.2.6を参照します。 alert($.fn.jquery); // => 1.2.6 // jQuery は jQuery ver1.2.6を参照します。 alert(jQuery.fn.jquery); // => 1.2.6 // $j は jQuery ver1.4.2を参照します。 alert($j.fn.jquery); // => 1.4.2 </script> </head> <body></body> </html>
noConflictって他のライブラリとの併用だけでなく、jQueryの複数バージョンもOKだったんですね。
1.8.2で実装を確認してみました。
//............................................ // Map over jQuery in case of overwrite _jQuery = window.jQuery, // Map over the $ in case of overwrite _$ = window.$, //...................................... jQuery.extend({ noConflict: function( deep ) { if ( window.$ === jQuery ) { window.$ = _$; } if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } return jQuery; }, //......................... // Expose jQuery to the global object window.jQuery = window.$ = jQuery; //........................
true渡すと window.$だけじゃなく、window.jQueryも _jQueryに保持されている古いjQueryオブジェクトを参照するようにしてますね。