あんパン

こしあん派

オブジェクトストレージ Minioで遊ぶ

これはKMC Advent Calendar 2015 15日目の記事です。

昨日は id:jf712 さんの @uiureo さん誕生日おめでとうございます - 霊安日記 でした。

目次

はじめに

こんにちは、id:masawadaです。KMC内でもアカウント名はmasawadaです。東京にある電気通信大学という大学に通っています*1。YAPC2015で入部しました。

本日はAmazon S3互換のオブジェクトストレージMinioを紹介します。

Minioとは

MinioはAmazon S3互換のオブジェクトストレージを構築するソフトウェアです。

Golangで記述されておりApache License v2の元で公開されています。

本体は非常にコンパクトで、ひとつのバイナリをfetchし実行権限をつけて叩くだけで起動することができます。例えばMacであれば以下の3コマンドで起動することができます。

$ curl https://dl.minio.io:9000/updates/minio/2015/Dec/darwin-amd64/minio > minio
$ chmod +x minio
$ ./minio server ./

以下のテキストは2015年12月12日時点でのものです。これ以降のバージョンでの動作は保証しません。

Minioの使い方

サーバを起動する

「はじめに」でも記述した通り、以下の3コマンドで取得と実行をすることができます。

$ curl https://dl.minio.io:9000/updates/minio/2015/Dec/darwin-amd64/minio > minio
$ chmod +x minio
$ ./minio server ./

64bitのLinuxであればURLが

https://dl.minio.io:9000/updates/minio/2015/Dec/linux-amd64/minio

に変わるだけです。詳しくはこのページをご覧ください。

実行するとカレントディレクトリを起点にオブジェクトストレージのサーバが起動します。初回起動時に$HOME/.minio/config.jsonが作成され、accessKeyIdおよびsecretAccessKeyが生成されます。これらのキーはMinioを起動したコンソールにも表示されるので、控えておきましょう。

サーバを叩く

MinioにはmcというCLIがあり、これを用いることでオブジェクトストレージを操作することができます。しかしコマンドがAmazon S3のAPIとは対応しておらず直感的でないのでここでは取り扱いません。詳しくはGitHubのリポジトリをご覧ください。

Node.jsから叩く

MinioのJavaScript向けライブラリがあるため、これを用いることができます。事前にnpm i minioしましょう。

以下のコードを保存し実行権限を付与して叩くことでBucketsのリストを表示することができます。

#!/usr/bin/env node

var Minio = require('minio');

var s3client = new Minio({
  url:  'http://localhost:9000',
  accessKey: 'YOUR-ACCESSKEYID',
  secretKey: 'YOUR-SECRETACCESSKEY'
});

s3client.listBuckets(function(e, bucketStream) {
  bucketStream.on('data', function(obj) {
    console.log(obj);
  });
});

Minioオブジェクトを初期化する際、ライブラリのバージョンが0.2.9ではエンドポイントをurlで指定します。2015年12月15日現在のmasterブランチにあるライブラリではこれがendPointとなるので注意してください。

Rubyから叩く

RubyにはMinioの公式ライブラリが存在しません。そこで、aws/aws-sdk-rubyを利用します。事前にgem install aws-sdkしましょう。

以下のコードを保存し実行権限を付与して叩くことで、Bucketsのリストを表示することができます。

#!/usr/bin/env ruby

require 'aws-sdk'

credentials = Aws::Credentials.new(
  'YOUR-ACCESSKEYID',
  'YOUR-SECRETACCESSKEY',
  nil
)

client = Aws::S3::Client.new(
  credentials: credentials,
  endpoint: 'http://localhost:9000',
  region: 'us-east-1',
  force_path_style: true
)

res = client.list_buckets
res.buckets.each do |bucket|
  p bucket.name
end

Amazon S3互換オブジェクトストレージに関する雑談

Minio向けライブラリのコードを読むとわかりますが、Amazon S3以外のS3互換オブジェクトストレージを叩く際、regionはus-east-1を指定しておくと良いそうです(おそらく何を指定しても同じと思いますが、、)。

S3互換のオブジェクトストレージには

  • Minio
  • Google Cloud Storage (Compatibility Mode)
  • Openstack Swift + Swift3 middleware
  • Ceph Object Gateway
  • Riak CS

