Hatena::ブログ(Diary)

130単位

2013-07-06

フィリピンでMinaの開発者と会いました

Mina

約1年前にデプロイツールCapistranoの対抗として登場したMina。自分も少しだけ使ったことがありました。ただ最近は開発がアクティブでなかったため、Capistranoでいいじゃんとツイートしたこともありました。そんなMinaフィリピン発なんですね。

で、自分が今フィリピンにきていて、Minaを現地エンジニアとの話のきっかけにしたりも何度かしました。そして開発者の GitHub followers が500超なのを見るに、Nadareiというチームはおそらくフィリピンで一番いけてるエンジニア集団なのではないかと勝手に想像してました。そんないけてる開発者と、あわよくば会えたりしたらいいなあと思っていました。

Manila.js meetup

Mina開発者が発起人でもあるManila.jsというコミュニティ。月イチでミートアップを開いていて*1、たまたま当日の開始1時間前に気づくことになったんですね。

Manila.js JavaScript meetup 016

チケットはSOLD OUTだったんですが、インターンの縁を利用して参加可能か確認して、勢いで参加してみました。バスとジプニーを計4台乗り継いでなんとか辿り着いたときには既にイベント終了間際でした。発起人 @rstacruzJSクイズを出してノベルティをプレゼントしてました(jQueryの最新バージョンは?とかEmber.jsの開発者は?とか)。

f:id:deeeki:20130705045610j:image

Recorded videos

Talking w/ authors

イベント終了後、これまたありがたいことにインターンエンジニア仲介してもらって、@rstacruz 、そしてチームメンバーでMinaメイン開発者である @mikong と話すことができました。

  • 忙しかっただけで開発意欲はあって、つい最近Issue処理を再開したこと
    • "please be patient" といわれた
  • submodule対応のpull reqを送ったことがあること
  • 本番環境で使っているか?と聞かれて、いや趣味でだと答えたこと*2
  • チームでは基本的にRailsアプリを開発していること
    • でも最近はアプリの8割くらいJSを扱ってたりすること
  • どうやってインターン先を見つけたのかということ

衝撃だったのは、"マイナ"だと思っていた読み方が実際は"ミーナ"だったことでした。

それにしても、先にプロダクトの利用、PRがあったのちに、こうしてリアルに海外のエンジニアと会って話せるというのは感慨深いものですね。もっとこういう体験をしてみたいと強く思いました。できればプロダクト提供側としても、というのと、技術的な深い話もできるよう英語力を上げていきたいですね。

JSConf.asia

今年の11/28-29にマニラで開催予定だそうです。興味のある方は行ってみるといいんではないでしょうか!(スピーカーも募集しているみたいです)

関連記事

*1:今月で4回目

*2:実際は既にCapistranoに置き換えたのだけど

2012-12-24

デプロイ用gem CapistranoとMinaの比較

Capistrano

  • 多機能
  • capify -> cap setup -> cap deploy
  • Capfile, config/deploy.rb
  • バージョン管理しない共通ファイル/ディレクトリの管理に一工夫いる
    • symlinkを張るタスクを定義する必要あり
  • バージョン管理しない共通ファイル/ディレクトリは :shared_children 変数で管理できる
  • git以外のSCMにも対応
  • remote-cache strategyは--recursiveなnon-bareリポジトリを保持
    • submodulesがあっても早い
    • scpによるstrategyもある
  • リリースパスにコピーしたあと.gitは消さない
  • リリースのバージョンはタイムスタンプ
  • capistrano-ext gem でマルチステージ対応
  • GitHubのヘルプにあるくらいデファクトともいえる

Mina

  • シンプル
  • mina init -> mina setup -> mina deploy
  • config/deploy.rb のみ
  • バージョン管理しない共通ファイル/ディレクトリの管理が楽
    • shared_paths にパスを配列で指定すれば良い
  • gitのみ対応
  • bareリポジトリを保持
    • submodulesがある場合時間がかかる
  • リリースパスにcloneしてから.gitを消す
  • リリースのバージョンは連番
  • マルチステージ非対応
  • フィリピン マニラ発プロダクト

