読者です 読者をやめる 読者になる 読者になる

Rock Me!開発者ブログ

DEVELOPERS BLOG

新規開発案件のため、WEB開発トレンドをアップデートしてみた

年明けから本格的に新しいシステムを作りはじめているのですが、スクラッチで構築するのは4年ぶりになるため、ベースの技術も一新していきたいと思っています。

今のメインシステムは、2012年末にRock Me!に入社し、4ヶ月ほどで作りあげ、ベース部分は1、2年くらいかけてブラッシュアップしていきました。 システムがだいぶ落ち着いたころに娘が生まれ、そこからは子育てと平行モードに。 コードは書いていたけど、ベース技術はわりとそのままで、システム内のコンテンツを増やすことに注力していました。

娘が3歳になり、すこし子育ても落ち着いてきたのと、ビジネスの状況も変わってきたので、最近の技術トレンドを踏まえつつ、頭を開発モードに切り替えているところです。

今、色々と追っかけているところですが、どんな変化を取り込もうとしているかご紹介します。

インフラ

基本的にはAWSを採用していて、これはこのまま継続します。

VPC

現システムのリリースがちょうどVPCがデフォルトになった時期で、テスト含めるとちょっと移行はきついかなあと思い、見送っていました。 今思えば、あの時無理しておけばよかった気がしなくもないですが、ネットワーク構築がどういうものか、あまりわかってなかったのでしょうがないですね。

下記のような資料を参考に、実際に手を動かしているところです。慣れてきたらCloudFormationなど構築ツールを導入する予定です。

環境構築

今はchefを使っています。
naoyaさんの入門Chef Solo をきっかけに導入して、今のシステムは全部chefで構築、管理できるようになっています。 ただ、ちょっと複雑で見通し悪いかなという感じがあり、ここまで必要ない感かなと感じてます。 後述するようにRubyからPythonに切り替えていこうかと思っているので、ついでにAnsibleを試しているところです。
まあ、Ansibleはyamlな世界らしいので、あまりPython関係ないかもですが。

開発環境

chefを導入したころはchef + vagrantが流行っていたのですが、立ち上げの時間や容量など考えるとめんどくさくなってしまい、使わなくなっていきました。 結局、安いec2を立ち上げっぱなしで、簡単な修正は直でVimで、そこそこのものはmacにsshfsして、IDEから操作して・・・みたいな開発をしています。(遅延は思ったより気にならない) ただ、これはこれでIDEの機能をフルに使えなかったりする難点もあります。

Docker

そんな中、vagrant -> dockerみたいな流れもあり、Dockerやりたいなあとは思っていたのですが、なかなか手がでず。 初めはいまいちどんな風に使ったらいいのか、どんな仕組みになっているのかが飲み込めず、放置してしまっていました。 これを機に仕組みの理解と実際に手を動かしてみると、下記のようなキーワードがしっくりきました。

  • プロセスを実行するツール
  • アプリケーションの入れ物
  • OSレベルの仮想化(vagrantなどはハードウェアレベルの仮想化)

実際にdocker内でpsすると、プロセスはひとつ、もしくは少数しか動いていないんですよね。
ただ、まだモヤモヤしている部分があって、このプロセスがOSの機能をどう利用しているのか、各ライブラリをどのように使っているのかのイメージがつかめないてないんですよね。 この辺は地道にちゃんと勉強しなきゃですね。 低レベルなところでのUNIXプログラミングみたいのをやればいいのか、ここを理解できるとだいぶスッキリする気がします。

実用的には、開発時に公式のイメージを利用して、さくっとMySQLを立てるとか、そんなレベルから初めていきます。 フル活用するとプロダクションでオーケストレーションツールを使って・・・と、広がっていきますが、まだ自分の知識では扱えないかなという印象です。 ただ、micro service的に作っていければ自然とマッチしていくと思うので、引き続きウォッチしていくつもりです。

プログラム言語、フレームワーク