などがあり、このうちMinio以外はSignatureの生成方式が若干古いため大方のMinio向けライブラリでは対応できません*2。ざっと見minio/minio-goのみ対応しているようでした。実際、openstack/swift3を見たところVersion 4 is not readyとなっていたので注意が必要です。

総評

1バイナリでそれなりのサーバが立ち上がるMinio、意外と使えるのではないかという感想です。特に、簡単なウェブサービスなどであればAmazon S3を開発のテストに使わなくても良くなるなどでメリットを享受できそうです。

ただ、開発のスピードがかなり速いため先人の記録が使い物にならないこともしばしばあります。前述の通り、GitHubのドキュメントを読んでいたらnpmに上がっているライブラリのバージョンがほんの僅かに古く、masterブランチのサンプルコードが一切動かないという現象に遭遇しました。

じっくりと本体及びライブラリのコードを読む姿勢が大切と思います。

明日は id:itochan315 さんの番です。

宣伝

京大マイコンクラブではオブジェクトストレージが大好きな部員を募集しています。年齢性別所属宗教等の制限はありません。東京の大学に通っていても入部可能です。詳しくは以下の案内をご覧ください。

*1:大阪電気通信大学でも、国立(くにたち)にあるわけでもありません

*2:https://github.com/minio/minio-go/blob/dd3182/README.md

RTX1100初期設定

これはmasawada Advent Calendar 2015 4日目の記事です。

初期化

RTX1100の後方にinitボタンがあるので、押しながら起動すれば初期化できる。

DHCPサーバの設定まで

telnetする

RTX1100はデフォルトでIPv4のDHCPサーバとなっていないのでなにもできない。IPv6のリンクローカルアドレスにpingを送り、帰ってきたアドレスにtelnetすることで設定を開始することができる。

$ ping6 -I en3 ff02::1

ping6コマンドでIPv6のpingを送ることができる。-Iオプションでネットワークインタフェースを指定する必要がある。また

$ telnet ...%en3

のように、telnetするときも末尾にインタフェースを指定する。

administratorのパスワード指定する

> administrator
# administrator password encrypted ...
# console character ascii
# save

管理者パスワードをencryptして保存するようにする。端末はutf8で、そのまま使うと日本語が化けるのでasciiにしてすべて英語で出力する。

IPv4設定, DHCPサーバ起動する

# ip lan1 address 192.168.0.1/24
# dhcp service server 
# dhcp scope 1 192.168.0.100-192.168.0.200/24 
# dns server pp 1 
# dns private address spoof on
# save

これくらい入れといたらよさそう。

PPPoE喋らせる

# ip route default gateway pp 1
# pp slect 1
pp1# pp always-on on
pp1# pppoe use lan2
pp1# pp auth accept pap chap
pp1# pp auth myname [user] [pass]
pp1# ppp lcp mru on 1454
pp1# ppp ipcp ipaddress on
pp1# ppp ipcp msext on
pp1# ppp ccp type none
pp1# ip pp mtu 1454
pp1# ip pp intrusion detection in on reject=on
pp1# ip pp intrusion detection out on reject=on
pp1# ip pp intrusion detection out winny on reject=on
pp1# ip pp nat descriptor 1
pp1# pp enable 1
pp1# pp select none
# save

こんなんで外と通信できるんじゃないかと思う。別途フィルタとか定義すると良い。

余談

L2TP/IPsecの設定をしたとき

# ip lan1 proxyarp on

これがないとルータに接続できても、他の端末につなぐなどができない。


本当はL2TP/IPsecの設定とか載せようと思ったけどあんまよくない気もするしやめた。

高専カンファ100で発表します

高専生ではないのですが、スタッフに高専生じゃない人もいるということで、高専カンファレンス100 in 東京で発表させていただくことになりました。

まだタイムテーブルなどは出ていないのですが、そのうち出るような気がします。高専カンファ100自体は12/19、12/20の2日続けて開催で、自分の発表は複数トラック発表のため20日の方になります。(19日も見に行くかもしれないです。)

すでにタイトル/概要は提出済みで、ScratchXの話をしようと思っています。ScratchはMITで開発されたビジュアルプログラミング環境で、ScratchXはこれを元にJavaScriptで拡張できる実験的リリースという立ち位置のツールです。