Mina雑感

導入に関しては特に問題ありませんでした。Capistranoの経験があれば、デフォルトテンプレートを読めばほぼ理解できました。ただでかいsubmodule(WordPress)を含むリポジトリで試してみたのですが、デプロイの度にsubmoduleをcloneするので毎回時間がかかるのがいけてないところです(せっかくなのでPull Request送ってみました *1 )。良く言えば、まだまだこれから進化する余地のあるプロダクトといえます。

  • SCMgitでsubmoduleなし
  • プロジェクトが小規模でデプロイが本番のみ
  • 新しもの好き、Minaパッチを送って使いやすくしたい

このような条件/環境であれば、Minaを使ってみるのもいいかもしれません。そうでなければ、プロジェクト間の統一性の観点から、現状ではCapistranoを使っておいたほうが無難かと思います。

あわせて


4873114934
ウェブオペレーション ―サイト運用管理の実践テクニック (THEORY/IN/PRACTICE)

2012-10-02

CapistranoでローカルからApache設定の更新/反映

LPなどの関係でRewriteRuleをよく追加するようなアプリを運用していて、Apache設定ファイルもリポジトリに含めたいと思ったのがそもそものきっかけでした。それで一度タスクを作って運用していたのですが、いまいちな部分もあったので今回ブラッシュアップしてみました。

環境

旧レシピ

namespace :httpd do
  task :update_conf, :roles => :web do
    run "cp -rf /etc/httpd/conf.d ~/httpdconf_bak"
    sudo "cp -rf #{latest_release}/config/httpd/#{stage}/* /etc/httpd/conf.d/", :pty => true
  end

  after "httpd:update_conf", :roles => :web do
    sudo "/etc/init.d/httpd configtest", :pty => true
    sudo "/etc/init.d/httpd reload", :pty => true
  end
end
仕様
  • config/httpd 以下に設定ファイルを環境ごとに格納
  • アプリ自体をいったんデプロイ
  • cap httpd:update_conf 実行
    • 現在の設定ファイルをバックアップ
    • 最新リリースから設定ファイルをコピー
    • configtestしてreload(configtestでエラー発生したらreloadは実行されない)
課題
  • Apache設定反映のためにリポジトリにcommit/pushされている必要がある
    • ローカルから設定反映して成功したらリポジトリにcommitしたい
  • 環境ごとのディレクトリのため重複が発生している
    • 環境によって変わらない共通な設定は1箇所にまとめたい

で、これらの課題を解決したものをつくってみました。

新レシピ

namespace :httpd do
  namespace :deploy do
    set :local_src_path, "#{Dir.pwd}/config/httpd/conf.d"
    set :remote_src_path, "#{shared_path}/httpd/conf.d"
    set :remote_dest_path, '/etc/httpd/conf.d'

    task :default, :roles => :web do
      transaction do
        on_rollback do
          run "for file in `find #{remote_dest_path} -type l`; do sudo rm $file; done;", :pty => true
          run "rm -rf #{remote_src_path}"
          run "cp -rf #{remote_src_path}.prev #{remote_src_path}"
          sudo "ln -s #{remote_src_path}/*.{conf,passwd} #{remote_dest_path}", :pty => true
        end
        update
        reload
      end
    end

    task :setup, :roles => :web do
      run "mkdir -p #{shared_path}/httpd/conf.d #{shared_path}/httpd/conf.d.prev"
    end

    task :update, :roles => :web do
      #remove old symlinks
      run "for file in `find #{remote_dest_path} -type l`; do sudo rm $file; done;", :pty => true
      #backup old files
      run "rm -rf #{remote_src_path}.prev"
      run "cp -rf #{remote_src_path} #{remote_src_path}.prev"
      #upload new files
      Dir.glob("#{local_src_path}/{*,environments/#{stage}}.{conf,passwd}").each do |file|
        upload(file, remote_src_path, :via => :scp)
      end
      #create new symlinks
      sudo "ln -s #{remote_src_path}/*.{conf,passwd} #{remote_dest_path}", :pty => true
    end

    task :reload, :roles => :web do
      sudo '/etc/init.d/httpd configtest', :pty => true
      sudo '/etc/init.d/httpd reload', :pty => true
    end
  end
