Norikra meetupで話してきた

Norikra meetupで話してきました.

資料

感想

皆さんNorikraを使いこなしてた. 特に@ixixiさんの発表が凄かった.NorikaのLOOPBACK+UDA?Fで,データをパイプライン的に処理するのはかなり良さげだった.

lxc.mount.entryで指定したマウントは,ホストからは見えないんだよ

LXCは設定ファイルにlxc.mount.entryを書いておくと,起動時にマウントしてくれるわけですが,そのマウントはホストからは見えません.namespaceが別だから.

...
lxc.mount.entry = /usr/lib usr/lib none bind,ro 0 0
...

例えば,上記のような設定ファイルを書いた場合,それの意味するところは,ホストの/usr/libを,ゲストの/usr/libにマウントしてね,という意味になるわけですが,コンテナを起動させた後でls -l /path/to/rootfs/usr/libとかしても期待する中身は見れません./proc/mountsにも現れません. これは,mount namespaceが異なるためで,ホストが見ている/path/to/rootfs/usr/libと,ゲストが見ている/path/to/rootfs/usr/lib(ゲストのinit以下のプロセスからは/usr/libに見える)は別物だということです.なので,ホストでは見えなくても,sshとかlxc-consoleとかでゲストに入ってls -l /usr/libとかすると期待通りのものが見れます.

ゲストにログインせずにホストから見たい場合は,namespaceを切り替える必要があるので,nsenterコマンドを使います.

nsenter -t $(lxc-info -p -n CONTAINER_NAME | awk '{print $2}') --mount -- ls -l /usr/lib

あるプロセスがどのnamespaceに属しているかは,/proc/[pid]/ns/以下を見ると分かります.

$ ls -l /proc/self/ns 
total 0
lrwxrwxrwx 1 kawamuray users 0 Jul  3 01:51 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 kawamuray users 0 Jul  3 01:51 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 kawamuray users 0 Jul  3 01:51 net -> net:[4026531956]
lrwxrwxrwx 1 kawamuray users 0 Jul  3 01:51 pid -> pid:[4026531836]
lrwxrwxrwx 1 kawamuray users 0 Jul  3 01:51 uts -> uts:[4026531838]

カッコ内の数字はinode numberです.この番号が同一であれば同じnamespaceに属していると考えることができます. man 2 setnsすると分かりますが,Linuxのnamespaceはファイルディスクリプタによって識別されており,あるnamespaceに切り替える際にはこのファイルのdescriptorを渡します.

nsenterコマンドは,このファイルを渡すことでも実行できます.

nsenter --mount=/proc/[pid]/ns/mnt -- ls -l /usr/lib

MBAのSDカードスロットを使ってRaspberryPI用のSDカードにGentooがインストールされたディスクイメージを書き込む方法

私のGentooマシンにはSDカードスロットがついてなくて,RaspberryPIのためだけに買ってくるのもなんなので,MBAについているSDカードスロットを使って書き込みを行おうと思った.しかしOSXの/sbin/fdiskはutil-linuxのそれとは全く使い方が違って使いたくなかったし,そもそもGentooマシンのほうがいろいろやりやすいので,OSX上でインストール作業をするのは諦めて,ディスクイメージを作ってからそれを丸っとSDカードに書き込む方法をとることにした.

# SDカードと同じサイズのディスクイメージを作る.512はセクタサイズ,30881792はセクタ数
$ dd if=/dev/zero of=sdcard.img bs=512 count=30881792
$ /sbin/fdisk sdcard.img
# 普通にパーティショニングする.3番目のパーティションを30881758にしているのは,SDカードのlast usable sectorがそこまでだから.
...
Command (m for help): p

Disk sdcard.img: 15.8 GB, 15811477504 bytes, 30881792 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x9160bad5

     Device Boot      Start         End      Blocks   Id  System
sdcard.img1            2048      835379      416666    c  W95 FAT32 (LBA)
sdcard.img2          835584     2932735     1048576   82  Linux swap / Solaris
sdcard.img3         2932736    30881758    13974511+  83  Linux

