Misocaのリゾートワーカーの仕事環境

初めまして。Misocaの大沢( @ooswatech )です。主に開発やデザイン以外の大抵の仕事をしています(職種名なんだろ…🤔🤔🤔名前はまだ無い)。最近は主にMisocaのプロダクトについていろいろ考える仕事をしています。

さて、先週は弊社の @hidakatsuya が、Misocaのリモートワーカーの仕事環境について紹介させていただきました。 tech.misoca.jp ちなみに私も東京(普段は秋葉原にある弥生株式会社にいます)からのリモートワーカーなのですが、この記事に参加させてもらえませんでした、なぜなら…

f:id:oosawatechnica:20170816163608j:plain

🇷🇺ロシア🇷🇺に行っていたからです。

Misocaでは、旅をしながら仕事することも可能です。 今回私は、下記のような形で旅行のスケジュールを立てました。

日付 滞在場所 会社のスケジュール
8月6日(日) 東京⇢ウラジオストク
8月7日(月) ウラジオストク 夏休み
8月8日(火) ウラジオストク 夏休み
8月9日(水) ウラジオストク 夏休み
8月10日(木) ウラジオストク リゾートワーク
8月11日(金) ウラジオストク 祭日
8月12日(土) ウラジオストク⇢東京

10日(木)さえ現地で働けば、ウラジオストクに一週間滞在できるぞ…!!!ということで、今回は海外滞在のうち、1日をリゾートワークの日としてセッティングしました。

早速、Misoca のリゾートワーカーの仕事環境について、Q&A方式でご紹介したいと思います。

リゾートワーク歴を教えてください

仕事環境を見せてください

www.tripadvisor.jp

  • ネット環境だけは事前にレビューなどを見て念入りに調べ、このホテルにしました。そのおかげで、ネット環境はとても良かったです(zoom常時接続に耐えれていました)
  • 飲み放題のコーヒーや紅茶があったので仕事中も快適でした
  • スタッフは英語がわかるので、意思疎通も問題なかったです
  • 主に共同リビングのソファで座って、zoomを常時接続しながらMisocaのメンバーとミーティングしたり、作業したりしていました
  • 日本とウラジオストクの時差は1時間。日本とのミーティング時間設定など、仕事をしていく上で何の支障もなかったです

働き方を教えてください

  • 常時オフィスが見えていて音声も聞こえているので、リモートだからといっての孤立感を感じることは少ないです。Misoca素敵
  • 早寝・早起きするように心掛けています
  • Misocaには残業はないので、夕日が沈む前に仕事を終えられます。カメラを持って散歩に出て、なるべくよく歩くようにしています
  • 仕事中はzoomのおかげで距離を感じません。みんな渋谷あたりのオフィスにいるのかなと錯覚することがありますが、だいたい名古屋で、今同じチームにいる人は京都と鳥取でした
  • 通勤が無いので朝食を家族とゆっくり取ったり、仕事終わるとすぐ一緒に食事できるのも良いですね

最後に

いかがでしたでしょうか。そして、お気づきでしょうか。「働き方を教えて下さい」の部分は、先週の「Misocaのリモートワーカーの仕事環境」記事からの抜粋です。つまり、海外にいても、インターネット環境さえキープできれば、リモートワーク勢と同じように働くことができます。 「海外にいてもちゃんと仕事できるのかな?」と不安に思っている方々の参考になれば幸いです。

採用

ということで、Misocaでは世界を旅する開発者を探しています。 もちろんリモートでの面談・面接も行っています!お気軽にお問い合わせください。

Misocaのリモートワーカーの仕事環境

こんにちは、松江オフィスの日高(hidakatsuya)です。最近はイカの新規勢として子供達と一緒に楽しんでます。楽しい。

私が入社した2015年当時、リモートワーク勢は私含め2人でした。それが、2017年8月現在では6人まで増えとても賑やかになりました。そこで、今回はそのリモートワーク勢が「どんな仕事環境」で「どのように働いているか」について、各メンバーへのインタビュー形式でご紹介したいと思います。

では、早速紹介していきます。メンバーごとに回答をまとめています。

mugi_uno

富山県、リモートワーク歴6ヶ月

仕事環境を見せてください

f:id:hidakatsuya:20170809041040j:plain

  • 机は奥行きに余裕があるものが好きで、IKEAのを使っています
  • ケーブル類はテーブル下のケーブルボックスにまとめてスッキリ
  • 左にある存在感のあるマイクは Yetiです。プレゼントでいただきました。YouTuber感がスゴい
  • 椅子はオカムラコンテッサを使ってます。思い切った買い物でしたが、だいぶ楽になりました
  • ネット回線が1本しかないのが課題かな〜と思ってます