リリース当初はすべてPHPだったのですが、途中でバックエンドはRailsで刷新しました。 ただ、どうもこれが肌に合わず・・・なぜだか、のめり込めない自分がいました。 勉強不足も多分にあるのですが、ブラックボックス感がぬぐえず。。

というわけで最近の機械学習流行りもありPython、Djangoを試しているところです。 まだ使いはじめですが、Pythonの考え方やDjangoの考え方はわりと共感できるかなと思っています。

WEBサーバ

今はほぼapacheなのですが、そろそろnginx使ってみようかな、というようなレベルです。 apacheでもいいのですが、せっかくのチャンスなので、nginx + gunicorn + djangoみたいな組み合わせを試していこうかと思います。

DBサーバ

今はmysql5.5とMongoDBを使っています。 auroraやらpostgresql、DynamoDB、redisなど、必要に応じて選択していくつもりです。

まとめ

下の方はまだこれからなので、だいぶ記事が薄いですね(笑)

色々なことが利用可能になっていってるけども、ちゃんとしたベースの知識がないと役に立たないことも痛感しました。 何となくわかっているつもりの知識がけっこう多いもんです。。
VPCを構築するなら、もちろんネットワークの知識が必要だし、Dockerをちゃんと運用するには、Linuxやプログラムがどう動いているのかLowレベルのところで理解していないとやれないなと強く感じました。

また、知識がないからといって実行しないのも良くないなと。 ベタですが、やはり知識と経験のバランスが大切ですね。

また各トピックについて理解が進んだら記事を書いていこうと思います。

Amazon Dash Buttonを押したらSpreadSheetが更新されるようにしてみた(Mac, Python3編)

だいぶ今さら・・・感のあるネタですが、最近はじめたPythonの練習がてらにやってみました。
node.jsの例が多いのですが、やっている事は単純なのでもちろんPythonでもできます。
環境はmac(Sierra),Python3です。
まだ勝手がわからず、自分で書いたところはぎこちないですが。。

dash buttonを検知する

Python2の例が多かったのですが、こちらが3でやっていたので検知部分を参考にさせていただきました。
Hacking the Amazon Dash Button to Make a Simple, Cheap, IoT Place-Anywhere Networked Button

MACアドレスを調べる

参考スクリプトで取っ掛かりからつまづいて、原因がよくわからなかったので、ひとまずシェルで取得しちゃいました。(0.0.0.0じゃなかったみたい)
dash buttonを押して、下記のように表示されたら、MACアドレスの34:d2:70:ac:1b:c0 と192.168.1.13をメモ。普通は0.0.0.0なのかな。(あとで調べる)

$ sudo tcpdump -e arp -c 100
12:00:49.971730 34:d2:70:ac:1b:c0 (oui Unknown) > Broadcast, ethertype ARP (0x0806), length 42: Request who-has 192.168.1.1 tell 192.168.1.13, length 28

python環境の構築

# 仮想環境構築
python3 -m venv --copies dashbutton
cd dashbutton/
. bin/activate
    
# 必要ライブラリのインストール
pip install --upgrade pip
pip install scapy-python3
pip install netifaces

brew install --with-python libdnet

検知部分の作成

from scapy.all import *

def arp_display(pkt):
    if pkt[ARP].op == 1:
        if pkt[ARP].psrc == '192.168.1.13': # メモのIP
            if pkt[ARP].hwsrc == '34:d2:70:ac:1b:c0': # メモのMACアドレス
                print("Pushed Button 1")
            elif pkt[ARP].hwsrc == 'XX:XX:XX:XX:XX:XX':
                print("Pushed Button 2")
            else:
                print("ARP Probe from unknown device: " + pkt[ARP].hwsrc)

print(sniff(prn=arp_display, filter="arp", store=0))

実行

$ sudo python ./dash.py

GoogleSpreadsheetに書き込む

Google Drive APIの設定を行い、OAuthとSpreadSheet用のライブラリを使用します。
こちらの記事を参考にさせていただきました。
pythonでGoogle Spread Sheetをいじる(OAuth) - Qiita

OauthのライブラリでSignedJwtAssertionCredentialsからServiceAccountCredentialsへの変更があったようなので、こちらの書き方が良いようです。

