RubyでConoHaオブジェクトストレージの使用率を監視

こんにちは、虎の穴開発室です。

弊社の一部サービスではストレージとしてConoHaオブジェクトストレージを利用していますが、日々運用しているとログファイルなどが溜まったりして、いつの間にかストレージのディスク容量が枯渇する可能性があります。
ConoHaのコントロールパネルにてディスク容量は確認出来ますが、毎日確認するのも大変です。
そこで、ConoHaが提供しているAPIでディスクの使用率を取得し、Slackに通知する仕組みをRubyにて作ってみました!

ConoHa のAPIドキュメントは、以下にて公開されています
https://www.conoha.jp/docs/

処理の流れ

  • Identity APIを使用して、トークンIDを発行する
  • ObjectStorage APIを使用してオブジェクトストレージの使用率を割り出す
  • Slackに通知する

▪️Identity APIを使用して、トークンIDを発行する

まず、APIにてオブジェクトストレージの情報を取得する為には、
トークンIDの発行が必要ですので、Identity APIを使用して、トークンIDを発行します。
またIdentity APIには、APIユーザー名とAPIユーザパスワードとテナントIDが必要になります。
テナントIDは、ConoHaのコントロールパネルにて確認出来きます。
f:id:toranoana-lab:20180405192114p:plain

トークンIDは、APIのレスポンスbodyの access > token > id にて取得出来ます。
またトークンIDは、発行してから24時間が有効期間です。

require 'net/https'
require 'uri'
require 'json'

# ConoHaAPI ユーザー名
CONOHA_API_USER = '*****'.freeze
# ConoHaAPI ユーザーパスワード
CONOHA_API_KEY = '*****'.freeze
# ConoHaAPI テナントID
CONOHA_API_TENANT = '*****'.freeze
# ConoHaAPI Identity API (トークン発行)
CONOHA_API_TOKEN_URL = 'https://identity.tyo1.conoha.io/v2.0/tokens'.freeze
# ConoHaAPI ObjectStorage API
CONOHA_API_STORAGE_URL = 'https://object-storage.tyo1.conoha.io/v1/nc_'.freeze

def conoha_api_token
  # アクセスするためのURLを生成
  uri = URI.parse(CONOHA_API_TOKEN_URL)
  https = https_config(uri)
  req = Net::HTTP::Post.new(uri.path)

  req.body = JSON.generate(api_param)

  # リクエスト送信
  res = https.start do |x|
    x.request(req)
  end

  # 取得したJSON形式のレスポンスをオブジェクトに変換
  JSON.parse(res.body)['access']['token']['id']
end

def https_config(uri)
  # HTTPSを使うための設定
  https = Net::HTTP.new(uri.host, uri.port)
  https.use_ssl = true
  https.verify_mode = OpenSSL::SSL::VERIFY_NONE
  https
end

def api_param
  # 送信するパラメータを設定
  {
    'auth' => {
      'passwordCredentials' => {
        'username' => CONOHA_API_USER,
        'password' => CONOHA_API_KEY
      },
      'tenantId' => CONOHA_API_TENANT
    }
  }
end

▪️ObjectStorage APIを使用してオブジェクトストレージの使用率を割り出す

上記にて取得したトークンIDを使用して、ObjectStorage APIにて
実際にオブジェクトストレージの情報を取得します。

def storage_capacity(api_token)
  # アクセスするためのURLを生成
  uri = URI.parse(CONOHA_API_STORAGE_URL + CONOHA_API_TENANT)
  https = https_config(uri)
  req = Net::HTTP::Get.new(uri.path)

  req['Accept'] = 'application/json'
  # トークンIDを設定
  req['X-Auth-Token'] = api_token

  # リクエスト送信
  res = https.start do |x|
    x.request(req)
  end
  calculate_usage(res)
end

APIのレスポンスヘッダの中に
[x-account-meta-quota-bytes] ディスク容量
[x-account-bytes-used] ディスク使用量
が含まれていますので、それを使って使用率を算出します。

