2014/05/25

Google Cloud Platformでdockerに入門する

dockerが何かよく分かってないのでとりあえず使ってみて「コレはなにか?」「何ができるのか?」を実践しながら理解する。

STEP1: Google Compute Engine(GCE)のセットアップ
Google Cloud ConsoleでCloud Projectを作ってCompute EngineをEnableにする。Billingを設定していないとCompute Engineは使えないので注意。
Cloud Projectの設定は
・PROJECT NAME: Docker Test
・PROJECT ID: docker-project
とする。PROJECT IDはデフォルトで設定されている値を使ってもよい。

STEP2: Google Cloud SDKをインストール
% curl https://dl.google.com/dl/cloudsdk/release/install_google_cloud_sdk.bash | bash
% gcloud auth login

ブラウザが開くのでGoogle Compute EngineをセットアップしたGoogleアカウントの認証を行う。
ログインが完了すると。
You are logged in as adamrocker@gmail.com
などとコンソールに表示される。

STEP3: GCEにインスタンスを追加する
ブラウザからGoogle Cloud Console経由でGCEにインスタンスを追加することもできる。GUIがあるので簡単だけど、今後の自動化を考慮してコンソールからCUIでインスタンスを作る。
利用できるインスタンスイメージを知る
% gcutil listimages --project=docker-project

Debianのインスタンスを作る場合、以下のコマンドを実行。
% gcutil addinstance docker-test --image=backports-debian-7-wheezy-v20140415 --project=docker-project

docker-testはインスタン名を意味するので好きな名前を設定してよい。
imageは利用できるインスタンスイメージを指定する。Debian以外にもCentOS,RedHat,SUSEなどが選べる。

CUI内でインスタンスを作るゾーンを選ばされるので、とりえあずネットワーク的に近いasiaにしておく。
Select a zone:
1: asia-east1-a
2: asia-east1-b
3: europe-west1-a  (maintenance starts in 68 days)
4: europe-west1-b
5: us-central1-a
6: us-central1-b
>>> 1
次はマシンタイプを選ばされるので一番安い(しょぼい)n1-standard-1を試す。
Select a machine type:
1: n1-standard-1 1 vCPU, 3.75 GB RAM
2: n1-standard-16 16 vCPUs, 60 GB RAM
3: n1-standard-2 2 vCPUs, 7.5 GB RAM
4: n1-standard-4 4 vCPUs, 15 GB RAM
5: n1-standard-8 8 vCPUs, 30 GB RAM
6: n1-highcpu-16 16 vCPUs, 14.4 GB RAM
7: n1-highcpu-2 2 vCPUs, 1.8 GB RAM
8: n1-highcpu-4 4 vCPUs, 3.6 GB RAM
9: n1-highcpu-8 8 vCPUs, 7.2 GB RAM
10: n1-highmem-16 16 vCPUs, 104 GB RAM
11: n1-highmem-2 2 vCPUs, 13 GB RAM
12: n1-highmem-4 4 vCPUs, 26 GB RAM
13: n1-highmem-8 8 vCPUs, 52 GB RAM
14: f1-micro 1 vCPU (shared physical core) and 0.6 GB RAM
15: g1-small 1 vCPU (shared physical core) and 1.7 GB RAM
>>> 1
十数秒だけ待つと完了する。
確認のため、ブラウザでCloud Consoleを見ると、確かにインスタンスが作られていた。

STEP4: GCE上にdockerをインストールして実行する
まずはSSHでGCEにログイン
% gcutil --project=docker-project ssh docker-test
adam@docker-test:~$