さきほどの検知部分に処理を追加すると、下記のようになります。
書き込み内容は用途によって変更してください。

gspreadの使い方はGitHubに載っているので参考に。

from scapy.all import *
import gspread
from oauth2client.service_account import ServiceAccountCredentials
from datetime import datetime


def update_spreadsheet():
    scope = ['https://spreadsheets.google.com/feeds']
    doc_id = 'doc_id'
    path = os.path.expanduser('./XXXXXXX-XXXXXXXXX.json')

    credentials = ServiceAccountCredentials.from_json_keyfile_name(path, scope)
    client = gspread.authorize(credentials)
    gfile = client.open_by_key(doc_id)
    worksheet = gfile.sheet1
    records = worksheet.get_all_values()
    new_row = len(records) + 1

    now = datetime.now()
    worksheet.update_cell(new_row, 1, now.strftime("%Y/%m/%d %H:%M:%S"))
    worksheet.update_cell(new_row, 2, 1)


def arp_display(pkt):
    if pkt[ARP].op == 1:
        if pkt[ARP].psrc == '192.168.1.13':
            if pkt[ARP].hwsrc == '34:d2:70:ac:1b:c0':
                print("Pushed Button 1")
                update_spreadsheet()
            elif pkt[ARP].hwsrc == 'XX:XX:XX:XX:XX:XX':
                print("Pushed Button 2")
            else:
                print("ARP Probe from unknown device: " + pkt[ARP].hwsrc)


if __name__ == "__main__":
    print(sniff(prn=arp_display, filter="arp", store=0))

Dockerに躊躇してる人は公式チュートリアルをやってみると良いかも

こんにちは。福本です。

時々フロントエンドの手伝いをしてもらってる方と、ふとインフラの話になって、お互いに、Dockerやってみたいんだけど何か進まないよね。。本だけ溜まって。。みたいな話をしていました。 なんとなくの仕組みはわかるけど、ちゃんとやろうとすると時間かかりそうだなあという意識の壁にさえぎられ、一歩が進まず。

そんな時、社内wikiにCrowiを導入するのがきっかけで、ちょっと手をつけることができました。 最新のバージョンで検索機能が加わって、本格的に使ってもよさそうだな〜と思っていたのですが、動かすのにNode, Mongo, Redis, ElasticSearchなどが必要で、Mongo以外はちゃんと使った事がなく、環境構築めんどくさいな〜と、まあこちらも二の足を踏んでました。 ただ、調べてみるとDocker ImageとDocker Composeでの構築方法を公開してくれている方がいて(bakudankun/crowi - Docker Hub)、これならさくっとできるかもしれないと思い、踏み出してみました。(Crowiの導入記事は後ほどアップします)

ひとまずDockerのベーシックな動きは把握しておかないとと思い、チュートリアルを探すと意外と本家のがシンプルで良い感じでした。
Get started with Docker
Dockerの本は色々とでてますが、どれもちょっと重いなあという印象だったのですが、こちらは超初心者向けで、英語もとてもやさしく書いてあるのでサクサク進められます。 自分と同じく何となく躊躇している方にはおすすめです。

実際さわってみると、今までの概念が変わってくるなあとちょっとした感動。 アプリケーションと実行環境が一緒になって、こんな軽量に動くのか〜。 クラウドが浸透してきて、Function as a Serviceやマイクロサービスへの動きも活発になっていくなかで、コンテナ技術は重要な存在だな。 とりあえず一歩踏み出しておいてよかった。

APIGatewayのベンチマークにwrkを使ってみた

こんにちは。福本です。

サーバレス流行ってきていますね。
Rock Me!ではAWSをメインに使っているのですが、実際Productionで使ってるのは、
EC2, ELB, S3, RDS, Route53
くらいで、クラウドの第1世代といった感じでしょうか。
使い始めのころベンダーロックインしないように気を使いすぎて、ちょっと出遅れぎみです。
ようやく、細かな案件や新規の案件を進める中で、いくつか新しい事に取り組めるようになってきました。

