VyattaでNAT stateful failoverを使う場合の制限。

VyattaでVRRPを使っている場合、VRRPのfailoverが発生してもBackupに引き継いでそのまま通信できるようにNAT stateful failverを使うと思います。が、NATテーブルのエントリ数がある一定を超えると、failoverが発生してからNATテーブルのエントリが引き継がれる途中でBackupがカーネルごと落ちてしまう、という事象に遭遇しました。もうそのまんまなので特にひねりもないのですが、一応検証を行った条件を掲載しておきます。

環境。

  • メモリ 2GB

  • Vyatta core 6.3 64bit

CPUとかディスクとかは実質ほとんど影響ないので省略。

条件。

VyattaでNATします。負荷検証には、専用のアプライアンスを使い、Webサーバに対してApacheのindex.htmlをGETするだけの負荷をかけました。fail overの基準とする数値はNATテーブルのエントリ数で、/proc/sys/net/netfilter/nf_conntrack_countの値を下記のような感じで監視しました。実際には下記のコマンドでこの数値を観察しながらfailoverさせました。

$ mkfifo nf_conntrack_count
$ while true; do date > nf_conntrack_count; cat /proc/sys/net/netfilter/nf_conntrack_count > nf_conntrack_count; sleep 1; done &
$ tail -f nf_conntrack_count

ネットワーク構成は下記。Vyatta0の10.0.10.10-10.0.10.250はNAT用のIPアドレス。

結果。

最初、200万程度NATテーブルにエントリがある状態で通信させている状態でfailoverさせてみたところ、Backup側に当初は切り替わりましたが、途中で通信できなくなりBackup側もカーネルごとrebootまたは落ちてしまいました。エントリ数を下げてやってみたところ、7万程度ならfailoverできることは確認しました。これがメモリを2GBから増やした場合変わるのかどうかも気にはなったものの、そもそもこんな低い値では使い物になりません。Masterが落ちた場合に全面ダウンしてしまいます。なので、NAT stateful failover自体を行わないことにしました。単体でNAT処理させる場合は、メモリ2GBのIAサーバでもNATテーブルのエントリが200万は処理できた(それ以上はアプライアンス側の制約で負荷を掛けられず)ので、fail over時の通信およびスイッチのMACアドレス学習までの数秒は諦める、ということにしました。

mkpasswdコマンドを使ってshadowパスワードを生成する。

passwdコマンドでの対話形式ではなく、任意のshadowパスワードを予め生成しておきたい場合、mkpasswdコマンドを使えますよ、という小ネタ。/etc/shadowの第2フィールドの文字列は、単純に任意の文字列をmd5sumコマンドを使ってもダメですが、mkpasswdコマンドを使うと簡単に生成できます。mkpasswdはwhoisパッケージにあるので、これをインストールしておきます。

$ sudo apt-get install whois

インストールした後、生成するには次のコマンドを実行します。

$ mkpasswd -S $(head -c 4 /dev/urandom | xxd -p) -m md5
Password:
$1$a243949c$w2efZ4cQRTDGxaZNuFDAG/