dockerをインストール
adam@docker-test:~$ curl get.docker.io | bash
このコマンドだけで、gitをインストールしたり、dockerのリポジトリとかを設定したり、そこからdockerのイメージをインストールしたり、、、とりえあずdockerを実行するのに必要なツール全部をインストールしてくれる。便利だが何をしているのか謎…。
とりあえずdockerのインストールが完了したので、実行してみる。
adam@docker-test:~$ sudo docker run busybox echo 'docker on GCE!!'
docker on GCE!!
なんか実行できた。
これでdockerコンテナを起動して、その上でechoコマンドを実行。
全コマンドが終了したのでdockerコンテナが終了した。
起動中のdockerコンテナを一覧するコマンドを叩いてみる。
$ sudo docker ps
CONTAINER ID    IMAGE    COMMAND    CREATED    STATUS    PORTS    NAMES

何もリストされていない。dockerコンテナが終了した事が確認できた。
docker runはコンテナプロセスの起動コマンド。
busyboxは起動するコンテナイメージ。
echo 'docker on GCE!!'はbusybox上で実行するコマンド。

試しに別のコマンドを実行してみる。
adam@docker-test:~$ sudo docker run -i -t busybox:latest
# cd /tmp
# echo 'Hello, docker!' > test
# cat test
Hello, docker!
# exit
-iオプションはインタラクションモード。dockerコンテナ内で作業ができる。終わったらexitでホストOSに抜け出す。
-tオプションはタグの指定。イメージ(busybox)のブランチを指定して起動している。
コンテナイメージの/tmpの下にtestというファイルを作ったが、ホストOS上では
adam@docker-test:~$ cat /tmp/test
cat: /tmp/test: No such file or directory
となり、ファイルが読み込めない。
これはコンテナ毎にファイルシステムが独立して管理されているから。
AUFS(Another Union File System)というらしい。
read-onlyでファイルシステム(busybox:latest)を読み込む。
read-onlyで読み込んだファイルシステムに更新が生じたら、
writeできるファイルシステムに当該ファイルをcopyしてwrite。
いわゆるcopy-on-write。
コンテナから見えるファイルシステムは、ベース(read-only)のファイルシステムとwriteできるファイルシステムを透過的に重ね合わせられている。

つまり、/tmp/testファイルはread-onlyのファイルシステムではなくwritableなファイルシステムから読み込んでいるのに対して、それ以外のファイル、例えば/bin/bashなどはread-onlyのファイルシステムから読み込んでいる。

CD(DVD)ブートしたOSと似たようなイメージ。
writableなファイルシステムをメモリ(RAM)上に構築して、OSとして普通に使えるようにしていて、CD(DVD)を取り出したら当然、writeしたファイルも全部消えちゃう。

STEP5: コンテナイメージを作る
コンテナ上でファイルを作ってもコンテナを終了するとファイルもなく(みえなく)なってしまうのでは、dockerを起動するたびにファイルをイチから作らなければならないので面倒だ。
ということで、ファイルを作成したコンテナの状態を新たなコンテナイメージにすれば良い。
言い換えるとbusybox:latestというイメージを起動し、/tmp/testというファイルを作り、それを新たなコンテナイメージ(例えばbusybox2)にする。testというファイルを利用したければbusybox2というコンテナイメージを起動すれば良い。

