備忘録 blog

Docker/Machine Learning/Linux

cross-originでiframeが埋め込めないとき

What I want to do

あるサービスをwww上で展開しているのだが、元のドメインのURLをそのまま晒すのがちょっと嫌なのでそれを隠すためにurl-forwardingをしたい。

tkドメインを試す

www.dot.tk

*.tkとかいうドメインはタダで手に入る。(但し有効期限がある) 登録画面は割と癖のある挙動。登録から割り当てまで時間がかかるので注意。メアドを登録せずに匿名でも登録できるのがウリか。信頼性は低そう。 無料版の範囲だとhttps対応していない。

これでURL-forwardingを試してみたが、やっていることはforward先のurlをiframeで埋め込むことだった。 但し、あるサービスはX-Frame-Options:SAMEORIGINであったので、このままではcross-originエラーが出て何も表示されない。

URL-forwardingといっても結局はforward先のurlをiframeで埋め込むのであれば、わざわざ独自ドメインをとらなくてもどこか信頼性の高そうなドメインホスティングすればよいということになった。

動的にiframeを埋め込むようにする

人力検索はてなでも質問がされていた。

q.hatena.ne.jp

が、Stackoveflowが解決策としては一番わかり易かった。

stackoverflow.com

cross-originを外すために、以下のサイトを媒介する。

An open source alternative to AnyOrigin

このサイトにパラメータとしてurlを渡すと、html部分を含んだ結果をJSON形式で取得できるので、コールバックでcontentsだけを取得して、divに注入するようにすればよい。ただしリンクは元のドメインのURLのままなので、このページからのリンクもそれぞれ静的なページで用意して、……としない限りはリンク先がおかしいぞ、となってばれてしまう。(もちろんソースコードを見れば一発だけれど) さすがに全ページを静的なページでプロキシするのは現実的でないので、トップページだけiframeの埋め込みでごまかすことで妥協しようと思う。

Dockerでサーバーを立てる(1)

はじめに

様々なところで語られていますが、Dockerはコンテナ型のサーバー仮想化のエコシステムとして知られている。ここでは、DockerでRailsアプリを立てることを目標とする。

大まかな概略をつかむには以下のページが参考になった。

Dockerについての調査まとめ、基本機能+主な特徴+Vagrantの連携 あたり · GitHub

細かなtips

具体的な構成は次に譲るとして、ここでは細かいtipsや周辺技術を書き留めておくこととしたい。

モニタリング

モニタリングツールは群雄割拠していてどれを選ぶかは難しいが、ここでは

github.com

これを利用して、コンピュータ上でどのコンテナが立っているかをモニタリングする。

docker run -d -p 9000:9000 --privileged -v /var/run/docker.sock:/var/run/docker.sock dockerui/dockerui

一度立てた後は

docker start dockerui

で起動可能。

コンテナ内に入る

qiita.com

docker exec -it nginx bash

supervisordを使う

本来のdocerは1コンテナ1プロセスが基本ですが、複数プロセスを立ち上げたいことがあるかもしれません。 そのときにこれを使います。

qiita.com

実際にそれを使ってRoR4のコンテナを立ち上げた例がこちら。

qiita.com

データボリュームについて

しばしばbusyboxなどでデータボリュームコンテナを立てて、その上にマウントした設定ファイルやログ用のフォルダをsqlやnginxなどのコンテナで共有するパターンがあります。こうすることで、ログ等を永続化できます。

そのとき、dockerコマンドのオプションをどう設定するかのtipsが、以下にまとまっています。

qiita.com

sshdを立てる

dockerでsshdを立てることはどうなのよ、という意見もありますが、立てている例があります。

qiita.com

docs.docker.com

gentoo/stage3-amd64でemergeする

docker run -v /home/#{name}/gentoo:/usr/portage/ -it gentoo/stage3-amd64 bash

みたいにすれば、emergeコマンドによるrsyncを永続化できます。これでDocker上で手軽にGentoo LinuxPortageシステムを体験することができます。

DockerでMattermostサーバーを立てる

自前のサーバーでSlack, Hipchat系のチャットサービスを使いたいと思った時に。Golang製。

Mattermost

立ててみる

Local Machine Setup and Upgrade — Mattermost 2.0 documentation

docker run --name mattermost-dev -d --publish 8065:80 mattermost/platform

http://localhost:8065/にアクセス。それ以後は一回立てた後はこれでOK。

docker start mattermost-dev

他のチャットサービスとの比較