働き方を教えてください

  • 集中すると無限に座り続けてしまうので、意識して休憩に立つようにしています
  • 健康面は課題だらけです。とりあえずピカピカのランニングシューズは持ってます
  • 常時オフィスが見えていて音声も聞こえているので、リモートだからといっての孤立感を感じることは少ないです。Misoca素敵

eitoball

岐阜県、リモートワーク歴9年

仕事環境を見せてください

  • http://tech.misoca.jp/entry/2015/10/16/111103 の頃とほとんど変わっていません。Vim から NeoVim に変わって、janus を止めて、pathogen を使って必要なプラグインをインストールしています。後、iTerm2 をフルスクリーンで使うようになりました。相変わらず、80x34 に pane を分割して使っています
  • キーボード・マウスは、RealForce 87UB(静音モデル)・Logicool G700s を使うようになりました。パソコンは、このスタンド を無理矢理使っています

働き方を教えてください

通常は、午前9時から午後6時まで勤務しています。MacBreak Z というソフトを使っていて、それに従って、休憩しています。勤務時間で気をつけているのは、以下の3点です。

  • 週6ぐらいでジムに通って、通勤しない分の運動をするようにしています。筋トレしたり、有酸素運動をしたりしています
  • 早寝・早起きするように心掛けています
  • 毎日、本を読むようにしています

tkyk

京都府、リモートワーク歴約10年

仕事環境を見せてください

f:id:hidakatsuya:20170808121006j:plain

  • MacBook Pro15インチ、EIZO製27インチディスプレイ2枚、12.9インチiPad Pro、計4台をモニターアーム2本で配置しています
  • 椅子はアーユルチェアです。これを使い始めて腰痛から解放されました
  • iPad Proはzoom用*1に使っています。外付けのマイク・スピーカーを使うべきか、いま検討しているところです

働き方を教えてください

  • 心身の健康を維持するために、水曜休の週4日で働いています
  • 昼食時は必ず外に出ます。自宅でなにか作って食べるより、たとえコンビニ飯であっても、外に出て食べた方が調子がいいようです
  • Misocaには残業はないので、夕日が沈む前に仕事を終えられます。カメラを持って散歩に出て、なるべくよく歩くようにしています

monoooki

東京都、リモートワーク歴約11年

仕事環境を見せてください

f:id:hidakatsuya:20170809131118j:plain

  • MacBook Pro13インチ、I-O DATAの20インチディスプレイの2画面で作業しています。ディスプレイアームなので好きな位置に動かせて便利です
  • 右端は古いMacBook Air11インチで、Zoom用端末として使っています
  • 椅子はミラチェアを使っています。それなりな椅子に正しい姿勢で座ると、腰痛になるまでの時間を伸ばせます
  • 以前はEIZOのディスプレイを使っていましたが、最近は目が疲れなければなんでもいいやと適当になっています。表示端末が多くなってきているので積極的な諦め

働き方を教えてください

  • 子供が二人いて、下の子がまだ小さいため、家事全般も行っています。朝は家族の朝食と上の子の弁当作り、幼稚園の送迎、帰宅して家の掃除を済ませてから仕事を始めます
  • 仕事中はZoomのおかげで距離を感じません。みんな渋谷あたりのオフィスにいるのかなと錯覚することがありますが、だいたい名古屋で、今同じチームにいる人は京都と鳥取でした
  • ずっと普通のフリーランス生活をしてきたので最初はカメラに抵抗がありましたが、3日で慣れました。不思議なものですね
  • 19時頃仕事を終わると、すぐ夕食→上の子のお風呂→下の子のお風呂→下の子の寝かしつけをします。21時頃からようやく自由時間です
  • 21時から自室で1時間ほど自転車に乗ります。有酸素運動は体にいいと聞きました。そんな気がします

f:id:hidakatsuya:20170809131219j:plain

lulu-ulul

鳥取県、リモートワーク歴約2年6ヶ月

仕事環境を見せてください

f:id:hidakatsuya:20170809143720j:plain

  • ビデオ会議用ノートPCとスピーカーマイク・WebCam には会社から支給してもらえるキット使ってます
  • 机には物をなるべく置かない方針でやってます、がガムと目薬は必須です
  • 椅子はリープチェアのハイバック使ってて、購入してから一日の疲労が大分軽減されました
  • メインディスプレイは 目に優しい(と聞くので) ノングレアの IPS パネルのものにしています
  • たまに会話が聞き取りづらかったり打鍵音を拾ったりしてるので音響周りは改善していきたいです
  • またペアプロ等で高解像度いいなあと思ったので27インチのディスプレイ購入予定です