そんな中で、AWSのAPIGatewayを試していて、ハマったことがあるので解決策を残しておきます。

ある案件で、処理としては単純なんだけど、そこそこピークリクエストが高いというのがあって、
これはAPIGateway+Lambdaでいけるかなと思い試してみました。
パフォーマンスの目安がApache Benchのサンプルコマンドで示されていたので、
軽くサンプルを作って試してみることに。

まずは適当に打ってみたところ、

ab -n 100 -c 10 https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/test/xxxxxxxxxxxxxx
〜〜〜
140737154737160:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:/Library/Caches/com.apple.xbs/Sources/libressl/libressl-11/libressl/ssl/s23_clnt.c:541:
ずらずらずら

何やらSSLのエラーがでている。
色々と調べてみるとAPIGatewayではTLSv1.2を強要すること、SNI(Server Name Indication)を使用しているのでこれらに対応しているクライアントではないとダメとの事。

他のベンチマークツールを見てみると、
wrk(GitHub)というツールが対応している模様。
Mac(10.12.1)にインストールしてみると、DLしてきて単純にmakeするだけですんなりバイナリが出来上がったのでお手軽でした。

使い方もよくあるオプションなので、すんなり使えると思います。

# 2スレッド、コネクション400、5秒間
wrk -t2 -c400 -d5 --latency https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/test/XXXX
Running 5s test @ https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/test/XXXX
  2 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   258.60ms   80.31ms   1.07s    58.74%
    Req/Sec   511.38    250.80     0.94k    64.58%
  Latency Distribution
     50%  302.91ms
     75%  325.37ms
     90%  334.22ms
     99%  403.74ms
  4909 requests in 5.03s, 2.71MB read
Requests/sec:    976.77
Transfer/sec:    551.34KB

あと、Luaで動作拡張ができるらしいです(これはまだやってないです)

古めのベンチマークツールで困ったことがあったら試してみてください。

Homebrew-caskとBrewfileでGUIアプリも管理する

開発部の福本です。

Macのクリーンインストールする必要があり、ついでに環境構築の自動化を進めてみます。 chefやvagrantが当たり前になってきたので、手元のMacも同じように管理したいですよね。 App Storeのものはまだ良いですが、DL元探してきてゴニョゴニョとしていくのはさすがにしんどいです。 brewの拡張であるHomebrew-caskを使うことによって、通常brewにはないGUIアプリについても管理していきます。

準備

  • brewのインストール
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
  • Xcodeの規約に同意してない警告がでたら、下記でサクッと。
sudo xcrun cc

Homebrew-caskのインストール

# caskのDL先をbrewと同じ/usr/local/以下に、シンボリック先を/Applications/に変更
export HOMEBREW_CASK_OPTS="--appdir=/Applications --caskroom=/usr/local/Caskroom"

brew install caskroom/cask/brew-cask

これで使えるようになっているはずです。

brew cask search hoge

で検索できるので、アプリが見つかったら

brew cask install hoge

でインストールができます。

他にも下記のようなコマンドがあります。

brew cask search hoge # 検索
brew cask install hoge # インストール
brew cask uninstall hoge # アンインストール
brew cask list # インストールしたアプリのリスト
brew cask cleanup # 不要ファイルの掃除

Bundlefile

ここまででアプリのインストール作業の自動化ができました。 もう一歩進めてBrewfileでこれらのアプリをまとめて管理できるようにします。 おなじみのGemfileやVagrantfileのbrew版になります。

が、、、現在は本体から外されてしまっているみたいですね。
homebrew - brew bundleが使えなくなったのでとりあえず使えるようにした - Qiita こちらを参考に、

brew tap homebrew/boneyard

で、使えるようにしました。

下記のようにBrewfileを用意して、

brew bundle

と打つと、インストールされていきます。
(インストール済みのものはWarningがでます)

参考までにBrewfileを晒しておきます。(まだ全部の挙動を確認できてないですが^^;)

update
upgrade

install git
install zsh