slack

slack.com

みんな大好きSlack。日本のスタートアップ企業でも圧倒的シェアを誇っています*1

Slackではできるけど現段階のバージョンでのMattermostでできないこと。

  • slackbotみたいな存在がない。
  • snippet, postを貼れない。
  • htmlを入力してもogが表示されない。
  • スラッシュコマンドが乏しい。
  • Androidネイティブアプリがまだ正式リリースされていない。

Rocket.Chat

デモは以下。

Rocket.Chat

こちらはjsフレームワークのMeteor製。Meteorには割と注目しているのだが、若干洗練されていないデザインであるという印象。

トラブルシューティング

このサーバーで実際に複数人が接続して試してみたときの備忘録です。

  • 他のユーザーが登録できない!
    • 最初のユーザーはteamを作るときに登録できますが、そうでないユーザーはチームの画面に行ってもsign upできずに何もできません。実は招待urlから入るしかないので、最初のユーザーはメニューからInviteを選択しましょう。
  • 最新版にアップデートしたい!
    • 公式ドキュメントによれば、これはPreview版にすぎないため一度dockerイメージを削除してからpullするしかないようです。もちろんデータは全部消えてしまいます。
  • 日本語のUIがない
    • Slackも同じなのでがんばりましょう。
  • Admin Consoleでユーザーの権限を誤ってSystem_adminから格下げしてしまった!
    • これを一度してしまうと、System_adminでないとユーザー権限を変更できないので、二度とAdmin Consoleにログインできなくなり、設定を戻せなくなって詰みます。

しかも、docker内にはplatformというバイナリがあって、それを用いて本来はユーザーの権限が変更できそうなのですが、docker execで中に入ってバイナリを実行しようとしても動かなくなります。というわけで、一度dockerイメージを削除して立ち上げ直しました。

インターンシップを終えて

IT系のインターンシップに1週間ほど行っていたので、感想を簡単に記す。

概観

求められる水準は高く、仕事中は常に頭脳をフル回転させていなければならなかった。そのためインターンシップの期間中は全くといっていいほど、それ以外のことに手がつけられなかった。寝まくったがいくら寝ても体力が回復せず、自らのバイタリティーの乏しさを感じた。

学んだこと

  • Macの使い方
  • gitの活用。プルリクとイシューの立て方
  • GitHub Frow による開発
  • Ruby on Railsの開発、きれいなコードの書き方
  • Atomの使い方、Slackを使ってみた
  • Rspecの書き方(web mocksによるスタブの活用)
  • フィーチャーテストの書き方
  • Hamlの書き方
  • Coffee scriptの解読
  • APIの叩き方。アクセストークンの設定方法
  • Active recordのクエリの書き方
  • 大規模サービスを影で支える人たちの存在

更に学んでいること

今後の展望

Devise, Rake, Redisへの理解を深める必要がある。 特にRakeコマンドは、単なるおまじないとしての取り扱いが大きかったように感じるので、使いこなせるようになりたい。 Coffee scriptぐらいは書けるようになりたい。 Atomは大きいデータを扱い出すと途端に重くなり、ハングアップすることがあるので、やはりvimに戻ろうかと思う。

インターン中に読んだ本

Unix哲学に触れた。1つのプロセスが1つだけのことをするのが良いというのはDockerの思想ともつながっており、とても興味深かった。

UNIXという考え方―その設計思想と哲学

UNIXという考え方―その設計思想と哲学

Python2を高速化するtips(続)

sharply.hatenablog.com

これの続き。

単純に高速なアルゴリズムを使う

例えば"ham"という文字列がある配列に含まれるか?という問いに対して、

some_list = ["spam", "ham", "eggs"]
if "ham" in some_list

というリスト検索ではO(log(n))ですが、RubyにおけるHashと同様のものがPythonでも辞書(Dictionaly)として提供されており、

some_dict = {"spam":1, "ham":1, "eggs":1}
if "apple" in some_dict

とすればO(1)になります。もちろんこれが使えるのには条件がありますが、これで数秒程度早くなりました。

並列計算する

python律速となっているのはだいたいfor文であり、このfor文の実行回数をいかに減らせるか、ということがポイントとなります。 並列計算には、スレッド並列化(メモリを共有する)とプロセス並列化(メモリを共有しない)の2種類があります。しかしCPythonの実装ではGIL(Global Interpreter Lock)というものがあるので、プロセス並列化ぐらいしかできません。