f:id:masawada:20151125012459p:plain

Scratch自体難しいツールではない(日本語、ひらがなで扱えるため小学生にもユーザが多い)ので、プログラミングに関する知識などなくてもある程度は楽しめる発表にする予定です。
ぜひお越しください。

詳しくはこちら: 高専カンファレンス100 in 東京 - 高専カンファレンス Wiki
場所がなんと電通大なので、定期圏内ということで最高に素敵。

dokku上で動作する係り受け解析APIサーバの作り方

係り受け解析はあくまで例なので、これに関して詳しく知りたい人は他をあたってください。本稿はdokku(Bashスクリプトで作られたHerokuライクなオンプレミスPaaS環境)上でCaboChaを用いて係り受け解析をする簡単なAPIを作成する、というシナリオで、システムコマンドをインストールするような複雑なアプリケーションの作成方法を解説するものです。

といっても、その方法はお粗末なものなので、より良い方法があるかもしれません。あくまで手軽に実験することができる、程度で読んでください。

dokkuについて

dokkuはBashスクリプトで作られたHerokuライクなオンプレミスPaaS環境です。Dockerコンテナを作成し、Herokuが提供しているbuildpackを利用してアプリケーションをデプロイします。インストールやHTTPS化などについては以下を御覧ください。

masawada.hatenablog.jp

係り受け解析について

係り受け解析というと馴染みのない方もいらっしゃると思います。ある文中の文節間にどのような修飾(係)・被修飾(受)関係があるかを解析するものです。形態素解析では文を品詞に分解するところまでを行いますが、係り受け解析をすることにより、自然言語の文をよりシステムが理解しやすいように落としこむことができます。

日本語ではCaboChaを使うのが一般的ではないかと思います。今回はこのCaboChaを用いて係り受け解析をするAPIサーバを作成する、ということを目標にします。

本題

というわけで、ここからはcabocha-apiという名前のアプリケーションを作成してdokkuにデプロイするまでを解説していきます。Herokuで少し複雑なアプリケーションを作ったことがある方はすぐに理解できるかと思います。

dokkuでheroku-buildpack-multiを使う

buildpackとは、言語やフレームワーク、アプリケーション等を手軽に利用できるようパッケージ化したものです。Herokuによって作られたものや、ユーザによって作られたものが存在します。

通常、Herokuにアプリケーションをデプロイする際は1つのbuildpackが自動的に選択されます。ffmpegやmecab等のbuildpack使いたい場合は言語のbuildpackとあわせて複数のbuildpackを利用できるようにする必要があります。複数のbuildpackを扱うには、buildpackとしてheroku-buildpack-multiを指定します。

$ dokku apps:create cabocha-api
$ dokku config:set cabocha-api BUILDPACK_URL=https://github.com/ddollar/heroku-buildpack-multi.git

これでdokkuのアプリケーション作成と複数buildpackを扱う設定がおわりました。

buildpackを設定する

MacにHomebrewがあるのと同じく、LinuxにはLinuxbrewがあります。LinuxbrewはHomebrewのforkです。そのため、Homebrewで入れられるアプリケーションのほとんどはLinuxbrewでも入れることができます。本稿ではLinuxbrewを用いてCaboChaをインストールします。

ところが、本家のLinuxbrewではCaboChaをインストールすることができません。素直にインストールしようとするとlibiconvがない、とエラーを吐いてデプロイプロセスが強制終了します。そこで、独自のCaboChaインストーラを利用するために修正を施したheroku-buildpack-linuxbrewを用います。また、APIサーバをRubyで書くのでRubyのbuildpackも設定します。

以下を.buildpacksに記述してください。

https://github.com/masawada/heroku-buildpack-linuxbrew.git
https://github.com/heroku/heroku-buildpack-ruby.git

CaboChaのインストールを設定する

heroku-buildpack-linuxbrewは.cellarというファイルにアプリケーション名を記述するだけで、デプロイ時にそのアプリケーションを自動的にインストールします。ところが、本家のheroku-buildpack-linuxbrewでは独自のHomebrew formulaを利用することができません(brew tapすることができない)。そこでmasawada/heroku-buildpack-linuxbrewではtapをすることができるよう改良を施しています。