働き方を教えてください

  • 家族の世話で定期的に数分離席する必要があるのですが、休憩がてら数分席外すだけで対応できるのがリモートワークの利点だと思います
  • 通勤が無いので朝食を家族とゆっくり取ったり、仕事終わるとすぐ一緒に食事できるのも良いですね
    • 夕食に合わせて勤務時間も少し後ろにずらしました
  • 健康面ではまるでケアできてないので他の人みたいに運動していきたいです…

最後に

いかがでしたでしょうか。私も基本は松江オフィス勤務ですが、週の半分ぐらいは自宅勤務しています。ただ、最近腰が痛くなることが多く、「みんなどうしてる?」と聞いてみたところ、それぞれが様々な工夫をしていることがわかり、今回ブログとしてまとめてみようと思ったのでした。リモートワーク勤務のメンバーが増え、リモートワークにおける問題点や課題について相談でき、いろいろな意見が聞けるようになってとても良いなぁと感じます。

私同様、リモートワークの課題を抱えている方々の参考になれば幸いです。

採用

*1:2017年8月現在、Misocaではメインのビデオ会議ツールとしてzoomを使っています

DaruとStatsampleを使ったデータ分析を試してみた

はじめに

こんにちは、Misoca開発チームの洋食(yoshoku)です。 私は、Python十年選手な機械学習メンですが、MisocaではRuby小僧なRailsキッズしてます。 データ分析のフィールドでは、RやPythonがメジャーなプログラミング言語ですが、 SciRubyプロジェクトを中心に、 Rubyでもデータ分析やるぜ的なバイブスが上がってきています。 そんなわけで、レペゼンMisocaで、基礎的なデータ分析を試してみました。 f:id:yoshoku:20170802232449p:plain

DaruとStatsample

Daru(Data Analysis in RUby)は、その名のとおり、 Rubyでのデータの操作や可視化を実現するライブラリで、 PythonのPandasに相当するものです。 Statsample は、 統計的な分析・検定手法を提供するライブラリで、 PythonのStatsModelsに相当するものです。 どちらもgemコマンドでインストールできます。

$ gem install daru statsample

requireもライブラリ名そのままです。

require 'daru'
require 'statsample'

いろいろやってみよう

データの読み込み

Daruでは、データを、ExcelファイルやCSVファイルを読み込むことや、SQLの実行結果から得ることができます。 今回はCSVファイルから読み込むことにします。 使用するデータは、UCI Machine Learning Repositoryで公開されている、ワインの品質に関するデータを選びました。 このデータは、拡張子はCSVですが、項目はセミコロン(;)で区切られています。 Daruでは、from_csvメソッドでCSVファイルを読み込みます。 このとき、セパレータを指定できるので、カンマで区切られていなくても、読み込むことができます。

df = Daru::DataFrame.from_csv 'winequality-red.csv', {col_sep: ';'}

平均や標準偏差を見てみよう

ワインデータには、アルコール度数などのワインのパラメータと、ワインの品質が10段階で評価された値が含まれています。 いくつかのパラメータの平均や標準偏差を見てみましょう。 データから特定の項目を複数とり出したい場合は、項目名をカンマ区切りで指定します。

ds = df['fixed acidity','alcohol']

describeメソッドにより、各データ項目の平均や標準偏差を確認することができます。 Daruでは、to_sメソッドは、単なる文字列ではなく、htmlを出力するものが多いです。 これは、ReportBuilderに渡して、実行結果をhtmlで書き出すことを想定している様です (いまは Jupyter Notebook + iruby な時代ですが、せっかくなので使ってみましょう)。

rb = ReportBuilder.new
rb.add(ds.describe.to_s)
rb.save_html('result.html')

とすると、データ数・平均・標準偏差・最小値・最大値の表が作成されます。 ※表が大きくなるので小数点5桁までとしました。

alcohol fixed acidity
count 1599 1599
mean 10.42298 8.31963
std 1.06566 1.74109
min 8.4 4.6
max 14.9 15.9

相関行列を計算してみよう

相関行列も、corrメソッドにより、簡単に計算できます。

ds = df['fixed acidity','residual sugar','density','alcohol']
rb.add(ds.corr.to_s)

出力された相関行列をみると、「fixed acidity」と「density」の間に相関関係がありそうです。

