2017年5月1日月曜日

nginxによるアクセス制御に関して調べてみた

業務でアクセス制御する必要があったので、どのような解決策があるかを調べてみた。


要件

ある外部システムをWebAPIで叩いて連携する必要があるが、そのシステムはURLごとに2req/sしか叩かれないように制御したい。

例えば
/searchと/user はそれぞれに2req/sになるように制御したい。

この要件を聞いてみて使えそうかな?とおもったnginx調べてみた。

nginx

http limit req moduleでいけるか調べてみる。
ある$keyごとに1req/secondなど柔軟に処理できそうなので、URLごとにリクエストを制御できるかテストしてみる。

検証環境はmac
  • brew install nginx
  • sudo nginx
  • http://localhost:8080/にアクセスするとデフォルトページが表示された。
index.htmlを / と /testの2つに用意
mkdir /usr/local/var/www/test
cp /usr/local/var/www/index.html /usr/local/var/www/test
そこに$uriごとにアクセス制限をかける以下を追加

http {
    limit_req_zone $uri zone=one:10m rate=2r/s;

    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/access.log  main;

    sendfile        on;

    keepalive_timeout  65;

    server {
        limit_req zone=one burst=5;
        listen       8080;
        server_name  localhost;

        location / {
            root   html;
            index  index.html index.htm;
        }

設定完了したので、nginx再起動。

sudo nginx -s reload

そしてアクセスログを見守りつつ、/ と /testにpararel 4,  request数12で飛ばす。
ab -n 12 -c 4 http://127.0.0.1:8080/index.html & ab -n 12 -c 4 http://127.0.0.1:8080/test/index.html
するとアクセスログは以下のように同じ秒間にはuriごとに2リクエストしかさばいてないので、nginxの方でよしなに遅延させて処理してくれた模様。
[01/May/2017:00:31:23 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:23 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:23 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" [01/May/2017:00:31:26 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:26 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:26 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:26 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
秒間をこえたリクエストを遅延して処理するかどうかはburstが決めているのでそれをいじってエラーにしてみる。

十分これで目的を達成できそうな気がするな。

2017年4月22日土曜日

react-router  を使った遷移の話

キンドルセール情報のサイトでreact-routerを使ってホーム画面と検索画面の遷移を作成したのでメモ。
はまったのは検索画面のURLが直接叩かれても、正しい検索結果を返さなければならないところ、普通にやるとサーバサイドのURLはホーム画面しかないので検索画面のURLを入力しても404になってしまう。

ホーム画面
検索結果画面



そこでreact-routerの処理だけでなく、railsの方にも同じURLを登録すると、ホーム->検索画面といったノーマルな遷移だけでなく、検索画面URLが直接叩かれたり、ブラウザの戻るににも対応できる。

rails側 config/routes.rbに設定しURLを有効にする
ここで重要なのは/booksで受け取ったものはホーム画面と同じパスに渡して、ルーティング処理はフロントのreact-routerに任せるところ。
root 'main#index' # ホーム画面
get '/books', to: 'main#index' # 検索結果画面

react側のルーティング処理 
import React from 'react';
import ReactDOM from 'react-dom';
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme';
import lightBaseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import Sales from './components/sales.jsx';
import Books from './components/books.jsx';
import injectTapEventPlugin from 'react-tap-event-plugin';
import { IndexRoute, Link, Router, Route, browserHistory } from 'react-router';

export default class Main extends React.Component {

  constructor(props) {
    super(props);
    injectTapEventPlugin();
  }

  render() {
    return (
      <MuiThemeProvider muiTheme={getMuiTheme(lightBaseTheme)}>
        <div>
          <Header query={this.props.location.query}/>
          { this.props.children }
          <Footer />
        </div>
      </MuiThemeProvider>
    );
  }
}
ReactDOM.render((
  <Router history={browserHistory} > 
    <Route path="/" component={Main}>
      <IndexRoute component={Sales} />
      <Route path="/books" component={Books} />
    </Route>
  </Router>

  ), document.getElementById('app'),
);

なかなかWebにぴったりの情報がなくてはまったが、これでうまくいき検索結果がブックマークできるようになった。









2017年4月16日日曜日

EC2の外部接続許可について

セルフプロジェクトとして頑張っている、Kindleセール情報おすすめサイトの開発環境、バッチサーバをAWSに移行したのだが、外部からの接続ではまったのでメモ。

通常サーバを立ち上げたあと、セキュリティの設定iptablesなどいじいじしてポートを開けたりしなければならないのだがEC2ではその必要がなさそうだ。


EC2でサーバを立ち上げた後、開発環境なので

bundle exec rails s -b 0.0.0.0 -p 3000

で開発環境サーバを立ち上げ、外部から接続してみたが繋がらないのでIptables -L で調べてみると何も設定されたない。。。

なんじゃこりゃ?と思ってAWSコンソールを調べてみると、なんのことはない、Security Groupを設定する必要があった。

以下画像のように開けたいポートをSecurity GroupのInboundに追加する必要あり。




AWSやっぱすごい。

2017年4月10日月曜日

Ubuntuスクレイピングサーバの構築

なんかしらの価値ある情報サービスを提供するばあい、

  1. 自分でコンテンツを作成する
  2. コンテンツを集めて加工する
  3. ユーザがコンテンツを提供するフラットフォームを提供

のどれかの手段を取る必要があるが、今回作成したキンドルセール情報の検索サイトは「2」なので、スクレイピングして情報を集めることにした。

結構この手段を使うひとはいると思うので、構築手順を書いておく。

スクレイピングサーバ構築手順

node.js install
 sudo apt-get install nodejs
ruby install
apt install rbenv ruby-build
git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
sudo apt-get install -y autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm3 libgdbm-dev ruby-dev  libmysqlclient-dev
mkdir -p "$(rbenv root)/plugins"
git clone https://github.com/rkh/rbenv-update.git "$(rbenv root)/plugins/rbenv-update"
rbenv install 2.3.1 
ruby project deploy
git clone xxxxxxx
sudo apt install ruby-bundler
bundle install
ブラウザ動作環境を整える
chromium install
sudo apt-get install chromium-browser
sudo apt-get install xvfb
chrome-driver install
wget https://chromedriver.storage.googleapis.com/2.26/chromedriver_linux64.zip
unzip chromedriver_linux64.zip
cp chromedriver ~/.rbenv/versions/2.3.1/bin
~/.bash.rcに追加
# rbenv
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
nohup Xvfb :99 -ac -screen 0 1024x768x8 &
export DISPLAY=":99" 

のちにAnsibleで書いて自動化する気持だけは強くもっている。




2017年3月26日日曜日

キンスメの技術スタックの話

シンガポールから帰還後、時間があったのでKindleのセール情報を収集して、検索できるサイトを作成している。

このサイトでどんな技術を使っているか紹介する。自分でサイトを作成するとき興味があるもの、つかってみたいものが遠慮なく使えるのがいいなぁと

とはいいつつ興味があるものを選択しながら、開発スピードが出るものを選ぶのが結構難しい。

サーバ


  • ruby 2.3.1
  • ruby on rails 5.0.1
  • MySQL 5.7
  • Ubuntu 14.04
  • nginx
  • unicorn

バッチ

  • ruby on rails (railsのタスクとして実装)
  • chrome (スクレイピングよう)
  • selenium web driver (スクレイピングよう)

Gem


  • jbuilder (jsonよう)
  • vacuum (Amazon Associate API のラッパーかなり助かった)
  • nokogiri
  • whenever
  • selenium-webdriver
  • paranoia
  • unicorn

フロント

  • node.js
  • npm
  • react
  • material-ui
  • awesome-font
  • babel
  • webpack (設定がかなり面倒だった。。。)
フロントは初めてReact, webpackなど使ったので苦労した。フロント周りはまだこれを入れれば設定完了!みたいな至れり尽くせりけいのパッケージがなく自分でどれを組み合わせるか考え、設定ファイルを書くのがしんどい。みんなやることは大して変わらないと思うんだけどなぁ。

徐々にサイトを作る上でハマった点や、サービスのグロースについて書いていければと。




2016年4月18日月曜日

Rubyの継承, include, prepend, extendの違い

Rubyの継承の仕方
Rubyはオブジェクト指向言語であるのだけれど、Javaの継承と考え方、方法が違うようなので、メタプログラミング Rubyを読みつつ調べてみた。

Module
RubyにはModuleという概念があり、これはメソッドがまとめられたものである。通常の継承のほかにこのModuleをincludeやprependすることにより、メソッドをクラスに取り込むことができるもよう。

早速試してみる。

通常の継承の例
[1] pry(main)> class MySubClass
[1] pry(main)*   def subClass
[1] pry(main)*     p "sub class"
[1] pry(main)*   end  
[1] pry(main)* end  
=> :subClass
[2] pry(main)> class MyClass < MySubClass
[2] pry(main)*   def myClass
[2] pry(main)*     p "my class"
[2] pry(main)*   end  
[2] pry(main)* end  
=> :myClass
[3] pry(main)> myclass = MyClass.new
=> #<MyClass:0x0000000d1eb628>
[4] pry(main)> myclass.subClass
"sub class"

=> "sub class"
ふむ、普通にメソッドを継承してる。


includeの例
[2] pry(main)> module MyModule
[2] pry(main)*   def myModuleMethod
[2] pry(main)*     p "myModuleMethod"
[2] pry(main)*   end  
[2] pry(main)* end  
=> :myModuleMethod
[3] pry(main)> class MyClass
[3] pry(main)*   include MyModule
[3] pry(main)*   def myMethod
[3] pry(main)*     p "myMethod"
[3] pry(main)*   end  
[3] pry(main)* end  
=> :myMethod
[4] pry(main)> myClass = MyClass.new
=> #<MyClass:0x0000000bf719e8>
[5] pry(main)> myClass.myModuleMethod
"myModuleMethod"

=> "myModuleMethod"
むむ、こちらも普通にメソッドを継承してる。

prependの例
[3] pry(main)> module MyModule
[3] pry(main)*   def myModuleMethod   
[3] pry(main)*     p "myModuleMethod"     
[3] pry(main)*   end     
[3] pry(main)* end  
=> :myModuleMethod
[4] pry(main)> class MyClass
[4] pry(main)*   prepend MyModule  
[4] pry(main)*   def myClass  
[4] pry(main)*     p "my class"    
[4] pry(main)*   end    
[4] pry(main)* end  
=> :myClass
[5] pry(main)> myclass = MyClass.new
=> #<MyClass:0x0000000cd80e08>
[6] pry(main)> myclass.myModuleMethod
"myModuleMethod"

=> "myModuleMethod"
はい、こちらも普通に継承

extendの例
[1] pry(main)> module MyModule
[1] pry(main)*   def myModuleMethod   
[1] pry(main)*     p "myModuleMethod"     
[1] pry(main)*   end     
[1] pry(main)* end  
=> :myModuleMethod
[2] pry(main)> class MyClass
[2] pry(main)*   extend MyModule  
[2] pry(main)*   def myClass  
[2] pry(main)*     p "my class"    
[2] pry(main)*   end    
[2] pry(main)* end  
=> :myClass
[3] pry(main)> myclass = MyClass.new
=> #<MyClass:0x0000000d374c88>
[4] pry(main)> myclass.myModuleMethod
NoMethodError: undefined method `myModuleMethod' for #<MyClass:0x0000000d374c88>
from (pry):13:in `<main>'
[5] pry(main)> MyClass.myModuleMethod
"myModuleMethod"

=> "myModuleMethod"
おお、extendはクラスメソッドになった!

じゃあinclude と pretend は一体何が違うのかというと、メソッドを呼び出していく順番に違いが出てくるらしい。

Includeの例 クラスの親階層にはいる。
2.1.5 :001 > module MyModule
2.1.5 :002?>     def my_class
2.1.5 :003?>         p "my_class in my module"
2.1.5 :004?>       end
2.1.5 :005?>   end
 => :my_class
2.1.5 :006 > class MyClass
2.1.5 :007?>     include MyModule
2.1.5 :008?>     def my_class
2.1.5 :009?>         p "my class"
2.1.5 :010?>       end
2.1.5 :011?>   end
 => :my_class
2.1.5 :012 > class SubMyClass < MyClass; end
 => nil
2.1.5 :013 > SubMyClass.ancestors
 => [SubMyClass, MyClass, MyModule, Object, Kernel, BasicObject]

2.1.5 :019 > sub_my_class = SubMyClass.new
 => #<SubMyClass:0x000000024ecff8>
2.1.5 :020 > sub_my_class.my_class
"my class"
 => "my class" 
Pretendの例 クラスの子階層の子になる。
2.1.5 :001 > module MyModule
2.1.5 :002?>     def my_class
2.1.5 :003?>         p "my_class in my module"
2.1.5 :004?>       end
2.1.5 :005?>   end
 => :my_class
2.1.5 :006 > class MyClass
2.1.5 :007?>     prepend MyModule
2.1.5 :008?>     def my_class
2.1.5 :009?>         p "my class"
2.1.5 :010?>       end
2.1.5 :011?>   end
 => :my_class
2.1.5 :012 > class SubMyClass < MyClass; end
 => nil
2.1.5 :013 > SubMyClass.ancestors
 => [SubMyClass, MyModule, MyClass, Object, Kernel, BasicObject]
2.1.5 :016 > sub_my_class = SubMyClass.new
 => #<SubMyClass:0x000000011fabc0>
2.1.5 :017 > sub_my_class.my_class
"my_class in my module"
 => "my_class in my module"

SubMyClassから呼び出した時に、PretendだとMyModuleが先にメソッドがあるかどうか走査され、IncludeだとMyClassが先に走査される。 

2016年1月26日火曜日

2015 オープンソースプロジェクト Top 10

あけましておめでとうございます。今年から日本に帰ってきて働いております。
去年は1回しか更新しないという暴挙にでましたが、今年はまず月一ぐらいの更新を目指しますw

去年の記事は2014 Top Open Source Projectを訳したので、今年の一発目は2015 Top Open Source Projectで行きたいかと思います。しかし、何を持ってTopなのか・・・


ここへきてGitが入っているのが?ですが、これに変わる履歴管理のプロダクトはそうそう出て来なそうですね。Githubみたいな、それをベースにしてもっと便利にするようなWebサービスが他のオープンソースでも出てくるかもですね。個人的には入ってませんがTensor flowなど機械学習系のオープンソースに興味ありです。


Apache Spark

BigData処理がオープンソース界隈にきてから、Hadoopは一つだけの解ではなくなった。
Apache Sparkは一般的にはデータ処理ツールで大量のデータ、ノードをコーディネイトする。そのためユーザは自分の使っているプログラミング言語での処理に集中できる。
今年の初めに私たちは大量データの世界記録 100TB を23分で処理したとアナウンスした。
Apache Sparkへの関心はとどまることなく、プロジェクトは多数の新しいコントリピュータとAadoptersが参加している。

Blender

Blender Foundation は "フリーでオープンソースで完璧な3D作成環境をアーティストやスモールチームに提供" するというミッションの途中だ。今年、私たちはBlenderのパワーをOpensource.com内のBlenderに関連する記事で見た。ライターである Jason van Gumsterはアムステルダムで開かれた、Blender Conferenceを含む複数のそれらの話を紹介した。 

D3

大量のデータがある環境で働いている場合、データの可視化はあなたが今何を見ているのか?を理解するいい方法だ。webで理解のしやすいインタラクティブな可視化を追加することができる。その一つの方法がD3である。D3はJavascriptベースの可視化フレームワークで、チャート、グラフなど様々な描画ができる。私たちは今年のはじめD3を8 excellent data visalization toolsの一つに取り上げた。

Dolphin

もしあなたがローカルPCのファイルを探すのに時間を浪費しているとしたら、あなたのニーズにぴったりで、素早く、早くファイルをコントロールできる機能のあるファイルマネージャが欲しいだろう。DolphinはKDEベースのディストリビューションで多くデフォルトファイルマネージャとして使われている。それはパワフルであなたのファイル整理を助ける。より多くのDolphinに関する情報はDevid Bothの幅広いレビューと今年のはじめのガイドに載っている。

Git

世界のバージョンコントロールはGitが参入した10年前から確かに変わった。それからGitは急速に最も有名なバージョンコントロールツールにないr、それはコードに対してだけではない。Gitはリビジョニング、ブランチングなどのファイル管理も助け、協調した開発のワークフロー改善などの助けにもなる。あなたがまだ古いソースコード管理プロジェクトを使っているなら、ここに移行のための記事がある。https://opensource.com/business/15/7/interview-emma-jane-hogbin-westby-git

Mattermost

Mattermostはチームチャットに対するとてもモダンなアプローチだ。現在βリリースで、GolangとJavascriptはReactフレームワークを使用している。機能的にはプライベート、パブリックのチャット機能を持っていて、1対1、保存性、そしてインターフェースはSlackに似ていて、期待しているものほどんどを保持している。事実もしあなたがSlackを使っているなら、チェンネル、アーカイブを移行する機能をもっている。MattermostはLDAP, Active Directory authentication systemsとの連携もできる。

Piwik

PiwikはGoogle Analyticsに変わるオープンソースで、Scott Nesbittによると、あなたの欲しい機能を入れるチャンスがある。機能としていかを含む。
  • ビジター数の測定
  • 訪問者がどこから来たか
  • どこのページで離脱しているか?
  • どこのサーチエンジンから来たか?
そしてPiwkiはカスタマイズ可能な豊富なレポートを持っている。あなたの生活をもっと楽にするために、Piwkiは65以上のコンテンツマネジメントができる、WordPress, Mageneto, Joomla!, vBulletinをプラグインを使うことで可能である。どれもトラッキングコードをweb上から入れるだけで、可能となる。いつくかのウェブホスティング会社は、Piwikをワンクリックパッケージとして提供している。

R

ビックデータの時代、データサイエンティスト、統計コンピューティング、グラフィックスそしてビックデータのアナリストに褒めちぎられたR言語を学ぶときかもしれない。今年のはじめRはLinux Fundation Collaborativeプロジェクトになった。このプロジェクトはR-Hubといる、新しいコードホスティングプラットフォームの開発、やRへの貢献のサポートを提供するためであ。

SugarCRM

このプロダクトはオープンソースのカスタマーリレーションシッププロダクト界隈で大きなシェアを占める。そしてtop 5 CRM toolsのうちの1つである。コミュニティーエディションは組織が望んでいる、契約を管理したり、アクション可能なリストに名前を入れるなどの管理が、すぐに使用可能だ。多くの機能、カスタム可能なアーキテクチャーで、組織の契約管理の大きな問題解決になる。コミュニティーエディションはもっとも一般的なバージョンで、未だ大多くの人に使われている。SugarCRM CEも育ってきている。

Vagrant

Vagrantはvirtual machineの設定、起動などができるコマンドラインツールだ。Vagrantを使えば、環境は再設定可能で、持ち出し可能だ。そして、環境が描いてあるファイルはテキストファイルで記述さているため、履歴管理が容易で、コードで仮想マシンの管理ができる。VagrantはあなたがどんなOSを使っていようとも、本番環境に近い環境をあなたのローカルマシンに構築できる。そして始めることが容易である。