仙石浩明の日記

システム構築・運用

2013年12月13日

nexus5 の充電をワイヤレス (Qi 給電) にしたので、バックアップもワイヤレスにしてみた 〜 ssh サーバを nexus5 上で動かす 〜

昨今の円安のため香港ドルが高い (>_<)。 昨年は 10円/HK$ 台だったのに、いまや 13円/HK$ を超えている。 香港 (に限らないが) の人たちが大挙して日本に買物に来る気持ちが分かる。 これだけ円安が進めば、 日本じゅうどこへ行っても、 全てのものが安く感じられるのだろう。

ARENA Scientific Icey QI Charging Pad

逆に、 日本人が香港へ行くと、全てのものが以前より 3割ほど高く見えるわけで、 物欲が萎えてしまいほとんど買物しなかった (おまけに、香港に行く直前に日本で nexus 5 を買ってしまったし)。 とはいえ、 香港までわざわざ行っておきながら何も買わないというのもアレなので、 Qi 充電器を買ってみた。 深水埗 黄金電腦商場 地下35號舖 Sunny Computer Digital Co 力生電腦數碼公司 →

HK$199 = 約2700円なので、 ちっとも安くない。 「おにぎり」 こと、 ワイヤレスチャージャー 03 なら 2200円くらいで売っているが、 「おにぎり」 の電源が専用アダプタであるのに対し、 これは汎用の micro USB ケーブルが使えるのでよしとしよう。

この Qi 充電器を USB ハブの余っているポートにつないで机の上に置き、 その上に nexus 5 を置く。 使ってみると想像以上に便利。 電話がかかってきたとき、 以前はいちいち USB ケーブルを抜いていたのだけど、 Qi 充電器ならサッと nexus 5 を手に取れるし、 電話が終わったら Qi 充電器の上に戻すだけ。 はやく全てのケータイが Qi に対応して、 喫茶店などのテーブルに Qi 充電器を標準装備して欲しいなどと思う今日このごろ。

充電がワイヤレスなのに、 PC との通信に USB ケーブルを使っていては片手落ちである。 私は普段 rsync を使って nexus 5 上のデータを丸ごと PC へバックアップしているが、 有線な adb (Android Debug Bridge) を使うのは止めて Wi-Fi を使うことにした。

ここで注意したいのは、 主導権を握る (コントロールする) のは PC 側でなければならない、 ということ。 スマホ側 (nexus 5) が主導して rsync を起動するアプリならすでにいくつか出回っているが、 PC が目の前にあるときに何が嬉しくてスマホの小さい画面をいじらなきゃならないのかと思う。 Qi 充電器の上に置いたら、 もう 1 タッチといえどスマホには触りたくない。 全ての作業は PC のキーボードで完結させたい。

つまり、 PC がクライアントとなり、 スマホをサーバとして扱いたい、 ということ。 サーバのキーボードやモニタはトラブル発生時でもなければ使わないのと同様、 家にいるときはスマホは充電器の上に置きっぱなしにしておきたい。 あるいは寝室専用になってしまっているスマホ (各部屋に一台以上、専用スマホ/タブレットが置きっぱなしにしてある) は、 寝室に置きっぱなしのままで (別の部屋の) PC から操作したい。 スマホを PC から操作できれば、 コマンド一発で、 家じゅうのスマホ (10台くらいある) をいっぺんにバックアップしたり、 相互にデータを同期させたり、 何でも思いのまま (^^)。

スマホをサーバとして扱うには、 スマホ上で ssh サーバを動かしておけばよい、 ということで早速 dropbear サーバ (軽量 ssh サーバ) と rsync を nexus 5 (だけでなく私が持っている全ての android スマホ) にインストールした。

以下、インストールのメモ:

もっと読む...
Filed under: Android,システム構築・運用 — hiroaki_sengoku @ 09:07
2013年3月30日

UCOM光電話の VoIP アダプタ (Aterm BH812V) を LAN 内に設置してみた

UCOM光が導入されているマンションに住んでいるので UCOM光電話を使っている。 UCOM から貸与された VoIP (Voice Over IP, IP 電話) アダプタは、 グローバル IP アドレスが必要と説明書にあった。 UCOM光で各戸に割当てられるグローバル IP アドレスは 5個しかないのに、 うち 1個を VoIP アダプタごときに専有されるなんてトンデモナイ。 なんとか VoIP アダプタを、 次図のように LAN 内に設置することはできないか?

                    宅内 ←:→ UCOM
                        :       :
      LAN    ┌─────┐  DMZ   :       :
           │NAT 機能付│      :       :
───┬────┬──┤ルータ  ├──┬───────┬────→ インター
   │    │  └─────┘  │   :   │   :  ネット
┌──┴─┐┌─┴─┐   :   ┌─┴─┐ : ┌─┴─┐ :
│ VoIP ││ PC等 │   :   │公開 │ : │SIP  │ :
│アダプタ│└───┘   :   │サーバ│ : │Proxy │ :
└────┘        :   └───┘ : └───┘ :
              :
プライベート IP アドレス  :    グローバル IP アドレス

SIP (Session Initiation Protocol, VoIP で使われるプロトコル) は NAT と相性が悪いとはよく言われるが、 それは UA (User Agent) 同士が直接通話する場合の話。 SIP Proxy 経由で通話する場合であれば、 端末 (VoIP アダプタ等) は特定の SIP Proxy に接続すれば事足りるので、 端末が NAT の内側 (つまり LAN 内) でも何の問題もない。 だから VoIP アダプタにグローバル IP アドレスが必要と言われても納得しかねる。

私の場合、 VoIP アダプタとして Aterm BH812V (UZ) を貸与された。 このアダプタに、 フツーの (アナログ) 電話機をつなぐとフツーの (050 な電話番号ではなくフツーの市外局番な番号の) 固定電話として使える。 BH812V は VoIP アダプタなのに VoIP 関連の設定項目が全く無く、 ましてプライベート IP アドレスで使うための設定方法など望むべくもない。 仕方がないのでとりあえずそのまま BH812V を LAN につないでみた。 上図中 「NAT 機能付ルータ」 は実際は Linux マシンで、 このマシン上で DHCP (Dynamic Host Configuration Protocol) サーバを走らせている。 つまり、 この DHCP サーバから BH812V に対してプライベート IP アドレスが割当てられる。

BH812V 前面

BH812V の筐体には、 「ステータス」 「電話サービス」 「電話1」 「電話2」 「インターネット」 と書かれた 5 つのランプがあり、 正常な定常状態では全て緑色に点灯する。 ところが、 BH812V を LAN につないで電源を入れると、 「ステータス」 が橙点滅、 「インターネット」 が橙点灯したままになり、 「電話サービス」 他のランプは消灯したままになってしまった。 もちろん、 BH812V につないだ電話機は使用不能。 BH812V のログはこんな感じ:

2013/03/29 00:39:15 NAT GET 192.168.10.130 (IP-PORT=1)
2013/03/29 00:39:15 WAN  Port is UP for Local Router mode
2013/03/29 00:39:15 WAN  Connect request from 192.168.19.1 for Local Router mode
2013/03/29 00:39:15 DHCP_Client IP ADDRESS Get 192.168.10.130 (IP-PORT=1)

プライベート IP アドレス 192.168.10.130 が配布されたことは分かるが、 SIP 関連のエラーは全く出力されていないので、 このログではなぜ電話機が使えないか何も分からない (>_<)

ちなみに、 BH812V にグローバル IP アドレス 122.218.XX.XX を割当てて正常に動作したときのログはこんな感じ:

2013/03/29 00:51:09 NAT GET 122.218.XX.XX (IP-PORT=1)
2013/03/29 00:51:09 WAN  Port is UP for Local Router mode
2013/03/29 00:51:09 WAN  Connect request from 192.168.19.1 for Local Router mode
2013/03/29 00:51:09 DHCP_Client IP ADDRESS Get 122.218.XX.XXX (IP-PORT=1)

電話が使えない異常状態と、正常状態とで、 ログが (割当てられた IP アドレス以外は) 全く同じというのはいかがなものか。

そこで、 BH812V にグローバル IP アドレスを割当てたときと、 プライベート IP アドレスを割当てたときとで、 どのような挙動の違いがあるか調べてみる。 まず UCOM DHCP サーバから グローバル IP アドレスを割当てるとき、 BH812V と UCOM との間でどのような通信が行なわれるか? BH812V と UCOM との間にブリッジ (という名の Linux マシン) を挟んで、 どのようなパケットがやりとりされているか tcpdump (ネットワークを流れるパケットを表示するツール) で調べてみる。

   ┌────┐  ┌─────┐  宅内 ←:→ UCOM
   │ VoIP ├──┤ブリッジ ├──┐   :
   │アダプタ│  └─────┘  │   :       :
   └────┘  ┌─────┐  │   :       :
           │NAT 機能付│  │   :       :
────────┬──┤ルータ  ├──┼───────┬────→ インター
        │  └─────┘  │   :   │   :  ネット
      ┌─┴─┐       ┌─┴─┐ : ┌─┴─┐ :
      │ PC等 │       │公開 │ : │SIP  │ :
      └───┘       │サーバ│ : │Proxy │ :
                  └───┘ : └───┘ :

上図のように 「VoIP アダプタ」 (BH812V) を LAN から (ブリッジを介した) DMZ へつなぎ替えたわけだが、 このようなネットワーク構成の変更が、 物理的な配線変更を行なわずにできるのが、 スマートスイッチならでは (^^)v。

もっと読む...
Filed under: システム構築・運用 — hiroaki_sengoku @ 22:53
2013年3月19日

GS108E / GS116E の ProSafe Plus 設定ユーティリティが 「HTTP request error」 で使えないときの対処法

安価なスマートスイッチ GS108E / GS116E の設定ユーティリティ 「ProSafe Plus」 を起動したとき、 以下のようなエラーダイアログが表示されて使用不可能に陥ることがある:

Web サービス サーバと通信中にエラーが生じました。エラーメッセージ:HTTP request error

「サーバと通信中にエラーが生じました」 と言われても、 そもそもこの 「ProSafe Plus 設定ユーティリティ」 はサーバと通信するツールではないので途方に暮れてしまう。 「サーバ」 というのはこのツールの設定対象であるスイッチ GS108E/GS116E のことなのか? この設定ユーティリティは起動時にスイッチを探す (UDP broadcast) が、 もちろんプロトコルは HTTP ではない。

「HTTP request error」 というエラーメッセージが唯一の手がかりなので、 とりあえず google で検索してみる。 私と同様に途方に暮れている人が何人もいるようだ。

幸い、 そのうちの一人が解決方法を発見していた:

FIXED: Prosafe Plus Configuration Utility - HTTP request error

I Fixed it!!! : The problem seemed to be caused by the 'Internet Connection Sharing Service (ICS)'.
Some how I have been configuring this service on my laptop. When I stop this service, the utility works again. Because I do not need this service most of the time I changed the startup mode of this service to manual.

ICS ? そんなものを設定した覚えはないのだけど... と思いつつ、 「ネットワークと共有センター」 から 「アダプターの設定の変更」 を選び、 ネットワーク アダプターの 「プロパティ」 を開いて 「共有」タブを選択する (Windows7 あるいは Windows8 の場合)。 すると...

インターネット接続の共有 ネットワークのほかのユーザに、このコンピューターのインターネット接続をとおしての接続を許可する

がーん、 「インターネット接続の共有」(ICS) が許可されている orz.
誰が許可したんだ?

そういえば先月 Wi-Fi USBアダプタ GW-USFang300 を購入 (e-trend で 1280円で売っていたので衝動買い ^^;) した際、 この PC を Wi-Fi アクセスポイントとして使用したのだった。 アクセスポイントなので、 当然 ICS を許可することになる。 一時的に使用しただけなので、 今はこの Wi-Fi USBアダプタを外しているのだが、 ICS が許可されたままになっていたのだろう。

この 「ネットワークのほかのユーザに、このコンピューターのインターネット接続をとおしての接続を許可する」 のチェックを外して 「OK」 を押したところ、 無事 「ProSafe Plus 設定ユーティリティ」 が使えるようになった。 よかった〜

なお、 上記 google 検索で見つけた解決方法は、 「I changed the startup mode of this service to manual」 すなわち 「『Internet Connection Sharing (ICS)』 サービスの 『スタートアップの種類』 を 『手動』 にした」 とあるが、 ネットワーク アダプターの 「プロパティ」 で ICS 許可のチェックを外しても同じ効果が得られるし、 「プロパティ」 で設定変更するほうが素直な対処方法だと思う。

Filed under: システム構築・運用 — hiroaki_sengoku @ 10:41
2012年9月4日

個人でも気軽に買える安価なスマートスイッチ GS108E (IEEE 802.1Q タグVLAN 機能付) を使ってみた 〜 UCOM光 マンション全戸一括タイプの戸内配線上にプライベートネットワークを構築

先日、 UCOM光 マンション全戸一括タイプが導入されているマンションに引っ越した。 各部屋に LAN コンセントがあり、 UTPケーブルをつなぐだけでインターネットに接続できる。 USENのスピードテストで測定したところ、 50Mbps 以上の通信が可能であるようだ。 個人ユースであれば充分な帯域。

     UCOM
       │
       │
   ┌───┴───┐
   │ マンションの│
   │  ルータ  │
   └┬┬┬┬┬┬┬┘
┌───┘│││││└───┐
│ ┌──┘│││└──┐ │
│ │ ┌─┘│└─┐ │ │
: : :  │  : : :
 各戸へ   │   各戸へ
       │
    ┌──┴──┐
    |各戸のハブ| /29
    └┬─┬─┬┘
   ┌─┘ │ └─┐
   │   │   │
   ↓   ↓   ↓
  各部屋の LAN コンセント

各戸に半固定な /29 グローバル IP アドレス空間 (つまり 8個の IP アドレス) が割当てられていて、 LAN コンセントに PC 等をつなぐと、 マンション内に設置されたルータが DHCP でグローバル IP アドレスを配布する。 8個のアドレスのうち、 1個はこのルータが使い、 ネットワークアドレス (下位 3ビットが 000) とブロードキャストアドレス (下位 3ビットが 111) は配布されないので、 実際に配布されるのは (下位 3ビットが 010 〜 110 の) 5個のアドレスのみ (IPv4 アドレスが枯渇している昨今、 3/8 を無駄にするのはいかがなものか?)。

