Siburlog

SiblogだとSI BlogっぽいのでSiburlogとする

CoreOSでもtmuxがしたい!

概要

CoreOSでもtmuxくらいは備えてないと、接続が不安定な環境では怖くて使えないので、汚い手で対処したという話。

経緯

GCEのimageメニューの中にCoreOSっちゅーのがある。CoreOSの名前と概要だけは聞いたことがあった。Docker専用の軽量Linuxディストリビューションである。Dockerは流行りだし、いっちょ使ってみるかってことで試し始めた。

Dockerの使い方はここを読みながら弄ってたらなんとなく分かった。

しかし問題が一つあった。CoreOSにはtmuxが備わってないのだ(screenも無いです)。作業中に通信が切れたらと思うと怖い。なんとかしてtmuxが使いたい。

解決方針

CoreOSは、原則としてそれ自体のソフトウェア構成はimmutableに保つ思想のOSである。アプリケーション環境はあくまでDockerコンテナの中に構築せよ、というのが本来の筋。CoreOS自体にはyumrpmもaptもgccも何も無く、ソフトウェアを(エレガントに)追加する方法は無い。

でも今回の話は、CoreOS自体にtmuxを追加しないと意味がない。ので、エレガントじゃなくてもいいやってことで、出来合いのtmuxバイナリを外から持ち込んで使うことにした。CoreOSもx86-Linuxであることに変わりは無いので、バージョンが近い他のx86-Linuxディストリビューションから持ってきても動くだろうと考えた。

バイナリの持ち込み

  • コピー元
    • OS : CentOS7(v3.10)
  • コピー先
    • OS : CoreOS(v3.16)
  • コピーしたファイル
    • /usr/bin/tmux
    • /usr/lib64/libtinfo.so.5.9

使用方法

単純に下記の要領でtmuxを起動すると、一見上手くいったように見えるが、detachしてサーバからlog offし、再度log inしてps aux | grep tmuxなどとしてみると、tmuxが死んでしまっているのが分かって愕然とするだろう。

$ ls $HOME
tmux libtinfo.so.5.9
$ mv libtinfo.so.5.9 libtinfo.so.5
$ LD_LIBRARY_PATH=. ./tmux

詳細はよく分かってないが、下記の議論にあるように、systemd-run -rを使ってやらないと、log off時に残っているプロセスは皆killされてしまうようだ。 https://groups.google.com/forum/#!topic/coreos-dev/JAeABXnQzuE

したがって、結局、下記のようにすることになる。

$ sudo systemd-run --uid=YOURID --gid=YOURID -r sh -c "LD_LIBRARY_PATH=$HOME $HOME/tmux -C"

最後に、作成されたtmuxセッションに対してattachする。このtmuxセッションはサーバとの接続が不慮の事故で切れても維持される。

$ LD_LIBRARY_PATH=. ./tmux attach

まとめ

  • (今現在の)CentOS7からバイナリを持ってくれば、(今現在の)CoreOS上でも動作する。
  • log off後も維持したいプログラム(=tmuxの親プロセス)は、systemd-runを使って起動しないといけない。

gemビルド中にOOMが走ってしまうのでこう対処した

経緯

td-agent2を自分でビルドしようとしている。

READMEに書いてある通りに下記コマンドを実行すると、途中でOOMが発生して何度やっても失敗してしまう状況になった。

$ bundle install --binstubs

これは必要なgemを端からビルドしてインストールしていくコマンドなのだが、gemによってはRubyコードに加えてC/C++などで書かれたライブラリを内部的に備えたものもある。インストール時にそれらのライブラリがビルドされるのだが、ビルド方法は各gem作者が決める。大抵はMakefileを書いてそれを叩くやり方だろう。

今回問題になったのはridleyというgemで、こいつはインストール時に"make -j 5"によってライブラリをビルドする。私が使っているGCE g1-smallのメモリ量では、この5並列ビルドに耐えられずOOMになる運命らしかった。何度やっても失敗した。

対処法

makeのコマンドオプションのうち、"-j <数字>"を削除してから、本物のmakeを呼び出すラッパスクリプトを作った。自分はシェルスクリプトあまり得意ではないのでエレガントなコードとは言い難いだろうけども。

このスクリプトをmakeという名前にして、PATH検索で最優先になるよう細工すれば、並列ビルドが要求されても無視してシリアルにビルド出来る。結果として当該のコマンドは走りきることが出来た。

Elasticsearch+Kibanaのインストールで嵌ったこと