# ディスクイメージの各パーティションをdevice-mapperでfsにマップしてやる.これで普通のブロックデバイスのパーティンションが如く扱える.
$ sudo kpartx -a sdcard.img
$ ls -l /dev/mapper
total 0
crw------- 1 root root 10, 236 Apr 27 21:34 control
lrwxrwxrwx 1 root root       7 Apr 30 13:23 loop0p1 -> ../dm-0
lrwxrwxrwx 1 root root       7 Apr 30 13:23 loop0p2 -> ../dm-1
lrwxrwxrwx 1 root root       7 Apr 30 13:23 loop0p3 -> ../dm-2

# 諸々physical fsを作ってやる
sudo mkfs.vfat -F 16 /dev/mapper/loop0p1
sudo mkswap /dev/mapper/loop0p2
sudo mkfs.ext4 /dev/mapper/loop0p3

# mountする
sudo mkdir -p /mnt/raspberrypi/boot
sudo mount /dev/mapper/loop0p3 /mnt/raspberrypi
sudo mount /dev/mapper/loop0p1 /mnt/raspberrypi/boot

# 普通にGentooとRaspberryPIのファームウェア系をインストールする
$ cd /mnt/raspberrypi/
...

# umountしてdevice-mapperの解放
sudo umount /mnt/raspberrypi/boot
sudo umount /mnt/raspberrypi/
sudo kpartx -d /dev/loop0
# ループバックデバイスのアロケーションはkpartxが勝手にやってくれるが,
# 解放はしてくれないので自分でやる.
$ /sbin/losetup -a
/dev/loop0: []: (/home/kawamuray/sdcard.img)
$ sudo /sbin/losetup -d /dev/loop0

# SDカードにMBA経由で書き込む
$ ssh -C <MBA address> sudo dd if=/dev/stdin of=/dev/disk2 bs=512 count=30881792 < sdcard.img

ちゃんと動いた.

今年もGoogle Summer of Codeに採択された

Google Summer of Code2014(GSoC)に応募してたのが採択されました. OrganizationはGanetiで,Projectは"Improve LXC Support"です.

https://www.google-melange.com/gsoc/project/details/google/gsoc2014/kawamuray/5673522948997120

今年はタイムテーブル早まったのを忘れていたので締切り1週間前にようやくAccepted Organizationsリストを眺め始めるような超スロースタートで,Proposalに至っては締切り2日前に調査開始して書き上げるという超ギリギリスケジュールでしたがなんとかなって良かった...

GanetiはGoogle発の仮想マシンクラスタマネジメントソフトウェアです.OpenStackとかそういう奴と同族です. PythonHaskellで書かれていて,LightweightかつRobustなのが特徴だと思っています.コードが少なめで奇麗にまとまってるので,弄りやすいと思います.

なにをやるのか

"Improve LXC Support"というタイトルだけでは具体的になにをやるのか分かりづらいですが,簡単に言ってしまうと,現状GanetiはLXCをhypervisor(ここではGanetiにとっての仮想化機能提供ソフトウェアを指す)として認識はしていて,なんとなく実装したコードは存在するが,メンテされておらずそもそも実装も不完全で使い物にならないので,使いものになるようにしよう,ということです.

なにがうれしいのか

今のところGanetiで使えるハイパーバイザの選択肢は(事実上)kvmxenしかないが,LXCも使えるようになる.

抱負

acceptされた以上実装を完成させてprojectを成功させるのはあたりまえなので,今年はprojectの中で得られた知見をブログなどでoutputしていけるようにしたい.あと今年のテーマは性格上document書かないとあんま意味ない感じするので,documentをまともな英語でちゃんと書きたい.あと去年は序盤に飛ばしすぎて後半余裕ありまくったのでサボった結果サボりすぎて最後のほうがギリギリになってしまったので今年はそういうの無いようにしたい.

今年のStudentはMountain Viewに招待されるという噂もあるので楽しみですね.

FEATURES='distcc'っていうのがとても捗る

RaspberryPIにGentooを入れて遊び始めたが,emergeが遅すぎてつらい.まあcross compile前提だよねーと思って環境を作ってみたものの,/以下まるっとrsyncとかなんか怖いしqpkgとか使い方しらんし覚えたくねーなって思っていたところ,Portageがdistccをサポートしているという事を知ったので使ってみている.

ref: http://wiki.gentoo.org/wiki/Raspberry_Pi_Cross_building#distcc