UCOM に問合わせたところ、 各戸のハブ (以下、ここでは 「戸ハブ」 と呼ぶ) は、 浴室の天井裏に設置されているらしい。 また、 各戸に割当てられるグローバルアドレスは、 通常は変化せず (機器構成の変更等で変わる可能性がある)、 全てのパケットはフィルタリングせずに届けられるらしい。

インターネット上の任意のホストから任意の通信が可能であるわけで、 (特に XP 以前の脆弱な) Windows マシン等を LAN コンセントに直結するのは、 セキュリティ上あまりよろしくない (有料オプションで、セキュリティ対策サービスがあるらしい)。 また、 5台以上の PC をつなぎたい場合もあるだろう。 特に UCOM光電話を使う場合は、 IP電話アダプタがアドレスを一つ使う (使わずに済ませる方法) ので、 残り 4個になる。 フツーの家庭でも 4個では足らなくなるのでは? もちろん私の場合は 12個でも足らない。;-)

普通は、 PC を LAN コンセントに直結してグローバルアドレスを使うのではなく、 NAT 機能付ルータ (無線LAN ルータ等) を LAN コンセントにつないで、 PC にはプライベートアドレスを割当てることになるだろう。 各部屋で有線LAN を使いたい場合は、 各部屋にルータ (以下、 「部屋ルータ」 と呼ぶ) を用意して PC をつなぐことになる。

UCOM によると、 マンションによっては、 戸ハブの代わりにルータを各戸に設置して、 プライベートアドレスを配布しているケースもあるとか。 セキュリティを気にするのであれば、 戸ハブをルータと交換してもらっても構わないとまで言っていたが、 私はグローバルアドレスを使いたいので、 現状の仕様のほうが嬉しい。

ところが、 この方法だと各部屋の LAN は互いに異なるプライベートネットワークになってしまい、 異なる部屋 (そういくつも部屋があるわけでもないのだが ^^;) の PC と通信したいとき困る (居間にサーバを置くのは無粋なので、 ネットワークメディアプレーヤを使う場合とか)。 各部屋ルータの間で VPN を張って、 各部屋のプライベートネットワークを一つにする方法もあるが、 VPN のオーバヘッドがモッタイナイ。

もちろん、 部屋間に (廊下などに) UTP ケーブルを這わせれば済む話だが、 美観上好ましくないのと、 私の場合は購入ではなく賃貸で借りたマンションなので、 むやみにケーブルを配線するのも憚られる。 各LAN コンセントは、 壁裏配線を介して同じ戸ハブ (天井裏の写真 ↓ ダムハブ ^^;) につながっているのだから、 一つの LAN コンセントからパケットを送れば、 他の LAN コンセントに届く。 マンションのルータは当然 IP パケットの発信元/宛先アドレスをチェックしているだろうから、 発信元/宛先アドレスがプライベートアドレスなら外部へは出さないだろう。

Baffalo Dumb Hub

したがって、 グローバルアドレスなパケットに対してはルータとして、 プライベートアドレスなパケットに対してはブリッジとして機能するブルータを、 部屋ルータとして用いればよい。 ただし、 一般に売られている安価なルータにブルータの機能を求めるのは無理がある。 Linux マシンを使えばブルータを実現するのは容易だが、 各部屋 (特に寝室) で Linux マシンを 24時間稼働させるのはいかがなものか。

もっと安易に、 各PC を LAN コンセントにそのまま (あるいはハブを介して) つなぎ、 PC にはプライベートアドレスを割当てる方法もありそう。 あらかじめ 5個のグローバルアドレス全てを使いきってしまえば (例えば各グローバルアドレスを持った PC を前もってつないでおく)、 マンションのルータが (新たにつないだ) PC にグローバルアドレスを割当てることを防ぐことができる。 そして、 プライベートアドレスを配布する DHCP サーバを動かしておけばよい。 プライベートアドレスを割当てられた PC 同士は、 異なる LAN コンセントにつながれていても、 戸ハブ経由で通信できる。

ただしこの方法は、 PC にグローバルアドレスが割当てられてしまうことを完全には防げない。 なんらかのトラブルによりグローバルアドレスを使いきれない状態が生まれると、 そのとき LAN コンセントにつないだ PC には、 グローバルアドレスが割当てられてしまう。 グローバルアドレスが割当てられても、 (当然) フツーに通信できるわけで、 ユーザはグローバル空間に晒されていることに気付かない。 セキュリティ的にかなり好ましくない事態と言える。

各部屋にブルータ (という名の Linux マシン) を配置するしかないのか? と思っていたら、 タグVLAN (IEEE 802.1Q) 機能を持った安価なスイッチングハブを見つけた。 タグVLAN は業務用のインテリジェントスイッチでないと使えないと思っていたが、 1万円以下 (6400円) で買えるとわ... 思わず e-TREND で衝動買い。

本当は 5ポートの GS105E を買いたかったが、 日本では入手するのが難しそう。 8ポートの GS108E なら、 e-TREND の他、 NTT-X Store などでも送料込 6400円で購入できる (どちらのショップも 「在庫なし」 と表示されるが、 私が e-TREND に注文したときは 1週間程度で届いた)。

タグVLAN 機能付ハブを使えば、 ブルータよりもっとスマートにプライベートネットワークが実現できる。 つまり、 部屋間のプライベート通信はタグを付けて行なう。 戸ハブは (ダムハブなので) タグの有無にかかわらずなんでも中継してくれるし、 マンションのルータはタグ付パケットを無視する。

GS108E-living

GS108E を 3個購入し、 各部屋 (便宜上、ここでは居間、寝室、書斎とする) に配置する (写真 → は、居間に設置した GS108E, その上に置いてあるのは無線LAN AP, 左は IP電話アダプタ)。

VLAN ID 1 をグローバルネットワークに、 VLAN ID 2 をプライベートネットワークに使うことにする。 各 GS108E のポート 01 には、 各部屋の LAN コンセントをつなぎ、 VLAN ID 1 をタグ無しで、 VLAN ID 2 をタグ付で流す。 ポート 04 〜 08 は、 プライベートネットワーク専用ということにして、 VLAN ID 2 のみをタグ無しで流す。

グローバルネットワークに接続する必要があるのは、 グローバルアドレスをプライベートアドレスへ変換する部屋ルータ (という名の Linux サーバ) と、 IP電話アダプタ (UCOM光電話) のみ。 前者 (部屋ルータ) は書斎にある。 部屋ルータは、 グローバルとプライベートの両方のネットワークに接続する必要があるが、 幸い Linux はタグ付パケットを扱えるので、 単一の NIC で両方のネットワークに接続できる。 書斎の GS108E のポート 02 に部屋ルータをつなぎ、 ポート 01 と同様、 VLAN ID 1 をタグ無しで、 VLAN ID 2 をタグ付で流す。 書斎に他の PC が無ければ、 部屋ルータを LAN コンセントに直接つないでもよい。

後者 (IP電話アダプタ) は居間にある。 IP電話アダプタはグローバルネットワークにだけつなげればよいので、 居間の GS108E のポート 02 にIP電話アダプタをつなぎ、 VLAN ID 1 をタグ無しで流す。 急遽グローバルネットワークに接続したい機器が増えた場合に備えて、 ポート 03 にも VLAN ID 1 をタグ無しで流す (つまりグローバルネットワーク専用) 設定にした。

GS108E-living VLAN config

タグVLAN は、 一本のケーブル上に複数のネットワークを同居させることができる便利な規格。 ケーブルを何本も這わすことが (美観上の理由で) 難しい家庭でこそ必要な機能なのに、 普及価格帯のハブでタグVLAN をサポートしているのは (私が知る限り) GS105EGS108E のみ。 タグVLAN 機能を持った安価なスマートスイッチが増えることを願ってやまない。

Filed under: システム構築・運用 — hiroaki_sengoku @ 11:40
2011年7月31日

OpenVZ な ServersMan@VPS で独自 OS を動かしてみた

国内に (自宅以外で) IPv6 が使えるサーバが欲しかったので、 ServersMan@VPS を使ってみた。 ServersMan@VPS は仮想化プラットフォームが OpenVZ なので今まで敬遠していたのだが、 Osukini サーバ (Xen) も、 さくらの VPS (KVM) も、 いまのところネイティブな IPv6 はサポートしていない (さくらの IPv6 は 6rd) ので、 やむなく契約してみた次第。

Xen や KVM などの完全仮想化と異なり、 OpenVZ はホストOS のカーネルがゲスト OS のカーネルとしても使われる。 つまり VPS (Virtual Private Server) サービスのユーザが別のカーネルを立ち上げることができない (ServersMan@VPS Perfect は完全仮想化だが月額 3150円と高いのでここでは考えない)。 OS は CentOS, Debian, ubuntu から選ぶことになる。

しかしながら、 私が個人的に管理しているサーバは、 全て OS を独自の 「my distribution」 (便宜上ここでは GCD OS と呼ぶ) に統一していて、 全サーバでディスクの内容を同期させている。 つまりある特定のサーバ固有の設定情報も、 全サーバが共有している。 共有していないのは各サーバのホスト名と、 秘密鍵などごく一部の情報だけ。 だからサーバが壊れた場合も、 新しいマシンを用意して他のサーバからディスク内容を丸ごとコピーするだけで済む。

私個人で管理しているサーバ (もちろん会社で運用しているサーバは除く) は、 仮想環境も含めると 20台ほどになるので、 異なる OS はできれば管理したくない。 ServersMan@VPS で提供されるカーネルを使うのは (OpenVZ の仕組み上) 仕方がないとして、 ディスクの内容は GCD OS と入れ替えることにした。

稼働中のサーバをいじるとき重要なのが、 トラブった時に 「元に戻せるか?」 ということ。 元に戻せるなら多少の失敗を恐れることはない。 ほとんどの VPS サービスは、 最悪の事態に陥っても初期化すれば元通りになるので、 操作をミスっても一からやり直せばいいのだが、 OS を入れ替えようとする場合は (当然) 新しい OS 一式を送り込む必要があり、 初期化するとこれが消えてしまうので再度転送する羽目になる。 GCD OS は最小セットで 7GB 近くあるので、 何度も転送を繰り返したりすると VPS サービスの契約ネットワーク帯域を使いきってしまう。

幸い、 ServersMan@VPS に帯域制限は無いが、 一日に 何十GB も転送していたら、 きっと管理者に睨まれるはず。 そこで、 どんなに失敗しても、 再起動すれば ssh でログインできる状態に戻るような OS 入れ替え手順を考えてみた。 ssh でログインできさえすれば後は何とでも修復できる。 逆に言うと ServersMan@VPS のようなコンソールが提供されない VPS サービスでは ssh でログインできなくなると万事休す、 残された復旧手段は初期化しかない。

まず ServersMan@VPS Standard プランを契約 (月額 980円) して、 Ubuntu(64bit) の最小構成 (シンプルセット) を選択。 ssh でログインして netstat でソケットを開いているデーモンを調べ、 片っ端から dpkg --purge (アンインストール) する。 もちろん sshd (ssh サーバ) だけは purge してはいけない。 syslog や cron などフツーは決して purge しないデーモンも遠慮無く purge する。 ps したとき sshd のプロセスのみが表示されるような状態になるまで purge しまくる。 で、 一通り purge し終わったら念のため再起動してみる。 もしここで ssh でログインできなくなってしまっていたら、 初期化して振出しに戻る。

この時、 sshd が 22番ポートで listen している場合は、 GCD OS が起動する sshd と衝突するので、 22番ポート以外に変えておく。 幸い ServersMan@VPS の場合は sshd が初めから 3843番ポートで listen する設定になっていた (なぜ?) ので、 そのままにしておく。

次に、 デーモン類以外のパッケージも、 残しておくとディスクの肥やしになるだけなので、 できるだけ purge する。 とはいっても、 多くのパッケージが数MB 以下で容量的には誤差の範囲なので、 無理に purge して再起不能状態に陥るリスクを冒すより、 ディスクの肥やしにしておいた方がマシ。 で、 一通り purge し終わったら念のため再起動してみる。 もしここで ssh でログインできなかったら、 初期化して振出しに戻る。

こうして netstat -nap しても ps axf しても sshd 以外のプロセスが一切残っていない状態になったら、 いよいよ GCD OS 一式を送り込む。

senri:/ # mirror -v -r /usr/local/gcd -e 'ssh -p 3843' 'core64[183.181.54.38]' > /tmp/serversman &

mirror というのはサーバ間で GCD OS の同期を行なうためのスクリプト。 64bit (x86_64) の最小セットをコピーするために引数として 「core64」 を指定した。 このスクリプトは、 同期すべきファイルのリストを作成して rsync を呼び出す。 「-e 'ssh -p 3843'」 オプションは、 そのまま rsync に渡される。 このコマンド列で GCD OS 最小セット約 7GB が VPS の /usr/local/gcd ディレクトリ以下へ丸ごとコピーされる。 7GB の転送にどのくらいかかるかと思っていたら、 わずか 10分弱で終わってしまった。 100Mbps 以上の帯域ということになる。 結構すごい。

ホスト名を chiyoda.gcd.org に設定し、 このサーバ専用の秘密鍵を作成すれば GCD OS のインストールが完了。 あとは、 /usr/local/gcd 以下へ chroot して GCD OS を起動するだけ。 次のような GCD OS 起動スクリプト /etc/init.d/chroot を書いてみた。

#!/bin/sh
root=`echo $0 | sed -e 's@/etc/init.d/chroot$@@'`
if [ ! -d $root ]; then
   echo "Can't find root: $root"
   exit 1
fi
mount -obind /lib/modules $root/boot/lib/modules
chroot $root sh <<EOF
mount -a
svscanboot &
/etc/rc.d/rc.M
EOF

このスクリプトも GCD OS 一式をコピーするときに /usr/local/gcd/etc/init.d/chroot へコピーされる。 で、/usr/local/gcd/etc/init.d/chroot を、 とりあえず手動で実行。 手動で実行するところがミソで、 もしこのスクリプトにバグがあって異常事態に陥っても、 再起動すれば元に戻る。

上記 /usr/local/gcd/etc/init.d/chroot は、 chroot /usr/local/gcd sh を実行して、 chroot 環境下で svscanboot と /etc/rc.d/rc.M を実行する。 svscanboot は daemontools の起動スクリプト。 GCD OS のほとんどのデーモン類は daemontools の管理下で起動される。 一方 /etc/rc.d/rc.M は、 GCD OS のブートスクリプトで、 ファイアウォールなどネットワークまわりの設定や、 個々のサーバ特有の設定、 および一部のデーモン類の起動を行なう。