早速やってみる。
adam@docker-test:~$ sudo docker ps -a
CONTAINER ID        IMAGE                       COMMAND                CREATED             STATUS                         PORTS               NAMES
bfbdf28957c2        busybox:buildroot-2014.02   /bin/sh                4 minutes ago        Exited (127) 2 minutes ago                         prickly_ptolemy   
44449bb3a8e7        busybox:buildroot-2014.02   echo 'docker on GCE!   About an hour ago   Exited (0) About an hour ago                       prickly_tesla       
09ff9045e8e6        busybox:buildroot-2014.02   echo 'Docker has bee   About an hour ago   Exited (0) About an hour ago                       naughty_torvalds   
実は、いままでdockerコンテナを起動しread-write系のコマンドを実行していたものは全て別コンテナとして存在している。
つまりbusyboxイメージのブランチイメージとして存在する。docker runコマンドを打つたびにあらたなコンテナをドンドン作っていたことになる。
ということなので、testファイルを作ったコンテナ(ID: bfbdf28957c2)をコンテナイメージとして登録してみる。
adam@docker-test:~$ sudo docker commit bfbdf28957c2 busybox:busybox2
利用できるコンテナイメージの一覧を見る。
adam@docker-test:~$ sudo docker images
REPOSITORY          TAG                   IMAGE ID            CREATED             VIRTUAL SIZE
busybox             busybox2              1772b0d9129c        8 seconds ago       2.433 MB
busybox             latest                4c0f792ebd1e        29 hours ago        2.433 MB
早速、busybox2を起動してみる。
adam@docker-test:~$ sudo docker run -i -t busybox:busybox2
# cat /tmp/test
Hello, world!
ちゃんと/tmp/testファイルが残っていた。
コレができるようになると、コンテナイメージをどんどん作れる。試しに作ってみて、上手くいかなかったら消す。上手くいったところまでをcommitしてセーブしておく。システム構築がgitでソース管理するかのように気軽にできるようになる。

ちなみにコンテナを削除するには
$ sudo docker rm <CONTAINER ID>
まとめて削除するには
$ sudo docker rm `sudo docker ps -a -q`

STEP5: dockerをOS起動時から使えるようにしておく
おまけとして、dockerデーモンを起動スクリプトに追加しておき、OS起動時からdockerが使えるようにしておく。
$ sudo update-rc.d docker defaults


参考:
docker.io - Google Cloud Platform
Dockerを支える技術
GoogleのDockerレポジトリ

2014/05/22

User Timing APIを使ってWebアプリケーションの性能を測定する

Webアプリを作っていてチューニングしたいんだけど性能測定が難しかった。
ChromeのProfileを使ったり、console.timeを使ったりしてみたけど、User Timing APIという便利なAPIがあるらしいのでそれを使ってみた。

■環境
Chrome 35.0.1916.99 beta
※サポート外のブラウザで動作させたい場合のPolyfill(機能差分を埋めてくれるライブラリ)が公開されているのでそれを使うと良いそう。

■参考
User Timing API あなたの Web アプリをもっと理解するために

■仕込み
性能測定に使う主なメソッドは以下だけ。
window.performance.mark(...)
測定したいポイントにこのマークを設置する。 例えば、
window.performance.mark('load_file_start');
...
window.performance.mark('analyze_file_start');
...
window.performance.mark('load_file_end');
...
window.performance.mark('analyze_file_end')
のようにmarkをどんどん設置していく。

■測定
マーク間の時間を測定したい場合にmeasureメソッドを使う。
window.performance.measure('load_file', 'load_file_start', 'load_file_end');
第一引数は測定値に対する名前なので分かりやすい名前を付ける。
第二引数は測定の開始点のマーク名。
第三引数は終点のマーク名。
測定値はwindow.performanceが保持しているので、値の取得は
var items = window.performance.getEntriesByName('load_file');
などとする。
ByNameの他にByTypeなどもある。
実際の数値の出力は
for ( var i = 0; i  < items.length(); i++ )
  console.log( items[i].name + ':' + items[i].duration + ' ms' );
などとする。

■ちょっと便利なマーク値
User Timing APIが便利なのは事前に幾つかマークが仕込まれていること。
例えば、
HTMLの読込を開始する時は'fetchStart'
DOMの読込が完了した時は'domComplete'
完全にHTMLの読込・解析が完了した時は'loadEventEnd'
など。
全内容はコチラを参照→W3C Navigation Timing 
ユーザがJSで仕込める以外の部分にもマークが仕込まれているのが便利。

DOMの読込が完了してからHTMLの全ロードが完了するまでの時間を測定したい場合は。
window.performance.measure('afer_dom', 'domComplete', 'loadEventEnd');
とすればマークを何も設置せずに測定できる。
便利!

2014/05/21

