新しいさくらVPSにGentoo入れるスクリプト

そういえば、ブログの存在を思い出したので、唐突に書いてみる。

さくらVPSが新しくなって、自分の環境も移行するかーということで、またGentooをインストールしなおした。
前の利用させてもらったこちらスクリプトを使ってやればいいかーとおもったんですが、さくらVPSが基本的にディスクがvirtioなものに変わってしまっているようで(カスタムインストールでFreeBSDを選ぶと、SATAのディスクとして見えるようになる模様)、そのままのlivecdではディスク認識できなくて力尽きた。

というわけで、livecdのinitrdをvirtio-blkを読むこむように変えて、hda,sdaと書かれている部分をvdaに書き換えたものを、上記のスクリプトをForkさせてもらって修正してみた。
要はinitrdにsquashfsに含まれるvirtio,virtio-ring,virtio-blkをコピーしただけ。

スクリプトここに置いてます。

あと、カーネルの設定に関しても、3.2.12の.configも含めるようにした。最低限の設定なので人によってはすこしいじったほうがいいかも。
その他、すこし趣味にあわせて、こまかくいじってしまってます。

かなりやっつけ感があふれるけど、
とりあえず、
CentOS起動→bootstrap-0-prepare.sh→reboot→cd root/gentoo-sakuravps/scripts→bootstrap-1-base.shと実行して、のんびりまってると、rootパスワードを求められるので任意のパスワード入力すると、2回ほど再起動して、Gentooが立ち上がってきます。

すでにスクリプトがあったので、いくつか修正するだけですぐにGentoo入れれるのは幸せですね。

zipのCRC

とりあえず、WebDAVにファイルを置いてると、やっぱちょっと想定から外れているのかCRCの計算がめんどくさいです。
CRC算出するためには、どうしてもファイル全体が必要なので、結局、アプリ側でもファイル全体を一旦読まないといけなくなります。
順番に処理できるようになるし、出力されるzipをバッファするわけでもないので、メモリ的にはぐっと楽になりますが、まあなんか格好わるいです。

ちなみに、PythonCRCを計算するのは以下のような方法でやっています。

crc = ('%08X' % (zlib.crc32(buffer) & 0xffffffff,)).lower()

とりあえず、素直にzlibで計算して、ASCII化しているだけです。これもたぶんもっと速い方法とかあるんだろうなぁ、とかおもいつつですが。

そこで、mod_zipを見ると、CRCに"-"を指定すればCRCを算出しなくともzipを生成すると書かれています。
これを試してみたんですが、Windows標準ツールやzipコマンドでは、CRCが違うよと警告されつつも、ファイルを解凍できるのでが、
とりあえず、Macアーカイブユーティリティではエラーとなって解凍できないファイルが生成されてしまうようです。
zipの仕様的には問題ないようなのですが、strictにCRC32をチェックするツールが結構あるので今のところ、この方法はあまり使えない感じです。

というわけで、このままは微妙すぎるので、今後は2つのどちらかの解決方法を採ろうと思っています。
・そもそも今回の場合、CRC計算もmod_zip側でやって欲しいので、mod_zipを改造して、たとえば"+"を指定すれば計算するモードを追加する改造をする
WebDAVへのファイル保存時にそもそもCRCを計算して先に、ファイルとともに保存しておく

mod_zipを改造すると、
メリット → 既存システムに全く影響がない、CRC計算をCPUが比較的空いているリバースプロキシ側で行える
デメリット→ 改造としては結構めんどくさいのと、バージョンアップごとにパッチを作り続けないといけない可能性がある(取り込んでくれればいいけど)

WebDAVCRC保存するようにすると、
メリット → mod_zipに改造を加えなくていい、ファイル破損チェックに他の場面でも使える
デメリット→ 既存システムの割と根幹ぽいところをいじる必要がある、そもそもファイル保存をフックして毎回CRC32を計算すると結構負荷が高い?

という感じでどっちにするかはなんとも言えないところです。
んー、すこし悩んでみて、実装してみよう。

アプリ

とりあえず、必要な条件は以下

・レスポンスヘッダーにX-Archive-Files: zipという行を出力する
・bodyにzipにしたいリソースのCRC, size, url, filenameの4つの要素をスペース区切りで書く

d7ecd7c6 69162 /zip/photos/sdc/d/c/f/00000000000000710822/original.jpg photo_0.jpg
ff6d69da 99458 /zip/photos/sdc/7/d/6/00000000000000710821/original.jpg photo_1.jpg
2181b9ad 99286 /zip/photos/sda/7/c/6/00000000000000710820/original.jpg photo_2.jpg
6d9a2019 267190 /zip/photos/sdc/5/c/d/00000000000000710819/original.jpg photo_3.jpg

設定

基本はなにも必要なし。
ただし、今回は以下の点を設定しています。

・zipを生成するときに指定するファイルは別サーバのWebDAVにあるので、upstreamとしてWebDAVを指定したURLを作成。
もっといい方法があるのかもしれないけど、よーわからんかったのでいろいろ試したらコレでいけた。
イメージとしては、

        upstream webdav {
                server 10.1.60.254:8081;
        }
        location /zip {
                proxy_pass http://webdav/;
        }

という感じのlocationを追加しておいて、アプリ側からは/zip/hoge/hoge.jpgみたいに指定します。

・ proxy_buffer_size, proxy_buffersを大きく設定しておく
これは、nginxを動かすマシンとご相談ですが、この値が小さいと結局WebDAVから取ってきたファイルを一時ファイルとして書き出してしまうので、
メモリの許す限り大きい値を設定するようにしています。
使ってみている感じ問題は起きてないけど、どれくらいまで値を大きくしてもよいかは正直よくわかりません。

インストール

mod_zipはgooglecodeにあります→mod_zip
nginxコンパイル時に--add-module=を指定するだけで、スンナリコンパイルできました。
nginx 0.8.31, 0.7.64で試しましたが、どっちでも問題ないようです。
私の場合は、Gentooなので、ebuildにUSE="zip"を追加する改造して、0.7.64-r3を使っています。

nginx+mod_zip


サーバにあるファイルとか、でかいデータをzipに固めてダウンロード、という特殊だけどたまに欲しくなる機能を作る場合に、nginx+mod_zipは便利です。

そもそも、mod_zipを使わなくても、アプリでがんばってzipを作るっていう選択肢もあるにはあります。(pythonだとzipモジュールがあるので、比較的気軽にzipは生成できます)
しかし、前提条件として、zipに固めたくなる場合は、中身のサイズが結構大きくなることが多いと思います。
そうすると、アプリでとりあえず素直に、データ読み込み→zipに追加を繰り返していくと、メモリをがっつり使うか、一時ファイルを作るしかなくなります。
最近触るサーバは、8GBくらいのSSDしか載せてなくて、ramfsなものが大半なので、正直、どちらもあまりやりたくありません。

そこで、むしろメモリ余ってるのはリバースプロキシ側だろということで、アプリは最低限の処理だけをして、
zipの生成はリバースプロキシ側でやってくれるのが、mod_zipです。