マシンパワーのあるGentooマシンをWorkerと呼ぶことにする.

  • RaspberryPIとWorkerにdistccをemergeする.
  • RaspberryPIの/etc/distcc/hostsにWorkerのIPアドレスををコンパイラワーカとして追加.左にあるほど優先的に使われるらしい.
# /etc/distcc/hosts
192.168.1.xxx 127.0.0.1
  • RaspberryPIの/etc/portage/make.confにFEATURES追記.emergeがdistccに対応してくれる.
# /etc/portage/make.conf
FEATURES='distcc'
  • Workerの/etc/conf.d/distccd--allowオプションを追加.RaspberryPIからのリクエストのみ受け付ける.
DISTCC_OPTS="... --allow 192.168.1.yyy"
  • Workerの/usr/lib/distcc/bin/以下をcross-compile対応する.symlinkじゃなくてwrapperを用意しているのは,distccがargv[0]に応じて動作を変えるから.
cd /usr/lib/distcc/bin
sudo rm gcc g++ cc c++
cat <<'EOS' | sudo tee armv6j-hardfloat-linux-gnueabi-wrapper
#!/bin/bash
exec /usr/lib/distcc/bin/armv6j-hardfloat-linux-gnueabi-g${0:$[-2]} "$@"
EOS
sudo chmod +x armv6j-hardfloat-linux-gnueabi-wrapper
sudo ln -s armv6j-hardfloat-linux-gnueabi-wrapper gcc
sudo ln -s armv6j-hardfloat-linux-gnueabi-wrapper g++
sudo ln -s gcc cc
sudo ln -s g++ c++
sudo ln -s /usr/bin/distcc armv6j-hardfloat-linux-gnueabi-gcc
sudo ln -s /usr/bin/distcc armv6j-hardfloat-linux-gnueabi-g++
sudo ln -s /usr/bin/distcc armv6j-hardfloat-linux-gnueabi-c++

TODO: なんかmakeが並列化されてる様子がなくて全然Workerのパワー使いきってないのでどうやるのか調べる

Module absolute import in python

Python defaults to import module relatively. Here is description of python's module search order.

Give example:

$ mkdir -p /tmp/abs-import-test/{foo,bar}
$ cd /tmp/abs-import-test
$ touch {foo,bar}/__init__.py # make foo and bar as a python module
$ touch bar/boo.py            # make bar.boo module
# make foo.bar module. it depends to bar.boo module created at above
$ echo "import bar.boo" > foo/bar.py

$ python
Python 2.7.5 (default, Oct 17 2013, 21:18:01) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import foo.bar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "foo/bar.py", line 1, in <module>
    import bar.boo
ImportError: No module named boo
>>> 

Above script failed because python understands import bar.boo as "Import boo module which is relatively located under the bar module currently executed(foo/bar.py)" so python tries to load foo/bar/boo.py but it doesn't exists because I was expected to load bar/boo.py.

This can be solved by using absolute_import future.

$ echo -n "from __future__ import absolute_import\nimport bar.boo" > foo/bar.py
$ python
Python 2.7.5 (default, Oct 17 2013, 21:18:01) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import foo.bar
>>> foo.bar.bar.boo.__file__
'bar/boo.py'

4byteのUTF-8文字を置換する

mysqlCHARSET=utf8なVARCHAR型等のカラムでは3byteまでのUTF-8文字しか格納できず,4byte文字をINSERTしようとするとIncorrect string valueと言われてしまう.これはutf8mb4を指定することで回避できるが,最大長が255文字でかつインデックスを貼る必要があるとutf8を使わざるを得ないので(さらにユースケース的に4byte文字の中身とかどうでもよいので),4byteのUTF-8文字を下駄マーク(\x3013)に置換する.

$s =~ s/[\x{10000}-\x{3ffff}\x{40000}-\x{fffff}\x{100000}-\x{10ffff}]/\x{3013}/g;

置換後の文字は,そもそもUTF-8としてデコードできなかった文字と区別するために,\xfffdではなく\x3013(〓)にしている.

ref: http://perldoc.perl.org/perlunicode.html#Unicode-Encodings http://reishi42.blogspot.jp/2008/06/ufffd-replacement-character.html