fixed acidity residual sugar density alcohol
fixed acidity 0.99999 0.11477 0.66804 -0.06166
residual sugar 0.11477 1.0 0.35528 0.04207
density 0.66804 0.35528 1.0 -0.49617
alcohol -0.06166 0.04207 -0.49617 1.0

そんなわけで、Statsampleを使って散布図を見てみましょう。

rb.add(Statsample::Graph::Scatterplot.new(df['fixed acidity'], df['density']))

とすると、散布図が出力されます。

f:id:yoshoku:20170731170156p:plain:w320

※今回「fixed acidity」と「density」との間になにか相関関係があることは確認できましたが、 その意味するところは、私はワインの専門家ではないのでわかりません。 パっと思いつくのは「説明変数としてはfixed acidityかdensityのどちらか一方を削っちゃうかも」ぐらいです。 データ分析では、そのデータに対する知識も必要ですね。

重回帰分析をしてみよう

最後に、Statsampleを使って重回帰分析をしてみます。 ワインの各パラメータから、品質を表現してみましょう。 Statsample::Regression.multipleに、データと、データ中で目的変数とする項目名(ここでは品質を表すquality)を与えるだけでOKです。

model = Statsample::Regression.multiple df, 'quality'
puts model.summary

得られたモデルのsummaryメソッドで、決定係数などを確認できます。 ワインの品質には「free sulfur dioxide」「sulphates」「alcohol」あたりが重要そうな感じです。

# ここでは省略しますが説明変数のt値の一覧なども出力されます。
  R=0.600
  R^2=0.361
  R^2 Adj=0.356
  Std.Error R=0.648
  Equation=21.965 + 0.025fixed acidity + -1.084volatile acidity + -0.183citric acid +
  0.016residual sugar + -1.874chlorides + 0.004free sulfur dioxide +
  -0.003total sulfur dioxide + -17.881density + -0.414pH + 0.916sulphates + 0.276alcohol
  ...

この他、Statsampleには、t検定やカイ二乗検定といった検定も用意されているので、A/Bテストなどにも使えます。

まとめ

RやPythonと比べると、実装されていない機械学習アルゴリズムもあったりしますが、 Rubyでも、回帰分析や主成分分析など、基本的なデータ分析はできます。 ログからエビデンスを集め、お客様が必要とするサービスを、 データドリブンにデベロップしていく基盤が用意されつつあります。

採用

Misocaではサービス開発の基盤作りにLOVEなバイブスあふれたエンジニアを募集しています!

自転車で秋田からMisocaにきました

はじめまして!7月からMisoca開発チームにジョインしたfukayatです。

製造業勤務を経て、Misocaにジョインしました。

プログラマとしての業務経験も、Webの経験もないのでこれからどんどん勉強していきます。

ジョインしたらブログを書くという流れに乗って、自己紹介とMisocaにきて感じたことを綴ります。

どこからきたのか

秋田県の出身です。

のどかな田園風景広がる、時間もゆっくりとした場所で生まれました。

自転車が大好きです。

f:id:fukayat:20170728173049j:plain

なにをしてきたのか

学生時代

学生時代は部活動でEVエコランと飛行ロボコンというのをやってました。

EVエコランとは、オリジナルの電気自動車を製作し、大会から支給されるバッテリーのエネルギーでどれだけ長い距離を走れるかを競う競技です。

電気回路の設計・製作やモータの開発などに携わっていました。

f:id:fukayat:20170727095609j:plain ※真ん中の車体が我々の製作した車体です。

飛行ロボコンとは、オリジナルのラジコン飛行機を製作し、大会から課されるミッションをこなしてポイントを稼ぎ、競う競技です。

機体の設計・製作、自動制御システムの設計・プログラム・製作、パイロットに携わっていました。

f:id:fukayat:20170727095118j:plain

これだけではイメージが沸かないと思うのでYouTubeにある飛行動画をどうぞ!


2015年式Pegasus飛行練習9 20150807

卒業後

卒業後は製造業に従事していました。

製品開発に携わりたいはずだったのに、現場配属だったのではじめはがっかりしていましたが、 もともとプログラミングが好きだったので、個人的にオンライン講座を受講したり、ArduinoRaspberry Piをいじったりしていました。

現場で2ヶ月半働いてみて、「やっぱり自分の好きなプログラミングを活かした仕事に就きたい」という思いが強くなり、転職を決意しました。

なぜMisocaを選んだのか

地元就職は難しい!

「地元大好き人間」なのでもちろん地元への転職を考えていました。