cask install appcleaner
cask install alfred
cask install astah-community
cask install clipmenu
cask install chefdk
cask install cyberduck
cask install dropbox
cask install firefox
cask install flux
cask install genymotion
cask install google-chrome
cask install google-drive
cask install google-japanese-ime
cask install imageoptim
cask install iterm2
cask install karabiner
cask install macvim
cask install phpstorm
cask install rubymine
cask install seil
cask install shupapan
cask install totalfinder
cask install vimr
cask install vagrant
cask install virtualbox
cask install vlc

cleanup

注意点

Alfred

補足で、ランチャーに古いバージョンのAlfredを使っていると、シンボリックリンクされたアプリを拾ってれなく対応が必要だったのですが、v2.6からは対応不要です。 App StoreのAlfredは古かったので、caskから入れるようにしました。

GoogleChrome

シンボリックリンクがはられた状態だと、1Passwordのプラグインでformに書き込みができなくなってしまったので手動インストールに変更しました。


弊社ではエンジニアを募集しています。 是非リクルートページをご覧になってください。

リクルートページ

FuelPHPのMongoDBでデータベースを使い分ける

弊社のあるシステムではMongoDBを使用しています。
参照データは基本的にMySQLから一度使いやすい形にしてMongoDBに格納し、APIからはMongoのデータをメインで使用する事によってパフォーマンスを保っています。
データを本番反映するまでテスト -> チェック -> 本番と確認のステップを分けており、各環境で確認を行うことができるようにしています。
これを実現するためにMongoDB上に同じ構成のDBを3つ作り、確認を得たデータからSync処理を行うことにより反映していきます。

サーバ構成図

サーバ構成図

設定ファイル

MongoDBに下記のように3つデータベースを構築し、設定しておきます。

config/development/db.php

<?php
    return array(
        'default' => array(
            'connection'  => array(
                'dsn'        => 'mysql:host=localhost;dbname=test_database',
                'username'   => 'username',
                'password'   => 'XXXXXXX',
            ),
        ),
        'mongo' => array(
            'default' => array(
                'hostname'   => 'localhost',
                'database'   => 'test_database',
            ),
            'check' => array(
                'hostname'   => 'localhost',
                'database'   => 'check_database',
            ),
            'prod' => array(
                'hostname'   => 'localhost',
                'database'   => 'prod_database',
            ),
        ),
    );

使い方

FuelPHPのMongo_Dbではインスタンス作成時にDB名を指定できます。(デフォルトはdefaultに指定したもの)

<?php
    $db_name = 'prod' // or 'check' or 'default'
    $mongo = \Mongo_Db::instance($db_name);
    $mongo->where(array('id' => $id));
    $data = $mongo->get_one($collection);

Sync

サンプルとして、シンプルにひとつのデータだけをSyncするクラスを書いてみました。
単純にfromとtoを指定して、同じコレクション、idのデータをSyncします。
弊社システムではこのような処理を積み重ねた、もっと大きなデータセットのSyncを行っています。

<?php
class Mongo_Sync
{
        private $from;
        private $to;

        function __construct($from, $to) {
            $this->from = $from;
            $this->to = $to;
        }
 
        private function sync_one($collection, $id)
        {
            $data = $this->get_one($collection, $id);
            if ($data) {
                $this->save_one($collection, $id, $data);
            } else {
                // TODO:Error
            }
        }
    
        private function get_one($collection, $id)
        {
            $mongo = \Mongo_Db::instance($this->from);
            $mongo->where(array('id' => $id));
            $data = $mongo->get_one($collection);
            return $data;
        }
    
        private function save_one($collection, $id, $data)
        {
            unset($data['_id']);
            $mongo = \Mongo_Db::instance($this->to);
            if (! $mongo->where(array('id' => $id))->update($collection, $data, array("upsert" => true))) {
                // TODO:Error
            }
        }
    }

弊社ではエンジニアを募集しています。 是非リクルートページをご覧になってください。

リクルートページ

Rock Me!でのAWSの使いどころ

今回は弊社内のインフラについて話をしようと思います。