普通の Linux OS だと init から直接起動されるデーモンもあるが、 GCD OS の場合 init が起動するのは /etc/rc.d/rc.S と /etc/rc.d/rc.M および svscanboot だけ。 /etc/rc.d/rc.S は、 OpenVZ 環境下では不要な処理ばかりなので実行する必要はない。

こうして chroot 環境下で GCD OS が起動したら、 chroot /usr/local/gcd sh などと実行して GCD OS 環境へ入ることができる。 各種設定が正しく機能しているか、 デーモン類が正しく動いているか確認する。

ServersMan@VPS で使われているカーネルが、 2.6.18-194.3.1.el5.028stab069.6 と、 かなり古い (2.6.18 などという 5年も昔のカーネルを使い続けないでほしい > RHEL) ので、 GCD OS をきちんと動かすには問題があった。 特に困ったのが、 iptables の owner モジュールが使えない点:

chiyoda:/ # uname -rv
2.6.18-194.3.1.el5.028stab069.6 #1 SMP Wed May 26 18:31:05 MSD 2010
chiyoda:/ # iptables -t nat -j REDIRECT -p udp --dport 53 --to-port 2053 -A dnscache.lo -s 127.0.0.1 -d 127.0.0.1 -m owner ! --uid-owner Gdnscache
iptables: No chain/target/match by that name.

このエラーは、 カーネルに CONFIG_NETFILTER_XT_MATCH_OWNER の設定がないのが原因。 NETFILTER_XT_MATCH_OWNER が導入されたのは 2.6.25 以降なので、 そもそも元から 2.6.18 には存在しない。

なぜ --uid-owner が必要かと言えば、 GCD OS では tinydns と dnscache を、 同じ IP アドレスで動かすことが基本になっているから。 つまり、 通常の名前解決に 127.0.0.1 の dnscache を利用するのだが、 dnscache (Gdnscache 権限で動作) が 127.0.0.1 に問合わせる時に限り mydns が返事をするようにしたい。

仕方がないので、 iptables に --uid-owner を指定してエラーになる場合は、 --uid-owner 抜きで iptables を再実行するように修正した:

nsredirect="-t nat -j REDIRECT --dport 53 --to-port $PORT"
chain=dnscache.lo
iptables -t nat -N $chain 2>/dev/null || iptables -t nat -F $chain
nsinner="$nsredirect -A $chain -s 127.0.0.1 -d 127.0.0.1 \
	-m owner ! --uid-owner Gdnscache"
iptables -p udp $nsinner
if [ $? -ne 0 ]; then
    nsinner="$nsredirect -A $chain -s 127.0.0.1 -d 127.0.0.1"
    iptables -p udp $nsinner
fi
iptables -p tcp $nsinner

このような修正を、 chiyoda.gcd.org だけでなく、 GCD OS をインストールしている全サーバで一斉に行なう点がミソ。 サーバごとにファイルの内容が微妙に異なっていたりしたら、 GCD OS を使う意味がない。

当然、 --uid-owner 抜きで iptables を実行した場合は、 dnscache が 127.0.0.1 の mydns に問合わせをすることができないが、 127.0.0.1 以外、 つまり 183.181.54.38 あるいは 2001:2e8:634:0:2:1:0:2a ならば mydns に問合わせることができるので問題無い。

じゃ、 なんのために、 わざわざ --uid-owner を使って 127.0.0.1 の mydns に問合わせられるようになっているかというと、 127.0.0.1 以外の IP アドレスが動的に変わるサーバ (ノートPC など) も想定しているから。 GCD OS は VirtualBox や Xen などの完全仮想化環境だけでなく、 coLinux や今回の OpenVZ など、 仮想化環境としてはやや異質なものもサポートしている。

以上のような細かい修正を行なっていって、 GCD OS が問題無く立ち上がるようになったら、 /usr/local/gcd/etc/init.d/chroot の呼び出しを (ubuntu の) /etc/rc.local に追加して、 VPS の起動時に自動的に GCD OS が起動されるようにする。

GCD OS が正しく立ち上がれば、 外部から 22番ポートに対して ssh ログインして GCD OS が使える。 22番ポートでログインできることが確認できたら、 3843番ポートの sshd は止めてもよい。 chroot 環境からはいつでも脱出できるので、 3843番ポートを止めても本来の (chroot する前の) ubuntu 環境にアクセスすることが可能:

senri:~ # ssh chiyoda.gcd.org
Enter passphrase for key '/root/.ssh/id_rsa':
Last login: Sat Jul 30 09:14:54 2011 from 2409:82:5fff:0:5542:d84e:971a:9656
Linux 2.6.18-194.3.1.el5.028stab069.6.
chiyoda:~ # ls -F /					↓ GCD OS
bin@   dev/  ftp/   lib/    proc/  run/   sys/  usr/
boot/  etc/  home/  lib64@  root/  sbin@  tmp/  var/
chiyoda:/ # chroot_escape /bin/bash			← chroot から脱出
groups: cannot find name for group ID 11
groups: cannot find name for group ID 14
root@chiyoda:/# ls -F --color=never			↓ ubuntu
aquota.group@  boot/  fastboot  lib32/  mnt/   sbin/     sys/  var/
aquota.user@   dev/   home/     lib64@  proc/  selinux/  tmp/
bin/           etc/   lib/      media/  root/  srv/      usr/
root@chiyoda:/# cat /etc/debian_version
squeeze/sid
root@chiyoda:/# lsb_release -r
Release:	10.10
root@chiyoda:/# exit
chiyoda:~ # 						↓ GCD OS

「chroot_escape /bin/bash」 が、 chroot 環境から脱出するコマンド。 脱出して、 「本来の」 root 環境 (この例では ubuntu) 下で、 引数のコマンド 「/bin/bash」 を実行する。 この bash を使って ubuntu の操作ができて、 exit すると元の GCD OS へ戻る。 まるで chroot 下の GCD OS の方が 「主」 で、 本来の root が 「従」 のように見える ;-)。

なお、 chroot_escape コマンド実行時の 「groups: cannot find name for group ID 〜」 というエラーは、 GCD OS の /etc/group と ubuntu の /etc/group が異なるため。 つまり GCD OS の root は ID 11 と 14 のグループに属しているが、 ubuntu には ID が 11 と 14 のグループが存在しないため、 このようなエラーが表示される。

ここまでやるなら、 chroot といわず root に GCD OS をインストールしてしまえば? という声が聞こえてきそうであるが、 ServersMan@VPS ではコンソールが利用できないため、 トラブったときのために何らかの 「バックドア」 は残しておきたい。 GCD OS がどのような状況に陥っても、 3843番ポートの sshd (init から起動されるので kill しても再起動する) にログインできれば、 ubuntu 環境で GCD OS の修復が可能。

というわけで一週間ほど ServersMan@VPS Standard プランを使っているが、 意外に (失礼!) 使えるので驚いた。 実は、 OpenVZ な 512MB ということであまり期待していなかった。 OpenVZ は swap を使えないので、 メモリ 512MB だと、 ちょっと重い処理をさせるだけですぐ OOM Killer が動き出すのだろうと思っていた。 ところが、

chiyoda:~ $ free
             total       used       free     shared    buffers     cached
Mem:       2097152     425020    1672132          0          0          0
-/+ buffers/cache:     425020    1672132
Swap:            0          0          0

512MB というのは実メモリ? の割当量のようで、 見かけ上は 2GB のメモリがある。 OpenVZ な VPS サービスによっては、 これをメモリ 2GB と言い張るところもあるんじゃないかと思うので、 ServersMan@VPS は良心的。

どのくらいのパフォーマンスなのか、 この日記 (WordPress を使用) の処理時間を測ってみる。 senri.gcd.org から ApacheBench でアクセスすると:

senri:~ $ /usr/apache2/bin/ab -n 10 http://chiyoda.gcd.org/blog/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
	...
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        6    7   0.3      7       7
Processing:   992 1116  94.1   1139    1259
Waiting:      305  403  78.3    380     561
Total:        998 1122  94.1   1146    1265

これを、 Linode Xen 512MB プラン (fremont.gcd.org) と比較する。 fremont.gcd.org は米国西海岸にある VPS なので、 同じく西海岸にある prgmr.gcd.org から ApacheBench でアクセスすると:

prgmr:~ $ /usr/apache2/bin/ab -n 10 http://fremont.gcd.org/blog/
	...
              min  mean[+/-sd] median   max
Connect:        2    3   0.1      3       3
Processing:   996 1081  73.8   1084    1197
Waiting:      354  391  30.5    388     450
Total:        999 1084  73.8   1086    1200

両者は、 ほとんど同等のパフォーマンスであることが分かる。 Linode Xen 512MB プランは、 ディスク 20GB で月額 $19.95 (約 1600円) なので、 ServersMan@VPS Standard プラン (ディスク 30GB, 月額 980円) の方がコストパフォーマンスが良い。

もちろん、 ServersMan@VPS Standard には、 カーネルのバージョンが古すぎ、という問題点があるし、 メモリ 512MB を超える部分のパフォーマンスは、 ホストOS 側の負荷状況に左右されると思われるので、 単純に比較すべきではない。

Filed under: IPv6,システム構築・運用 — hiroaki_sengoku @ 10:48
2011年7月24日

フレッツ 光ネクストの IPv6 IPoE 接続 (ネイティブ方式) を使ってみた

IPv6 閉域網であることを今までさんざん dis られてきたフレッツ網 (NGN, 次世代ネットワーク) が、 ついに 7月21日からインターネットに接続できるようになった。 これでもう 「NGN と IPv6 インターネットは併用できない」 などとは言わせない。 私は IPv6 を既に PPPoE 接続で使っているのだが、 トンネル方式 (PPPoE) よりネイティブ方式 (IPoE) のほうがいいにきまってる、 ということでさっそく申し込んでみた

NGN のサービス情報サイト (NGN からでないとアクセスできない) のページで 「サービス申込受付」 をクリック。 「お客様ID」 と 「アクセスキー」 を入力してログインすると、 「フレッツ・v6オプション」 を申し込むことができる (このページから申し込むと無料)。

申込み後、 NGN から流れてくる IPv6 ルータ広告 (RA, Router Advertisement) を tcpdump で監視していたら、 34分経過した頃にプレフィックスが突然変わった。 NGN の契約以来、 今まで一度も変わったことがなかったプレフィックス 2408:82:5fff:86a::/64 が、 2408:282:5fff::/64 になった。 これはきっとインターネットと通信できるプレフィックスに違いないと思って、 他のサイトから ping6 を打ってみた。 が、 NGN からは RA 以外は何も流れてこない。 うーん。 ちなみに RA の送信元 (NGN のエッジ・ルータ) は fe80::21e:13ff:fec2:69c2 のまま変わらず。

その後 1時間ほど放置してみたが何も状況が変化しなかったので、 「フレッツ・v6オプション」 って何? と思い直して (サービス内容をよく確認せずに申し込んでしまっていた)、 あらためて FAQ を見ると、

 Q
「フレッツ・v6オプション」を利用してインターネットへの接続はできますか?
 A
「フレッツ・v6オプション」 は、NTT東日本が構築するNGN内での通信が可能ですが、 「フレッツ・v6オプション」 のみではインターネットへの接続はできません。 インターネットへの接続には、 別途プロバイダサービスをお申し込みいただく必要があります。

インターネットへ接続するには、 フレッツ・v6オプションとプロバイダ契約の両方が必要らしい。 では、 どのプロバイダの、 どんなサービスを申し込めばいいんだろう? と思って、 フレッツ 光ネクスト IPv6 IPoE対応プロバイダを調べてみると、 神奈川県だと現時点で対応しているのは IIJmio だけだった (神奈川県だけでなく他県も同様)。 IIJ は今まで契約したことがなかったが、 他に選択肢が無いのであれば仕方がない。 さくっとクレジットカード番号を入力して IIJmio FiberAccess/NF を契約した (月額 2100円)。 これで半固定 IPv6 アドレスによる IPoE サービスと、 動的割当て IPv4 アドレスによる PPPoE サービスが利用できる。

Ether 上に IP を流すのはごくごく普通のことなので、 あらたまって 「IPoE」 (IP over Ether) と表現されると何だか妙な感じ。 「半固定」 というのも微妙な表現だが、 注意書きには 「お客様の移転、フレッツ回線の品目変更やNTTのメンテナンスにより、 変更になる場合があります」 と書いてあるので、 普通に使ってる限りプレフィックスが変わることは無さそう。

mio FiberAccess/NFサービスは、 インターネットマルチフィード株式会社が提供する 「transix (トランジックス)」 サービスを利用して、 NTT東西の 「インターネット(IPv6 IPoE)接続」 に対応したIPv6接続を提供します。 IPv6接続に加えて、 PPPoE接続方式によるIPv4接続もあわせて提供するため、 お客様は一つのサービスでIPv6、 IPv4の両方の接続環境を利用することができます。
IIJmio FiberAccess/NF概要 から引用

IPv6 接続は全て transix が担っていて、 IIJmio はネットワーク的には何の役割も果たしていない。 IIJmio がやってるのは課金などユーザ管理関連だけ。 プロバイダである IIJmio が絡むから、 IPv4 接続も提供するなどという抱き合わせ商法になる。 動的割当の IPv4 PPPoE 接続サービスなんて要らないから、 もう少し安いプランがあればいいのにと思う。

本来、 ネイティブ方式の IPv6 接続サービスは、 NTT東西だけで提供するのが自然な形だった。 ところが、 NGN を持っていて地域独占な NTT東西が接続サービスまで提供してしまっては、 他のプロバイダの出る幕がなくなると猛反発されて、 BBIX, JPNE, インターネットマルチフィード の三社が接続サービスを提供することになった。 なぜ三社だけかといえば、 プロバイダを増やすと経路情報の処理量が膨大になって NGN の各ルータの処理能力の限界を超えてしまうから。

ところが、 三社だけでは少なすぎると他のプロバイダ達が反対したので、 その他大勢の中小プロバイダにも参入の余地を無理矢理作ったということなのだろう。 でも、 やってることは単なるユーザ管理なので、 通信事業者じゃなくてもできる簡単なお仕事。 この期に及んで業界保護みたいなことはやめてほしい。 インターネット接続サービスは既にコモディティ化しているのだから、 体力のないところは淘汰されるべき。