Bloggerで簡単にシンタックスハイライトする方法

google-code-prettifyというライブラリを使うのがとてもラクだと思うので、これを導入します。

あとビジュアル的にシンプルなので好み。
行番号を表示したい場合は別のライブラリを使うことをオススメ。
SyntaxHighlighterとか。

テンプレートの「HTMLの編集」で<body>タグの閉じる直前に以下のJSを読み込む。
JSはCDNを利用させてもらうことで更にラクします。
<script type="text/javascript" src="http://cdn.jpillora.com/js/jp-prettify.js"></script>
投稿内でコードを表示したい部分を
<pre class="prettyprint">
... {{ some codes }} ...
</pre>
という具合に囲む。
{{ some codes }}の中はHTML特殊文字エスケープする事を忘れずに。

Polymer.jsを使ってWeb Componentsを試す

Webフロントまわりの開発をやっているとサーバサイドに比べてあまりにも面倒。調べているとWeb Componentsがかなり便利そうだったので調べたものをメモ。

■環境
Google Chrome 35.0.1916.99 beta

■参考ページ
Web Components普及の夜明け!?Polymer.jsを試してみた。
なぜWeb Componentsはウェブ開発に革命を起こすのか

■ライブラリを整える
ライブラリをGitHubから取得する。
まずブラウザの機能補完(Polyfill)ライブラリを取得する
%git clone https://github.com/Polymer/platform.git
次にWeb Componentsの実装Polymer.jsを取得する
%git clone git://github.com/Polymer/polymer.git
独自にコンポーネントを作ることもできるけど、今回は簡単に試すために既にあるパッケージ群(Toolkit-UI)をゲットしておく。
%git clone https://github.com/Polymer/toolkit-ui.git

■ページを作る
Web Componentsを使った簡単なHTML(index.html)をつくる(参考)。
<!DOCTYPE html>
<html>
  <head>
    <script src="polymer/platform.js"></script>
    <script src="polymer/polymer.js"></script>
    <link rel="import" href="toolkit-ui/elements/g-icon.html">
  </head>
  <body>
    <g-icon src="http://www.adamrocker.com/blog/images/category_7.jpg"></g-icon>
    <img src="http://www.adamrocker.com/blog/images/category_7.jpg" id="icon">
  </body>
</html>

<link>タグでg-icon.htmlコンポーネントを読み込む。
<g-icon>はToolkit-UIの中で独自に作られたタグ。このタグを使うとHTML/CSS/JSのパッケージが展開されたかのうように表示される。
Custom Elements/Shadow DOM/Templateあたりの要素技術を使っている。

■ブラウザで表示する
index.htmlをそのままブラウザで開いても何も起きない。
<link> タグのimportがローカルファイルに対応していないのでg-icon.htmlファイルを読み込めないため。
なので以下のコマンドでローカルに簡単なWebサーバを立てる。
コマンドはindex.htmlファイルと同階層で実行する。
%python -m SimpleHTTPServer

ブラウザでhttp://0.0.0.0:8000/index.htmlにアクセスすればアイコンが2つ表示されるはず。1つは24px角の小さなアイコンで、これはg-iconが以下のように展開されている。
<style>
      @host {
        * {
          display: inline-block;
          vertical-align: middle;
        }
      }

      #icon {
        width: 24px;
        height: 24px;
        cursor: pointer;
        background-repeat: no-repeat;
        background-position: center;
        background-size: 100% 100%;
      }
</style>
<div id="icon" style="background-image:url(http://www.adamrocker.com/blog/images/category_7.jpg); width:24px; height:24px">
</div>

<g-icon>が展開されると<div>要素のidがiconだが、index.htmlの<img>要素のidもicon。バッティングしてアウトな感じだが、Shadow DOM内はカプセル化されているので実際は<g-icon>が展開されたidはindex.html内のidに影響しない。当然classとかも。素晴らしい!
Web Componentsが広まれば<link> タグでコンポーネントをimportするだけでWebページの部品が使える世界になる。

  ■Web Componentsとは