エンジニア一人ですと、インフラ構築から開発、運用までを全てをやらなくてはいけません。
全てを熟知してこだわり抜いて・・・とかやっていると、さすがに仕事が終わらないです。
ポイントを抑えつつ色々なサービスを使用して、本当に自分にしかできない事にリソースをフォーカスできるように注意しています。

いまいちなサービスを使ってしまうと、やりたい事ができなかったり、余計にコストが掛かったりしてしまいますが、インフラ周りに限っていえば、AWS(Amazon Web Service)を選んでおけば間違いはないと思います。
弊社のインフラは全てAWSでまかなっているので、弊社での使いどころを紹介したいと思います。
こちらはある課金サービスのサーバ構成図になるのですが、こちらを参考に説明していきます。

サーバ構成図

EC2(Elastic Compute Cloud)

わずか数分で起動可能な仮想サーバで、後から性能変更できるのでとても使い勝手が良いです。
サーバ構成図のグレーの四角は全てEC2のサーバインスタンスになります。

CPUやメモリが足りなくなったら、インスタンスのタイプを変更する事によりスケールアップする事ができます。
ディスク容量に関してもあとから増減する事ができます。
(どちらも一回インスタンスを停める必要はありますが)

このシステムではMONGOサーバと、本番(PROD)のWEB、APIサーバは常に負荷が掛かるので、しっかりとしたインスタンスタイプ複数台で構成しています。
それ以外のサーバについては、t2.microという一番ミニマムで安いサーバを使用しています。
1台のサーバで複数用途のシステムを共存する事はできるのですが、どうしても設定が複雑になり取り回しがめんどくさくなってきます。
そこでt2.microを使用することで、コストを抑えつつもシンプルな構成で管理できるようにしています。

また、このシステムでは常時稼働のサーバが多いので、リザーブドインスタンスを適用する事でコストを大幅にカットしています。
t2.microを1年間のリザーブドインスタンスを適用すると、初期費用$85 + 従量課金$43.8 = $128.8掛かります。
一月サーバ1台千円強で使用する事ができます。

それ以外のサーバはけっこう良いものを使用していますが、これくらいのサーバ構成で月数万円程度になります。

ELB(Elastic Load Balancing)

ちゃんとしたハードウェアを買うとけっこう高いロードバランサですが、ELBを使用すれば安定したロードバランサが安価で使用する事ができます。
バランシングだけだったら自前で構築できたりもしますが、手間や運用など考えるとELBを使用した方が圧倒的にコスト削減になります。
また、自前で立てたものが落ちてしまったら終わりなので、安定性でもこちらの方が有利です。

このシステムは課金要素を含むため、可用性を重視しています。
ですので、外部向けのWEBサーバ、APIサーバにはELBを使用しています。

RDS(Relational Database Service)

同じようにデータベースも可用性向上の部分でAWSに頼っています。
RDSではMySQLなどリレーショナルデータベースをサービスとして使用する事ができます。
こちらもEC2同様に後からスケールアップをする事が可能です。
そしてRDSの重要な機能にMulti-AZというものがあります。
通常可用性を高めるためにはレプリケーションなど設定しなくてはいけませんが、それらを自動的に行ってくれます。
何か障害が起こった場合、スタンバイに自動的にフェイルオーバーするので、すぐにデータベースの動作を再開できます。
こちらも真面目に作るとそれなりに手間と運用が発生しますが、それらの部分を任せる事ができます。

Route53

DNSのサービスになります。
SLA100%としていてだけあって安心はできます。(絶対落ちないといっているわけではないですが)
設定ツールも比較的使いやすく、何と言ってもELB,EC2,S3などの他のサービスと連携させて使用すると、かゆいところに手が届く、AWSならではの一体感によりスムーズなシステム構築ができます。

今はまだこれくらいしか使っていませんが、まだまだ使えていないサービスも多いので、用途に合うものがあればこれからも取り入れていく予定です。


弊社ではエンジニアを募集しています。 是非リクルートページをご覧になってください。

リクルートページ