GILとは、並列実行したときに安全でないコード(例えばグローバル変数を書き換えるような、スレッドセーフでないコード:しばしばCのモジュールに存在する)を実行しないようにするために、そのコードを他のスレッドで呼ばれないようにする排他ロックのことで、pythonrubyといったインタプリタ言語では一般に1つのプロセスに対して1つのGILが存在する。

GILがない実装としてJPython(JAVAによる実装)やIronPython、PypyのSTM版があげられますが、ここでは措きます。

CPythonでプロセス並列化によって高速化するには、for文の区間を分割して部分和を並列で計算し、あとでその総和をとるという手段が用いられます。しかしCのopenMPのように動的にfor文の処理をスレッドに割り当てるといったことは標準では用意されていないので、自分で実装するなりする必要があります。

qiita.com

Boost.pythonを使う

結局pythonで計算させるには限界があるので、C++で書いたコードをコンパイルしたものを共有ライブラリとしてpython側から呼び出す実装にしてみましょう。

#define BOOST_PYTHON_STATIC_LIB
#include <boost/python.hpp>

static void image_putpixel(image &i, const boost::python::tuple &x, const boost::python::tuple &y){
  double point[2] = {boost::python::extract<double>(x[0]), boost::python::extract<double>(x[1])};
  uchar color[3] = {boost::python::extract<uchar>(y[0]), boost::python::extract<uchar>(y[1]),boost::python::extract<uchar>(y[2])};
  i.putpixel(point, color);
}

BOOST_PYTHON_MODULE(brush)
{
    using namespace boost::python;

    class_<image>("image")
        .def("show", &image::show)
        .def("brush", &image_brush)
        .def("putpixel", &image_putpixel)
        .def("load", &image::load)
        .def("get", &image::get);
}

上記でわかるように、C++のクラスをpythonのクラスにみなせたり、pythonのtupleを引数としてとるような関数を定義することができます。

コンパイルオプションは例えばUnix環境ではこんな感じ。

g++ -std=c++11 -O2 -I`python -c 'from distutils.sysconfig import *; print get_python_inc()'` -DPIC -fPIC -shared -o brush.so src/brush.cpp -lboost_python

-Iにインクルードパスを指定したいのですが、そのパスが異なるコンピュータ上でも共通に実行できるように、``でpythonを実行するコードを囲うことでそれをシェル上で評価した結果が返ってきます。

python側からは、soファイルを同じディレクトリに置いてファイル名でimportすればOKです。さらに、openMPで実装したC++のコードをpython側から呼び出すこともでき、さらに速度が上がる可能性もあります。

光学設計者の学習メモ: Boost.pythonでOpenMP

APIサーバーが必要となった時のために

自前で実装する

サーバー側にけっこう大きなロジックが必要となる場合。この場合は、単なるRESTなリソースを提供するだけでなく、返り値のロジックが必要となるので、結局自分で全部書いたほうがラクになるということになる。HerokuやOpenShiftといったPaaSに立てることとなる。

Ruby on Railsの場合

qiita.com

Grapeというのがやりやすいらしい。

github.com

Pusherを使う

APIにしてスマホのネイティブアプリを作るのならばともかく、ブラウザでアクセスしてもよいということにして、かつWebSocket的なことがやりたいのであれば、Rails5を待つかコレを使う。

Pusher | Leader In Realtime Technologies

例えば、クライアントはpythonでも書ける。

github.com

Golangの場合

作ろうとするAPIがRESTfulなものでなくてよいなら、むしろこの程度シンプルなもののほうが作りやすいかもしれない。こっちのほうが当然ながら早い。

aial.shiroyagi.co.jp

qiita.com

BaaSサーバーの候補

サーバーは単にデータストア程度でよいとするならば、BaaSサーバーを使うという手がある。2015/10現在で試用が期限なし無料のサービスを列挙してみた。

国産

無料だとpush数が少ないのが劣る点。 www.appiaries.com

海外産

  • Parse

実質最大手。 www.parse.com

  • Quickbox

quickblox.com

変わり種

  • Mongolab

mongodbがクラウドで扱えるらしい。

mongolab.com

参考

iphone-dev.g.hatena.ne.jp

qiita.com

Python2のコードを高速化するための覚書

実行時間の測定方法

CPythonでpythonの素のコードを実行するとヤバイぐらいに時間がかかる。実際にどのぐらいかかるのかを調べる。

import time
def main():
  start = time.time()
  hoge()
  elapsed_time = time.time() - start

