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とかそういう奴と同族です. PythonとHaskellで書かれていて,LightweightかつRobustなのが特徴だと思っています.コードが少なめで奇麗にまとまってるので,弄りやすいと思います.
なにをやるのか
"Improve LXC Support"というタイトルだけでは具体的になにをやるのか分かりづらいですが,簡単に言ってしまうと,現状GanetiはLXCをhypervisor(ここではGanetiにとっての仮想化機能提供ソフトウェアを指す)として認識はしていて,なんとなく実装したコードは存在するが,メンテされておらずそもそも実装も不完全で使い物にならないので,使いものになるようにしよう,ということです.
なにがうれしいのか
今のところGanetiで使えるハイパーバイザの選択肢は(事実上)kvmとxenしかないが,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文字を置換する
mysqlはCHARSET=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