しかし、地元にはプログラマとしての採用口がほとんどなく、あったとしても魅力的な業務ではありませんでした。

リモートワーク

そんなときに偶然リモートワークという言葉に出会い、その魅力にとりつかれて仕事を探した結果がMisocaです。

リモートワークを推奨しているこの会社なら、僕のわがままを叶えてくれるだろうと感じ、応募しました。

現在は名古屋にいますが、将来的には秋田に戻ってリモートワークで働きたいと考えています。

転職してみた感想

前職に1年ちょっとしかいなかったこと、Webの経験がほとんどないこと、プログラマとしての経験も浅いことから、 そもそも転職できるのか、まわりについていけるのか、かなり不安でしたが、諸先輩方の暖かいフォローのおかげですぐに慣れることができました。

Misocaの先輩方、ありがとうございます!

Misocaについて思ったこと

すべてのスピードがはやい!

Misocaにきてはじめに思ったのは、ミーティングのスピードがすごく速いということです。

バンバン意見が飛びかって、すぐに内容が決まってしまいます。

担当者を決めたり、役割を決めたりするときには率先して手を挙げている姿が印象的です。

「わからない」と自信をもって言える

Misocaにはわからないことを「自信をもって」わからないと言える環境があります。

コーディングで行き詰まってしまっても、社内チャットで誰かにひとこと「助けて!」と声をかければ教えてくれます。

基本的にリモートにいるメンバーは常時ビデオチャットでつながっているので、リモートにいるメンバーとも画面共有を利用して情報交換をすることができています。

残業はしない

事前に「基本的に残業はしません」と聞いていて、正直にいって、そんなの嘘だと思っていました。

ところが本当に残業はなくて、むしろちょっと多めに働いてしまった分はその分早く帰ることができます。

限られた時間内でいかにパフォーマンスを発揮するかを常に考えているから実現できていることだと思います。

おわりに

最終的に、転職をして本当によかったと感じています。

まだまだプログラマとしても、社会人としても未熟ですが、わからないことを少しずつ吸収しながら成長していきたいと考えています。

さらに、秋田に戻ったときにはセンサやドローンを駆使した農家として活躍したいと考えています。

これからよろしくお願いします!

f:id:fukayat:20170728154329j:plain

採用

Misocaでは自転車が大好きなエンジニアを募集しています!

CodeRetreatに参加しました! 〜ペアプロのすゝめ〜

こんにちは、Misoca開発チームのころちゃん(corocn) です。最近はイカ2の前夜祭に参加しました。

今回は07/08に名古屋で開催された CodeRetreat に参加した感想を書きたいと思います。 参加者は約20人で、Misocaからは、dominion525(主催)、eitoballcorocnの3名が参加しました。

CodeRetreat

CodeRetreatとは、プログラマのスキル向上を目的として、世界各地で定期的に開催されているイベントです。 ざっくりと説明すると

  • テーマは全員共通「コンウェイライフゲーム」を開発する
  • ペアプロで開発する
  • 言語やツールは自由だが、ペアと相談して決める
  • 1セッション45分として、セッションが終わったらコードは全部消す
  • ペアを変えて5〜6セッション回す。後のセッションになるほどルールが厳しくなる。

のような特徴があります。詳しくは以下を参照してください。

意気込み

※どんな方でも安心して参加いただけます

会場

毎週月曜日に名古屋ギークバーが開催されている、Club Adrianaさんで行いました。 何回か来たことがありますが、ここは飯が美味いのです。

当日の流れ

ファシリテーターの原田さんから、挨拶を兼ねて進め方やライフゲームの説明。

参加者の使用言語は、Java, C#が半数、Ruby半数な感じで、Scala, F#, Groovyチョットデキル勢がいました。 JavaScriptPHP扱える人も勿論いましたが、今日は別の言語でやるよ!って人が多かったように思えます。 共通言語がないからC言語で書いたというペアも。私はRubyで参加しました。

以下、各セッションのルールと内容をまとめてみました。 なお、CodeRetreatにおけるルールはオプションなので、採用しなくてもOKです。疲れたからこのセッション休憩しますもあり。

session 1

  • ルール
    • 自由に開発してみよう
  • やったこと
    • 順当に対象セルの周りを調べて生存判定をするコードを書きました

みんなもくもくペアプロしてますね。