def calculate_usage(res)
  # 使用率を算出
  used_storage = res['x-account-bytes-used'].to_i / 1_073_741_824
  max_storage = res['x-account-meta-quota-bytes'].to_i / 1_073_741_824
  proportion = ((used_storage.to_f / max_storage.to_f) * 100).round

  # Slackに通知するメッセージを整形
  message_header = if proportion >= 80
    # ディスク使用率が80%以上に達した時は、メンション付きで、さらに強調して通知
    %(<!here>*【現在、ConoHaのディスク容量が少なくなってきています!対応をお願いします!!】*)
  else
    %(【現在のConoHaのディスク容量をお知らせします】)
  end

  %(#{message_header}
    容量: #{max_storage} G / 使用中: #{used_storage} G
    *使用率: #{proportion} %*)
end

▪️Slackに通知する

最後に、ディスク使用率など監視情報をSlackに通知します。
上記にてSlackに投げるメッセージ本文は用意してあるので、
あとはそれをSlackのWebhook URLに投げます。

Webhook URLの取得方法は、以下の記事を参考にして下さい。
toranoana-lab.hatenablog.com

# Webhook URL
SLACK_HOOK = 'https://hooks.slack.com/services/*****/*****/*****'.freeze

def send_slack(message)
  uri = URI.parse(SLACK_HOOK)
  payload = {
    text: message
  }
  Net::HTTP.post_form(uri, payload: payload.to_json)
end

上記メソッドを次の通りに呼べば、
オブジェクトストレージの使用率を監視プログラムの完成です。

api_token = conoha_api_token
message = storage_capacity(api_token)
send_slack(message)

これを実行すると以下の通り、ディスク容量情報をSlackに通知してくれます。
・通常の場合
f:id:toranoana-lab:20180405202344p:plain
・閾値を超えた場合
f:id:toranoana-lab:20180406110448p:plain

あとはこのRubyプログラムをcronに設定すれば、定期自動監視も可能になります。
これで夜も安心して眠れますね。

また、今回のソースコードは以下にて公開していますので、ぜひご参考にして下さい。
github.com


虎の穴では、現在エンジニアの仲間を絶賛募集しています。
Rubyを使ったシステム開発も多数ありますので、
興味を持っていただけた方はぜひ弊社の採用情報をご覧下さい。

www.toranoana.jp

Kotlin 勉強会第2回を開催しました

みなさんこんにちは。虎の穴開発室です。

3/29(木)に「オタク×Kotlin勉強会(第2回)」を開催しました。

勉強会ではアニメ一覧を表示する Web アプリケーションの作成をハンズオン形式で実施し、社外からも12名の参加者にお越しいただきました。

yumenosora.connpass.com

詳しい内容は SlideShare にアップしています。

また、勉強会の題材として使ったソースコードは以下にございますので、自主学習等にご活用ください。

github.com

当日の雰囲気

f:id:toranoana-lab:20180402194716j:plain

f:id:toranoana-lab:20180402182607j:plain

駄菓子等は過去の勉強会( Python勉強会第2回を開催しました - 虎の穴 開発室ブログ )に引き続き スーパーポテト秋葉原店 さんの5Fで購入しました。

今後の勉強会について

虎の穴開発室では今後も様々な勉強会を企画していきます!

yumenosora.connpass.com

「ユメノソラホールディングス(とらのあな)」グループに入っていただくと、新しい勉強会が追加された際に通知されます。

ご興味ある方は是非ご参加をお願い致します!


最後に、虎の穴では一緒に働く仲間を絶賛募集中です。

弊社では一部プロジェクトで Kotlin を採用中ですので、興味を持っていただけた方は是非弊社の採用情報をご覧下さい。

www.toranoana.jp

第1回アキバエンジニア懇親会を開催しました

みなさんこんにちは、虎の穴開発室です。

先週木曜日(3/1)にアキバエンジニア懇親会と題して秋葉原のエンジニア界隈を盛り上げるべく、とらのあな秋葉原C店イベントスペースにて懇親会を開催しました。

懇親会では秋葉原近辺で勤務している方、秋葉原勤務に興味がある方、秋葉原によく行く方など対象者を狭めましたが、約40名の方に参加いただけました。

yumenosora.connpass.com

懇親会の様子

懇親会では歓談だけでなく6名の方にLT発表いただきました。「炎上しないための利用規約」や「どうぶつの森 ポケットキャンプのフレンド登録自動化」などオタクなLTをしていただき盛り上がりました。

発表者の方にはこの場をお借りしてお礼申し上げます。

以下が発表の様子です(顔が写っているのは弊社社員です)

f:id:toranoana-lab:20180306191251j:plain

エンジニア懇親会ではお馴染み(?)のピザと寿司で歓談しました。歓談中は今期のアニメ、オタクなサービス、好きな漫画などなど、秋葉原ならではの話題で盛り上がっていました。

f:id:toranoana-lab:20180306191802j:plain 
その他いくつか企画も行いました!

  • 弊社とらのあな開発室の紹介
    ※詳しく知りたい方は以下記事をご覧ください。

    toranoana-lab.hatenablog.com

  • LT発表(6名、前述の通りです)
  • 宣伝用の同人誌コーナー設置
    参加者の同人誌、技術書、自社パンフレットを自由に置いて宣伝できるスペースを設置しました。デブサミや説明会等でも配布している、弊社オリジナルステッカーの配布も行いました(写真はデブサミ2018出展時のものです)。

    f:id:toranoana-lab:20180221140934p:plain

  • くじ引き大会!
    弊社サービス「とらのあなクラフト」で制作したタペストリーやマグカップなどのグッズが全員に当たるくじ引き大会を行いました。 とらのあなクラフトは、イラストが1枚あればオリジナルグッズを作成して購入や販売ができるサービスです。写真のようなクッションカバーなどさまざまなグッズを制作することが可能です。

    f:id:toranoana-lab:20180306195850p:plain

次回予告! 

…と言いたいところですが、6月くらいに第2回の開催を検討中です。次回開催決定時にもconnpassで告知しますので、「ユメノソラホールディングス(とらのあな)」へメンバー登録いただけますと幸いです。

Developers Summit 2018 出展レポート

こんにちは、虎の穴開発室です。

弊社は先週の2/15(木)から2/16(金)にかけて行われたDevelopers Summit 2018 (デブサミ 2018)にて、ブース出展とランチセッションでの発表を行いました。本ブログでは、ブースや発表の様子を紹介したいと思います。

ランチセッションの発表

ランチセッションでは、「ゼロから始めるエンジニア採用。虎の穴が0人から10人の仲間を集めるまで」と題して弊社エンジニアより発表を行いました。ランチセッションはおかげさまで満員となり盛況でした。詳しい内容は動画とスライドをアップしていますのでそちらを参照下さい。

動画:

vimeo.com

スライド:

www.slideshare.net

 

ブースの様子

弊社ブースも盛況いただきました。ランチセッションを聞いた方、虎の穴が出展!?と聞いた方などさまざまな方にお越しいただきました。

弊社が言うのも何ですが、デブサミでは異彩を放つブースになりました。

f:id:toranoana-lab:20180221140440p:plain

「オタクなエンジニア、募集してます。」

f:id:toranoana-lab:20180221140709p:plain

とらのあなCMも放映しました。

f:id:toranoana-lab:20180221140814p:plain

ブースでは激萌えステッカーや…

f:id:toranoana-lab:20180221140934p:plain

1、2日遅れのバレンタインチョコも。

f:id:toranoana-lab:20180221141013p:plain

採用案内のパンフレットも配布しました。

f:id:toranoana-lab:20180221193842j:plain

ジョブボードにもチラシを貼りました。

f:id:toranoana-lab:20180221141122p:plain

以下は弊社公式Twitterのツイートです。

まとめ

今回のデブサミでは多くの方にセッションを聞いていただいたりブースにお越しいただいたり、一企業として、微力ながらエンジニア界隈を盛り上げる一助になれたのではないかと思っています。今後も弊社はイベントへのスポンサー出展などを通し、エンジニアコミュニティへの貢献を行っていく予定です。

また、デブサミではアキバエンジニア懇親会、勉強会、説明会の募集も告知させていただきました。特に3/1(木)に開催するアキバエンジニア懇親会は多くの方にお越し頂けると幸いです。申し込みは以下ページからお願いします。それ以外の勉強会・説明会もconnpassの「ユメノソラホールディングス(とらのあな)」から申し込みが可能です。

yumenosora.connpass.com


最後に、虎の穴ではエンジニアをはじめとして一緒に働く仲間を絶賛募集中です。興味を持っていただけた方はぜひ弊社の採用情報をご覧下さい。

www.toranoana.jp

Ruby on RailsにおけるreCAPTCHAの実装

こんにちは、虎の穴開発室です。

 

本日はRuby on Railsにおける「reCAPTCHA」(リキャプチャ)の導入方法をご紹介します。

 

reCAPTCHAって?

Googleが提供する、送信者のBOT判別を行うシステムです。

BOT判別というと、従来は文字がぐにゃっとしたものを入力させる型(CAPTCHA)が主流でした。皆さんもあのシステムを利用されたことが一度はあると思います。あのぐにゃっとした文字ですが、人間でも判別できなかったりしますよね。何度打ち込んでも認証を通らない…なんてことを皆さん経験されているのではないでしょうか。

そんな中、新たにGoogle社から提供されたシステムが「reCAPTCHA」です!なんとあのややこしい文字判別が不要!クリックをするだけでBOT判別を行ってくれる素晴らしいシステムです。この画期的なreCAPTCHAですが、なんと無償で提供されているのです。

f:id:toranoana-lab:20180205001537p:plain

 

reCAPTCHAの導入準備

まずはreCAPTCHAのAPIを利用するために、ユーザ登録をする必要があります。ユーザ登録は以下のページから行えます。

reCAPTCHA: Easy on Humans, Hard on Bots

まずは画面右上の「Get reCAPTCHA」をクリックします。以下のボタンです。

f:id:toranoana-lab:20180204120528p:plain

 次に入力フォームから必要な情報を入力します。リキャプチャを導入するサイトの情報ですね。

f:id:toranoana-lab:20180204120819p:plain

これで登録を行うと、リキャプチャを使用する準備が整います。「Site key」と「Secret key」が発行されますので、この情報を大事に保管しておきましょう。

なお、ここで設定するドメインによって、keyの値が変わります。ローカル環境で動作させる場合には「localhost」によって取得する必要がありますので、要注意です。

 

f:id:toranoana-lab:20180204121226j:plain

Ruby on Railsで使ってみる

リキャプチャを簡単に扱えるGemが公開されていますので、インストールしましょう。

gem "recaptcha", require: "recaptcha/rails"
bundle install

Gemの詳細はこちらをご覧ください。

 

1.設定

config/initializers/recaptcha.rb に設定ファイルが作成されていますので、その内容を編集します。

ここで先ほど取得した「Site key」と「Secret key」を入力します。それぞれ「config.public_key」と「config.private_key」に設定します。

Recaptcha.configure do |config|
  config.public_key  = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  config.private_key = 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'

end

 

2.Viewの編集

さて続きましてViewの方はというと…

<%= recaptcha_tags %>

なんとこれだけです。リキャプチャを挿入したい場所に、上記のタグを入れてください。なお、上記タグを利用するには、環境変数に以下の定義がされている必要があります。

RECAPTCHA_SITE_KEY='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
RECAPTCHA_SECRET_KEY='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'

環境変数の設定を忘れないようにしましょう。

 

3.Controllerの編集

Viewは簡単だったから、Controllerは複雑なんでしょう…?

if verify_recaptcha
	# 正常時に実行する処理
end

 なんとこれだけです。リキャプチャが正常の場合はverify_recaptchaがtrueで返されますので、その後の処理を記述しましょう。

 

以上で、簡単にリキャプチャ処理が実装できてしまいました。うーん、シンプルでとても良いですね。

 

4.リキャプチャ処理の完了を待つ

さて、以上でリキャプチャ処理が実装できましたので、虎の穴開発室内でテストプレイをしてみました。するとなんと…「リキャプチャ失敗するんだけど!」という声が一部の人から上がるではありませんか。話を聞いてみると、一刻も早くsubmitをしたいがために、リキャプチャのチェック部分をクリックしてからすぐに他のボタンを押していたようです。

リキャプチャの応答が返されるまでは若干かかりますので、その一瞬をついて、リキャプチャ完了前にsubmitしてしまうわけですね。これは困ります。何か抑止する方法はないかなーと思いGemのREADMEを読んでいると、いいものがありました。今回使用したGemですが、リキャプチャ処理が完了した時点で、javascriptのfunctionをコールバックできるようです。

Viewのソースを以下のように書き換えます。

<%= recaptcha_tags callback: 'recaptchaCallbackFunction' %>

あわせて、「recaptchaCallbackFunction」というfunctionを記述しておきます。これにより、リキャプチャ完了時に「recaptchaCallbackFunction」がコールされることになります。

あとは簡単ですね。submitをするボタンをまずは非活性(disabled)にしておき、コールバックファンクションの中で活性化してあげればよいのです。これによって、せっかちな人でも、リキャプチャ完了前にsubmitしてしまうなんとことがなくなりました。

 

いかがでしたでしょうか。BOTを判別するリキャプチャ処理、こんなにも簡単に実装できてしまうんですね。

機会がありましたら是非ご活用ください。

Python勉強会第2回を開催しました

みなさんこんにちは。虎の穴開発室です。

1/30(火)にオタク×Python勉強会第2回と題して、WebフレームワークのDjangoでアニメ一覧を表示するシンプルなサイトをハンズオンで構築するという勉強会を開催しました。

社外からも10名ほどの参加者にお越しいただきました。

yumenosora.connpass.com

詳しい内容はslideshareにアップしていますのでご参考に下さい。

www.slideshare.net

 

また、勉強会の題材として使ったソースコードは以下に保管してありますのでそちらも参考に下さい。※CSSが最小限だったりテンプレートをべた書きしているなど、変更すべき点がいくつかありますがご容赦下さい。

github.com

勉強会の雰囲気

ゆる〜い勉強会を目指し、駄菓子を用意して休憩時間や演習の時間は参加者が自由に食べながら作業したり質問したりという会になりました。駄菓子は虎の穴開発室のインスタにもアップしています。

ちなみに駄菓子は主にスーパーポテト秋葉原店さんの5Fで購入しました。昔ながらの駄菓子屋さん風コーナーがあり楽しみながら買えます。品揃えは某アニメを参考にしています。

今後の勉強会について

虎の穴開発室では今後、社外の方も参加可能な勉強会をいくつか企画しています。

  • 2/20(火) Kotlin勉強会
  • 2/22(木) Pythonもくもく勉強会
  • 2/28(水) オタク×Node.js勉強会

yumenosora.connpass.com

すべて定員以上の申込みをいただいておりキャンセル待ちになりますが、ご興味あればお気軽に申し込み下さい。 


最後に、虎の穴では一緒に働く仲間を絶賛募集中です。興味を持っていただけた方はぜひ弊社の採用情報をご覧下さい。

www.toranoana.jp

delayed_jobの死活を監視して自動で再起動させる

こんにちは、虎の穴開発室です。

Railsでバックグラウンドで非同期処理を行う一般的な方法として、delayed_jobがよく使われます。このdelayed_jobにちょっとした工夫を加えることで、実運用を想定した以下要件を満たすことができます。

要件

  • メール送信とバッチ処理などdelayed_jobプロセスを分割する
  • delayed_jobプロセスの死活を監視し、死んでいたら再起動する
  • 再起動の結果をslackに通知する

メール送信とバッチ処理などdelayed_jobプロセスを分割

メール送信とバッチ処理など複数の性質の異なるジョブを1つのdelayed_jobで実行すると、バッチ処理が終わるまでメール送信ができない状態になってしまいます。そんな時は名前付きキューを利用してジョブの種類ごとに名前を付け、さらにその名前ごとにdelayed_jobのプロセスを割り当てると便利です。

名前付きキューを利用してジョブを登録: 

object.delay(:queue => 'mail').my_method

delayed_jobの起動:

cd /home/my_user/rails_app
bin/delayed_job -i 1 --queue=mail start 

iオプションででこのdelayed_jobを一意に示す数値、queueオプションでこのdelayed_jobが引き受けるジョブを指定しています。起動すると以下のようになります。

ps aux|grep delayed
(略) ... 6:11PM 0:00.36 delayed_job.1

注意として、statusを見る際にはidentifierの指定が必要です。

cd /home/my_user/rails_app
bin/delayed_job -i 1 status
delayed_job.1: running [pid 30499]
bin/delayed_job status
delayed_job: no instances running

delayed_jobプロセスの死活を監視し、死んでいたら再起動する

delayed_jobが予期せぬ理由で死亡した場合に備え、プロセスの死活を監視して、死亡時には再起動をかけられるようにします。

方法としては対象のdelayed_jobのプロセス数を定期的に取得し、0だったら再起動をかけます。プロセス監視ツールなどを使う方法もありますが、今回はシンプルにシェルスクリプトをcronに登録する実装としました。※以下の例はidentifierが1のdelayed_jobの場合です

#!/bin/bash

count=`ps -ef | grep "delayed_job.1" | grep -v grep | wc -l`
if [ $count = 0 ]; then
  cd /home/my_user/rails_app
  RAILS_ENV=production bin/delayed_job -i 1 --queue=mail restart
  after_count=`ps -ef | grep "delayed_job.1" | grep -v grep | wc -l`
  if [ $after_count = 0 ]; then
    # 再起動失敗
  else
    # 再起動成功
  fi
else
  echo "OK. mail delayed_job is running"
fi

上記をcronに追記します。

*/5 * * * * /bin/bash -l -c 'RAILS_ENV=production /home/my_user/rails_app/scripts/monitor_delayed_job.sh >> /home/my_user/rails_app/log/monitor_delayed_job.log 2>&1'

再起動の結果をslackに通知する

再起動が発生するということは何らかの原因でプロセスが死んだということですので、その時はすぐわかるようslackに通知をしておきます。

slackへの通知は事前にincoming webhookの設定が必要ですが、以下記事を参考に下さい。

toranoana-lab.hatenablog.com

Webhook URLを発行したらそのURLへPOSTでリクエストを行います。まとめると、スクリプトは以下のようになります。

#!/bin/bash

count=`ps -ef | grep "delayed_job.1" | grep -v grep | wc -l`

if [ $count = 0 ]; then
  cd /home/my_user/rails_app
  RAILS_ENV=production bin/delayed_job -i 1 --queue=mail restart
  after_count=`ps -ef | grep "delayed_job.1" | grep -v grep | wc -l`
  if [ $after_count = 0 ]; then
    msg="本番のxxxサーバでdelayed_jobが起動していません。再起動も失敗しました。"
  else
    msg="本番のxxxサーバでdelayed_jobが起動していません。再起動が完了しました。"
  fi
  echo $msg
  curl -XPOST \
    --data-urlencode "payload={'channel': '#test',
    'username': 'xxxサイト監視bot',
    'link_names' : 1 ,
    'text': '@channel ${msg}' }" \
    https://hooks.slack.com/services/xxxxxxxx
else
  echo "OK. mail delayed_job is running"
fi

以上で後はプロセス死亡時に以下のような通知が来ます。

f:id:toranoana-lab:20180126114746p:plain

通知自体はインシデントなので真面目ですが、せめてアイコンだけでも可愛くしています。

最後に

今回紹介したスクリプトは実サービスでも運用しています。今のところは日陰者ですが、Webサービスとしてはそのほうがありがたいですね。 

 


虎の穴では一緒に働く仲間を絶賛募集中です。興味を持っていただけた方はぜひ弊社の採用情報をご覧下さい。

www.toranoana.jp