HTML/CSS/JSのかたまり。ボタンやアラートやカレンダー、カラーピッカーなど、HTML/CSS/JSのセットで使いまわされるであろう機能部品を1つのかたまりとしてパッケージ化するブラウザ技術。
標準化に向けたW3Cのワーキングドラフト→Introduction to Web Components

Web Componentsはいくつかの要素技術が統合されている。
Template
Mutation Observer
HTML Imports
Custom Elements
Shadow DOM
Object.observe()
Pointer Events
Pointer Gestures
Web Animations

ブラウザネイティブでサポートしているのはごく一部の要素技術だけ。
Chromeでも全ての要素技術をサポートしているわけではない。

■Polymer.jsとは
Web Componentsを使えるようにするJavascriptライブラリ。
ブラウザの差分を埋める(Polyfill)ためにplatform.jsと併用して使う。
それによりWeb Componentsの要素技術が使える数とブラウザが飛躍的に増える。
ブラウザの互換性一覧はコレ→Browser Compatibility

■jQueryと違うのか?
考え方のオリジナルはjQueryっぽい。jQueryが成功しているので足りない部分を補完して、完成度の高いブラウザ標準機能にしようとしているみたい。
足りない部分とは、例えば、jQueryプラグインはHTMLをセットで動く事が多いけどjQueryプラグインの内部にHTMLを加えるには、DOMを作る要領で作ることはできるが…面倒。CSSも加えるとなると更に面倒。そしてクラス名などが他のライブラリとバッティングする事も考える必要が出てくる。そこらへんをまとめてWeb Componentsが面倒を見てくれる。

例えばHTML Importsを使えばHTML/CSS/JSのまとまりを読み込めるので、HTMLの生成をJSで行う必要がなく簡単。

Templateを使えば、HTMLの生成が飛躍的に楽になる。Template技術はサーバサイドでのHTML生成では当たり前に使われている。これは、そもそもWebフロント領域の話なので、これがHTMLだけで何とかなるようになると仕事がめっちゃ楽になる。いちいちサーバサイドのプログラム(JSPとかPHP、Python、Ruby)を弄る必要がなくなる。

Shadow DOMを使えば、HTML/CSS/JSのまとまりをカプセル化できるので、名称の汚染がない。CSSのクラス名などがHTML/CSS/JSのまとまりの中でしか適用されないので他のライブラリやコンポーネントのことを意識する必要がない。

2014/05/20

Chromeを使ってJavascriptの性能測定をする方法

いろいろライブラリを使えば細かくできるとは思うけど、サクッとザックリ簡単にやりたい場合。
console.time('NAME')
doSomething();
console.timeEnd('NAME')
'NAME'で挟んだ部分の処理の時間を
NAME: 345.321ms
のように出力してくれる。
Firefoxでも同じ方法でできるらしいけど未確認。

Chromeの場合、DevToolsのProfilesタブを使えば、もっと詳細にプロファイルできる。
あくまでconsole.timeはサクッとザックリ。

2014/05/19

Pythonの標準デバッガpdbの使い方

コマンドラインからPythonの標準デバッガ「pdb」を使うときに忘れがちなのでメモ。よく使うデバッガコマンドだけ。
(PyCharmとかのIDEを使えばもっと簡単に使える)

■コマンド
% python -m pdb test.py
test.pyをデバッグ実行できる

■pdbのデバッガコマンド

l
list。実行中のプログラムの周囲11行を表示。第一引数で数字を指定した場合は、その行の周囲11行を表示。例えば「l 12 」。指定した範囲のプログラムリストを表示したい場合は「l 10, 40」とする。PC(プログラムカウンター)がどこにあるかも確認できるしブレイクポイントを貼るときの行数の確認にもなるのでまずはコレ。