session2

  • ルール
    • TDDで開発すべし
  • やったこと
    • TDDが良い感じで回せて、全体にお披露目 (ただしルールによりコードは削除 😭
    • 誕生なんて生ぬるいので bakutan! メソッドを実装
    • 常にHi-Fiveしながら開発!! (めっちゃ楽しい)

振り返りとして、良さげな実装を皆で見ます

昼食

  • 無限生ハム原木と美味しい昼食でひと休み
  • みなさん休憩せずに、ずっと設計の話をしているようでした。みなさん好きですねー。

生ハムは切るのが難しい!

この他にもローストビーフやパスタが提供されました。飲酒してる人もちらほら。

session3

  • ルール
    • 配列禁止
    • TDDサイクルを10回以上回すべし
  • やったこと
    • 色々迷走して上手く実装できず。MAP使えば良かった・・・
    • 死滅セル=無職、生存セル=有職という独自の世界観の構築に成功

session4

  • ルール (Evil Mute A/B pairing)
    • 会話禁止
    • 片方がテストを書き、片方(Evil coder)が対象コードを実装するべし
    • Evil coderはテストを通るだけのミニマムなコードを書くべし
    • ただしEvil(邪悪)なので、テストは通るが、テスターの意図を外したような実装をすべし
  • やったこと
    • ルールは共通言語が一緒のみ可能なので、今回は断念。
    • セルが周りに生存メッセージを投げる方法を試してみました。

おやつタイム

www.youtube.com

session5

  • ルール
    • 疲れ切ってて全く覚えてないのですが、最後は「良いコードを書こう!」だったようです。
  • やったこと
    • ペアの方がJavaScriptで実装しましたが、テストツールが上手く動かずはまりました。上手くアドバイスできず 😭
    • DOM使えば配列いらんな。とか思いながら進めました。

懇親会

  • 懇親会は6割程度の方が参加していました。
  • 今後のCodeRetreatの活動の話、TDDの話、普段書いているコードや、普段参加している勉強会の話をしていました。
  • 前回はみんな疲れ切ってて 懇親会自体行わなかったそうですが、今回は休憩を長めにとったせいかみんな元気に酔っ払っていましたね。

まとめ

ざっと紹介しましたが、ルールのおかげでいい感じに負荷がかかり、どなたでも同じぐらいの疲労度で1日楽しめるイベントという印象でした。 学生から社会人まで幅広い業種の方が参加しており、普段一緒にコードを書かない人とペアプロできるので、かなりオススメのイベントです。

次回は Global Day of Coderetreat と呼ばれるイベントが2017年11月に開催予定です。 Misocaではペアプロを積極的に取り入れていますが、普段ペアプロをしない方もぜひぜひ参加してみてはイカがでしょうか。

採用

Misocaではペアプロ大好きなエンジニアを募集しています!

AWS SSM を使って、Thor タスクを実行する

AWS SSM を使って、Thor タスクを実行する

id:eitoball です。Misoca では、減量ブームでそれに乗っかろうとしましたが、一生懸命、筋トレをしたためか、体重が増えてしまい途方に暮れているこのごろです。

先月、id:dominion525 に誘われて、AWS Summit Tokyo 2017 に1日だけ参加してきました。それ以来、AWS の様々なサービスに興味を持つようになっています。

Slackの発言

というのを見かけたので、少し早い夏の自由研究として、AWS SSM(EC2 System Manager)で、Run Command という機能を使って、EC2 インスタンスにログインすることなく、Rails アプリケーションの Thor タスクを実行するようにしてみました。

実行までの流れ

今回は、AWS SSM の Run Command を使って、特定のEC2インスタンスに対して、決められた Thor タスクを実行するようにします。Rails アプリケーションが動作する EC2 インスタンスを1つ準備して以下のような流れを実施しました。

  1. EC2インスタンスの設定
  2. ユーザーの作成・ロールの付与
  3. System Manager ドキュメントの作成・登録
  4. RunCommand によるタスクの実行・結果の閲覧

    1. EC2 インスタンスの設定

まず、EC2インスタンスに割り当てられている IAM ロールに「AmazonEC2RoleForSSM」というポリシーを付与します。インスタンスに IAM ロールが割り当てられていない場合は、新たにロールを作成して、割り当てて下さい。詳しくは、AWS EC2 のドキュメントなどを参考にして下さい。 そして、インスタンスに SSM エージェントをインストールします。Ubuntu 16.04 LTS (64 bit)の場合だと以下のようになります。他のOS等のインストール方法については、ドキュメントに記載されています。

$ curl -L -O https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/debian_amd64/amazon-ssm-agent.deb
$ sudo dpkg -i amazon-ssm-agent.deb
$ sudo systemctl enable amazon-ssm-agent

2. ユーザーの作成・ロールの付与

特定のインスタンスに対してのみタスクを実行するためだけのユーザーを作成します。今回は、作成したユーザーに以下のようなポリシーを直接、付与しました。「i-12345abcde67890fg」は、今回、使用している EC2 インスタンスのIDです。「RunThorTask」は、次のステップで作成する System Manager ドキュメントの名前です。ssm:SendCommand などを許可する場合、 System Manager ドキュメントと実行する EC2 インスタンスの両方を Resource に含める必要があります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:ListCommandInvocations",
                "ssm:GetCommandInvocation",
            ],
            "Resource": [
                "arn:aws:ec2:ap-northeast-1:*:instance/i-12345abcde67890fg",
                "arn:aws:ssm:ap-northeast-1:*:*",
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "ssm:SendCommand",
                "ssm:DescribeDocument",
                "ssm:GetDocument"
            ],
            "Resource": [
                "arn:aws:ec2:ap-northeast-1:*:instance/i-12345abcde67890fg",
                "arn:aws:ssm:ap-northeast-1:*:document/RunThorTask"
            ]
        }
    ]
}