生成された文字列はvipw -sで任意のユーザアカウントの第2フィールドに記入すれば、入力したパスワードでログインなりsuなりできるようになります。ちなみに上記の文字列を生成するために入力した文字列(パスワード)は、11111111なのでそのまんま使わないようにね。(わら

名前付きパイプを知らない?

名前付きパイプを知らないという人が意外といるみたいなので、小ネタとして紹介します。名前付きパイプとは、パイプ’|’の代わりに使える特殊ファイルです。mkfifoコマンドで作成します。

$ mkfifo hoge

このhogeというファイルをreadしておき、別のプロセスでこのファイルに何らかの出力を書き込んでやると、hogeをreadしている側でその書き込まれた出力が読めます。

たとえば、Netfilterのカウンター(/proc/sys/net/netfilter/nf_conntrack_count)を見たい場合、

$ watch cat /proc/sys/net/netfilter/nf_conntrack_count

とかでも良いですが、上記を名前付きパイプに常に書き込む用にしてやっても良いわけです。この値だけを書き込むだけならあまり意味がありませんが、ちょっと加工したい場合に便利です。

$ mkfifo hoge
$ while true
do
  date > hoge;
  cat /proc/sys/net/netfilter/nf_conntrack_count > hoge
  sleep 1
done &
$ tail -f hoge

こうしてやると、

Thu May 24 21:00:28 JST 2012
21130
Thu May 24 21:00:29 JST 2012
21173
Thu May 24 21:00:30 JST 2012
21201
Thu May 24 21:00:31 JST 2012
21216
(snip)

というように見ることができます。ssh経由で扱うこともできます。

$ ssh remotehost tail -f hoge
Thu May 24 21:07:08 JST 2012
20587
Thu May 24 21:07:09 JST 2012
20585
Thu May 24 21:07:10 JST 2012
20594

ログはローカルに吐きたくないけれど、ログ監視はしたい、でもsyslogで転送したくない、という場合は、これを使うとできますね。どんなケースだ、それ。

CouchDB 1.2.0をようやく導入した話。

CouchDB 1.2.0がリリースされて早一ヶ月。なかなか導入する暇が無かったので放置していました。が、さくらのVPSの移行のタイミングで1.1.0で動かしている こまちゃん監視カメラのビューワ を1.2.0にすることにしました。

こまちゃん監視カメラ の現在の仕様はWebカメラでひたすら動体検知や明度の変化を検知した瞬間の写真をJSONに変換してCouchDBに保存し、不連続での過去10時間分を閲覧できるものです。昨年の震災をきっかけにした不在中のこまちゃんの様子を確認するためのツールなので、古い画像は必要ありません。が、画像及び画像を内部ドキュメントとして格納したドキュメントは定期的に削除していません。1画像あたり8-10KB程度なのでスマホでも簡単に確認できるのでますが、塵も積もればなんとやらで、移行時点で既に4GBを超える量。さくらのVPS 512では20GBのディスクで、LXCでのDebianのコンテナが5,6個動かしていたので圧縮して移行する余裕はありません。なので、新しくSqueezeのコンテナを作り、そこでDebianパッケージを作ることにしました。

Debianパッケージの作成事前準備。

CouchDBのビルドに必要なパッケージを手っ取り早くインストールするために、SqueezeのCouchDB 0.11.0に依存するビルド環境を整えます。

$ sudo apt-get build-dep couchdb

次にCouchDBのソースパッケージをダウンロードします。

$ apt-get source couchdb

devscriptsのuscan && uupdateでCouchDBのソースパッケージをアップデートしてみましたが、残念ながらSidでの1.1.1までしかアップグレードされません。原因は1.2.0からパスが変更されたため、debian/watchのパスと異なるためです。下記のように書き換えます。

$ diff -u a/debian/watch b/debian/watch
--- a/debian/watch      2012-05-22 01:22:34.000000000 +0900
+++ b/debian/watch      2012-05-22 01:22:39.000000000 +0900
@@ -1,3 +1,3 @@
 version=3

-http://www.apache.org/dist/couchdb/([\d\.]+)/apache-couchdb-([\d\.]+)\.tar\.gz
+http://www.apache.org/dist/couchdb/releases/([\d\.]+)/apache-couchdb-([\d\.]+)\.tar\.gz

変更したら、ソースパッケージをアップグレードします。

$ uscan
couchdb: Newer version (1.2.0) available on remote site:
 http://www.apache.org/dist/couchdb/releases/1.2.0/apache-couchdb-1.2.0.tar.gz
 (local version is 1.1.1)
couchdb: Successfully downloaded updated package apache-couchdb-1.2.0.tar.gz
    and symlinked couchdb_1.2.0.orig.tar.gz to it
$ uupdate ../apache-couchdb-1.2.0.tar.gz 1.2.0
New Release will be 1.2.0-1.
-- Untarring the new sourcecode archive ../apache-couchdb-1.2.0.tar.gz
Unpacking the debian/ directory from version 1.1.1-2 worked fine.
Remember: Your current directory is the OLD sourcearchive!
Do a "cd ../couchdb-1.2.0" to see the new package

Backportのパッケージ入手。

CouchDB 1.2.0は、Erlang R15B以上でなければなりません。SqueezeはR14Aなのでbackports.debian.orgを使い、置き換えることにしました。/etc/apt/soruces.listに下記を追記します。

deb http://backports.debian.org/debian-backports squeeze-backports main
deb-src http://backports.debian.org/debian-backports squeeze-backports main

sudo apt-get updateを実行後、CouchDBのビルドに必要なパッケージを下記のようにsqueeze-backportsを指定してインストールします。

$ sudo apt-get -t squeeze-backports install erlang-base erlang-crypto erlang-dev \
            erlang-syntax-tools autoconf erlang-eunit erlang-inets erlang-os-mon \
            erlang-tools erlang-xmerl libjs-jquery

ソースコードを元に普通に./configure && make && sudo make installをできることを確認します。問題なくビルドできたら、いよいよDebianパッケージの作成です。

Debianパッケージのビルド。

実はCouchDB 1.2.0はJavaScriptエンジンとして、Spidermonkeyの1.8.5が必要 です。が、Squeezeにも、Backportsにもありません。Sidにはlibmozjs185-1.0, libmozjs185-devがパッケージになっているので、Sidの環境でソースパッケージを取得し、ビルドに必要なパッケージをインストール後、このソースパッケージを使ってSqueeze向けのlibmozjs185を作ります。

$ sudo apt-get install libffi-dev zip pkg-kde-tools
$ debuild
$ sudo dpkg -i ../libmozjs185-1.0_1.8.5-1.0.0+dfsg-3_amd64.deb \
             ../libmozjs185-dev_1.8.5-1.0.0+dfsg-3_amd64.deb

ビルドしてできたlibmozjs185パッケージをインストールしたら、CouchDBのビルドを行います。debian/ディレクトリ以下のファイルの設定が一部不足しているので、以下のようにしました。

debian/control

$ diff -u couchdb-1.1.1/debian/control  couchdb-1.2.0/debian/control
4,5c4,5
< Maintainer: Erlang Packaging Team <pkg-erlang-devel@lists.alioth.debian.org>
< Uploaders: Sergei Golovan <sgolovan@debian.org>, Sam Bisbee <sbisbee@computervip.com>, Elliot Murphy <elliot@ubuntu.com>
---
> Maintainer: Kouhei Maeda <mkouhei@palmtb.net>
> Build-Depends: debhelper (>= 7.0.50~), autotools-dev, erlang-eunit, erlang-base, erlang-crypto, erlang-dev, erlang-syntax-tools, autoconf, libmozjs185-dev, cdbs
7,9d6
< Build-Depends: cdbs (>= 0.4.42), debhelper (>= 7.2.11),
<  erlang-dev (>= 1:13.b.1-dfsg-3), help2man, libcurl4-openssl-dev,
<  libicu-dev, libmozjs-dev, libreadline-dev
11,12d7
< Vcs-Svn: svn+ssh://svn.debian.org/svn/pkg-erlang/couchdb
< Vcs-Browsern: http://svn.debian.org/viewsvn/pkg-erlang/couchdb
16,17c11,12
< Depends: ${misc:Depends}, ${shlibs:Depends}, ${erlang:Depends},
<  ${erlang-abi:Depends}, adduser, libjs-jquery, lsb-base, procps, mawk
---
> Depends: ${shlibs:Depends}, ${misc:Depends}, ${erlang:Depends},
>  ${erlang-abi:Depends}, adduser, libjs-jquery, lsb-base, procps, mawk, libmozjs185-1.0
29c24
<  languages and environments.
---
>  languages and environments.

debian/rules

DEB_CONFIGURE_USER_FLAGの指定が肝ですね。

$ diff ../couchdb-1.1.1/debian/rules  debian/rules
15a16,17
> DEB_CONFIGURE_USER_FLAGS += \
>        --with-js-lib-name=mozjs185
34a37
>       mkdir -p debian/couchdb/usr/share/lintian/overrides/
39,41c42,44
<       chmod 660 debian/couchdb/etc/couchdb/local.ini
<       chmod 750 debian/couchdb/var/lib/couchdb
<       chmod 750 debian/couchdb/var/log/couchdb
---
>       chmod 664 debian/couchdb/etc/couchdb/local.ini
>       chmod 755 debian/couchdb/var/lib/couchdb
>       chmod 755 debian/couchdb/var/log/couchdb

/etc/init/coudhb.tpl.inの修正

$ quilt diff | sed 's/^/    /g'
Index: couchdb-1.2.0/etc/init/couchdb.tpl.in
===================================================================
--- couchdb-1.2.0.orig/etc/init/couchdb.tpl.in      2012-05-20 01:02:37.495545236 +0900
+++ couchdb-1.2.0/etc/init/couchdb.tpl.in   2012-05-20 01:09:00.859545321 +0900
@@ -84,6 +84,7 @@
     # Start Apache CouchDB as a background process.

     mkdir -p "$RUN_DIR"
+    chown "$COUCHDB_USER":"$COUCHDB_USER" "$RUN_DIR"
     command="$COUCHDB -b"
     if test -n "$COUCHDB_STDOUT_FILE"; then
         command="$command -o $COUCHDB_STDOUT_FILE"

これでdebuildし、できたパッケージをインストールすれば、上記のリンク先の問題もクリアした上でSqueeze向けの 1.2.0を使えるようになります。

LXCのマイグレーションを行った話。

さくらのVPS 512から1Gに契約を切り替えで、使用しているLXCの移行を先週行いました。が、ちょいとハマったのでメモ。同じ環境の人は多分いないと思うので、同じようにハマる人は少ないと思いますが。

既存環境。

もともとの512の方は、Debian GNU/Linux LennyをインストールしSqueezeにアップグレードした環境でした。SqueezeではLXCを使うには一部カーネルオプションが無効になっているのでカーネルビルドが必要です。Linux Kernel 2.6.39.1でリビルドし、Debianパッケージで提供されているlxc 0.7.2-1を使っていました。( lxcを久々に使うことに。on さくらのVPS 512

また、2009年に0.6.2だか0.6.3のころから、SidのDebianパッケージで使い始めていましたが、このころは自動起動の仕組みが無く、自分でスクリプト書いていたこともあり、0.7.2に存在する自動起動の仕組みは使わずに使っていました。コンテナのrootfsをインストールしていた先も、パッケージでの標準の/var/lib/lxcではなく、/lxcrootディレクトリを作りこの下にdebootstrapで作ったイメージを置いていました。

新環境。

1Gでは512を使い始めた時と違い、Squeeze用のインストール用ISOイメージが提供されています。今回はSqueezeをインストールした後、Linux Kernel 3.3.6とDebianパッケージのlxcおよび最新のlxc 0.8.0 rc1を試そうとしました。最終的には元々の環境と同じメインバージョンの、2.6.39.4、lxcはsqueezeの同じDebianパッケージを使いました。

ハマったことその1。

一つは、最初にインストールしたDebianのディストリビューションの違い。LennyのカーネルではCONFIG_VIRTIO_BLKが無効になっていますが、Squeezeではこれが有効になっているので、Lennyからアップグレードした512の環境ではディスクが/dev/sdaとして認識していました。しかし1Gの環境では/dev/vdaです。1Gの環境で2.6.39.4でビルドする際に512の/boot/config-2.6.39.1をベースにしてビルドしたのですが、このカーネルでもCONFIG_VIRTIO_BLKは無効にしたままだったため、リブート時にinitramfsがrootfsを見つけられなくてブート途中で止まってしまう、という初歩的なミスでハマりました…。

ハマったことその2。

二つ目は、Linux Kernelのバージョンの違いによるものです。当初、3.3.6でビルドしたカーネルを使おうとしたのですが、SqueezeのDebianパッケージとしてあるlxc 0.7.2-1でも、0.7.2-1のソースパッケージからuscan;uupdateで取得した0.8.0 rc1でも、プロセスすら起動できない、という状況。発生するエラーは、

$ sudo lxc-start -n anycontainer
lxc-start: No such file or directory - failed to rename cgroup /var/local/cgroup//lxc/11783->/var/local/cgroup//lxc/anycontainer

だったはず。2.6.39系だと、cgroup filesystemに作成されるコンテナのメタ情報は、/var/local/cgroup/anycontainerディレクトリの下ですが、3.3系だと、そのパスが変わってしまっている様子。5/19で期間延長が終了予定で、原因追求している時間もとれないので、3.3.6で使うのは今回は諦めました。敗北…。

ハマったことその3。

3.3系でダメだった際にlxc-0.8.0-rc1のDebianパッケージを作成したので、これも3.3系だけでなく、2.6.39.4で試して見ました。が、こっちもダメ。こちらのエラーも、

$ sudo lxc-start -n anycontainer
lxc-start: No such file or directory - failed to rename cgroup /var/local/cgroup//lxc/11783->/var/local/cgroup//lxc/anycontainer

なので、3.3系は0.8以降で使えるようになるはず?

環境できてれば後は楽。

コピー先のLXCの環境さえできてしまえば、512の方でlxc-freezeし、コンテナのrootfsとconfig含んだディレクトリをtarballにし、伸長します。コンテナの設定ファイル(anycontainer/config)のうち、

  • lxc.rootfs

  • lxc.mount.entry=proc

  • lxc.mount.entry=devpts

  • lxc.mount.entry=sysfs

の4ヶ所のパスを/lxcrootにしていたところを、Debianパッケージのデフォルトの/var/lib/lxcに変更し、次のコマンドを実行します。

$ sudo lxc-create -n anycontainer -f /tmp/anycontainer/config -t debian

を実行すると、/var/lib/lxcディレクトリ下にanycontainer/{config,rootfs}がコピーされます。ホストの起動時に自動起動させるには、/var/lib/lxc/anycontainer/configを、/etc/lxc/anycontainer.confにコピーし、/etc/default/lxcを下記のように変更すれば、OKです。

RUN=yes <- コメントを外す
CONF_DIR=/etc/lxc
CONTAINERS="anycontainer" <-/etc/lxc/ディレクトリ下に置いた*.confのうち、起動させたいコンテナを'.conf'を取り除いた形で列挙する。複数ある場合はスペース区切り