hello-world
webエンジニアのメモ。とりあえずやってみる。

[rails]cap deploy時に複数のAuto Scalingグループにもデプロイしたい

公開日時

先日、AWSのAuto Scallingを使った際に、cap deploy時にAuto Scaleインスタンスにも自動でデプロイできるようにする必要があったので調べたところ、

jq - cap deploy時にAutoScalingで立ってるサーバにも同時にdeployさせる - Qiita

こちらの記事を参考にさせていただき、無事にデプロイを実行することができるようになりました。

その後、また別の機会でAuto Scallingを使ったのですが、この時は SQSを使って、appサーバからbatchサーバに処理を投げるという構成だったので、appサーバとbatchサーバそれぞれにAuto Scalingグループを設定する必要がありました。(batchのほうは Job Observerパターンと呼ばれるそうです)

前回と同様にcap deploy時にAuto Scalingで作成されたインスタンスにもデプロイできるようにしようとしたのですが、ここで問題が発生しました。

前回は1つのAuto Scalingグループのみだったので、起動中のAuto ScalingインスタンスのPrivateIpAddressを取得すればよかったのですが、今回は2つのAuto Scalingグループがあり、appロールとbatchロールに分けてサーバ設定を行う必要がありました。

そこで、まずAuto Scalling グループのタグ設定で、appサーバの場合は「app-auto」、batchサーバの場合は「batch-auto」というNameをつけるように設定しました。

auto2

そして、awsコマンドとjqコマンドを組み合わせて、以下のようなタグ名とipの組み合わせを取得するようにしました。

{
  "ip": "xx.xx.xx.xx",
  "name": "app-auto"
}
{
  "ip": "xx.xx.xx.xx",
  "name": "batch-auto"
}

取得した組み合わせを更に加工してjsonとしてparseできるように変換し、それぞれのタグ名に応じてロールを切り替えるようにしました。

最終的なdeploy.rbは以下のようになりました。

require 'json'

set :stage,          :production
set :rails_env,      fetch(:stage)
set :deploy_to, "/home/app/#{fetch(:application)}/#{fetch(:rails_env)}"

server 'xx.xx.xx.xx', user: 'app', roles: %w{app db}
server 'xx.xx.xx.xx', user: 'app', roles: %w{batch}

def installed?(cmd)
  `which #{cmd.to_s} > /dev/null; echo $?`.to_i.zero?
end

if installed?(:aws) && installed?(:jq)
  instance_ids = `aws autoscaling describe-auto-scaling-instances | jq ".AutoScalingInstances[].InstanceId"`.split("\n")
  if instance_ids.size > 0
    instance_list = `aws ec2 describe-instances --instance-ids #{instance_ids.join(' ')} | jq '.Reservations[].Instances[] | { ip: .PrivateIpAddress, name: (.Tags[] | select(.Key == "Name") | .Value) }'`.gsub(/\s/, '').gsub(/\n/, '').gsub(/}{/, "},{")
    JSON.parse("[#{instance_list}]").each do |instance|
      if instance['name'] =~ /batch/
        eval "server '#{instance['ip']}', user: 'app', roles: %w{batch}"
      elsif instance['name'] =~ /app/
        eval "server '#{instance['ip']}', user: 'app', roles: %w{app}"
      end
    end
  end
else
  puts '[ deploy to autoscaling servers skipped. ]'
  puts 'awscli and jq required. For Mac OS X, try "$ brew install awscli jq"'
end

jqの結果をjsonに変換する部分でgsubを使って力技でなんとかしてしまっているのを綺麗にしたかったのですが、うまくできず。。。

とりあえずはこれで、cap deploy時に複数のAuto Scalingグループにもデプロイできるようになりました。

参考


Related #aws

[aws]s3 lsで取得したファイルを更新日時順でソートする

s3 lsコマンドを利用するとバケットに保存されているファイル情報を取得できます。

AWS SAMを使って署名付きURL発行APIを作る

S3の署名付きURL発行機能の検証を兼ねて、S3のキーをパラメータとして受け取り、署名付きURLを発行するAPIを作ってみました。

s3cmdの設定をプロジェクト毎に管理する

以前、 s3cmdをmacで使う方法 を書きましたが、 プロジェクトごとに異なるバケットを使用している場合は設定ファイルもプロジェクト毎に管理したいです。

[aws]s3バケットにIP制限をかける

s3にはbasic認証を設定することはできないのですが、IP制限なら設定することができます。