3. System Manager ドキュメントの作成・登録

特定の Thor タスクを実行するための コマンドの System Manager ドキュメントを作成します。今回は、あるユーザー(john.doe)が、 RVM(Ruby Version Manager)を使って、実行することとしています。Rails アプリケーションは、/var/www/vhosts/www.example.com/current にインストールされているとしています。 下記のような JSON ファイル(document.json)を作成します。今回は、allowedValues で、実行することのできる Thor タスクを listhelpversion の3つに制限しています。

{
    "schemaVersion": "2.0",
    "description": "Thor タスクを実行します。",
    "parameters": {
      "action": {
        "description": "Thor タスクを実行します。",
        "type": "String",
        "allowedValues": [
          "list",
          "help",
          "version"
        ]
      }
    },
    "mainSteps": [
      {
        "action": "aws:runShellScript",
        "name": "runThorTask",
        "inputs": {
          "runCommand": ["sudo -u john.doe /bin/bash -l -c \"source /home/john.doe/.rvm/scripts/rvm && rvm use . && RAILS_ENV=production bundle exec thor {{ action }}\""],
          "workingDirectory": "/var/www/vhosts/www.example.com/current"
        }
      }
    ]
}

作成したドキュメントを AWS CLI を使って登録します。

$ aws ssm create-document --content "file://document.json" --name "RunThorTask" --document-type "Command"

4. RunCommand によるタスクの実行・結果の閲覧

全ステップで登録した System Manager ドキュメントを使って、タスクを実行します。

$ aws ssm send-command --document-name "RunThorTask" --instance-ids "i-12345abcde67890fg" --parameters '{"action":["list"]}' --region ap-northeast-1

上記のコマンドを実行するとJSONが出力されます。結果の閲覧に必要な CommandId 以外は、省略しています。

{
    "Command": {
        "CommandId": "abcd1234-ab12-ab12-ab12-abcdef123456",
    }
}

CommandId を使って、実行結果を確認します。

$ aws ssm get-command-invocation --command-id "abcd1234-ab12-ab12-ab12-abcdef123456" --instance-id "i-12345abcde67890fg"

実行が成功している場合、以下のような結果が出力されます。

{
    "Comment": "",
    "ExecutionElapsedTime": "PT11.275S",
    "ExecutionEndDateTime": "2017-07-01T00:00:00.000Z",
    "StandardErrorContent": "",
    "InstanceId": "i-12345abcde67890fg",
    "StandardErrorUrl": "",
    "DocumentName": "RunThorTask",
    "StandardOutputContent": "...",
    "Status": "Success",
    "StatusDetails": "Success",
    "PluginName": "runThorTask",
    "ResponseCode": 0,
    "ExecutionStartDateTime": "2017-07-01T00:00:00.000Z",
    "CommandId": "abcd1234-ab12-ab12-ab12-abcdef123456",
    "StandardOutputUrl": ""
}

感想

  • EC2 System Manager で、色々なコマンドをログインしないで実行できるのは便利だと思います。また、IAM を使って、細かい実行権限の管理ができそうなのも便利だと思います。
  • 今回は使いませんでしたが、System Manager ドキュメントの作成には、 rezept を使ってみるのもいいなぁと思いました。

    採用

Misoca では、AWS の様々なサービスの活用に興味あるエンジニアも募集しています。

📝ParsletによるPEGパーサ

mzpです。 先日、北海道旅行に行きました。