FiberAccess/NF を契約してから 1時間が経過したとき、 NGN から流れてくる RA のプレフィックスが 2409:82:5fff::/64 に変わった。 今度こそ疎通したかと思い、 senri.gcd.org に IPv6 アドレス 2409:82:5fff::3c20:55dc を割当てて、 他のサイトから 2409:82:5fff::3c20:55dc に対して ping6 を打ってみる。 すると無事、NGN IPoE 経由で senri.gcd.org に ICMPv6 パケットが届いた。

ただし、 まだ senri.gcd.org の routing 設定を行なっていないので、 返りパケットは PPPoE 経由で OCN 側へ行ってしまう (おそらく OCN 内部で捨てられる)。 そこで、 とりあえずの対策として NGN から届いたパケットは NGN へ返すように、 policy routing rule を設定した:

senri:/ # ip -6 rule add from 2409:82:5fff::/64 table 100 pref 25600
senri:/ # ip -6 route add default table 100 via fe80::21e:13ff:fec2:69c2 dev eth1

つまり、 送信元アドレスが 2409:82:5fff::/64 なパケットは routing table 100 を参照するようにして、 routing table 100 において default route を、 fe80::21e:13ff:fec2:69c2 (NGN のエッジ・ルータ) へ向ける。

これで ping に対して応答できるようになった。

fremont:~ $ ping6 -c 3 2409:82:5fff::3c20:55dc
PING 2409:82:5fff::3c20:55dc(2409:82:5fff::3c20:55dc) 56 data bytes
64 bytes from 2409:82:5fff::3c20:55dc: icmp_seq=1 ttl=49 time=122 ms
64 bytes from 2409:82:5fff::3c20:55dc: icmp_seq=2 ttl=49 time=122 ms
64 bytes from 2409:82:5fff::3c20:55dc: icmp_seq=3 ttl=49 time=122 ms

--- 2409:82:5fff::3c20:55dc ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 122.479/122.526/122.591/0.289 ms
fremont:~ $ tcpspray 2409:82:5fff::3c20:55dc
Transmitted 102400 bytes in 0.491628 seconds (203.406 kbytes/s)

RTT (Round Trip Time, 往復所要時間) が 122ms もかかってるのは、 fremont.gcd.org が米国の西海岸にあるため。 2400:400d:100::3c20:55dc (OCN の PPPoE 接続) 宛の場合↓ と比べると、 transix は RTT で 50ms ほど速く、 帯域 (tcpspray による簡易測定) で倍くらい広い。

fremont:~ $ ping6 -c 3 2400:400d:100::3c20:55dc
PING 2400:400d:100::3c20:55dc(2400:400d:100::3c20:55dc) 56 data bytes
64 bytes from 2400:400d:100::3c20:55dc: icmp_seq=1 ttl=49 time=174 ms
64 bytes from 2400:400d:100::3c20:55dc: icmp_seq=2 ttl=49 time=174 ms
64 bytes from 2400:400d:100::3c20:55dc: icmp_seq=3 ttl=49 time=174 ms

--- 2400:400d:100::3c20:55dc ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 174.046/174.386/174.593/0.539 ms

fremont:~ $ tcpspray 2400:400d:100::3c20:55dc
Transmitted 102400 bytes in 0.905523 seconds (110.433 kbytes/s)

参考までに IPv4 60.32.85.216 (OCN の PPPoE 接続) の場合も測ってみた。 すると RTT も帯域も transix と同程度だった。 つまり OCN の IPv6 PPPoE だけが突出して遅く、 帯域も狭い。

fremont:~ $ ping -c 3 60.32.85.216
PING 60.32.85.216 (60.32.85.216) 56(84) bytes of data.
64 bytes from 60.32.85.216: icmp_req=1 ttl=51 time=130 ms
64 bytes from 60.32.85.216: icmp_req=2 ttl=51 time=130 ms
64 bytes from 60.32.85.216: icmp_req=3 ttl=51 time=129 ms

--- 60.32.85.216 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 129.377/129.903/130.202/0.559 ms

fremont:~ $ tcpspray 60.32.85.216
Transmitted 102400 bytes in 0.518052 seconds (193.031 kbytes/s)

米国西海岸から transix までの IPv6 の経路はこんな感じ:

fremont:~ $ tracepath6 2409:82:5fff::3c20:55dc
 1?: [LOCALHOST]                        0.021ms pmtu 1500
 1:  2600:3c01:ffff:0:ca4c:75ff:fef5:d63f                  0.558ms
 1:  2600:3c01:ffff:0:ca4c:75ff:fef5:d63f                  0.480ms
 2:  10gigabitethernet2-3.core1.fmt1.he.net                3.149ms
 3:  10gigabitethernet1-2.core1.sjc2.he.net               11.042ms
 4:  equi6ix.sv.iij.com                                    1.834ms asymm  5
 5:  sjc002bf00.iij.net                                    9.384ms asymm  7
 6:  2001:48b0:bb00:8016::71                             120.588ms asymm  7
 7:  tky009bb11.IIJ.Net                                  120.730ms asymm  8
 8:  tky009ip50.IIJ.Net                                  121.048ms
 9:  2001:240:bb5c:1008::cafe                            120.365ms
10:  2404:8e00:feed:101::2                               121.852ms
11:  no reply
12:  no reply
13:  no reply
14:  no reply
15:  no reply
16:  2409:82:5fff::3c20:55dc                             127.409ms reached
     Resume: pmtu 1500 hops 16 back 49

「IIJmio はネットワーク的には何の役割も果たしていない」 が、 日米間の回線は IIJ が担っているようだ (あれっ? ^^;)。 日本に上陸後 (6 以降) はほとんど遅延していない。

OCN の PPPoE の場合だと、こんな感じ:

fremont:~ $ tracepath6 2400:400d:100::3c20:55dc
 1?: [LOCALHOST]                        0.047ms pmtu 1500
 1:  2600:3c01:ffff:0:ca4c:75ff:fef5:d63f                  3.935ms
 1:  2600:3c01:ffff:0:ca4c:75ff:fef5:d63f                  0.852ms
 2:  10gigabitethernet2-3.core1.fmt1.he.net                7.978ms
 3:  10gigabitethernet1-2.core1.sjc2.he.net                2.532ms
 4:  xe-0.equinix.snjsca04.us.bb.gin.ntt.net               2.018ms asymm  5
 5:  as-1.r21.osakjp01.jp.bb.gin.ntt.net                 168.074ms asymm 11
 6:  ae-0.ocn.osakjp01.jp.bb.gin.ntt.net                 167.792ms asymm 14
 7:  2001:380:8060:6::1                                  159.446ms asymm 13
 8:  2001:380:8170:4::1                                  167.630ms asymm 14
 9:  2001:380:8030:16::1                                 168.401ms asymm 15
10:  2001:380:8110:d::1                                  170.344ms asymm 14
11:  2001:380:8110:f::2                                  178.503ms asymm 13
12:  2001:380:8130:11::13                                178.131ms asymm 13
13:  2001:380:8270:8::2                                  172.448ms
14:  2001:380:4d:101::2                                  179.036ms
15:  2001:380:4d:182::2                                  181.317ms
16:  no reply
17:  2001:380:4d:181::2                                  173.127ms pmtu 1454
17:  senri.v6.gcd.org                                    183.023ms reached
     Resume: pmtu 1454 hops 17 back 49

日米間に 160ms もかかっている上に、 日本に上陸後 (5 以降) も 15ms ほど遅延がある。 なぜこんなに遅いのだろう? また、PPPoE なので mtu が 1454 になっている。

同じ OCN の PPPoE でも、 IPv4 だと遅くない (というか transix より若干速い) ので、 OCN の IPv6 PPPoE 接続サービスには、 なにか問題がありそう。 まあ、 追加料金無しのサービスなので、 IPv4 のオマケ的な位置づけなのかも?

fremont:~ $ tracepath 60.32.85.216
 1:  fremont.gcd.org                                       0.169ms pmtu 1500
 1:  184.105.143.85                                        1.702ms
 1:  184.105.143.85                                        0.418ms
 2:  10gigabitethernet2-3.core1.fmt1.he.net                0.665ms
 3:  10gigabitethernet1-1.core1.pao1.he.net                8.907ms
 4:  sjo-bb1-link.telia.net                                1.297ms asymm  5
 5:  verio-119529-sjo-bb1.telia.net                        4.568ms
 6:  ae-8.r20.snjsca04.us.bb.gin.ntt.net                   1.922ms
 7:  as-2.r20.tokyjp01.jp.bb.gin.ntt.net                 112.093ms asymm  8
 8:  ae-1.ocn.tokyjp01.jp.bb.gin.ntt.net                 119.692ms asymm 11
 9:  60.37.27.137                                        120.641ms asymm 10
10:  60.37.55.158                                        119.549ms asymm 11
11:  122.1.173.238                                       121.243ms
12:  118.23.5.78                                         128.853ms asymm 14
13:  no reply
14:  118.23.8.9                                          128.712ms pmtu 1454
14:  gcd.org                                             123.788ms reached
     Resume: pmtu 1454 hops 14 back 52
もっと読む...
Filed under: IPv6,システム構築・運用 — hiroaki_sengoku @ 18:33
2011年6月20日

フレッツ 光ネクストの IPv6 PPPoE 接続を OCN 光アクセスで使ってみた

6月1日から NTT東日本のフレッツ 光ネクストにおいて IPv6 PPPoE 接続の提供が始まった。 私は OCN光アクセスを契約しているが、 幸い OCN (NTTコミュニケーションズ) も、 NTT東日本に合わせて順次対応を開始ということなので、 さっそく OCN へ電話で問合わせてみたら、 申込書をメールで送るので記入押印の上 FAX で送り返して欲しい、とのこと。

いまどき Web で申し込めないなんて、 と思いつつ 8ページにもわたる申込書 (いつも感じるが OCN の申込書は無駄にページ数が多い *_*) を FAX で送付。 すると翌日電話がかかってきて、 開通日は 10日後などとおっしゃる。 それじゃ World IPv6 Day に間に合わないじゃんと思ったが、 どんな変更でも申込みから 7営業日は最低でもかかるらしいので仕方がない。 なお、 工事費および月額使用料は無料。

OCN には元々月額 315円の 「OCN IPv6」 というサービスがあるが、 OCN IPv6 はフレッツ網に PPPoE によるトンネルを張って IPv4 を通し (OCN フレッツ光)、 その IPv4 上に L2TP (Layer 2 Tunneling Protocol) によるトンネルを張って PPP セッションを通し、 その PPP 上に IPv6 を通すという屋上屋を架す方式だったのに対し、 6月1日から始まった 「IPv6インターネット接続」 はフレッツ網に PPPoE によるトンネルを張って IPv6 を通す方式。

つまり OCN フレッツ光の IPv4 の部分を IPv6 でそのまま置き換えたシンプルな方式。 もちろんフレッツ網に IPv6 を直接通す 「ネイティブ方式」 が一番シンプルだが、 ネイティブ方式に関しては 「平成23年7月を目途に提供を予定」 ということなので、 どのようなサービスが始まるのか今のところ不明 (もう来週には 7月が始まってしまうのだが)。 7/24追記: ネイティブ方式サービスが始まった!

開通日の 2日前に郵便で届いた 「ご利用内容のご案内」 の欄外の注釈に、

IPv6 でインターネットに接続する際、 認証ID の @ 右側を “@bizf.ocn.ne.jp” の場合は “@bizf6.ocn.ne.jp” に、 “@bizd.ocn.ne.jp” の場合は “@bizd6.ocn.ne.jp” に変更してご利用下さい。

と書いてあった。 IPv6 での接続に関する説明はこの部分だけなので、 あとは推測するしかない (サポートに接続方法を聞いても、 単に IPv6トンネル対応ルータを購入してくれと言われる)。

とりあえず、 ふだん IPv4 で接続するときに使ってる PPPoE スクリプト (RP-PPPoE) を、 認証ID を “xxxx@bizf.ocn.ne.jp” から “xxxx@bizf6.ocn.ne.jp” に変更して走らせてみる:

20:39:13 senri pppd[16587]: Plugin /etc/ppp/plugins/rp-pppoe.so loaded.
20:39:13 senri pppd[16587]: RP-PPPoE plugin version 3.10 compiled against pppd 2.4.5
20:39:13 senri pppd[16587]: pppd 2.4.5 started by root, uid 0
20:39:13 senri pppd[16587]: PPP session is 6394 (0x18fa)
20:39:13 senri pppd[16587]: Connected to 00:1e:13:c2:69:c2 via interface eth1
20:39:13 senri pppd[16587]: Using interface ppp0
20:39:13 senri pppd[16587]: Connect: ppp0 < --> eth1
20:39:13 senri pppd[16587]: Couldn't increase MTU to 1500
20:39:13 senri pppd[16587]: Couldn't increase MRU to 1500
20:39:13 senri pppd[16587]: PAP authentication succeeded
20:39:13 senri pppd[16587]: peer from calling number 00:1E:13:C2:69:C2 authorized
20:39:13 senri pppd[16587]: local  LL address fe80::fd61:ff9b:eb97:1f93
20:39:13 senri pppd[16587]: remote LL address fe80::0090:1a00:41a3:d3f3

PPP は 1 つ以上のネットワーク層プロトコルを選択できるので、 IPCP (IP Control Protocol) と IPv6CP (IPv6 Control Protocol) の両方が流れてくるのかと予想したのだが、 流れてきたのは IPv6CP のみだった。 つまり “@bizf.ocn.ne.jp” で IPv4 用、 “@bizf6.ocn.ne.jp” で IPv6 用、 計 2本の PPPoE セッションを張ることになる。

上記ログから分かる通り Link Local とはいえ IPv6 なアドレス fe80::fd61:ff9b:eb97:1f93 が割り振られたのだから、 IPv6 で通信できるはず。 試しに PPP の対向サーバへ ping を打ってみると、 ちゃんと応答が返ってきた:

senri:~ $ ping6 -c 3 fe80::0090:1a00:41a3:d3f3%ppp0
PING fe80::90:1a00:41a3:d3f3%ppp0 (fe80::90:1a00:41a3:d3f3%ppp0): 48 data bytes
56 bytes from fe80::90:1a00:41a3:d3f3%ppp0: icmp_seq=0 ttl=255 time=3.936 ms
56 bytes from fe80::90:1a00:41a3:d3f3%ppp0: icmp_seq=1 ttl=255 time=4.050 ms
56 bytes from fe80::90:1a00:41a3:d3f3%ppp0: icmp_seq=2 ttl=255 time=4.176 ms
--- fe80::0090:1a00:41a3:d3f3%ppp0 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 3.936/4.054/4.176/0.098 ms
senri:~ $ 