CaboChaのformulaにはlibiconvのオプションを設定している箇所があり、これが悪さをしているため、オプションを外した独自formulaをGitHub上に用意し、これを利用することにします。

以下のように.cellarを記述することで修正したCaboCha formulaを利用することができます。

tap masawada/cabocha-without-iconv
install cabocha-without-iconv

環境変数を設定する

ここからはdokkuのアプリケーションに環境変数を幾つか設定していきます。これを行わないとLinuxbrewでのビルドがうまくいかなかったり、サーバに用いるcabocha.gemのインストールがうまくいかなかったりします。

$ dokku config:set cabocha-api LIBRARY_PATH=/app/.linuxbrew/lib
$ dokku config:set cabocha-api LD_LIBRARY_PATH=/app/.linuxbrew/lib
$ dokku config:set cabocha-api LD_INCLUDE_PATH=/app/.linuxbrew/include
$ dokku config:set cabocha-api C_INCLUDE_PATH=/app/.linuxbrew/include
$ dokku config:set cabocha-api CPLUS_INCLUDE_PATH=/app/.linuxbrew/include
$ dokku config:set cabocha-api PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/app/.linuxbrew/bin

デプロイ後に環境変数を設定してからrebuildするとうまく設定されないようなので、必ず最初に設定するようにしてください。

APIサーバを書く

ここからはRubyとSinatraを用いてAPIサーバを書いていきます。

  • Gemfile: 依存ファイル
  • server.rb: 本体
  • Procfile: dokku上でアプリケーションを起動するためのスクリプト
    • web: commandという形式で書くことで、アプリケーションを起動し、リバースプロキシを設定する

また、事前にbundle installを実行してGemfile.lockを生成してください。これがない場合、デプロイ時にプロセスが強制終了します。

Gemfile

source 'https://rubygems.org'

gem 'sinatra'
gem 'cabocha'

server.rb

require 'sinatra'
require 'cabocha'

get '/' do
  parser = CaboCha::Parser.new
  tree = parser.parse(params["q"])
  @result = tree.toString(CaboCha::OUTPUT_RAW_SENTENCE)
  erb :index
end

__END__

@@index
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
  <style>pre { font: normal 14px/20px courier; }</style>
</head>
<body>
  <pre>
<%= @result %>
</pre>
</body>
</html>

Procfile

web: ruby server.rb -p $PORT

デプロイする

ここまできたらいつもどおりデプロイするだけです。上記までの作業をgit commitし、git remote add dokkuでdokkuの情報を登録します。

$ git push dokku master

でデプロイが始まります。幾つかのファイルをビルドするので、全作業を終えるのに数分かかります。作業を終えたらサーバにアクセスしてみましょう。ルートに?q=文章とクエリをつけることで、その文章の係り受け解析を行うことができます。

f:id:masawada:20150922174750p:plain

このように表示されれば成功です。

まとめ

多少手順は複雑でしたが、作業量としてはそんなに多くないのではないかと思います。Herokuの場合でも環境変数の設定をうまく行えば全く同じリポジトリをデプロイできるような気がしますが、なぜか失敗しました。今回はdokkuで動かすまで、ということでここまでにしておきます。

最後に、ここで作成したアプリケーションを以下のリポジトリに置いていますので、よろしければご活用ください(そのまま使うのは良くないです、アクセス制限をかける、入力文字列を制限するなどしたほうが良いかもしれません)。

github.com

Android版Firefoxでは文字選択後にtouchendが発火しない

というかマジかこれ

Android版Firefoxで文字選択をすると、まずselectionchangeが発火しない。これ自体は標準でそうなっているので仕方ないという感じがする。

詳細はここらへんを見るとわかる気がする。

もうselectionchangeが来るのは望み薄な気がする。それは良いとして、Android版のFirefoxだと文字選択をしてそのまま指を押し上げるとtouchendが発火しない。この時点でなんなんだこのブラウザはと思うんだけど、これもまぁiOSとかAndroid版Chromeと同じ挙動ではある気がする。

そして、何故か選択を解除するとtouchendが発火する。これが謎。

頼むからブラウザだけじゃなくてスマートフォンのイベント仕様もちゃんと整えてくれという気持ちでこの記事を書いています。

Android Chrome/標準ブラウザとiOSのSafariについてはこちら

masawada.hatenablog.jp