経緯

このチュートリアル記事に従ってEFKをインストールして遊ぼうとしている(まだインストール途中)。

このチュートリアルではE->K->Fの順にインストールしているのだが、今のところKまではインストール出来てDashboardが見れるようになったところである。そこまでの作業で(環境依存だけど)嵌りどころがあったので紹介する。

環境

  • 元記事: Ubuntu 14.04
  • 自分: CentOS7 on GCE

嵌ったこと

Dashboardが表示出来ない。具体的には以下のようなエラーになる。Elasticsearchへのアクセスに失敗してるっぽい。

f:id:siburu:20141007003412p:plain

Kibana3とElasticsearchの連携の仕組み

Kibana2はサーバサイドでElasticsearchと連携し、Viewを作成していたらしい。しかしKibana3では、HTML+JavaScriptからなる、完全にクライアントサイドの仕組みに変わったらしい(下記参照)

つまりKibana3を使う場合は、下図のような構成になり、別途Elasticsearchのポートをインターネットからreachableな状態にする必要がある。デフォルトではElasticsearchは9200番ポートを使用する。

f:id:siburu:20141007012128p:plain

しかしWebアプリのために80番以外のポートは開けたくないというのも普通の要求である。そこでチュートリアルでは、nginxを使って下図のように80番ポートをmultiplexingしている。

f:id:siburu:20141007012237p:plain

ところが、後者の構成では前述のようなエラーになってしまうのである。ちなみに、前者の構成にして9200番ポートを開けてElasticsearchへ直アクセスさせると、普通にDashboardが表示出来た。つまり、失敗しているのはnginxとElasticsearchの間の処理だということが、この時点で推測できた。

ログ調査

ESのログ

まずはESのログ/var/log/elasticsearch/elasticsearch.logを見てみた。 すると、どうもアクセス自体が届いてないようだ。ログに形跡がない。

nginxのログ

経路的にはESの前はnginxになる。なので次はnginxのエラーログ/var/log/nginx/error.logを見てみた。すると、下記のようなエントリを見付けた。

2014/10/06 02:24:27 [crit] 1571#0: *151 connect() to 127.0.0.1:9200 failed (13: Permission denied) while connecting to upstream, client: ***.***.***.***, server: kibana, request: "GET /_nodes HTTP/1.1", upstream: "http://127.0.0.1:9200/_nodes", host: "***.***.***.***", referrer: "http://***.***.***.***/"

エラー13はEACCES。どうもSELinuxの臭いがする。

SELinuxのログ

この辺は勘だけど、どうもSELinuxが怪しいなと思ったので、SELinuxのログ/var/log/audit/audit.logを覗いてみた。すると以下のエラーエントリを見付けた。

type=AVC msg=audit(1412562267.022:40595): avc:  denied  { name_connect } for  pid=1571 comm="nginx" dest=9200 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket

やはりSELinuxによってconnect(2)が失敗しているようだ。

解決策

まず下記のコマンドでSELinuxの設定状況を一覧出来る。

% getsebool -a

この設定の中をhttpで検索したところ、httpd_can_netword_connectという設定がoffになっていることが分かった。httpdを踏み台に他所に迷惑を掛けないための設定だと推察される。audit.logのエラーにはhttpd_tがどうのと書いてあったから、これが原因かなと思い、onにしてみた。

# setsebool httpd_can_network_connect on

すると以下のようにDashboardが表示出来るようになった。

f:id:siburu:20141007003424p:plain

まとめ

  • GCEのCentOS7のデフォルト設定では、nginxから他サービスへのフォワードが禁じられている。
  • SELinuxの設定httpd_can_network_connectをonにすれば解決出来る。

livedumpをgithubに上げた

経緯

2年前にLKMLへv3を投稿して以来、開発が止まっている拙作livedumpをgithubにアップした。アップストリームカーネルへの新機能追加を夢見たが、メリットやユースケースが曖昧な一方、デメリットは大きく、マージの可能性は個人的には低く感じた。結局色々と疲れもあって諦めていた代物である。LKMLのメールアーカイブに放置するよりは、完全なレポジトリの形にしておいた方がユーザが得られる可能性が0.01%くらいはあるかもしれないと思うので、今回回収してみた次第。

livedumpとは

OSを止めずにOSのメモリダンプを取る、という機能である。