じゃ、 Global なアドレス (固定アドレス契約なのでプレフィックスが 「ご利用内容のご案内」 に書かれていた) を付けて routing 設定を行なえば Global に通信できそうと思い、 試してみると...

senri:/ # ifconfig eth0 add 2400:400d:100::1/56
senri:/ # ip -6 route add default via fe80::0090:1a00:41a3:d3f3 dev ppp0
senri:/ # ping6 www.kame.net
PING www.kame.net (2001:200:dff:fff1:216:3eff:feb1:44d7): 48 data bytes
^C--- www.kame.net ping statistics ---
15 packets transmitted, 0 packets received, 100% packet loss
senri:/ # 

う〜ん、ダメか。 tcpdump を使って ppp0 に届く IPv6 パケットを監視してみたが、 OCN へ送信したパケットのみが表示され、 OCN 側からは何のパケットも届かない。

しかも、 他のサイトから 2400:400d:100::1 に対して ping6 を打ってみても何も届かない。 仮にこちらの設定に何か間違いがあったとしても、 OCN 側で 2400:400d:100::1 宛のパケットを routing していれば、 パケット自体は流れてきそうな気がするのだが... 少なくとも IPv4 の場合なら、 こちらの IP アドレス設定が間違っていても、 受け取れないだけでパケット自体は流れてくる。

ひょっとして、 「ご利用内容のご案内」に書かれていた 「2400:400d:100::」 というプレフィックスが間違っているんじゃ? と、 途方に暮れる。

もっと読む...
Filed under: IPv6,システム構築・運用 — hiroaki_sengoku @ 09:08
2011年3月7日

Osukiniサーバを使ってみた 〜 仮想コンソールが提供されない VPS で独自OS をインストールする方法

今まで米国の VPS を使っていたが、 いつのまにか日本の VPS もリーズナブルな値段になってきたらしい。 「さくらのVPS」 がメモリ 512MB で月額 980円、 「Osukini サーバ」 ST プラン がメモリ 1GB, ディスク 100GB で月額 980円。 「さくらのVPS」 でも充分安いが、 「Osukini サーバ」 の安さは目を疑うレベル。 これはもう試してみるしかない。

実は、 最初は 「さくらのVPS」 を申し込んだのだが、 rootパスワードが見つからない事件でイカってキャンセルしてしまった。 申し込んだ直後に VPS が起動できたので、 さくら++ と思いつつ root でログインしようとしたらパスワードが分からず Web じゅう探しまわる羽目に。 万策尽きてサポートに電話したら 15分以上待たされ、 しかも担当者には root と言っても話が通じず、 別の番号にかけなおせと言われる始末。 後ほど届いた 「仮登録完了のお知らせ」 メールに root パスワードが書いてあったのだが、 メールが届く前に VPS のコントロールパネルをいじれて、 起動までできてしまう現在の仕様はいかがなものか。

Osukini サーバの場合 OS は CentOS, Ubuntu, Debian から選べるが、 「my distribution」 以外は使う気が起きないので、 どうやって私の 「独自OS」 をインストールするか、 方法を考えてみた。 もちろん、 Osukini サーバのサポートの範囲外なので、 インストールする方法だけでなく、 トラブった時の復旧方法を考えておくことが重要。

Osukini サーバでは 仮想コンソール (hvc console, リモートコンソール) が提供されない。 OS の外部から操作する手段がほとんどなく、 ブートスクリプトの設定ミスなどで OS にリモートログインできなくなってしまったら最後、 OS の再インストールしか復旧手段はない (と思う)。 しかも、 (サポートの範囲外である) 独自OS の再インストールを支援してもらえるはずはないので、 せっかくインストールした独自OS は跡形もなく消えてしまう。

再起動すれば復旧できる一時的な障害はここでは考えない。 設定ファイルなどを不適切な内容に書き換えてしまった結果、 再起動してもリモートログインできない状態が続くケースのみを考える。 実際、 サーバを運用しているとそういうトラブルはよくある。 ネットワーク設定を間違えて通信不能になるだけで、 他は全く正常でもリモートログインはできなくなるし、 あるいは sshd の設定を間違えて sshd が起動しなくなっただけでもリモートログインできなくなる。
ネットワークが全く使えなくても、 sshd が立ち上がらなくなってしまっても、 OS 自体が正常に起動していれば init から起動される getty は生きていることが多いので、 仮想コンソールさえ使えれば、 大抵はログインできて修復できる。

他の VPS, 例えば Linodeprgmr などでは、 仮想コンソールが利用できる。 さらに、 両者とも GRUB が使えるので、 複数 OS をインストールしておいて切り替えて使うこと (いわゆる 「デュアルブート」) ができる。 つまり一つの OS 上で何かトラブルが起きて OS が立ち上げ不能になっても、 別の OS (いわゆるレスキュー用 OS) を立ち上げて、 トラブった OS を修復することができる。

リアルサーバでは、 (仮想ではなく物理的な) コンソールが利用できる (当たり前)。 さらに、 トラブった時はレスキュー用の CD-ROM / USBメモリからブートして復旧作業を行なったりする。 VPS でもリアルサーバでも、 イザというときに備えて、 通常使う OS とは別に、 修復作業を行なうためのレスキュー用の OS を用意しておくことが極めて重要。

ところが、 レスキュー用 OS が一切利用できないばかりか、 仮想コンソールから操作することすらできないのが Osukiniサーバ。 トラブルに対して極めて脆弱であると言わざるを得ない。

Osukini Server Control Panel

VPS にとって仮想コンソールは必須の機能だと思っていたので、 Osukiniサーバのコントロールパネルを見て驚いた。 「再起動」 「停止」 などの操作と、 OS の初期化しかできない (値段相応? でも、 仮想コンソール機能は Xen 標準なのに...)。

OS の初期化をすれば、 全てが消えてしまう。 いわば、 クリーンインストールしかできない CD-ROM からブートするようなもの。 トラブったからといって、 即クリーンインストールしたいという人がどれだけいると言うのか?

嘆いていても仕方がないので、 どうやってレスキュー用 OS 相当のことを実現するか考えてみる。 レスキュー用 OS を立ち上げることさえできれば、 独自 OS をインストールすることも可能になる。 こんなこともあろうかと、 2年前 (2008年10月) に作っておいた ptyd (Pseudo TTY Daemon) が役に立ちそう。

もっと読む...
Filed under: システム構築・運用 — hiroaki_sengoku @ 08:36
2010年6月17日

Linode から prgmr.com へ乗り換えてみた

今年 2月から使っている Linode (VPS, 仮想サーバ) は、 月額 $19.95 の最小プラン Linode 360 だと RAM 360MB なので WordPress を動かす (Apache+PHP+MySQL) には若干足らない (稀に スラッシング 状態に陥って無反応になる)。 もちろん、 一つ上のプラン Linode 540 (RAM 540MB) にすればいいのであるが、 これだと月額 $29.95 でちょっと高い (私の感覚だと月額 $20 あたりに心理的な壁がある)。

prgmr.com ならば、 RAM 512MB, ディスク 12GB が月額 $12 (年一括払いなら $115.2) で済むので乗り換えてみた。 Linode のようなユーザフレンドリーな Web ユーザインタフェースは無いし、 時々新規申込みの受付を中止したりする (今も RAM 1024MB 以上のプランは受付けていない) が、 逆に言えば Web インタフェースが不要な人 (含む私) にとっては prgmr.com のシンプルさがむしろ望ましく、 レスキュー用のブートイメージなど必要最低限のものは揃っているので、 不便と感じることはない。 また、 いったん申込みが完了してしまえば受付の一時停止は関係ないわけで、 むしろサーバリソースに見合ったユーザ数しか受付けない姿勢は好感が持てる。

Web から Signup すると、 以下のようなメールが届く。

you ordered a xen vps, 512MiB ram, 12GiB Disk 80 GiB transfer Xen VPS,  $12/month username sengoku 

Before I can set you up, I need to know what distro you would like and an OpenSSH format public key (on a *NIX, run ssh-keygen  and send me either the id_dsa.pub or id_rsa.pub file in an attachment)    

on putty/windows, see

http://www.unixwiz.net/techtips/putty-openssh.html#keypair

and scroll down to the screen shot where it says 'openssh format public key for pasting into authorized_keys' - that is what I need.

thanks. 

OpenSSH の公開鍵くらい Web から登録させればいいのにと思いつつ、 「I need to know what distro you would like」 などと聞いてくるということは多少の融通は聞くのかと思い、 パーティションの切り方をついでにリクエストしてみた (6/4 15:46)。 つまり、 自分で作った Linux distro (配布していないから 「distribution」 と呼ぶのは正確性に欠けるのだが、 それなら何て呼んだらいいのだろう?) をインストールしたいから、 最小のパーティション (例えば 2GB) に ubuntu をインストールしておいてもらえるか? などとリクエストしてみた:

Hi,

At Fri, 04 Jun 2010 05:48:05 +0000,
support@prgmr.com wrote:

> Before I can set you up, I need to know what distro you would like and
> an OpenSSH format public key (on a *NIX, run ssh-keygen and send me
> either the id_dsa.pub or id_rsa.pub file in an attachment)

I'd like to use my own linux-based image that is running on
fremont.gcd.org (linode) now.  Is it possible to make two partitions
(plus swap partition) ?  One is for a normal ubuntu, and the other is
for my own image.  I'd like to switch these two OSs by pv-grub.

Please minimize the ubuntu partition in order to maximize my own image.
For example, 2GiB for ubuntu, 1GiB for swap, and 9GiB for me.

I've attached my public key id_dsa.pub at the end of this mail.


#9860.
http://www.gcd.org/sengoku/		Hiroaki Sengoku <sengoku@gcd.org>

すると、 4日後の 6/8 09:03 に返事が来た。 リクエストはあっさり無視されて、 ディスク一杯に ubuntu をインストールした状態の VPS が提供されただけ。 個別対応しないのであれば、 自動化したほうがいいような。

Your vps is setup now, your host server is whetstone.prgmr.com.
Login with your username and ssh key and follow the instructions
at http://book.xen.prgmr.com/mediawiki/index.php/Quickstart
For more information about repartitioning, see
http://book.xen.prgmr.com/mediawiki/index.php/Repartition
The default root password for the vps is password, and you
should receive a bill soon by email. If you have any questions
please email support@prgmr.com. Thanks very much.
Nick Schmalenberger

言われた通り ssh でログインしてみる:

senri:/home/sengoku % ssh whetstone.prgmr.com
The authenticity of host 'whetstone.prgmr.com (65.49.73.105)' can't be established.
RSA key fingerprint is 97:52:07:d4:52:8d:c0:cc:13:c7:fb:5d:5d:1b:ab:b4.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'whetstone.prgmr.com,65.49.73.105' (RSA) to the list
of known hosts.
Name                                        ID   Mem VCPUs      State   Time(s)
sengoku                                    xxx   512     1     -b----     11.5

Options for sengoku
1. console
2. create/start
3. shutdown
4. destroy/hard shutdown
5. reboot
6. swap i386/amd64 bootloaders (pvgrub)
7. exit
press the number> 

「6. swap i386/amd64 bootloaders (pvgrub)」 が目を引くが、 PV-GRUB は DomainU 側で実行されるので、 PV-GRUB にて 32bit/64bit の両方のカーネルを立ち上げることができず、 PV-GRUB を実行する前にどちらか一方に決めておく必要がある、 ということのようだ。 デフォルトは (残念なことに) 32bit になっていて、 セットアップしてもらった ubuntu も 32bit 版だった。

「1」 を入力して VPS のコンソールを表示させてみる:

press the number> 1

Ubuntu 10.04 LTS sengoku.xen.prgmr.com hvc0

sengoku.xen.prgmr.com login: root
Password:
Last login: Mon May 31 23:51:42 UTC 2010 on hvc0
Linux sengoku.xen.prgmr.com 2.6.32-22-generic-pae #33-Ubuntu SMP Wed Apr 28 14:57:29 UTC 2010 i686 GNU/Linux
Ubuntu 10.04 LTS

Welcome to Ubuntu!
 * Documentation:  https://help.ubuntu.com/
root@sengoku:~# df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/xvda1            11812024   1068124  10143876  10% /
none                    249488       136    249352   1% /dev
none                    253744         0    253744   0% /dev/shm
none                    253744        28    253716   1% /var/run
none                    253744         0    253744   0% /var/lock
none                    253744         0    253744   0% /lib/init/rw
none                  11812024   1068124  10143876  10% /var/lib/ureadahead/debugfs
root@sengoku:~# 

前掲のメールに書いてあった通り、 ユーザ 「root」 パスワード 「password」 でログインできた。 初めてログインしたのに 「Last login: Mon May 31 23:51:42 UTC 2010 on hvc0」 などと出ているが、 この ubuntu イメージを作ったとき試しに root でログインしたのが残ってしまったのだと思われる。 新規ユーザのセットアップのたびに、 5/31 に作ったイメージを使いまわしているのだろう。

ディスク 12GB のプランのはずなのに 1GB ほど足りないのは swap パーティションがあるから?と思い、 fdisk で確認してみる:

root@sengoku:~# fdisk -l /dev/xvda

Disk /dev/xvda: 12.8 GB, 12884901888 bytes
255 heads, 63 sectors/track, 1566 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

    Device Boot      Start         End      Blocks   Id  System
/dev/xvda1               1        1494    12000523+  83  Linux
root@sengoku:~# 

シリンダの最大値は 1566 なので、 72 (=1566-1494) シリンダが使われずに余っている。 試しにパーティションを割当ててみたら普通に使えた。

自前 distro 10GB, swap 1GB, ubuntu 1GB といった切り分けかたにするため、 レスキュー用のカーネル 「CentOS 5.5 rescue」 をブートしてみる:

    GNU GRUB  version 0.97  (65536K lower / 0K upper memory)

 +-------------------------------------------------------------------------+
 | user bootloader configuration                                           |  
 | CentOS 5.5 rescue (2.6.18-194.3.1.el5xen)                               |
 | CentOS 5.5 installer                                                    |
 | NetBSD 5.0.2 installer                                                  |
 | Ubuntu 10.04 LTS installer                                              |
 |                                                                         |
 |                                                                         |
 |                                                                         |
 |                                                                         |
 |                                                                         |
 |                                                                         |
 |                                                                         |  
 +-------------------------------------------------------------------------+
    Use the ^ and v keys to select which entry is highlighted.
    Press enter to boot the selected OS, 'e' to edit the
    commands before booting, or 'c' for a command-line.