まあこれでもよいのだが、

python -m cProfile -c totaltime hoge.py

以上を実行すれば、それぞれの関数呼び出しの回数と、totalの実行時間が明らかになる。明らかになったところで、律速段階となっている関数の高速化に取り組みたいと思う。

高速化手法

numbaでjitを使う

from numba.decorators import jit

@jit
def hogehoge():

@jitをつけるだけでllvmjitしてくれる。あまり早くならなかった。

Numba — Numba

numpy.vectorizeを使う

numpy.vectorizeは配列を引数に取って配列として返す関数を作るものである。ここで、対象となる関数は引数が複数あってもよく、それぞれの引数についてベクトルを渡せばそれぞれの値に対して処理された結果が帰ってくるし、スカラーを渡せばそれはどのベクトルに対しても同じ値が引数として呼ばれる。

import numpy as np

def hogehoge(t, anchor):
    return "hogehoge"

def main()
    vhogehoge = np.vectorize(hogehoge, excluded=['anchor'])
    mlist = list(vhogehoge(np.arange(0.0, 1.01, 0.01), anchor=anchor))

引数のexcludedでanchorを除外することで、引数に配列を渡したいときにはその配列が分解されずにその関数に渡すことができる。 一方で、渡したいarray of arrayとなっている場合、引数に渡した配列excludedされては"array of array"のまま渡されるか、さもなければ1つのcellごと渡されることになるので、二次元配列を一次元分だけ渡すということはできない。

pypyを使う

これが現時点では最も効果が得られた。 pypyは、CPythonではないpythonの処理系の実装であり、JITコンパイルを適宜行って実行速度の改善が図られている。但しpypyではCPythonのCバインディングのところや、ライブラリの対応がまだ中途半端ということらしいが少なくとも、python2~3の互換性よりはpypyの方がスムーズに移行できた。つまり、コードの書き換えをほとんど必要としないということである。 実行するときは、公式サイトからダウンロードしたバイナリファイル(bin/pypy)をpythonの代わりに実行すればよい。 これを用いると、あるプログラムで11倍ほど高速化された。

pypy.org

Boost.Pythonを使う

これはpythonの範疇からはみ出してしまうが、C++でコードを書き、それをpythonでラッパーとして呼び出して実行する方法としてBoost.Pythonがある。 これについてはまだ研究中であり、ここでの詳述は避けたい。

http://alpha.osdn.jp/devel/boost.python_ja.pdf

Bootstrapの導入時に発生するエラーと解決法

ActionController::RoutingError (No route matches [GET] "/fonts/glyphicons-halflings-regular.woff")

Ruby on Rails4の開発で/vender/assets/stylesheets/によそからもってきたbootstrap.cssを入れているとき、上記のエラーが発生することがある。 その場合、フォントを/vendor/assets/fontsに置き、config/application.rbに

config.assets.paths << "#{Rails}/vendor/assets/fonts"

を挿入する必要があるが、もう1点しなければならないことがあり、それは/app/assets/stylesheets/custom.css.scssなどではなく、/vender/assets/stylesheets/bootstrap.cssを改変することである。

@font-face {
font-family: 'Glyphicons Halflings';
src: url("../assets/glyphicons-halflings-regular.eot");
src: url("../assets/glyphicons-halflings-regular.eot?#iefix") format("embedded-opentype"), url("../assets/glyphicons-halflings-regular.woff2") format("woff2"), url("../assets/glyphicons-halflings-regular.woff") format("woff"), url(     "../assets/glyphicons-halflings-regular.ttf") format("truetype"), url("../assets/glyphicons-halflings-regular.svg#glyphicons_halflingsregular") format("svg");
1215 }

上記に書き換えたところ、うまく動いた。

Note

webdesign.tutsplus.com

POH6をPythonで解く

動機

最近、学科内でPythonがブームとなっているようなので便乗して勉強してみた。 ただ勉強するだけでは面白くないので、オンラインハッカソンに挑戦して実際に書きながら学んでみたいと思う。

paiza.jp

コード

paiza.jp

input_lines = int(raw_input())
water = 0.0
powder = 0.0

for i in xrange(input_lines):
  s = raw_input().rstrip().split(' ')
  if s[0] == '1' :
    water += int(s[1])
  elif s[0] == '2' :
    powder += int(s[1])
  else :
    total = water+powder
    water -= int(s[1])*water/total
    powder -= int(s[1])*powder/total

print int(100*powder/(water+powder))