先日文書番号ルールの設定機能をリリースしました。 今回は、その実装に利用したパーサライブラリParsletを紹介します。

✨文書番号ルールの設定機能

f:id:mzp:20170628130956p:plain

文書番号ルールの設定機能は、請求書などの右上に記載される番号の初期値を設定できる機能です。

このルールは{Y}{M}{D}-{連番} といった形式で指定でき、 {} 内に文字列によって何に置換されるかが決まります。 ここで指定できる文字列には以下のようなものがあります。

文字列意味
{Y} 文書作成時の年 (4桁)
{M} 文書作成時の月 (2桁)
{D} 文書作成時の日 (2桁)
{連番} 作成開始時点での文書ごとの連番

💬PEGの採用

当初は1文字ずつ見ていく、いわゆる手書きの再帰下降パーサを検討していました。しかし、今後、構文規則が拡張されていくことが予想されたため、パーサライブラリを利用するように方針を切り替えました。

どのパーサライブラリを採用するかも迷いましたが、PEGという構文規則に基づくライブラリが、言語を問わず存在して便利そうだったので採用しました。

このときの会話は以下のようになっています。

📝処理の流れ

文字列のパース

文書番号のルールを記述した文字列をパースし、扱いやすいデータ構造にします。

例えば、{Y}{M}{D}-{連番} は以下のようなデータ構造になります。

# {Y}{M}{D}-{連番}
[
  { rule: { identifier: 'Y') } },
  { rule: { identifier: 'M') } },
  { rule: { identifier: 'D') } },
  { word: '-' },
  { rule: { identifier: '連番' } }
]

このパーサは以下のように定義しています。

class Parser < Parslet::Parser
  RESERVED_WORDS = %w({ } Y M D 連番).freeze

  rule(:word) { match('[^{}[:space:][:cntrl:]]').repeat(1) }
  rule(:identifier) { RESERVED_WORDS.map { |w| str(w) }.reduce(&:|) }
  rule(:rule) { str('{') >> identifier.as(:identifier) >> str('}') }
  rule(:numbering_rule) { (rule.as(:rule) | word.as(:word)).repeat }

  root :numbering_rule
end

パースした結果の変換

{ rule: { identifier: 'Y') } } といったハッシュのままだと処理しずらいので、文字列を内部的に扱いやすい形に変換します。

先ほどの例は、以下のようになります。

# [
#  { rule: { identifier: 'Y') } },
#  { rule: { identifier: 'M') } },
#  { rule: { identifier: 'D') } },
#  { word: '-' },
#  { rule: { identifier: '連番' } }
# ]
[
 :current_year,
 :current_month,
 :current_date,
 '-',
 :document_sequence_number
]

この変換は以下のように定義しています。

class Transform < Parslet::Transform
  IDENTIFIER = {
    'D' => :current_date,
    'M' => :current_month,
    'Y' => :current_year,
    '{' => :left_brace,
    '}' => :right_brace
  }.freeze

  rule(word: simple(:s)) { s.to_s }
  rule(identifier: simple(:i)) { IDENTIFIER[i.to_s]  }
  rule(rule: simple(:r)) { r }
  rule(rule: sequence(:a)) { a }
  rule('') { [] }
end

文書番号の生成

変換した結果を元に文書番号を生成します。

先ほどの例からは、以下のような文書番号が生成されます。

# [
#   :current_year,
#   :current_month,
#   :current_date,
#   '-',
#   :document_sequence_number
# ]
20170630-001

これは文字列ならばそのまま出力する、シンボルならば内部で定義したメソッドを呼ぶ、という形で実装しています。

class Evaluator   
  def execute(rule)
    transformed = Transform.new.apply(Parser.new.parse(rule))
                                              
    transformed.each_with_object(::String.new) do |r, s|    
      s << case r                                                                                             
               when ::String then r
               when ::Symbol then respond_to?(r, true) ? send(r) : ''
               end
    end
  end

  private
                          
  def current_time
    @current_time ||= Time.current
  end               
           
  def current_year
    current_time.year.to_s
  end                                               
           
  def current_month
    format('%02d', current_time.month)
  end                                     
           
  def current_date
    format('%02d', current_time.day)
  end             
           
  def document_sequence_number
    # ...
  end
end

💖感想

Parsletがだいぶ分かりやすかったと思う。 実際、学習を含めても1時間くらいで実装できた。

また、手書きするより見通しがよくなってよかったと思う。

🔊 採用

Misocaでは構文解析に興味あるエンジニアを募集してます。