二行目の 「CentOS 5.5 rescue (2.6.18-194.3.1.el5xen)」 を選択してブート。 root でログイン (パスワードは無し) して fdisk を使ってパーティションを切り直した。 せっかくセットアップしてもらった Ubuntu も、 3分と使わずにお別れ。

CentOS release 5.5 (Final)
Kernel 2.6.18-194.3.1.el5xen on an x86_64

sengoku.xen.prgmr.com login: root
[root@sengoku ~]# 
	...
[root@sengoku ~]# fdisk -l /dev/xvda

Disk /dev/xvda: 12.8 GB, 12884901888 bytes
255 heads, 63 sectors/track, 1566 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

    Device Boot      Start         End      Blocks   Id  System
/dev/xvda1               1        1306    10490413+  83  Linux
/dev/xvda2            1307        1438     1060290   82  Linux swap / Solaris
/dev/xvda3            1439        1566     1028160   83  Linux
[root@sengoku ~]# mount /dev/xvda1 /mnt
[root@sengoku ~]# 

私は個人で管理している Linux マシン (自宅と職場と VPS 合わせて十数台, もちろん商用サービスを行なっているサーバではない) のディスクの内容を、 コマンド一発で同一に保てるようにしている (つまりマスタで変更/追加/削除したファイルを各マシンへコピー/各マシンで削除)。

もちろん、 各マシンの性能や 32bit/64bit などの CPU 種別、 ディスクの容量に応じて違う部分もあるわけで、 この同期コマンドは同期先の各マシンに合わせてコピーしないファイルのリストを生成した上で rsync を実行している。 なので、 新しくマシンを増やすときもマスタ上で同期コマンドを実行するだけで、 インストールが完了するはずだが...

もっと読む...
Filed under: システム構築・運用 — hiroaki_sengoku @ 09:44
2010年4月20日

Linux サーバ同士をシリアルケーブルでつなぐには寡黙な getty が必要

私の自宅 LAN (GCD) の対外ルータである 2台の Linux サーバ (senriasao) は、 双方のシリアルポート (つまり DSUB9ピンの RS-232C) 同士がつながっている。 いまさら RS-232C ? と思う人が大半だと思うが、 最後の命綱としての安心感は測り知れない。

つまりサーバをリモートから (ネットワーク経由で ssh ログインして) いじっていると、 ちょっとしたミスで操作不能に陥ってしまうことがある。 例えば NIC を down してしまった、 iptables で DROP する設定にしてしまった、 sshd を殺してしまった、 等々。 あるいは、 リモートから再起動を行なう場合、 起動スクリプトのほんの些細な設定ミスで、 リモートからは操作不能になってしまう。

こんなとき、 2台のサーバのシリアルポート同士を RS-232C クロスケーブル (シリアルケーブル) で接続しておけば、 生きている方のサーバからシリアルケーブル経由でログインできて、 リモートからは操作不能に陥ったサーバのネットワーク設定を修復したり、 sshd を起動し直したり、 あるいは再起動の場合であれば、 GRUB を操作することができる (ML115 などであれば BIOS 設定までいじれる)。

職場のサーバ群は、 もちろん IPMI を利用していて大抵の操作は IPMI でできてしまうのでシリアルケーブルの出番はあまりないのだが、 それでもやはり最後の命綱がある安心感は何ものにも代えがたい。 しかも数百円のケーブル一本で済むのだから、 掛けておくべき保険だろう。

シリアルケーブル経由でサーバにログインするには、 そのサーバの /dev/ttyS0 (シリアルポート COM1 の場合) で getty を動かしておく必要がある。 例えば GCD の場合 mgetty を使っているので、 /etc/inittab に

# Dialin lines
s0:25:respawn:/usr/sbin/mgetty ttyS0

などと設定している。 シリアルケーブルでつながった 2台の Linux サーバ senri と asao において、 asao から senri へシリアルケーブル経由でアクセスすると、 senri のシリアルコンソールが表示される:

asao:/home/sengoku % cu ttyS0
Connected.

Welcome to Linux 2.6.31.13-x86_64.


senri.gcd.org!login: root
otp-md5 299 se5047 ext
Response or Password:
Last login: (null) on /dev/ttyS0

senri.gcd.org:/root # tty
/dev/ttyS0
senri.gcd.org:/root # 

たとえ senri のネットワーク機能が全滅していたとしても、 mgetty は /sbin/init から直接起動されるので影響を受けない。 シリアルコンソールから root でログインして復旧作業を行なうことができる。 逆に、 asao のネットワーク機能が全滅したときは、 senri へ ssh ログインした上で asao へシリアルケーブル経由でアクセスすればよい。 ネットワーク機能が麻痺する可能性があるような危険な作業を senri と asao の両方で同時に行なったりしないようにすれば、 何が起きてもどちらかは生きていることが保証できる。

さて、 両サーバで mgetty が動いているときは以上で問題無いのだが、 どちらかのサーバを再起動するときなど、 mgetty 以外のものが動くときは状況が変わってくる。

もっと読む...
Filed under: システム構築・運用 — hiroaki_sengoku @ 07:48
2010年2月25日

本ブログのサーバを海外レンタルサーバ Linode を使って冗長化・地域分散してみた

前回前々回に書いたように、 このブログ 「仙石浩明の日記」 (および 「仙石浩明CTO の日記」) は、 私の自宅にある PC サーバで動かしている。 2台の PC からなる冗長構成になっていて、 10年以上の安定稼働実績がある (両サーバ共に停止したことは皆無) が、 回線が (家庭用の) フレッツ光ネクストなので、 インターネットとの接続が切れてしまう可能性は皆無ではない。 実際、 Bフレッツからフレッツ光ネクストへ切り替えたときは 40分間ほど切れてしまった。 一応バックアップ回線として ADSL 回線も契約しているが、 こちらは固定 IP アドレスを割当てていないので WWW サービス用としては使いにくい。

短時間とはいえブログが見えないようなことがあると、 たまたまそのタイミングで (検索エンジン等で見つけて) 訪れた人が、 ブログが既に閉鎖してしまったものと勘違いしてしまうかもしれない。 ここは一つ自宅以外の場所にもサーバを立てて、 回線断の影響を受けないようにしたいところ。 海外のサーバなら地域分散もできてなおよい。

道楽で運営している自宅サーバにそこまで可用性を求めるのは、 やりすぎの感もあるが、 近頃流行りの VPS (Virtual Private Server, 仮想専有サーバ) は、 月額 $20 (初期費用無し) 程度で利用できるらしい。 $20 なら試しに使ってみるのも悪くない。

サービス
プラン名
メモリ
ディスク
帯域
追加額/単位
月額
年額
データセンタの
場所
ServerAxis Xen
VS000.5G-0025.0GP
512MB
25GB
0GB
$.05/GB
$15
$180
Chicago, IL
Linode
Xen 360
360MB
16GB
200GB
$10/100GB
$19.95
$215.46
Fremont, CA
Dallas, TX ...
VPSLink
Xen VPS Link-3
256MB
10GB
300GB
$.50/GB
$19.95
$201.12
Seattle, WA
New York, NY
slicehost
Xen VPS 256 slice
256MB
10GB
150GB
$.30/GB
$20
$216
Dallas, TX
St. Louis, MO

VPSLink 以外は最安のプランで比較した。 VPSLink には、 メモリ 64MB で月額 $7.95 の Link-1 プラン、 メモリ 128MB で月額 $13.95 の Link-2 プランもあるが、 256MB 未満のメモリではできることも限られてしまうので比較対象から外した。

月額基本料だけを比較すると、 ServerAxis が格安に見えるが、 これは帯域課金が含まれていないためで、 例えば 100GB (送受信の合計バイト数) 使うと $5 加算されて $20 と他社並になる。

データセンタの場所 (というかネットワーク上での位置) によって遅延時間が変わってくるので、 どこのデータセンタを使っているかも重要。 例えば同じ Linode でもデータセンタによって、 日本からアクセスしたときの RTT (Round Trip Time, 往復にかかる時間, ミリ秒) が倍以上変わってくる。 それぞれ 10回ずつ ping を打って、 RTT の最小/平均/最大を比較してみる:

データセンタの場所ホスト名 最小平均最大
Fremont, Californiafremont1.linode.com 121.341132.299146.939
Dallas, Texasdallas1.linode.com 171.049173.152174.905
Atlanta, Georgiaatlanta1.linode.com 183.184185.938190.174
Newark, New Jerseynewark1.linode.com 200.629203.053204.755
London, Englandlondon1.linode.com 269.324273.499276.822

米国西海岸だと RTT は 130msec 程度で済むが、 東海岸は 200msec を超えてしまい、 英国はもっと遠い。 西海岸にデータセンタがあるのは Linode と VPSLink だが、 Linode がデータセンタの情報を詳細に公開しているのに対し、 VPSLink は、 Spry Hosting のシアトルのデータセンタを使用している、 ということ以上の情報を公開していない (しかもこのページは 2006年8月の内容のまま) のが少し気になる。

サポートしている Linux ディストリビューションは、 各社だいたい共通で、 CentOS, Debian, Gentoo, Ubuntu の各バージョンが利用できるが、 VPSLink Ubuntu Plan のページに Ubuntu 9.10 Karmic が書かれていない点も、 ちょっと気になった (ちゃんとポリシーを持って 9.10 をサポートしないのならいいのだが、 どうもそうではなく単に運用の手を抜いているだけのような気配がする)。 Web 界隈での評判も Linode のほうがよさげだったので、 Linode を使ってみることに決めた。

サポートしているディストリビューションのバージョンが古くてもアップグレードできるのだろうが、 帯域で課金されるので最初から新しいバージョンをインストールできる方が好ましい。

サービス CentOSDebianGentooUbuntu Fedoraその他
ServerAxis 5.45.02008.09.10- Mandriva SUSE
Linode 5.35.02008.09.1011 Arch SUSE Slack
VPSLink 55O9.0411 Arch Slack
slicehost 5.45.02008.09.1012 Arch RedHat

おそらく各社ともカーネルも入れ替えることができるのだと思うが、 Linode 以外は使っていないので未確認。 Linode の場合は pv_ops (paravirtualization) を有効にしておけば任意のカーネルを利用できる。 したがって (帯域課金さえ気にしなければ ;-) 任意のディストリビューションの利用 (あるいは完全なカスタマイズ) が可能 (私はまだそこまではやっていない)。

なお、VPS サービスは探すといろいろあるようだ。 前述した 4社と比べると公開している情報が不十分 (特に Virtuozzo/OpenVZ な VPS は実際のパフォーマンスを予想しにくく、 実地に使ってみないとなんとも...) なので私は比較検討対象から外したが、 ダメ元で使ってみるのも面白いかもしれない:

サービス
プラン名
メモリ
ディスク
帯域
追加額/単位
月額
年額
データセンタの
場所
SplitServ
Xen 1024
1024MB
15GB
200GBs
$8/400GB
$14.95
$149.50
Los Angeles, CA
Kansas City, MO
WebKeepers
Virtuozzo ライト
512MB
50GB
?1280円
11760円
?
PhotonVPS
Xen VPS WARP 1
512MB
35GB
500GB
?
$16.95
$203.40
Los Angeles, CA
KnownHost
Virtuozzo VS2
512MB
30GB
750GB
$40/100GB
$35
$400
Los Angeles, CA
Dallas, TX
BurstNet
VPS PACKAGE #1
512MB
20GB
1000GB
$25/200GB
$5.95
$71.40
Scranton, PA
VPS NOC
OpenVZ Bronze
512 MB
20 GB
400 GB
?
$12.95
$155.40
Kansas City, MO
CoreNetworks
CoreMR
512MB
12GB
500GB
?
$19.95
$239.40
?
prgmr.com
Xen VPS
512MB
12GB
80GB
?
$12
$115.20
San Jose, CA
HostCadet
VPS Micro
512MB
10GB
400GB
?
$9.99
$119.88
Colorado Springs, CO
NY NOC OpenVZ
Super VPS #1
512MB
10GB
1000GB
?
$10.00
$120
Chicago, IL
North Bergen, NJ
ARP Networks
KVM/QEMU
512MB
10GB
100GB
?
$15
$180
Los Angeles, CA
VirtuallyDedicated
Xen VX384
384MB
24GB
300GB
?
$10.99
$131.88
Chicago, IL
Scranton, PA
GrokThis.net
Xen VPS
320MB
16GB
160GB
?
$20
$200
Philadelphia, PA
DMEHosting
OpenVZ VPS1
256MB
25GB
1000GB
$10/200GB
$5.95
$71.40
Denver, CO
Chicago, IL
Quantact
OpenVZ VS1
256MB
15GB
300GB
$1/GB
$14.99
$179.88
Santa Rosa, CA
RackspaceCloud
Xen CloudServers
256MB
10GB
0GB
$.08-$.22/GB
$10.95
$131.40
Dallas, TX
XENnode
XEN 256
256MB
10GB
200GB
?
$14.99
$143.99
Dallas, TX
Datarealm Xen
PowerVPS
256MB
10GB
1Mbps
Unmetered
$19.95
$215.52
?
HostVirtual Xen
XV0 Server
256MB
10GB
250GB
?
$14.95
$179.40
San Jose, CA
RackUnlimited
Xen RVPS-Starter
256MB
10GB
100GB
?
$8
$96
Asheville, NC
QuickWeb
Xen Lite
256MB
5GB
240GB
?
$17.95
$215.40
San Jose, CA
QuickVPS
Xen プラン1
256MB
10GB
50GB
?
2300円
21600円
日本国内
QuillHost
OpenVZ Standard
256MB
8GB
150GB
?
$9.99
$119.88
Washington, DC
Charlotte, NC

と、いうわけで、 Linode 360 を契約してみた。

もっと読む...
Filed under: システム構築・運用 — hiroaki_sengoku @ 08:58
2010年2月10日

CTO日記も livedoorブログから WordPress へ引越しました (URL は変更なし)

「仙石浩明の日記」 に続いて、 「仙石浩明CTO の日記」 も先週末に livedoorブログから自宅サーバへ引っ越した (つまりネームサーバの設定を変更して切替。有料プランの解約はこれから)。 もともと両ブログは相互にリンクを張って密接に連係していたので、 引越を機会に両者を統合した。