end
仕様
app_root/config/httpd/
└── conf.d
    ├── application.conf
    ├── environments
    │   ├── production.conf
    │   ├── production.passwd
    │   ├── staging.conf
    │   └── staging.passwd
    ├── passenger.conf
    └── ssl.conf
  • config/httpd/conf.d 直下に共通の設定ファイル
    • config/httpd/conf.d/environments 以下に環境ごとの設定ファイル
  • cap httpd:deploy 実行
    • WebサーバーのApache設定ディレクトリ内の現在のシンボリックリンクを削除
    • 現在の設定ファイルをバックアップ(1世代のみ)
    • Webサーバーのデプロイ先のsharedディレクトリに設定ファイルをSCPアップロード
    • sharedディレクトリからApache設定ディレクトリにシンボリックリンク作成
    • configtestしてreload
    • タスク実行時にエラーが発生したら前回の設定ファイルを戻す

これで共通部分もDRYにできて、ローカルからの反映が可能になりました。

ファイルごとにシンボリックリンクを張るめんどくさい仕様なのは、Webサーバーのデフォルト状態から極力離れないようにしたいという思いからです(他のアプリの設定ファイルをベタに置くことも考慮して)。シンプルにするなら、設定ファイルを入れるディレクトリをシンボリックリンクにして Include deployed_conf/*.conf などとしたほうがいいと思います。

気になる点としては、もし異なるアプリを同じ仕組みで同じサーバーにデプロイする場合は、アプリ名のプレフィックスなどをつける必要があるというところでしょうか。

わかったこと

  • Capistrano
    • Rails.root は使えないので Dir.pwd でプロジェクトのルートパスを取得
    • タスクをまたいで使いたい変数は set で定義
    • リモートのファイル操作は同じコンテキストのRubyでできないのでしんどい
      • でもワンライナーシェルでがんばればできた
    • on_rollback でエラー時の処理を書ける
      • task内にも書けるが、transactionブロック内にも書ける
  • Apache
  • シェル
    • find -type l でシンボリックリンクの抽出
    • ln -s file.. dir で file.. はワイルドカードでの複数指定可能
    • {a,b} でどちらかにマッチ

Gist

もっとこうしたほうがいいとかあればご指摘いただけると助かります!

参考リンク

2011-12-15

さいきんのRailsアプリで使ったgem 10個

最近は、運用中Railsアプリの管理画面をTwitter Bootstrapでリニューアルしたり、こまごまと機能追加なんかしたりしてました。そんな中で新たに使ったgemライブラリを簡単にまとめてみます。

Prawn

  • no title
    • PDF作成
    • 日本語フォントとあわせて日本語表示も可能
    • 表や図などある程度自由にレイアウトできる
    • prawn-railsというのもさっき見つけた

Haml-rails

erb2haml

  • no title
    • ERBのviewファイルを一括置換
    • Hamlの文法を覚える参考にもなる

Kaminari

  • no title
    • ページネーション
    • will_paginateよりもなんとなくこちら
    • will_paginateよりもプラガブルかつクリーンな作り(と思う)

SimpleForm

  • no title
    • フォーム生成補助
    • 記述は少なく済むけど凝ったレイアウトにはしづらい
    • 管理画面などとは相性良いはず

ShowFor

  • no title
    • 詳細画面生成補助
    • SimpleFormみたいな感じ

jpmobile

  • no title
    • ガラケー/スマートフォン対応
    • Rails3.0系にはjpmobile1系
    • 絵文字も1ソースで3キャリア対応できる

Airbrake

  • no title
    • エラー通知サービス(旧Hoptoad)
    • Egg Plan が無料で1プロジェクト導入可能
    • Capistrano対応
    • 予期しない部分のエラー検知に役立つ

pry-rails

  • no title
    • rails console で pry
    • 今のところカラー表示しかメリット享受してないけどirbよりはいいのかなと

rails_best_practices

  • no title
    • より良いRailsコードへのアドバイス的なツール
    • リファクタリングの指針として有用

Twitter Bootstrap/Haml/SimpleFormなどによる管理画面は、慣れてきたらかなり軽快に開発できた気がします。記述量が少ないおかげで、変更や機能追加にも対応しやすいのがいいと思います。

あと、Airbrakeはおすすめです。


4797363827
Rails3レシピブック 190の技

2011-03-07

AWS EC2 Webサーバーデプロイ用シェルスクリプト

EC2のWebコンソール画面から地道にデプロイするのもしんどくなってきたので、シェルコマンドで自動化を試みてみました。ここでのデプロイという言葉はWebサーバーの資源入れ替えを指してます。

前提

  • Webサーバー複数台でElastic Load Balancingを利用している
  • Webサーバーにセキュリティグループが設定されている
  • Webサーバーの初期実行コマンド(UserData)でデプロイするようになっている
  • EC2のAPIツールが使える
  • ELBのAPIツールが使える

シェルスクリプト

#!/bin/sh

if [ $# -lt 2 ]; then
	echo "Usage: sh deploy.sh (var file) (key file)"
	exit 1
elif [ ! -f "$HOME/aws/vars/$1" ]; then
	echo "var file not found."
	exit 1
elif [ ! -f "$HOME/aws/keys/$2" ]; then
	echo "key file not found."
	exit 1
fi

source $HOME/aws/vars/$1

KEY=$HOME/aws/keys/$2
DESC_CMD="ec2-describe-instances -F group-id=production-web"
INIT_CMD="/usr/bin/wget -q -O- http://169.254.169.254/latest/user-data | /usr/bin/base64 -d -i | /usr/bin/bzip2 -dcq | /bin/sh"
LB="production-lb"

for i in `$DESC_CMD | grep INSTANCE | cut -f2,4 | sed 's/\t/,/g'`
do
	INSTANCE=`echo $i | cut -f1 -d ','`
	HOST=`echo $i | cut -f2 -d ','`
	echo "***Deregistering $INSTANCE"
	elb-deregister-instances-from-lb $LB --instances $INSTANCE
	echo "***Deploying $INSTANCE"
	ssh -i $KEY root@$HOST $INIT_CMD
	echo "***Registering $INSTANCE"
	elb-register-instances-with-lb $LB --instances $INSTANCE
done

つかいかた

export EC2_CERT="$HOME/aws/keys/app/cert-XXXXX.pem"
export EC2_PRIVATE_KEY="$HOME/aws/keys/app/pk-XXXXX.pem"
export EC2_URL="https://ec2.ap-northeast-1.amazonaws.com"
export EC2_REGION="ap-northeast-1"

上記を環境変数定義ファイルに記述して

sh deploy.sh 環境変数定義ファイル SSH秘密鍵ファイル

せつめい

メリット

  • コマンド一発
  • 無停止デプロイ
  • オートスケーリングと共存可能
  • 可変なインスタンスに対応
  • 同じ仕組みの複数の本番環境に対応

デメリット

  • ロードバランサーの追加/削除に時間かかるため一時的に資源の差異が生じる

かなり偏った前提条件と環境ではあると思いますが、とりあえず効率化することができました。とはいえ特にWebサーバーが多いとデメリットも無視できないので、並列処理ができるらしいCapistranoを素直に利用したほうがよさそうな気がします。


4774142840
よくわかるAmazonEC2/S3入門 ―AmazonWebServicesクラウド活用と実践 (Software Design plusシリーズ)

4844329804
Amazon Web Services ガイドブック クラウドでWebサービスを作ろう!