OSのメモリ内容は/dev/memを読むことでも得られる。但しこの場合、/dev/memを読んでいる間にもメモリの内容はどんどん書き換えられていく。得られたダンプはある瞬間のメモリスナップショットを切り取ったものにはならない。ダンプ解析をしようとしても整合性が無いため失敗する可能性がある。

livedumpでは、stop_machine()という一時的にOSを停止する機能を使い、OSが使用しているメモリ全体に対してライトプロテクションを張る。それ以降OSのメモリに書き込みが生じると、ページフォルト例外が発生するので、ここで書き込まれようとしているメモリ内容を退避することができる。このような仕組みにより、メモリスナップショットが取得できるという仕掛けである。

コード

今後

今回githubにアップするにあたり、新たに動作テストなどは全く行っておらず、使い方は作者本人も忘れているような感じである。暇を見て、動作テストや最新カーネルへのrebaseを行っていく、かもしれない。

inotify(7)によるファイルアクセス検知能力の調査

概要

Linuxには、ファイルに関するイベントの検知を行うためのメカニズムとして、inotify(7)というのがある。検知出来るイベントには色々あって、詳しくは各位man inotify頂きたく。

今回調査したのはその中のただ2つ、IN_ACCESSとIN_MODIFY。前者はreadアクセスを後者はwriteアクセスを検知してくれる、らしい。しかしファイルへのreadとwriteには幾つか違う方法があるじゃないですか?ってことで、どういうアクセス手段に対して検知可能なのか、調べてみた。

具体的には、以下のアクセス手段について調査した。

  1. read(2)
  2. write(2)
  3. sendfile(2)
  4. mmap(2)してメモリ読み込みしてmunmap(2)
  5. mmap(2)してメモリ書き込みしてmunmap(2)
  6. mmap(2)してメモリ書き込みしてmsync(2)してからmunmap(2)

調査環境はsakura VPS上のCentOS6.5(=KVM上のLinux2.6.32)。

調査には以下のコードを使った。

結果

read(2)/write(2)以外はなんも検知出来なかった。 mmap(2)して〜ってのはダメかもなーと思ってたけど、sendfile(2)に無反応は意外。 splice(2)も調べようかなーと思ってたけどめんどくさいからやめておく、sendfile(2)に無反応ならsplice(2)も同じじゃないのかね。

dirty pageは下記のような感じで逐一accoutingされてるという理解なので、inotifyにも情報回ってくるだろうと予測してた。 mm: tracking dirty pages -v6 [LWN.net]

SRPMからのカーネル構築についてメモ

下準備:http://wiki.centos.org/HowTos/I_need_the_Kernel_Source#head-a8dae925eec15786df9f6f8c918eff16bf67be0d

手順:http://wiki.centos.org/HowTos/Custom_Kernel

 

  1. SRPMを取得(「下準備」に場所が書いてある)
  2. % rpm -ivh <kernel SRPM>
  3. % cd ~/rpmbuild/SPECS
  4. % rpmbuild -bp --target=$(uname -m) kernel.spec
  5. % cd ~/rpmbuild/BUILD/kernel-****/linux-****
  6. .configを適宜いじる。configs/以下にあるやつをベースにするか、/boot以下にあるやつをベースにしても、どこかから持ってきてもなんでも良い。
  7. % cp .config configs/kernel-***.config
  8. configs/kernel-***.configの先頭に「# x86_64」もしくは「# i386」を追記。
  9. % cp configs/* ~/rpmbuild/SOURCES
  10. 「手順」4章にしたがってspecファイルを書き換え。パッチ周りはパッチ追加しないなら無視で。
  11. % rpmbuild -bb --target=`uname -m` kernel.spec 2> build-err.log | tee build-out.log

 

最後のrpmbuildに--with ***とか--without ***とか付けて、必要十分なパッケージだけビルドするようにしたい。

少なくともxenは要らんだろう、というのは分かる。

実はx86だとupとsmpの区別が無く、--without upするとカーネル自体ビルドされないっぽい。

kabichkとかfipsは切ると時間短縮になる。

しかしまだイマイチ分かってない部分も多い。

gdbについてメモ

コアダンプの使い方。

zshのコアダンプcore.1234.zshがあるとする。

まず、zsh-debuginfoのインストールが必要。

その上で、下記のようにする。

% gdb /bin/zsh ./core.1234.zsh

 Kernel Hacksには、crash-gcoreに絡んだgdbの使い方説明で、以下のようにしろと書いてあるけれども、これは動かなかった。

% gdb /usr/lib/debug/bin/zsh.debug ./core.1234.zsh