統合といっても両ブログは微妙(?)に読者層が異なると思われるし、 何よりページの体裁が大きく変わってしまっては読者の方々を戸惑わせてしまうので、 CTO日記を 「仙石浩明の日記」 の一カテゴリという位置付けにして、 かつページの体裁は WordPress のテーマを切り替えることによって、 どちらのブログもあまり大きな変化がないようにしている。

「仙石浩明CTO の日記」 http://sengoku.blog.klab.org/ をアクセスすると、 次のような PHP スクリプトを走らせた上で、 WordPress を呼び出す (末尾の require 文):

<?php
$new = NULL;
if ($_SERVER['REQUEST_URI'] == "/") {
    $new = "/blog/category/cto/";
} elseif ($_SERVER['REQUEST_URI'] == "/feed/") {
    $new = "/blog/category/cto/feed/";
} elseif (preg_match('@^/\d+/\d+/\d+/@',
		     $_SERVER['REQUEST_URI'], $matches)) {
    $new = $_SERVER['REQUEST_URI'];
...(中略)...
}
if ($new) {
    ...(中略)...
    $ORIG_SERVER_NAME = $_SERVER['SERVER_NAME'];
    $host = "www.gcd.org";
    $_SERVER['SERVER_NAME'] = $host;
    $_SERVER['REQUEST_URI'] = $new;
    $_SERVER['SCRIPT_NAME'] = $new;
    $_SERVER['PHP_SELF'] = $new;
    $abspath = "/usr/local/www/wordpress/";
    $themepath = "${abspath}wp-content/themes/sengoku_cto/";
    define('WP_USE_THEMES', true);
    define('TEMPLATEPATH', $themepath);
    define('STYLESHEETPATH', $themepath);
    require("${abspath}wp-blog-header.php");
...(中略)...
}
?>

つまり http://sengoku.blog.klab.org/ へのアクセスは、 パス名に 「/category/cto/」 を追加することによって、 CTO日記カテゴリへのアクセスに変換する。

ページの体裁については、 「wp-content/themes/sengoku_cto/」 ディレクトリが、 CTO日記のテーマフォルダで、 二つの PHP 定数 TEMPLATEPATH と STYLESHEETPATH をこのディレクトリへ設定することによって、 テーマの切り替えを行なっている。

テーマフォルダの中にあるテーマ関数ファイル 「functions.php」 は、 WordPress の初期化中に読み込まれるので、 ここに PHP スクリプトを書いておくことによって WordPress の挙動を変更することができる。 例えばブログのタイトルを 「仙石浩明CTO の日記」 に変更するには、 以下のスクリプトを functions.php に追加しておけばよい:

function option_blogname_cto() {
    return '仙石浩明CTO の日記';
}
add_filter('pre_option_blogname', 'option_blogname_cto');

つまり、 pre_option_blogname フックに、 option_blogname_cto フィルタを登録する。

WordPress では、 ブログのタイトルなど各種オプションの設定値 (DB に格納している) を、 get_option($setting) 関数を呼び出すことで参照している。 例えばタイトルは get_option('blogname') を呼び出すことで得られ、 URL は get_option('home') で得られる。

get_option($setting) 関数は wp-includes/functions.php で定義されていて、 以下のようにフィルタフック pre_option_* が定義されている:

function get_option( $setting, $default = false ) {
    global $wpdb;

    // Allow plugins to short-circuit options.
    $pre = apply_filters('pre_option_' . $setting, false);
    if ( false !== $pre )
	return $pre;
    ...(中略)...
}

つまり、 「pre_option_設定名」 というフックに登録されたフィルタが値を返すなら、 get_option はオプションの設定値ではなくフィルタが返した値を返すようになる。 前述の例なら、 「pre_option_blogname」 フックに登録された 「option_blogname_cto」 フィルタが 「仙石浩明CTO の日記」 という値を返すので、 get_option('blogname') も 「仙石浩明CTO の日記」 という値を返すようになり、 結果としてブログのタイトルを変更できる、というわけ。

ただし、 前述したように CTO日記は 「仙石浩明の日記」 の一カテゴリという位置付けなので、 ブログのタイトルを変更しただけだと、 ブログ 「仙石浩明CTO の日記」 の 「仙石浩明CTO の日記」 カテゴリということで、 ページのタイトル等が 「仙石浩明CTO の日記 » 仙石浩明CTO の日記」 という冗長なものになってしまう。 そこで、 以下のようなスクリプトを 「functions.php」 に追加して、 タイトルとカテゴリ名が同じときはカテゴリ名が表示されないようにする:

function single_cat_title_cto($category_name) {
    $name = get_option('blogname');
    if ($category_name == $name) return "";
    return $category_name;
}
add_filter('single_cat_title', 'single_cat_title_cto');

single_cat_title フックは、 wp-includes/general-template.php で定義されていて、 ページのタイトルなどに表示されるカテゴリ名を変更することができる。

以上で、 「仙石浩明の日記」 の一カテゴリを 「仙石浩明CTO の日記」 の体裁で見せることができるようになる。 しかし、 元が 「仙石浩明の日記」 であるだけに、 リンク先が全て 「仙石浩明の日記」 のページになってしまう。 例えば、 「仙石浩明CTO の日記」 のトップページの一番下に、 「古い投稿 »」 というリンクがあるが、 このリンク先が http://www.gcd.org/blog/page/2/ になってしまい、 たどると 「仙石浩明の日記」 のトップページの 2ページ目へ遷移してしまう。

また、 本文中 (あるいはサイドバー) に現れるリンクも、 DB のデータは 「仙石浩明の日記」 のパーマリンクを用いているので、 たとえそれが 「仙石浩明CTO の日記」 カテゴリに含まれていても、 そのリンクをたどると 「仙石浩明の日記」 の記事として表示されてしまう。

そこで、 遷移先も 「仙石浩明CTO の日記」 として表示したいリンクを、 フィルタで書き換えることにした。 つまり DB のデータは 「仙石浩明の日記」 へのリンクのままで、 ブラウザに送信する前に都度書き換える。

対象となるリンクは、 記事本文中だけでなく、 前述したページナビ 「古い投稿」 「新しい投稿」 や、 サイドバー (「人気記事」 や 「最近の投稿」) にも現れる。 ページ丸ごと (つまり HTTP レスポンス丸ごと) HTML を書き換えられるフックがあるとよかったのだが、 残念ながらそういうフックは定義されていないようだ。 以下のフックそれぞれについてリンクを書き換えればよさげ:

フィルタフック フィルタが変更できる対象, 第2引数, ...
the_content 記事本文 HTML
the_category 記事の末尾に表示されるカテゴリーリストの HTML,
$separator, $parents
get_pagenum_link ページ末尾に表示されるページナビ 「古い投稿」 「新しい投稿」 の URL
post_link 記事の URL (パーマリンク), $post, $leavename
widget_text サイドバーに表示されるテキストウィジェットの HTML, $instance
wp_list_categories サイドバーに表示されるカテゴリーのリストの HTML
category_feed_link カテゴリーの RSSフィードの URL, $feed

書き換え対象のリンクを決めるために、 まず CTO日記カテゴリに属す記事の ID を取得する:

function setup_cto_id() {
    global $wpdb;
    global $is_cto_id;
    $result = $wpdb->get_results("SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id=17", ARRAY_N);
    foreach ($result as $row) {
	$is_cto_id[$row[0]] = 1;
    }
}

あるカテゴリに属す記事ID のデータを取得する関数など、 WordPress に含まれているんじゃないかと探してみたのだが、 見つからなかったので DB に問合わせて取得するようにしてみた。 毎回 DB アクセスが発生してしまうが、 キャッシュとかはアクセス数が増えてから考える (^^;)。 「term_taxonomy_id=17」 が CTO日記のカテゴリ (決め打ち ^^;)。 CTO日記カテゴリに属す記事は、 配列 $is_cto_id[記事ID] に 1 を代入しておく。

次に URL を書き換えるスクリプト:

function replace_URL_cto($matches) {
    global $is_cto_id;
    global $ORIG_SERVER_NAME;
    if (!is_array($is_cto_id)) {
	setup_cto_id();
    }
    if (is_null($matches[2])) {
	if ($matches[1] == "category/cto/") return "http://$ORIG_SERVER_NAME/";
	return "http://$ORIG_SERVER_NAME/$matches[1]";
    } elseif ($is_cto_id[$matches[2]]) {
	return "http://$ORIG_SERVER_NAME/$matches[1]";
    }
    return $matches[0];
}

function convert_URLs_cto($text) {
    $textarr = preg_split("/(<.*>)/U", $text, -1, PREG_SPLIT_DELIM_CAPTURE);
    $stop = count($textarr);
    for ($i = 0; $i < $stop; $i++) {
	$content = $textarr[$i];
	if (strlen($content) > 0) {
	    $content = preg_replace_callback(
		    '@http://www.gcd.org/blog/(\d+/\d+/(\d+)|category/cto/)@',
		    'replace_URL_cto', $content);
	}
	$output .= $content;
    }
    return $output;
}

顔文字を画像に変換して表示するフィルタ wptexturize (wp-includes/formatting.php で定義されている) を参考にさせてもらった。 preg_replace_callback() を使って書き換え対象リンクを探し、 replace_URL_cto で記事ID がCTO日記カテゴリに属す ($is_cto_id[$matches[2]] が TRUE) 場合のみ書き換える。

最後に、 この書き換えフィルタ replace_URL_cto を前述したフィルタフックに追加:

add_filter('the_content', 'convert_URLs_cto');
add_filter('the_category', 'convert_URLs_cto');
add_filter('get_pagenum_link', 'convert_URLs_cto');
add_filter('post_link', 'convert_URLs_cto');
add_filter('widget_text', 'convert_URLs_cto');
add_filter('wp_list_categories', 'convert_URLs_cto', 12000);
add_filter('category_feed_link', 'convert_URLs_cto');

wp_list_categories にフィルタを追加すると Category Order プラグインと衝突するので、 優先順位を下げて Category Order プラグインの後で実行されるようにしている。

また、 the_category, post_link, widget_text, category_feed_link 各フックは、 2つ以上の引数を持つが、 第1引数 (書き換え対象の HTML あるいは URL) のみ使用するので引数の数 (add_filter の第3引数) を省略している。

Filed under: システム構築・運用,プログラミングと開発環境 — hiroaki_sengoku @ 07:46
2010年1月28日

本ブログを livedoorブログから WordPress へ引越しました (URL は変更なし)

このブログ 「仙石浩明の日記」 は、 今まで livedoorブログの有料プラン (月額 315円) を利用していた。 比較的自由にデザインをカスタマイズできること、 URL のドメインを自由に設定できることから、 2006年3月9日にこのブログを開設して以来、 今まで 4年近く使い続けてきた。 しかし自前サーバでない不便さ、隔靴掻痒感はいかんともしがたく、 乗り換えを検討したことは何度もあって、 そのたびに不便さと乗り換えの面倒くささを天秤にかけて踏み切れずにいた。

例えば、 HTML文法エラーを修正できない問題点を見つけたときや、 ブログのサイドバーにある 「livedoor Reader」 「RSS」 「livedoor Blog」などのバナーを非表示にしていたら、 ライブドアから警告メールが来て、 やむなくバナー表示を復活させたときなど。 なかでも、 昨年ブログ管理画面 (有料プラン) がリニューアルされたときは、 とても大きなフラストレーションを感じた。 ライブドアはよかれと思ってリニューアルしているのだろうが、 JavaScript を多用した新管理画面は、 私にとっては使いにくいことこのうえないし、 生ログ取得スクリプトも使えなくなった。

そして、 今年に入って 「ブログ共通ヘッダー」 (最上端に表示される livedoor Blogのロゴ, 所属カテゴリ, テキスト広告) が勝手に表示されるようになったのが最後の背中のひと押しとなった。 これを非表示にしたければ PRO プラン (月額 315円) ではなく ADVANCE プラン (月額 840円) に変更しろという趣旨 (要は値上げ) なのだと思うが、 何の連絡もなく画面の一番目立つ最上端に、 醜悪なヘッダー (ADVANCE プランへの移行を促すためにわざと醜悪にしている? *_*) を勝手に挿入するデリカシーの無さに驚き呆れ、 自前サーバへの引越を決めた。

common header

ブラウザ画面最上端 ↑ の 「ブログ共通ヘッダー」 (所属カテゴリ 「IT > プログラミング 」 と 「受験にまつわるエピソードを教えてください」 という広告? 表示) は、 ライブドアのサーバが HTML 中に自動挿入する以下の JavaScript (settings/header.js) によって body 要素へ追加 (appendChild) されている。