b
ブレイクポイントを指定。 「b 10」で10行目にブレイクポイントを貼る。ファイル名を指定したい場合は「b test.py:10」。行番号を指定しない場合はブレイクポイントの一覧表示。

cl
clear。指定したブレイクポイントを解除。指定方法はブレイクポイントと同じ。

s
Step Into。中へ中へと進む。

n
Step Over。nextの意味らしい。関数呼出しは中にはいらない。

r
return。現在の関数が返るまで実行を継続。

c
continue。次のブレイクポイントまで実行。

p
PCのスコープ内でアクセスできる式を評価する。「p total」とすると変数totalの値の中身を見ることができる。

q
quit。デバッガを終了する。

2014/05/16

Chrome CanaryでBeacon APIを試す

■ビーコンAPIとは
Analyticsなどで細々したデータをサーバに送る場合、ブラウザ(ページ)をブロックせずに送信するメカニズム。バックグラウンドで送信してくれる。もうsync-XHRとか必要なくなる。

仕様:W3C
Firefox実装:Bugzilla 936340

■実験環境
クライアント:Google Chrome Canary (バージョン 37.0.1995.0 canary)
サーバ:RequesetBinでリクエストを監視。
     (ログインしておけばRequestの内容をキャプチャできるサービス)

■実験
Chrome Canaryのターミナルで以下を打つべし
> navigator.sendBeacon('http://requestb.in/1crhlwy1', 'test')

RequestBinの結果は以下のとおり

■注意
RequestBinから何も返さないのでChromeのNetwork Statusでは(canceled)になって届いていないように見える罠に注意。

■Source
https://plus.google.com/+agektmr/posts/8YDy7pAcaBn

Macで単語辞書を引くショートカット

よく忘れるのでメモ。

[command] + [control] + [D]


2014/05/14

Google ChromeでChrome for Androidで表示中のサイトをデバッグする

環境
・Android4.2以上
・Chrome for Android 32以上
・Androidの設定でUSB debuggingがONになっていること

準備
Google Chromeでchrome://inspect/#devicesを開き
左メニューにある「Devices」を開いて「Discover USB devices」のチェックボックスがONになっていることを確認

接続
AndroidをUSBに接続し「Allow USB debugging?」のダイアログで「OK」をタップすると、chrome://inspect/#devicesにChrome for Androidのタブ情報が表示されて「inspect」でDOM要素の検査ができる。


Google Cloud StorageのバケットにCORSを設定する方法

別ドメインからアクセスするとAccess-Control-Allow-Originというエラーがでるので、それを回避するためにGCSのBucketにCross-Origin Resource Sharing(CORS)を設定する。

事前準備
gsutilが未インストールならGoogle Cloud SDKを突っ込んでおけばOK。

事前確認
設定されているCORSを確認する
$ gsutil cors get gs://BUCKET-NAME

STEP1: CORS.xmlを作る
ローカルにcors.xmlファイルをテキトウに作り、CORSの設定をcors.xmlに記入する。
<?xml version="1.0" encoding="UTF-8"?>
<CorsConfig>
  <Cors>
        <Origins>
            <Origin>http://*.adamrocker.com</Origin>
        </Origins>
        <Methods>
            <Method>GET</Method>
            <Method>POST</Method>
            <Method>HEAD</Method>
        </Methods>
        <ResponseHeaders>
            <ResponseHeader>*</ResponseHeader>
        </ResponseHeaders>
        <MaxAgeSec>86400</MaxAgeSec>
    </Cors>
</CorsConfig>
Originタグでアクセス元のURLを指定する。例えば「http://www.adamrocker.com」。
Methodタグは許可するHTTPメソッド。
MaxAgeSecはブラウザキャッシュの時間。

STEP2: CORSをGCSのバケットに設定する
$ gsutil cors set cors.xml gs://BUCKET-NAME
設定が上手くいっているか確認。
$ gsutil cors get gs://BUCKET-NAME