(function () {
    var hd = document.createElement('div');
    var str = '';
    str += '<div id="header2" style="z-index:10001"><table cellspacing="0" class="blog-common-header" id="header">';
	...(中略)...
    hd.innerHTML = str;
    document.body.appendChild(hd);
	...(後略)...

ユーザがカスタマイズ可能な範囲の外であるため、 この JavaScript の実行そのものを止めることは無理っぽいが、 追加された子要素を削除する JavaScript を実行して消すことは可能。 例えば以下のようなコードを HTML ファイルのどこかに入れておけばよい。

<script type="text/javascript" src="http://www.gcd.org/sengoku/docs/livedoor.js"></script>

livedoor.js は、 body 要素の子要素 「header2」 を取り除く (removeChild) だけの JavaScript:

(function () {
    var element = document.getElementById("header2");
    element.removeChild(element.childNodes.item(0));
})();

正月早々 「ブログ共通ヘッダー」 が勝手に表示されるようになったことに気付き、 直ちにこの対策を行なって非表示にしたのだが、 以前バナーを非表示にしたときライブドアから警告メールが来たことを考えれば、 今回も警告メールが来るのは時間の問題だろうと、 引越を急いだ次第。

私はブログを書くときも HTML で書いていて、 あまり CMS 的な機能は必要としないので、 トラックバックとコメントを受付けるだけの簡単な Web アプリを書こうと思っていたのだが、 試しにインストールしてみた WordPress が思いの外シンプルな作りで、 ちょっといじっているうちに簡単にカスタマイズできてしまったので、 これを使うことにした。

livedoorブログでエクスポートしたデータを (Movable Type / TypePad のデータとして) WordPress でインポートしたら、 (pre 要素なのに) 行頭の空白文字が削除されてしまって往生したが、 大した量でもなかったので手作業で修正してしまった。 もう少し量が多かったら真面目に PHP コードを追ったのだが...

こんなに簡単にできるなら、 もっと早く WordPress へ移行すればよかった。 既存のテーマを見よう見まねでいじっただけなのだが、 以前のデザインをほとんどそのまま踏襲することができた (むしろ余計な div 要素を排除できたので、よりシンプルになった)。

livedoorブログと WordPress では URL (パーマリンク, permalink) の形式が異なる。 例えば、 あるエントリの URL は、 livedoorブログ (旧URL) と WordPress (新URL) で次のようになる:

旧: livedoorブログ新: WordPress
ベースURL http://blog.gcd.org http://www.gcd.org/blog
エントリ /archives/51168556.html /2008/04/154/
月別表示 /archives/2008-04.html /2008/04/
カテゴリ /archives/cat_50026701.html /category/enlighten/
RSS /index.rdf /feed/rdf/

一見して、 WordPress のパーマリンクの方が分かりやすい。 正確に言えば、 WordPress のパーマリンクの形式は任意に設定できて、 livedoorブログ (Movable Type ベース) の形式に合わせることも可能だが、 エントリID (上記の例だと 51168556 と 154) が異なるので形式を合わせること自体にはあまり意味はない。

livedoorブログを利用していた時の URL がそのまま使えるように、 旧URL を新URL へ変換する以下の PHP スクリプトを書いた (switch 文で URL ごとにずらずら case を並べただけ)。

<?php
$new = NULL;
if ($_SERVER['REQUEST_URI'] == "/") {
    $new = "/blog/";
} elseif ($_SERVER['REQUEST_URI'] == "/atom.xml") {
    $new = "/blog/feed/atom/";
} elseif ($_SERVER['REQUEST_URI'] == "/index.rdf") {
    $new = "/blog/feed/rdf/";
} elseif (preg_match('/^\/archives\/(20\d\d)-(\d\d)\.html$/',
		     $_SERVER['REQUEST_URI'], $matches)) {
    $year = $matches[1];
    $mon = $matches[2];
    $new = "/blog/$year/$mon/";
} elseif (preg_match('/^\/archives\/cat_(\d+)\.html$/',
		     $_SERVER['REQUEST_URI'], $matches)) {
    $id = $matches[1];
    $new = "/blog/category/";
    switch ($id) {
    case 50026701: $new .= "enlighten/";   break;
    case 50026704: $new .= "business/";    break;
    case 50026703: $new .= "engineer/";    break;
    case 50026699: $new .= "system/";      break;
    case 50035671: $new .= "hardware/";    break;
    case 50026700: $new .= "programming/"; break;
    case 50021362: $new .= "stone/";       break;
    case 50035209: $new .= "la-fonera/";   break;
    case 50041534: $new .= "hawaii/";      break;
    case 50045637: $new .= "hongkong/";    break;
    case 50026702: $new .= "others/";      break;
    default: $new = NULL;
    }
} elseif (preg_match('/^\/archives\/(\d+)\.html$/',
		     $_SERVER['REQUEST_URI'], $matches)) {
    $id = $matches[1];
    $new = "/blog/";
    switch ($id) {
    case 50071073: $new .= "2006/03/8/"; break;
	...(中略)...
    case 51168556: $new .= "2008/04/154/"; break;
	...(中略)...
    case 51552583: $new .= "2009/12/184/"; break;
    case 51555097: $new .= "2010/01/185/"; break;
    default: $new = NULL;
    }
}
if ($new) {
    $host = "www.gcd.org";
    $_SERVER['SERVER_NAME'] = $host;
    $_SERVER['REQUEST_URI'] = $new;
    $_SERVER['SCRIPT_NAME'] = $new;
    $_SERVER['PHP_SELF'] = $new;
    define('WP_USE_THEMES', true);
    require('/usr/local/www/wordpress/wp-blog-header.php');
} else {
    header("HTTP/1.1 301 Moved Permanently");
    header("Location: http://www.gcd.org/blog/");
    exit();
}
?>

http://blog.gcd.org/* にアクセスすると、 ↑ この PHP スクリプトが実行される。

これに加え、 逆方向の変換、 つまり新URL から旧URL への変換も必要。 例えば 「はてなブックマーク」 へ頂いたコメント (例えば前述したエントリに対するコメント一覧) は旧URL に紐づいているので、 各エントリに旧URL を登録しておく必要がある。 WordPress には カスタムフィールド という機能があって、ひとつのエントリに複数の 「キー」 と、 各キーにその値を登録することができる。 そこで沢山の 「ブックマーク」 を頂いたエントリには、 「hatena_b」 というキーで旧URL を登録しておくことにした。 すると、以下のような PHP スクリプトでブックマーク数 を表示できる。

<?php
  $hatena_b = get_post_meta($post->ID, "hatena_b", true);
  if ($hatena_b)
    echo ' <a href="http://b.hatena.ne.jp/entry/' . $hatena_b
       . '"><img style="border:0;" src="http://b.hatena.ne.jp/entry/image/'
       . $hatena_b . '" alt="" /></a>';
?>

最後に、 ネームサーバの設定変更を行なって、 blog.gcd.org レコード (TTL = 3時間) の値を 「CNAME blog-01.livedoor.jp」 から 「CNAME www.gcd.org」 へ変更した。 1/26 19:35 に変更を行なったところ、 19:46 には最初のアクセスが www.gcd.org へ届き、 20時台には大半のアクセスが www.gcd.org へ届くようになった。 20時台にライブドア側へ届いた blog.gcd.org へのアクセスはわずかに 7件、 その後は 1 時間〜数時間ごとに、ぱらぱらアクセスがあるという状況が続いている。 旧レコードを保持しているキャッシュネームサーバが残っていて、 そのネームサーバを使ってるブラウザからのアクセスのみが、 ライブドア側へ届いているといった感じ。

もっと読む...
Filed under: システム構築・運用 — hiroaki_sengoku @ 08:26
2009年11月12日

自宅回線を 100Mbps から 200Mbps へ、帯域を倍にしてみた ~ NGN が自宅にやってきた

私の自宅がある神奈川でも、 先月 13日から 「フレッツ 光ネクスト ファミリー・ハイスピードタイプ」 の申込受付が始まったので、 早速申し込んでみた。 今まで使っていたのは 「Bフレッツ ニューファミリータイプ」 だから、 下りの帯域が 100Mbps から倍の 200Mbps に増える。 月額利用料は変わらない。 工事費が 5827円かかるが、 キャンペーン期間中につき月額料金が 3ヶ月間無料になるので悪くない。

10/16日に NTT東日本 0120-116116 に電話して申し込んだところ、 回線切替工事まで最短で 10営業日かかり、 工事の予約状況によると最速で 11/1(日) の工事になるらしい。 続いて NTT コミュニケーションズ 0120-506-506 に電話して、 200Mbps に変更したときプロバイダ (OCN) 側の変更が必要か確認。 個人向けサービス (OCN 光 with フレッツ) は元々 200Mbps に対応しているから契約変更は必要無しとのことだったが、 あいにく私が契約しているのは法人向けサービスであるところの OCN 光アクセス IP8/IP16「Bフレッツ」プラン である。 この場合、 OCN 光アクセス IP8/IP16「フレッツ 光ネクスト」プラン への契約変更が必要となる。

NTT コミュニケーションズの担当者の話によると、 認証サーバの設定を変更するらしい。 PPPoE のユーザ名とパスワードはそのまま同じものを使っていい (新しいユーザ名も付与されるので新旧どちらのユーザ名も使える) が、 認証サーバ側の設定を変更すると旧回線 (つまり Bフレッツ) からの認証は拒否されるらしい。 すなわち認証サーバの設定変更後は、 新回線 (つまり フレッツ 光ネクスト) からでないと認証が通らない。 したがって、 回線が切り替わる前に PPPoE セッションが切れると、 旧回線のままでは再接続できなくなってしまう。 さらに、 設定変更は平日の未明 0:00 ~ 5:00 の間にしか実施しないらしい。

ということはつまり、 11/1(日) に回線工事を行なうには、 10/30(金) の未明に認証サーバの設定変更を行なうことになる。 10/30 未明から 11/1 の回線工事まで丸二日間、 もし PPPoE セッションが何らかの原因によって切れてしまうと、 工事完了後まで二度と再接続できなくなる。 最長丸二日間切れたままというのはあまりに不便なので、 11/2(月) の未明に認証サーバの設定変更を行ない、 同日午前 9:00-12:00 に回線切替工事を行なうことにした。 これなら PPPoE セッションが切れても数時間の切断で済む。

もっと読む...
Filed under: IPv6,システム構築・運用 — hiroaki_sengoku @ 10:00
2009年10月8日

__sync_bool_compare_and_swap_4 とは何か? ~ glibc をビルドする場合は、 gcc の –with-arch=i686 configure オプションを使ってはいけない

glibc-2.10.1 をビルドしようとしたら、 「__sync_bool_compare_and_swap_4 が定義されていない」 というエラーが出た:

senri:/usr/local/src/glibc-2.10.1.i386 % ../glibc-2.10.1/configure
	...
senri:/usr/local/src/glibc-2.10.1.i386 % make
	...
/usr/local/src/glibc-2.10.1.i386/libc_pic.os: In function `__libc_fork':
/usr/local/src/glibc-2.10.1/posix/../nptl/sysdeps/unix/sysv/linux/i386/../fork.c:79: undefined reference to `__sync_bool_compare_and_swap_4'
/usr/local/src/glibc-2.10.1.i386/libc_pic.os: In function `__nscd_drop_map_ref':
/usr/local/src/glibc-2.10.1/nscd/nscd-client.h:320: undefined reference to `__sync_fetch_and_add_4'
	...
/usr/local/src/glibc-2.10.1.i386/libc_pic.os: In function `*__GI___libc_freeres':
/usr/local/src/glibc-2.10.1/malloc/set-freeres.c:39: undefined reference to `__sync_bool_compare_and_swap_4'
collect2: ld returned 1 exit status
make[1]: *** [/usr/local/src/glibc-2.10.1.i386/libc.so] Error 1
make[1]: Leaving directory `/usr/local/src/glibc-2.10.1'
make: *** [all] Error 2

__sync_bool_compare_and_swap_4 は gcc の組み込み関数なので、 関数が未定義であることを示す 「undefined reference to ...」 というエラーメッセージは、 誤解を招く不親切なメッセージだと思う。

__sync_bool_compare_and_swap_4(mem, oldval, newval) は、 mem が指し示すメモリの値 (4バイト分) が oldval であれば newval に変更する、 という操作をアトミックに行なう組み込み関数。 アトミック (不可分) 操作とは、 操作の途中が存在してはいけない操作のことで、 この例なら比較 (メモリの値が oldval か?) と代入 (newval に変更) が必ず 「いっぺん」 に行なわれ、 「比較だけ行なったけどまだ代入は行なわれていない」 という状態が存在しないことを意味する。

アトミックに行なうためには、 当然ながら CPU でその操作をサポートしている必要がある (複数個の命令の列で実現しようとすると、 命令列の半ばを実行中の状態が必ず存在してしまう) わけだが、 残念ながら Intel 386 プロセッサでは、 この compare_and_swap (CMPXCHG 命令) をサポートしておらず、 サポートするのは Intel 486 以降の CPU である。 テストプログラムを書いて試してみる:

#include <stdio.h>

int main() {
    int mem[1], oldval, newval;
    oldval=0;
    newval=1;
    mem[0] = 0;
    __sync_bool_compare_and_swap(mem, oldval, newval);
    printf("mem[0]=%d\n", mem[0]);
    return 0;
}

見ての通り、 mem[0] の値を oldval の値 (0) と比較し、 一致していたら newval の値 (1) を代入し、 mem[0] の値を表示するだけのプログラムである。

関数名が 「__sync_bool_compare_and_swap」 であって、 後ろに 「_4」 がついていないことに注意。 gcc が引数の型 (この例では int) を見て、 その型のビット長を後ろにつけてくれる (この例では int 型は 4 バイトなので 「_4」 をつけてくれる)。

gcc では 「-march=タイプ」 オプションを指定することによって CPU タイプを指定できる。 -march オプションを指定しなかったり (この場合は全 CPU でサポートされる組み込み関数のみ利用できる)、 あるいは -march=i386 を指定したりすると、 コンパイル時にエラーになる:

% gcc -Wall test.c
/tmp/cc4eNX6L.o: In function `main':
test.c:(.text+0x3b): undefined reference to `__sync_bool_compare_and_swap_4'
collect2: ld returned 1 exit status
% gcc -Wall -march=i386 test.c
/tmp/cc6chtFj.o: In function `main':
test.c:(.text+0x36): undefined reference to `__sync_bool_compare_and_swap_4'
collect2: ld returned 1 exit status
% gcc -Wall -march=i486 test.c
% ./a.out
mem[0]=1

いまさら i486 というのもアレなので、 今なら i686 を指定するのがよさげ。 私の手元にはいまだ PentiumIII マシンがあるものの、 PentiumIII より古いマシンはない (昨年 ML115 と SC440 を買ったとき PentiumII マシンを引退させた) ので、 pentium3 を指定すれば SSE (Streaming SIMD Extensions) が利用できるようになるが、 glibc をビルドするときに必要かというと、 たぶん必要ない。

というわけでエラーの原因は分かったが、 では glibc をビルドするときは、 どうすればいいだろうか?

とりあえず google で検索してみたら、 gcc の configure オプションに 「--with-arch=i686」 を指定して gcc をビルドする必要がある、 と書いてあるページが見つかった。

--with-arch オプションは、 -march のデフォルトを設定するための configure オプションである。 つまり 「--with-arch=i686」 を指定して gcc を再インストールすると、 gcc に -march オプションをつけなくてもデフォルトが i686 になる。 なるほど確かにそうすれば、 glibc 側で何も変更せずに __sync_bool_compare_and_swap_4 関数が使えるようになりそうである。

いまどき i686 以前の CPU 用のコードが必要になりそうなケースは滅多にないだろうから、 -march オプションのデフォルトを i686 にするのも悪い選択ではないように思えた。 gcc をビルドし直すのは面倒だなーと思いつつも、 ついでに gcc のバージョンを上げておこうと gcc-4.3.4 をダウンロードしてきて 「--with-arch=i686」 付でビルドしてみた。

ところが!

もっと読む...
Filed under: システム構築・運用,プログラミングと開発環境 — hiroaki_sengoku @ 09:39
Older Posts »