2007年11月アーカイブ

LDAPのデータをコマンドラインで扱うのは結構きつい。Linuxで使いやすいGUIクライアントがないかと探していたら、LAT(LDAP Administration Tool)というものが見つかった。Fedora8からやyum install latでインストールできる。

いまいち動きはもっさりしているが、とりあえずは使えそう。こうやってGUIで見てみないとディレクトリの全体像はわからないなぁ。

一般的にWebサイト内には随所に公開したくない管理用やプライベートなページがある。Apacheではそのために設定ファイルのDirectoryディレクティブや各公開ディレクトリの.htaccessファイルでIPアドレスによるフィルタやBasic認証の設定が出来る。Basic認証は通常はApache独自のパスワードを管理するが、これをLDAPを参照するようにしたい。

PPGの3回目。先週初飛行したのでモチベーションが高い。天気もよく気持ちがいい。

しかし風が悪いのか、立ち上げの成功率が今ひとつ。というか成功率50%そこそこになってしまった。横にずれたときのリカバリができず、落としてしまう。たとえば風向が左にずれてキャノピーが右側に傾いたとき、どちらの手を引けばいいのか?どちらに走ればいいのか?

飛行機が横風で着陸する時からの考察では、機首をすこし風上に向ける。その場合風上側(左側)のほうが揚力が大きくなるので右に倒れてしまう。それを防ぐために左手を引く。しかしそうすると低くなっている右側にあわせて左側も落ちてしまうのでキャノピー全体が落ちてしまう。そうならないためには、キャノピーにより強いテンションを与えて、とにかく走る。なんて理屈でいいのかなぁ。

今日も夕方頃にエンジンの練習をして、フライト準備をする。前回よりも一回り大きなユニットで、馬力も重さも少し多い。しかし一回目のチャレンジではキャノピーが落ちてしまい中止。二回目のチャレンジでは途中でラインが絡んでしまってまた中止。自分では見えないので教えてもらわなければコケてただろう。そこで息が上がってしまい、いったん休憩。

しばらく休んで再チャレンジ。前回の軽いユニットのほうがいいかと聞かれたが、こんなところで苦手意識を作ってもつまらないと思って重い方を選んだ。三回目は無事に立ち上がり、助走もうまく出来てテイクオフ。上がってみると前回よりも周りがよく見えて、上空が寒いということにまで気が回った。前回よりも大きいエンジンで、フルパワー時の上昇スピードが明らかに違う。寒い上にコントローラを握って両手を上げた状態で肩がコチコチに固まっている。高度200mくらいをぐるぐる回る。眼下の川が真っ青で冷たそう。夕暮れ時で陽の光がきれい。遠くの山も少し見えたがどれがどれだかまではわからなかった。

ランディングは北から進入。高度処理はうまくいったが、最後に走り抜けることが出来ず、横に倒れてしまった。ちょっと残念だが機材を壊さなくてよかった。

先輩スクール生でおなじく着地時に尻餅をつき、ユニットのガード(プロペラにラインなどを巻き込まないようにする丸い外枠)を壊してしまった人がいた。これの修理(交換部品)代がなんと\42,000。もうすこし運が悪かったらプロペラ交換でプラス\50,000とかもありえる。これはちょっと恐ろしい遊びかもしれない...。

前回、Nagiosをインストールして動かすところまでたどり着いた。今回はNagiosの様々なプラグインを使用して、外部のサーバのサービスを監視する設定をする。変更をするファイルは/etc/nagios/localhost.cfgと/etc/nagios/commands.cfgのみ。

オープンソースのシステム・ネットワーク監視ツールとして、Nagiosがある。Webベースの管理画面を持ち、標準で用意されているさまざまなプラグインによってPingレベルからアプリケーションレベルまでの柔軟なサービス監視ができる。また被監視サーバ側にエージェントを入れることによりリソース監視もできる。

LVMでは、PV(物理ボリューム)を複数合わせてVG(ボリュームグループ)を作成し、その上にLV(論理ボリューム)を作成する。1つのVG上には複数のLVを作ることができる。ファイルシステムはLVの上に作成する。

LVMのPVを削除する

LVMでは、PVをVGに追加することによって容量を増やすことが容易に出来る。逆に、エラーが発生した場合やディスク構成を変えたい場合など、PVを削除したい場合がある。

XenではDomain-0上のファイルをDomain-Uのディスクとして使用できるが、物理的なディスクをそのまま使用することもできる。大きな容量を扱うのであればディスクを使用したほうがいいだろう。

物理ディスクをアタッチするには、Domain-Uの設定ファイルを以下のように編集する。

disk = [ 'tap:aio:/var/lib/xen/images/storage1,xvda,w']
disk = [ 'tap:aio:/var/lib/xen/images/storage1,xvda,w','phy:hda,hda,w']

そうしてDomain-Uを再起動すると、新しいディスクが/dev/hdaとして認識されているはず。

CentOS5ではXenを使用して多数のLinuxサーバを動かしているが、検証用にWindows 2003 Server R2を動かす必要が出てきた。Xenの完全仮想化でWindowsを動かすのも興味深いが、XenではGUIのデスクトップを見るのがVNC経由で面倒そうなので、手っ取り早くVMWare Playerを使うことにした。

Fedora8を入れたThinkPad R60eで、他のOSのインストールディスクを作るためにCD-Rを焼きたい。cdrecordというCLIツールでやってみようと思ったが、デバイスの指定がよく分からない。諦めてGUIでやってみたら驚くほど簡単にできてしまった。

1.ドライブに生ディスクを入れる。

2.イメージファイルの拡張子をisoにする。

3.イメージファイルを右クリックして、メニューから[ディスクへ書き込む]を選ぶ。

Fedora8の無線LANでWPA-PSKを使う

ThinkPad R60eにFedora8を入れて内蔵無線アダプタを認識させたが、いまどき無線LANをセキュリティなしには使えない。うちの無線LANはWPA-PSKによる暗号化をしているが、Fedora8でもちゃんと対応している。

パワードパラグライダーの2回目。まずはまた立ち上げの練習からはじめる。風がばっちりのときにはなんということもないが、風の向きが少し違ったり途中で変わったりするとぜんぜん対応できない。人が飛び立つのを見ていると、一発必中で上げてコントロールしないと危ない。途中でよろよろしたりしてる人を見るとこちらも怖いので、確率を上げられるように自分も練習に励む。

しかし、短距離とはいえ走るなんてめったにしないことだ。しかもキャノピーを上げるために全体重を前にかけて踏ん張りながら走る。たかだか数10mだが一本しっかりやるとすこし息が上がる。無理をしても雑になるし怪我もしかねないので、何本かやったら休憩という感じで、思った以上にのんびりと時間が過ぎる。

ユニットを背負って走る練習もして、そろそろ夕方になるころ、風も安定しているので飛んでみましょうかと言われた。待っていました!!ユニットを背負い、ヘルメットをかぶって準備をする。キャノピーの準備やハーネスとの接続はすべてインストラクターがやってくれる。立ち上げるタイミング、手を離すタイミング、エンジンパワーをかけるタイミング、すべてその場で教えてくれるので夢中でそのとおりにやれば大丈夫。一番難しいキャノピーの傾き修正も、前方にいるインストラクタがこっちに向かって走れといいながら左右に動いてくれるので、悩む必要はない。そうやって夢中で走っていると、やがて足が浮き始める。本当は完全に浮くまで走り続けなければいけないのだが、力を抜いてしまい少し落ちる。でも幸いそのまま上昇を続け、ついに飛び立った。

スカイスポーツは体で風を切るので上空は寒い。風で涙目になりながらも、きょろきょろと周りを見渡す。これが飛びたかった空だ。インストラクターが無線で常に話しかけてくれるので心細さや不安はない。風が安定しているので揺れることもなく、指示されたとおりに左手をゆっくり引くと左旋回し、戻すと直進する。緊張で肩はカチカチになっているが、難しいと感じる要素は特にない。

高度200mくらいでランディングエリアの周りを2周ほどして、アプローチの練習をする。すこし大回りに回ってからエンジンをアイドルにして、着地点に向かう。左右の方向調整は難しくない。難しいのは高度の調整だと思うが、今は言われたとおりにやるだけでぴったりと合う。ある程度の高度まで降りたらもう一度フルパワーで上昇し、さらに2周ほど。そうして再度アプローチをして、着陸直前に両手を肩まで下ろし、ついで尻まで下ろして着陸。走り抜けなければいけないのだが一瞬足が止まりつんのめる。幸い転ばずに持ち直すことが出来て、初フライトが終了。飛行時間にして約10分。怖さは感じなかったが、短いと思うほどの余裕もなかった。

念願の飛行が叶ったが、自分の力で飛んだわけではないので満足とは行かない。もっと練習をして早く自由に飛べるようになりたいと思った。

所有するなかで唯一のWindows機であるThinkPad R60eだが、行っている作業のほとんどがFirefoxとTeraTermを使っていることに気がついた。Windowsでなければ困る周辺機器は見当たらないし、ソフトウェアはVMWare上でWindowsを走らせれば問題ない。よし、Windows XPを消してFedora8に入れ替えてしまおう。

このThinkPad R60eはCPUがCore2Duo T5500/1.66Gで、チップセットはIntel 945GM Express、無線LANはIEEE802.11a/b/g対応のAtheros 5212、光学メディアはDVDマルチバーナーである。HDDは80GBでメモリは1.5GBに増設してある。

Fedora8のインストールは、ftp://ftp.jaist.ac.jp/あたりからFedora-8-x86_64-DVD.isoをダウンロードして、DVDに焼いて(Windows XPの最後の仕事!!)普通にインストールすれば何のエラーもなく終了。Xの画面もポインティングデバイスもそのまま使える。ネットワークも有線LANははじめから認識する。音も鳴る。

一手間かかったのが無線LANドライバのインストール。これをやるにはネットワークにつながないと大変で鶏と卵になりそうだが、有線LANが使えるので大丈夫。無線LANにはAtheros 5212というチップを使っているようで、これのドライバはmadwifiという名前でオープンソースとして公開されている。RPMパッケージも用意されており、Fedora用ではyumでインストールすることもできる。

まずはyumのリポジトリを追加する。

[root@r60e ~]# rpm -ivh http://rpm.livna.org/livna-release-8.rpm

そしてmadwifiをインストールする。いくつか依存関係にあるパッケージも同時にインストールされる。

[root@r60e ~]# yum install madwifi

そしてThinkPadを再起動すると、wifi0、ath0の2つのインターフェースが認識されている。wifi0はベースデバイスと呼ばれ、ath0はその上に作られたインターフェースで仮想APと呼ばれる。IPや認証の設定はath0を対象に行う。

[root@r60e ~]# ifconfig wifi0
wifi0     Link encap:UNSPEC  HWaddr 00-19-7D-39-5E-87-00-00-00-00-00-00-00-00-00-00  
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:75844 errors:0 dropped:0 overruns:0 frame:94418
          TX packets:1476 errors:7 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:199 
          RX bytes:6138023 (5.8 MiB)  TX bytes:88113 (86.0 KiB)
          Interrupt:17 

[root@r60e ~]# ifconfig ath0
ath0      Link encap:Ethernet  HWaddr 00:19:7D:39:5E:87  
          inet addr:192.168.1.16  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::219:7dff:fe39:5e87/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1492  Metric:1
          RX packets:3445 errors:0 dropped:0 overruns:0 frame:0
          TX packets:384 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:106451 (103.9 KiB)  TX bytes:31779 (31.0 KiB)

まだIPアドレスや無線LANの暗号化/認証などの設定をしていないが、近所のオープンなアクセスポイントを掴んでしまったらしい。WPAの設定はまた別途。

vsftpdはVery Secure FTP daemonの略で、CentOS5.0ではデフォルトでインストールされる。しかし実際に使うためにはvsftpd以外の部分でちょっと設定がいる。

SELinuxの設定

[root@storage1 ~]# setsebool -P ftp_home_dir=on

iptablesの設定

[root@storage1 ~]# vi /etc/sysconfig/iptables
...
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp -s 192.168.0.0/16 --dport 20 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp -s 192.168.0.0/16 --dport 21 -j ACCEPT
...

iptablesでFTPのデータコネクションを許可するためのモジュールをロード

[root@storage1 ~]# vi /etc/sysconfig/iptables-config
...
IPTABLES_MODULES="ip_conntrack_ftp"
...

そしてiptablesを再起動。

[root@storage1 ~]# service iptables restart

あとはservice vsftpd startでFTPサービスを開始すればよい。恒久的に使うのであればchkconfig vsftpd onとする。vsftpdの設定はデフォルトでroot以外のユーザはログインが出来て、anonymous ftpも使える。anoymous ftpはchrootが有効になっており、anonymousユーザには/var/ftpがルートに見える。

トランスペアレントキャッシュは透過キャッシュとも呼ばれ、クライアントPCへの追加設定なしにインターネットキャッシュを行う技術。キャッシュとは本来は企業などで複数のクライアントがいるとき、同一のコンテンツを取得するときに毎回インターネットから取得せずにLAN上のサーバに蓄えられたデータを使うことによって回線帯域の削減や応答時間の改善を目指すもの。ただし現在ではWAN帯域削減というよりはアンチウイルスや悪質サイトのURLフィルタ、あるいは社員がどんなサイトを見に行っているかのログ取得が主な目的となっている。なのでクライアントPC1台、ユーザ1人といううちの環境ではあまり意味がないが、技術的な興味で試してみる。

squidはプロキシ・キャッシュサーバとして歴史のあるソフトウェアで、CentOS5.0にも入っている。squid自体は自分宛に来たリクエストを処理することしかできないので、iptablesの機能を使ってLANから外に出て行くHTTPの通信を強制的にsquidに転送することにする。

まず簡単なiptablesの設定を作ろう。構成は以下のようになる。

                   eth1   eth0
(Internet)-----------[ml115]------------[Client PC]
                        |dummy0
                        |
                     [proxy1]

eth0から入ってきたあて先ポート=80の通信は、あて先IPをsquidに変更し、ポート番号もsquidで使用する3128番に変更する。これを実現する設定を/etc/sysconfig/iptablesに追加する。

[root@ml115 ~]# vi /etc/sysconfig/iptables
...
-A RH-Firewall-1-INPUT -i eth0 -j ACCEPT  ←元々あったeth0からのInputを全て許可するルール
...
-A PREROUTING -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.2.9:3128
...
-A POSTROUTING -o ppp0 -j MASQUERADE      ←元々あったppp0からのOutputを全てIPマスカレードするルール
...

[root@ml115 ~]# service iptables restart

squidの設定は、/etc/squid/squid.confに記述する。詳細なチューニングをするのでなければ変更するべきところは少なく、最低限アクセス制限の設定をする。デフォルトではlocalhostからの接続しか許可されないので、以下の設定を追加する。

[root@ml115 ~]# vi /etc/squid/squid.conf
...
acl private_net src 192.168.0.0/255.255.0.0    ←追加
http_access allow localhost
http_access allow private_net                  ←追加
http_access deny all
...
http_port 3128 transparent                     ←"transparent"を追加
...

デフォルトではキャッシュに使用するメモリは8MB、HDDは100MBとなっているが、増やしたほうがヒット率は上がる。ただある程度で頭打ちになる。

設定をしたらsquidを起動する。

[root@ml115 ~]# service squid restart

最後に、squidサーバのiptablesで、squidで使用する3128/tcpを許可する。

[root@proxy1 ~]# vi /etc/sysconfig/iptables
...
-A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 3128 -j ACCEPT
...
[root@ml115 ~]# service iptables restart

ここまでの設定で、クライアントPCからインターネットへのHTTPアクセスはすべてsquid経由になる。ためしにsquidのログを見ながらインターネットを見に行ってみよう。

[root@proxy1 ~]# tail -f  /var/log/squid/access.log
1195255448.391    405 192.168.0.3 TCP_MISS/200 46221 GET http://www.asahi.com/ - DIRECT/202.232.139.14 text/html
1195255448.567    175 192.168.0.3 TCP_MISS/200 862 GET http://imp.asahi.com/jserver/acc_random=71651847/SITE=TOP/AREA=BANNER/AAMSZ=728X90/OENCJP=EUC/pageid=40219793 - DIRECT/220.213.234.196 application/x-javascript
1195255448.589     21 192.168.0.3 TCP_MISS/200 26886 GET http://img.ak.impact-ad.jp/yc/ah/2007/11/071112his_onlinespbnr-1f0d3a5d6f615b03e325e5abc7e17a0654a6241b.gif - DIRECT/60.254.185.59 image/gif
1195255448.599     27 192.168.0.3 TCP_MISS/200 687 GET http://ad.jp.doubleclick.net/adj/asahi.np/top_text_1;sz=500x16;ord=3164293186689577.5? - DIRECT/210.153.90.13 application/x-javascript
1195255448.634     34 192.168.0.3 TCP_MISS/200 703 GET http://ad.jp.doubleclick.net/adj/asahi.np/top_text_2;sz=500x16;ord=6056704805117622? - DIRECT/210.153.90.13 application/x-javascript
1195255448.693     58 192.168.0.3 TCP_MISS/200 1134 GET http://imp.asahi.com/bservers/AAMALL/acc_random=78535733/pageid=40219793/AAMB1/SITE=TOP/AREA=BUTTON1/AAMSZ=80X45/OENCJP=EUC/AAMB2/SITE=TOP/AREA=BUTTON2/AAMSZ=80X45/OENCJP=EUC - DIRECT/220.213.234.196 application/x-javascript
....

実際に使ってみると、はじめて見に行くサイトはsquidの処理遅延が入るぶんやや遅くなる。2回目以降は早いが、実はブラウザもローカルにキャッシュをもっているので、効果はあまり変らないかもしれない。

仮想サーバを新しく作成して起動したら、他の仮想サーバが一切ネットワークにつながらなくなった。仮想サーバを1台シャットダウンしたら復旧した。Domain-Uの上限数に達してしまったらしい。

XenではDomain-Uをループバックデバイスとして認識するので、Domain-Uを1個起動するごとにループバックデバイスを1個消費する。CentOS5.0ではループバックデバイスは下記のようにデフォルトで8個であり、これが仮想サーバの上限になっている。

[root@ml115 ~]# ls /dev/loop*
/dev/loop0  /dev/loop2  /dev/loop4  /dev/loop6
/dev/loop1  /dev/loop3  /dev/loop5  /dev/loop7

ループバックデバイスの数はkernelモジュールのパラメータとして設定する。方法は起動時パラメータとして/etc/grub.confに書いたり、起動時スクリプトのどこかにmodprobeコマンドを呼び出したりと複数の方法があるが、ここでは/etc/modprobe.confに書き込む。

[root@ml115 ~]# vi /etc/modprobe.conf
...
options loop max_loop=16
...

設定したらDomain-0を再起動して、もう一度ループバックデバイスの数を調べる。以下のとおりちゃんと16個に増えていた。

[root@ml115 ~]# ls /dev/loop*
/dev/loop0   /dev/loop11  /dev/loop14  /dev/loop3  /dev/loop6  /dev/loop9
/dev/loop1   /dev/loop12  /dev/loop15  /dev/loop4  /dev/loop7
/dev/loop10  /dev/loop13  /dev/loop2   /dev/loop5  /dev/loop8

そこで9個目のDomain-Uを起動してみる。

[root@ml115 ~]# xm list
Name                                      ID Mem(MiB) VCPUs State   Time(s)
Domain-0                                   0     1223     2 r-----    159.8
db1                                        1      255     1 -b----     31.4
db2                                        2      255     1 -b----     32.4
lvs1                                       3      255     1 -b----     40.5
lvs2                                       4      255     1 -b----     42.1
manager1                                  11      255     1 -b----     21.6
ns1                                       10      255     1 -b----     27.2
storage1                                   7      255     1 -b----     41.1
www1                                       8      255     1 -b----     42.2
www2                                       9      255     1 -b----     46.9

ちゃんと起動して、ネットワークも問題なく動いた。

MySQLサーバを二重化し、マスター機からスレーブ機へレプリケーションする。MySQLでは、1台のマスタと複数台のスレーブの間でレプリケーションをすることができる。更新処理はマスタで行い、検索処理はマスタとスレーブで行えるが、普通はパフォーマンスを上げるためにマスタは更新専用にする。データの更新は非同期なので、スレーブの台数やパフォーマンスにマスタの動作が引っ張られることはない。そのかわり常にすべてのサーバで同じ情報があることは保障されない。

まず、マスターの設定をする。

[root@db1 ~]# vi /etc/my.cnf
...
[mysqld]
log-bin = mysql-bin
server-id = 1
...

マスターは更新処理の内容をバイナリログというファイルに書き込み、スレーブはそのファイルを読み込んで自分のデータを更新する。server-idは何でもよいが、ユニークな値を付与する。

マスターでMySQLを再起動し、レプリケーション用のユーザを追加する。

mysql>root@db1 ~]# service mysqld restart
Stopping MySQL:                                            [  OK  ]
Starting MySQL:                                            [  OK  ]

[root@db1 ~]# mysql -u root -p
Enter password:
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%.grandarbre.net' IDENTIFIED BY 'PASSWORD123';
Query OK, 0 rows affected (0.00 sec)

次にマスターでレプリケーション情報を取得する。まずすべてのデータをフラッシュし、書き込みステートメントをブロックする。

[root@db1 ~]# mysql -u root -p
Enter password:
mysql> FLUSH TABLES WITH READ LOCK;
Query OK, 0 rows affected (0.00 sec)

次に現在のバイナリログ名とオフセットを調べる。

mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |   158995 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

mysql>

そうして、スレーブに初期同期させるためのデータダンプを取得する。

[root@db1 ~]#  mysqldump --all-databases --lock-all-tables -u root -p > /tmp/dbdump.db
Enter password:

次にスレーブの設定をする。

[root@db2 ~]# vi /etc/my.cnf
...
[mysqld]
server-id=2
...

設定例によっては、my.cnfにマスターのホスト名や認証情報などを書いている場合もある。しかしいったんスレーブが設定されると、これらの情報は/var/lib/mysql/master.infoに保存されてmy.cnfは無視されるので、my.cnfに書く必要はない。

ここでスレーブのMySQLを再起動する。

[root@db2 ~]# service mysqld restart
Stopping MySQL:                                            [  OK  ]
Starting MySQL:                                            [  OK  ]

先ほどマスターで取得したダンプをFTPなどでスレーブにコピーし、MySQLに読み込ませる。

[root@db2 ~]# mysql -u root -p < /tmp/dbdump.db
Enter password:

スレーブのDBをマスターに接続する。

[root@db2 ~]# mysql -u root -p
Enter password:
mysql> CHANGE MASTER TO
    -> MASTER_HOST='db1',
    -> MASTER_USER='repl',
    -> MASTER_PASSWORD='replpass123',
    -> MASTER_LOG_FILE='mysql-bin.000001',
    -> MASTER_LOG_POS=158995;
Query OK, 0 rows affected (0.16 sec)

スレーブを開始する。

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

ここまでの作業でレプリケーションはできているはず。

マスターの状態を表示する。

mysql> show master status\G
*************************** 1. row ***************************
            File: mysql-bin.000002
        Position: 186113
    Binlog_Do_DB:
Binlog_Ignore_DB:
1 row in set (0.00 sec)

スレーブの状態を表示する。Slave_IO_Running:とSlave_SQL_Running:がyesだとslaveとして動いている。

mysql>
mysql> show slave status\G
*************************** 1. row ***************************
             Slave_IO_State: Waiting for master to send event
                Master_Host: db1
                Master_User: repl
                Master_Port: 3306
              Connect_Retry: 60
            Master_Log_File: mysql-bin.000002
        Read_Master_Log_Pos: 186113
             Relay_Log_File: db2-relay-bin.000004
              Relay_Log_Pos: 186250
      Relay_Master_Log_File: mysql-bin.000002
           Slave_IO_Running: Yes
          Slave_SQL_Running: Yes
            Replicate_Do_DB:
        Replicate_Ignore_DB:
         Replicate_Do_Table:
     Replicate_Ignore_Table:
    Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
                 Last_Errno: 0
                 Last_Error:
               Skip_Counter: 0
        Exec_Master_Log_Pos: 186113
            Relay_Log_Space: 186250
            Until_Condition: None
             Until_Log_File:
              Until_Log_Pos: 0
         Master_SSL_Allowed: No
         Master_SSL_CA_File:
         Master_SSL_CA_Path:
            Master_SSL_Cert:
          Master_SSL_Cipher:
             Master_SSL_Key:
      Seconds_Behind_Master: 0
1 row in set (0.00 sec)

mysql>

マスターでプロセスを見てみる。Binlog Dumpがあればよい。

mysql> SHOW PROCESSLIST\G
*************************** 1. row ***************************
     Id: 22
   User: root
   Host: localhost
     db: mt
Command: Query
   Time: 0
  State: NULL
   Info: SHOW PROCESSLIST
*************************** 2. row ***************************
     Id: 41
   User: repl
   Host: db2.grandarbre.net:56174
     db: NULL
Command: Binlog Dump
   Time: 323
  State: Has sent all binlog to slave; waiting for binlog to be updated
   Info: NULL
2 rows in set (0.00 sec)

mysql>

スレーブでもプロセスを見ると、2つのConnectがある。

mysql> show processlist\G
*************************** 1. row ***************************
     Id: 2
   User: root
   Host: localhost
     db: mt
Command: Query
   Time: 0
  State: NULL
   Info: show processlist
*************************** 2. row ***************************
     Id: 3
   User: system user
   Host:
     db: NULL
Command: Connect
   Time: 191
  State: Waiting for master to send event
   Info: NULL
*************************** 3. row ***************************
     Id: 4
   User: system user
   Host:
     db: NULL
Command: Connect
   Time: 11
  State: Has read all relay log; waiting for the slave I/O thread to update it
   Info: NULL
3 rows in set (0.00 sec)

mysql>

Webサーバを二重化したので、バックエンドのMySQLサーバも二重化してレプリケーションしたい。その前段階として、MySQLにネットワーク経由でアクセスできるようにしたい。

MySQLのユーザ情報や権限情報はMySQLのデータベースの中に保存されている。まず認証はuserテーブルで行う。どのホストから誰が接続してきたかという情報をもとにレコードとマッチさせ、パスワードが一致したら認証成功。この順序はまずホスト名でマッチし、次にユーザ名でマッチさせる。ワイルドカード(%)も使えるが優先順位は下がる。フィールドが空白の場合はすべてにマッチするが、それで許可されるわけではなく次の認証段階へ判断が持ち越される。

userテーブルの認証に成功したら、次にdbテーブルで権限をチェックする。userテーブルでも権限の付与は可能だが、そうするとすべてのデータベースに対して同じ権限を付与してしまうので、通常はuserテーブルではすべての権限をなし(N)としておき、dbテーブルでデータベースごとの権限を付与(Y)する。

まずローカルでMySQLに接続して設定をする。

ユーザ情報などを保存しているmysqlデータベースを選択する。

[root@db1 ~]# mysql -u root -p
Enter password:

mysql> use mysql;

現在登録されているユーザを確認。

mysql> select user,host from user;
+--------+---------------------+
| user   | host                |
+--------+---------------------+
|        | localhost           |
| mtuser | localhost           |
| root   | localhost           |
+--------+---------------------+
3 rows in set (0.00 sec)

ネットワークから接続できるようにユーザを追加。SQL文は途中で改行を入れても大丈夫で、その際に>が表示される。

mysql> INSERT INTO `user` VALUES ('www1.grandarbre.net','mtuser',PASSWORD('MYPASSWORD'),
>'N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N',
>'N','N','N','N','N','','','','',0,0,0,0);
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO `user` VALUES ('www2.grandarbre.net','mtuser',PASSWORD('MYPASSWORD'),
>'N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N',
>'N','N','N','N','N','','','','',0,0,0,0);
Query OK, 1 row affected (0.01 sec)

ユーザが追加されている。

 mysql> select user,host from user;
+--------+---------------------+
| user   | host                |
+--------+---------------------+
|        | localhost           |
| mtuser | localhost           |
| root   | localhost           |
| mtuser | www1.grandarbre.net |
| mtuser | www2.grandarbre.net |
+--------+---------------------+
5 rows in set (0.00 sec)

同様にホストを確認する。

mysql> select host,user,db from db;
+------------------+--------+---------+
| host             | user   | db      |
+------------------+--------+---------+
| %                |        | test    |
| %                |        | test\_% |
| localhost        | mtuser | mt      |
+------------------+--------+---------+
3 rows in set (0.00 sec)

同様にホストを追加。

INSERT INTO `db` VALUES ('www1.grandarbre.net','mt','mtuser',
>'Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
Query OK, 1 row affected (0.01 sec)
INSERT INTO `db` VALUES ('www2.grandarbre.net','mt','mtuser',
>'Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
Query OK, 1 row affected (0.01 sec)

以下のように追加されている。

mysql>mysql> select host,user from db;
+---------------------+--------+
| host                | user   |
+---------------------+--------+
| %                   |        |
| %                   |        |
| localhost           | mtuser |
| www1.grandarbre.net | mtuser |
| www2.grandarbre.net | mtuser |
+---------------------+--------+
5 rows in set (0.00 sec)

最後に、変更した権限情報を反映させる。

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

ネットワーク経由で接続するので、iptablesの設定をする。

[root@db1 ~]# vi /etc/sysconfig/iptables
...
-A RH-Firewall-1-INPUT -m state --state NEW -m udp -p udp -s 192.168.0.0/16 --dport 873 -j ACCEPT
...
[root@db1 ~]# service iptables restart

クライアント側からmysqlコマンドで接続確認をする。

[root@www2 mt]# mysql -h db1 -u mtuser -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 153 to server version: 5.0.22

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql>

クライアント側で、HTTPDがネットワーク越しにデータベース接続できるようにSELinuxの設定をする。

[root@www1 tmp]# setsebool -P httpd_can_network_connect_db on
[root@www2 tmp]# setsebool -P httpd_can_network_connect_db on

rsyncでWebコンテンツを同期

LVSでWebサーバを負荷分散できるようにしたので、同じコンテンツをもったWebサーバを作らなければいけない。普通はNFSなどの仕組みで共用ストレージを使うと思うが、ここではバックアップの意味も含めてrsyncでコンテンツのディレクトリをまるごとコピーしてしまう。

①オリジナルサーバ側、コピーサーバ側の両方にrsyncをインストール。多分もともと入ってる。

[root@www1 ~]#yum install rsync
[root@www2 ~]#yum install rsync

②オリジナルサーバ側の設定

[root@www1 ~]# vi /etc/rsyncd.conf
uid = apache
gid = apache

[wwwfiles]
        path = /var/www
        use chroot = no
        read only = no
[root@www1 ~]# cat /etc/hosts.allow
rsync:  192.168.2.5
[root@www1 ~]# chkconfig rsync on

ここまでは単純だったが、コピーサーバ側からrsyncをしてみるとSELinuxで引っかかってしまった。下記の手順で必要なアクセスを許可する。

いったんSELinuxを無効にする

[root@www1 ~]# setenforce 0

コピーサーバ側からrsyncを実行する

[root@www2 ~]# rsync -av --delete www1::wwwfiles /var/www

SELinuxのauditログから許可すべきポリシーを生成する

[root@www1 ~]# cat /var/log/audit/audit.log | grep rsync | audit2allow -M local

ポリシーの内容を確認する

[root@www1 ~]# cat local.te
module local 1.0;

require {
        class dir { getattr read search };
        class file { getattr read };
        type httpd_sys_content_t;
        type httpd_sys_script_exec_t;
        type rsync_t;
        role system_r;
};

allow rsync_t httpd_sys_content_t:dir { getattr read search };
allow rsync_t httpd_sys_content_t:file { getattr read };
allow rsync_t httpd_sys_script_exec_t:dir { getattr read search };
allow rsync_t httpd_sys_script_exec_t:file { getattr read };

ポリシーをインストールする

[root@www1 ~]# semodule -i local.pp

SELinuxを有効にする

[root@www1 ~]# setenforce 1

③crondで自動的に同期をする設定

[root@www2 ~]# vi /etc/cron.d/rsync
30 * * * * root rsync -aq --delete www1::wwwfiles /var/www

仕事柄BIG-IPをはじめとする負荷分散装置を取り扱っている。確かに高機能でよい製品なのだが最下位機種でも定価で400万円以上もするし、他社の安価な品でも売値で100万を切るものは少ない。また安いものは作りもそれなりなのである。負荷分散装置は冗長化で2台いれるのが常識なので、費用負担も倍になる。

ところが意外と知られていないが、簡単な負荷分散装置(L4スイッチ)はすべてオープンソースで作ることができる。高度な制御機能はないが、大半のユーザは単純なL4負荷分散くらいしか使わないので十分である。設定や管理が面倒な部分はあるが、CentOS5.0ではソフトウェア自体はすべてyumでインストールができるので、試してみる価値はあるとおもう。

以前の作業でXenを使って1台の物理サーバ上にデータセンタ構成を作った。これを利用してDMZ上にLVSによる負荷分散装置を利用したWebシステムを作る。

LVSの動作にはNATモードとDSR(Direct Server Return)モードがある。NATモードはVIPあてに来たパケットのあて先IPアドレスを実サーバに変換して実サーバに送る。そのため返信パケットも必ずLVSを通り、IPアドレスを元に戻さなければいけない。DSRモードはパケットのIPアドレスではなく、あて先MACアドレスのみを実サーバに変換する。よって戻りパケットはLVSサーバを通る必要がないが、複数の実サーバが同じIPアドレスを持つ必要があり、すこし設定が複雑になる。両者を比べるとDSRモードのほうがLVSの負荷が低くなり、大規模なシステムに向くといわれている。

NATモードとDSRモードでは物理的な繋ぎ方も違ってくる。NATモードではLVSサーバはファイアウォールのようにクライアントと実サーバの間にいなければいけないが、DSRモードではLVSサーバは実サーバと同じセグメントにいなければいけない。

はじめは概念や設定がシンプルなNATモードで試していたのだが、なぜか返信パケットにTCPチェックサムエラーが出てしまい通信ができない。LVSが返信パケットのアドレスを書き戻すときにバグがあるのかもしれない。いろいろ調べても解決できなかったが、多くの人が何も問題なく使えているようなので、もしかしたらXenに特有の問題なのかもしれない。

よって、DSRモードで設定することにする。構成は下図のようになる。

            peth1             eth1   eth0               peth0
[物理I/F]-----(xenbr1)----------[Domain0]----------(xenbr0)-----[物理I/F]
                                    |dummy0         | | | |    eth0
                                    |               | | | +-----[ns1]
                                    |               | | |      eth0
                                    |               | | +-------[ns2]
                                    |               | |        eth0
                                    |               | +---------[storage1]
                                    |               |          eth0
                                (xenbr2)            +-----------[manager1]
                                 | | | |
                                 | | | |eth0  eth1
                                 | | | +--[lvs1]---(xenbr4)
                                 | | |  eth0  eth1    |
                                 | | +----[lvs1]------+
                                 | |    eth0
                                 | +------[www1]
                                 |      eth0
                                 +--------[www2]

【lvsサーバの設定】

①以下のパッケージをインストールする。

[root@lvs1 ~]# yum install ipvsadm
[root@lvs1 ~]# yum install heartbeat
[root@lvs1 ~]# yum install heartbeat-ldirectord

ipvsadmは、サーバ負荷分散動作の管理をする。実際の負荷分散処理はカーネルモジュールとして実装されいている。

heartbeatは、VIPを作り、2台のLVSサーバ間で冗長化を実現する。

heartbeat-ldirectordは、実サーバの監視を行い、内部でipvsadmを使って自動的に負荷分散対象サーバの追加や削除をする。

②heartbeatを設定する。

/etc/ha.d/ha.cfはlvs1とlvs2で少しだけ設定が違う。

[root@lvs1 ~]# vi /etc/ha.d/ha.cf
logfile /var/log/ha-log

keepalive 2
deadtime 30
warntime 10
initdead 120

udpport 694
ucast eth2 192.168.4.2

auto_failback on

node lvs1 lvs2

ping 192.168.2.254

respawn hacluster /usr/lib64/heartbeat/ipfail

apiauth ipfail gid=haclient uid=hacluster
[root@lvs2 ~]# vi /etc/ha.d/ha.cf
logfile /var/log/ha-log

keepalive 2
deadtime 30
warntime 10
initdead 120

udpport 694
ucast eth2 192.168.4.1

auto_failback on

node lvs1 lvs2

ping 192.168.2.254

あとの2つの設定ファイルはlvs1とlvs2で同じ。

[root@lvs1 ~]# vi haresources
lvs1 IPaddr::192.168.2.1/24/eth0 ldirectord
[root@lvs1 ~]# vi authkeys
auth 1
1 crc
[root@lvs1 ~]# chmod 0600 authkeys

heartbeatを自動起動するようにする。

[root@lvs1 ~]# chkconfig heartbeat on
[root@lvs1 ~]# service heartbeat start

heartbeatを起動すると、アクティブ系のサーバではVIPができている。

[root@lvs1 ~]# ifconfig 
...
eth0      Link encap:Ethernet  HWaddr 00:16:3E:2B:02:02
          inet addr:192.168.2.2  Bcast:192.168.2.255  Mask:255.255.255.0
          inet6 addr: fe80::216:3eff:fe2b:202/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:69881 errors:0 dropped:0 overruns:0 frame:0
          TX packets:67564 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:7525114 (7.1 MiB)  TX bytes:6827200 (6.5 MiB)

eth0:0    Link encap:Ethernet  HWaddr 00:16:3E:2B:02:02
          inet addr:192.168.2.1  Bcast:192.168.2.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
...

③ldirectordを設定する。

[root@lvs1 ha.d]# vi /etc/ha.d/ldirectord.cf
checktimeout=5
checkinterval=60
autoreload=yes
logfile="/var/log/ldirectord.log"

virtual=192.168.2.1:80
        real=192.168.2.4:80 gate
        real=192.168.2.5:80 gate
        fallback=192.168.2.6:80 gate
        checktype=negotiate
        protocol=tcp
        service=http
        request="test.html"
        receive="i am alive"
        virtualhost="www.grandarbre.net"
        scheduler=rr
        persistent=600
        netmask=255.255.255.255

ここでautoreload=yesとしているので、今後ldirectord.cfの設定を変更しても自動的に反映される。

ldirectordはheartbeatに呼び出されて起動されるので、chkconfig ldirectord offとしておく。

また負荷分散装置としての設定はipvsadmが管理をするが、ldirectordが自動的にコマンドを発行してipvsadmを設定してくれる。よって別途ipvsadmを設定する必要はなく、chkconfig ipvsadm offとしておく。

上記の設定では、実サーバがダウンした場合にもpersistentテーブルに載っている通信は、そのままダウンしたサーバに送り続けられる。これを防ぐために、以下のカーネルパラメータを設定する。

[root@lvs1 ha.d]#echo 1 > /proc/sys/net/ipv4/vs/expire_quiescent_template

これを恒久的にする場合は/etc/sysctl.confに以下の行を追加する。

[root@lvs1 ha.d]# vi /etc/sysctl.conf
...
net.ipv4.vs.expire_quiescent_template = 1
...

【Webサーバの設定】

①ARPの設定

Webサーバでは、VIPをループバックインターフェースに設定する。また同じVIPを複数のWebサーバで共有するため、このVIPに関するARPを投げたり受けたりしないようにする。

[root@www1 ~]# vi /etc/sysctl.conf
...
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
...

[root@www1 ~]# sysctl -p

arp_ignore=1は、ARPリクエストのIPが、それを受診したインターフェースに設定されたIPであった場合にのみARPリプライを投げる。よってeth0でVIPあてのARPリクエストを受診してもリプライを返さない。

arp_announce=2は、ARPリクエストを送信する際の送信元IPとして、通信相手に一番近いインターフェースのIPを使う。つまりVIPを送信元アドレスとした通信を始める際に送信されるARPリクエストの送信元IPとして、eth0のIPを使う。

②ループバックインターフェースの設定

[root@www1 ~]# vi /etc/sysconfig/network-scripts/ifcfg-lo:0
DEVICE=lo:0
IPADDR=192.168.2.1
NETMASK=255.255.255.255
ONBOOT=yes

[root@www2 ~]# ifup lo:0

[root@www1 ~]# ifconfig lo:0
lo:0      Link encap:Local Loopback
          inet addr:192.168.2.1  Mask:255.255.255.255
          UP LOOPBACK RUNNING  MTU:16436  Metric:1

www2でも全く同じIPを設定する。

③ヘルスチェック用のHTMLを用意。

ldirectordの設定で下記のように設定しているので、Webサーバにこの内容のHTMLファイルを用意する必要がある。

...
        request="test.html"
        receive="i am alive"
...
[root@www1 ~]# vi /var/www/html/test.html
i am alive

【動作確認】

アクティブ側のLVSサーバで動作状態を確認する。

[root@lvs1 ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.2.1:80 rr persistent 1
  -> 192.168.2.4:80               Route   1      0          0
  -> 192.168.2.5:80               Route   1      0          0

Weightが1以上のサーバが稼動状態で、0のサーバはhttpdが落ちている状態。

クライアントからwgetを使ってVIPにアクセスしてみる。

[ishii@storage1 ~]$ wget -O - --quiet 192.168.2.1
<html>
<body>
<font color=red>This is www3</font>
</body>
<html>

せっかくサーバを仮想化しているのだから、ネットワークも仮想化して自由に構成したい。データセンターではセキュリティや管理の為にセグメントを分けるのは常識だし、クラスタ間は専用のネットワークを繋ぐ前提で作られているソフトウェアも多い。このネットワークシステムを、1台のサーバ内で仮想的に構築したい。

まずXenのネットワークの基礎を説明する。Xenでは仮想ネットワークは下記のような構造になる。

            peth0  vif0.0      eth0
[物理I/F]-----(xenbr0)----------[Domain0]
                |   |vif1.0    eth0
                |   +-----------[Domain-U]
                |vif2.0        eth0
                +---------------[Domain-U]

Domain0(実サーバ)やDomain-U(仮想サーバ)から見ると、自分が使っているインターフェースはおなじみのeth0という名前だが、その間はXenが作った仮想ブリッジ(xenbr0)でつながっている。また物理インターフェースも実サーバに直接つながっているわけではなく、仮想ブリッジにつながっている。こうすることで、仮想サーバも物理インターフェースから直接外部に出ることができるのである。

peth0、vif0.0、vif1.0などは仮想ブリッジ側のインターフェースであり、IPアドレスは付与しない。vif x.yのxは仮想サーバのIDをさしており、yは仮想サーバ側から見たインターフェース番号をあらわしている。つまり仮想サーバ1に2つのインターフェースを持たせてそれぞれeth0、eth1とすると、それにつながる仮想ブリッジのポートはvif1.0、vif1.1となる。なお仮想サーバのIDは起動するごとに変わるので不定である。

物理インターフェースが2つある場合は、単純に下記のようになる。

            peth0  vif0.0      eth0   eth1    vif1.0   peth1
[物理I/F]-----(xenbr0)----------[Domain0]----------(xenbr1)-----[物理I/F]
                |   |                               |   |
                |   |vif1.0    eth0   eth1    vif1.1|   |
                |   +-----------[DomainU]-----------+   |
                |vif2.0                           vif2.0|
                |              eth0   eth1              |
                +---------------[DomainU]---------------+

物理インターフェースが1つしかないが仮想サーバで2つのインターフェースを使いたい場合はdummyインターフェースを作成する。

            peth0  vif0.0      eth0   dummy0    vif1.0   peth1
[物理I/F]-----(xenbr0)----------[Domain0]----------(xenbr1)
                |   |                               |   |
                |   |vif1.0    eth0   eth1    vif1.1|   |
                |   +-----------[DomainU]-----------+   |
                |vif2.0                           vif2.0|
                |              eth0   eth1              |
                +---------------[DomainU]---------------+

Domain0のdummy0インターフェースにはIPを付与して仮想サーバと通信をすることも出来るし、IPを付与せず仮想サーバ同士の通信だけをさせることも出来る。

この考え方を元に、DMZや仮想サーバ間専用リンクを持った複雑なネットワークを作ってみる。なおvif名は設定上関係ないので省略する。

            peth1              eth1   eth0               peth0
[物理I/F]-----(xenbr1)----------[Domain0]----------(xenbr0)-----[物理I/F]
                                    |dummy0         | | | |    eth0
                                    |               | | | +-----[ns1]
                                    |               | | |      eth0
                                    |               | | +-------[ns2]
                                    |               | |        eth0
                                    |               | +---------[storage1]
                                    |               |          eth0
                                (xenbr2)            +-----------[manager1]
                                 |    |
                                 |    | eth0  eth1             eth0
                                 |    +---[lvs1]-----+   +------[www1]
                                 |          |eth2    |   |
                                 |       (xenbr4)   (xenbr3)
                                 |          |eth2    |   |     eth0
                                 +--------[lvs2]-----+   +------[www2]
                                        eth0  eth1

xenbr2~4はDMZに相当する。図では示していないがDomain0はxenbr3、xenbr4にdummy1、dummy2でつながっている。

①dummyインターフェースを複数使用可能にするため、カーネルモジュールの設定をする。またxenbrがループバックデバイスを消費し、デフォルト数の4を越えてしまうので増やしておく。(この2行の設定に行き着くまでにまる一日かかった...)

[root@ml115 ~]# vi /etc/modprobe.conf
...
options dummy numdummies=3
netloop nloopbacks=5
...

ここでいちど再起動をしたほうがいいと思う。

②dummyインターフェースの設定を作成し、起動させる。

[root@ml115 ~]# vi /etc/sysconfig/network-script/ifcfg-dummy0
DEVICE=dummy0
BROADCAST=192.168.2.255
HWADDR=00:16:3E:2B:02:fe
IPADDR=192.168.2.254
NETMASK=255.255.255.0
NETWORK=192.168.2.0
ONBOOT=yes

[root@ml115 ~]# ifconfig dummy0 up
dummy1、dummy2も同様

③Xenのネットワーク設定をする

/etc/xen/scripts/に下記の内容のファイルを作成する。

[root@ml115 ~]# vi /etc/xen/scripts/network-bridge.wrap
#!/bin/sh
# Exit if anything goes wrong.
set -e

# First arg is the operation.
OP=$1
shift

script=/etc/xen/scripts/network-bridge

case ${OP} in
  start)
        $script start vifnum=0 bridge=xenbr0 netdev=eth0
        $script start vifnum=1 bridge=xenbr1 netdev=eth1
        $script start vifnum=2 bridge=xenbr2 netdev=dummy0
        $script start vifnum=3 bridge=xenbr3 netdev=dummy1
        $script start vifnum=4 bridge=xenbr4 netdev=dummy2
        ;;

  stop)
        $script stop vifnum=0 bridge=xenbr0 netdev=eth0
        $script stop vifnum=1 bridge=xenbr1 netdev=eth1
        $script stop vifnum=2 bridge=xenbr2 netdev=dummy0
        $script stop vifnum=3 bridge=xenbr3 netdev=dummy1
        $script stop vifnum=4 bridge=xenbr4 netdev=dummy2
        ;;

  status)
        $script status vifnum=0 bridge=xenbr0 netdev=eth0
        $script status vifnum=1 bridge=xenbr1 netdev=eth1
        $script status vifnum=2 bridge=xenbr2 netdev=dummy0
        $script status vifnum=3 bridge=xenbr3 netdev=dummy1
        $script status vifnum=4 bridge=xenbr4 netdev=dummy2
        ;;

  *)
        echo 'Unknown command: ' ${OP}
        echo 'Valid commands are: start, stop, status'
        exit 1
esac

次に/etc/xen/xend-config.sxpを編集する

...
(network-script network-bridge)
...
↓↓↓
...
(network-script network-bridge.wrap)
...

④各仮想サーバ定義ファイルのネットワーク設定をする。いじるのはvif=の行。ちなみにMACアドレスを重複しないように決めるのが大変なので、IPアドレスの下2オクテットを16進数にしてMACアドレスの下2オクテットとして使っている。

[root@ml115 xen]# vi /etc/xen/lvs1
name = "lvs1"
memory = "256"
disk = [ 'tap:aio:/var/lib/xen/images/lvs1,xvda,w', ]
vif = [ 'mac=00:16:3e:2b:02:02, bridge=xenbr2', 'mac=00:16:3e:2b:03:fc, bridge=xenbr3', 
'mac=00:16:3e:2b:04:01, bridge=xenbr4'] ←前の行の続き。間で改行しない。
vfb = ["type=vnc,vncunused=1"]  
uuid = "f83c4a0b-4831-f424-d341-ccf824e91410"
bootloader="/usr/bin/pygrub"
vcpus=1
on_reboot   = 'restart'
on_crash    = 'restart'

他の仮想サーバも同様に設定する。

⑤各サーバを立ち上げてネットワーク設定をする

[root@lvs1 ~]# vi /etc/sysconfig/network-scripts/ifcfg-eth0
# Xen Virtual Ethernet
DEVICE=eth0
BROADCAST=192.168.2.255
HWADDR=00:16:3E:2B:02:02
IPADDR=192.168.2.2
NETMASK=255.255.255.0
NETWORK=192.168.2.0
ONBOOT=yes
[root@lvs1 ~]# vi /etc/sysconfig/network-scripts/ifcfg-eth1
# Xen Virtual Ethernet
DEVICE=eth1
BROADCAST=192.168.3.255
HWADDR=00:16:3E:2B:03:FC
IPADDR=192.168.3.252
NETMASK=255.255.255.0
NETWORK=192.168.3.0
ONBOOT=yes
[root@lvs1 ~]# vi /etc/sysconfig/network-scripts/ifcfg-eth2
# Xen Virtual Ethernet
DEVICE=eth2
BROADCAST=192.168.4.255
HWADDR=00:16:3E:2B:04:01
IPADDR=192.168.4.1
NETMASK=255.255.255.0
NETWORK=192.168.4.0
ONBOOT=yes
[root@lvs1 ~]#

ここで仮想サーバを起動していたら

Error: destroyDevice() takes exactly 3 arguments (2 given)

などというエラーがでて起動しなくなってしまった。これを追っかけていって上記のnetloop nloopbacks=5にたどり着いた次第。

⑥Domain0のiptablesを設定する

Domain0からみると新しいインターフェースdummy0ができるので、その先からの通信を許可する必要がある。ここはDMZなので本当は厳しくフィルタをする必要があるが、まずはテストなのですべて許可にしてしまう。

[root@ml115 ~]# vi /etc/sysconfig/iptables
...
-A RH-Firewall-1-INPUT -i dummy0 -j ACCEPT
...

[root@ml115 ~]# service iptables reload

⑦通信確認

構成図のlvs1とlvs2が出来上がったら、相互にpingを打って通信確認をしよう。

[root@lvs1 ~]# ping 192.168.2.3
PING 192.168.2.3 (192.168.2.3) 56(84) bytes of data.
64 bytes from 192.168.2.3: icmp_seq=1 ttl=64 time=0.968 ms
64 bytes from 192.168.2.3: icmp_seq=2 ttl=64 time=0.384 ms
64 bytes from 192.168.2.3: icmp_seq=3 ttl=64 time=0.451 ms

--- 192.168.2.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.384/0.601/0.968/0.260 ms
[root@lvs1 ~]# ping 192.168.3.253
PING 192.168.3.253 (192.168.3.253) 56(84) bytes of data.
64 bytes from 192.168.3.253: icmp_seq=1 ttl=64 time=0.438 ms
64 bytes from 192.168.3.253: icmp_seq=2 ttl=64 time=0.368 ms
64 bytes from 192.168.3.253: icmp_seq=3 ttl=64 time=0.432 ms

--- 192.168.3.253 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
rtt min/avg/max/mdev = 0.368/0.412/0.438/0.039 ms
[root@lvs1 ~]# ping 192.168.4.2
PING 192.168.4.2 (192.168.4.2) 56(84) bytes of data.
64 bytes from 192.168.4.2: icmp_seq=1 ttl=64 time=0.642 ms
64 bytes from 192.168.4.2: icmp_seq=2 ttl=64 time=0.476 ms
64 bytes from 192.168.4.2: icmp_seq=3 ttl=64 time=0.428 ms

--- 192.168.4.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
rtt min/avg/max/mdev = 0.428/0.515/0.642/0.093 ms
[root@lvs1 ~]#

Xenで複雑な仮想ネットワークを作ろうと考えていて、物理インターフェース数以上のネットワークを作ろうとしている。その際Domain0からはeth0などの実インターフェースではなくdummy0などの仮想インターフェースを使って接続することになる。

dummyインターフェースを使う機能はカーネルモジュールとして実装されていて、CentOS5.0ではデフォルトで利用可能になっていた。しかしifconfig dummy0 up、ifconfig dummy1 upなど複数使おうととしてもdummy0のひとつしか使えなかった。

これはdummyモジュールにnumdummies=<数>というパラメータを渡すことにより増やすことができる。

[root@ml115 ~]# modprobe dummy numdummies=3

これを恒久化したい場合は/etc/modprobe.confに下記を追記する。3にするとdummy0,dummy1,dummy2の計3つを使えるようになる。

options dummy numdummies=3

なお、こういったモジュールのパラメータ情報はmodinfoコマンドでしらべられる。

[root@ml115 ~]# modinfo dummy
filename:       /lib/modules/2.6.18-8.1.15.el5xen/kernel/drivers/net/dummy.ko
license:        GPL
srcversion:     CDD194430BC7DEC14488837
depends:
vermagic:       2.6.18-8.1.15.el5xen SMP mod_unload gcc-4.1
parm:           numdummies:Number of dummy pseudo devices (int)
[root@ml115 ~]#

あとは/etc/sysconfig/network-script/に設定を記述したファイルを用意する。

[root@ml115 ~]# cat /etc/sysconfig/network-script/ifcfg-dummy0
DEVICE=dummy0
BROADCAST=192.168.2.255
IPADDR=192.168.2.254
NETMASK=255.255.255.0
NETWORK=192.168.2.0
ONBOOT=yes

ここまで設定して再起動すると、新しいdummyインターフェースが認識される。

[root@ml115 ~]# ifconfig dummy0
dummy0    Link encap:Ethernet  HWaddr 00:16:3E:2B:02:fe
          inet addr:192.168.2.254  Bcast:192.168.2.255  Mask:255.255.255.0
          inet6 addr: fe80::1ca4:5ff:fe2c:ee8b/64 Scope:Link
          UP BROADCAST RUNNING NOARP  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 b)  TX bytes:294 (294.0 b)

認識しているインターフェースは/sys/class/netから情報が取れる。

[root@ml115 ~]# ls /sys/class/net/dummy0
address    carrier   flags    link_mode  statistics    type
addr_len   dormant   ifindex  mtu        subsystem     uevent
broadcast  features  iflink   operstate  tx_queue_len  weight

CentOS5.0でユーザ認証をLDAP化し、仮想サーバ間のホームディレクトリをNFS4で共有した。次にこれをSambaを使って共有するし、Windows XP端末からアクセスできるようにする。SambaでLDAP認証をするために、ちょっと細かい設定が必要になる。

仮想サーバのディスク容量をオンデマンドで増やすということを書いていながら、先日の記事ではディスクイメージ上に作ったext3ファイルシステムを仮想サーバでそのままマウントしていて、柔軟な容量調整ができていない。後から考えれば当然LVMを使うべきだろうということで、やってみた。

子供の頃から幾度となく空を飛ぶ夢を見た。ヘソのしたあたりにぐっと力をいれるとフワッと浮く。そうして人ごみを跳び越したり2階の部屋に直接いける。ただし浮く量は力の入れ具合に比例し、高く上がるには目一杯力まなければならない、そして力を抜くと落ちてしまうので、あまり自由に飛ぶことも出来ない。

なんでこんな夢を見るんだろうと思っていたが、自分は本当に飛びたいんじゃなかろうかと(遅まきながら)気が付いた。飛行機に乗るのは好きだし、万が一金持ちになったらセスナが欲しいとか思っていた。模型飛行機とかもやってみたいと思っていたが、それらは結局は空を飛びたいという願望が漏れ出たものではなかったか。

そんなふうに思い立って、空を飛ぶ方法を探してみた。ハンググライダーは失速したりダイブしたりして結構危ないらしいので、パラグライダーはどうだろうか。パラシュートにぶら下がって浮いているなんてスピード感がなさそうだが、手軽でいいかもしれない。

しかしパラグライダーは風のコンディションが難しく、そうそう飛べるものでもないらしい。おまけに山から飛ぶので遠いし、よっぽどのエキスパートにならない限り飛べる範囲が限定される。

そこで候補に挙がったのがパワードパラグライダー。背中にエンジンとプロペラを背負ってパラグライダーで飛ぶスポーツだ。エンジンを背負っているので平地から離陸できるし、パラグライダーほどには風にシビアではない。スクールも家から高速で1時間くらいのところにある。よし、これをやってみよう。

申し込んだのは3~5日くらい(コンディションによる)の入門コースで、機材レンタル込みで\31,500というもの。他に毎日\3,000の保険&設備使用料がかかる。

フライトエリアは広い河原を切り開いたもの。近くに高圧線などのない場所が選ばれており、当然のことながら空が広い。特徴的なものといえば四方と周囲の吹き流しと、エリア中央の着地点を示す丸い目印。あとは草サッカー場とか野天駐車場と変わらない。地面は短く刈ってあり、走りやすくなっている。

講習初日は地上でパラグライダーを立ち上げる練習。体にグライダー本体(キャノピーという)をつけて風上に走り、凧揚げのようにキャノピーを飛ばす。それによって布で出来たキャノピーが風をはらみ翼となる。風の状態がよくて初めてなのにそれなりに上げることが出来た。

それから、エンジン(ユニットという)を背負って走る練習もする。ユニットは20kg~30kgくらいの重さがあり、フルパワーにすると50kgくらいの推力を発生する。その力で翼に揚力を与えて飛び立つのだが、背中からぐいぐいと押されながら決して転ばずに風上に向かって勢いをつけて走らなければいけない。その練習として、エンジンをフルパワーにして走ることに慣れるわけだ。

ヘルメットは防音仕様になっていて、エンジン音が半分くらいに小さくなる。他の音は一切聞こえないので、特定省電力の無線受信機が仕込んであって、インストラクターの声が聞こえる。はじめは何から何まで言われたとおりにやればよいので、難しいことはほとんどない。

ここまで練習したんだから今日飛べるんじゃないかと期待したが、さすがに初日は飛ばしてもらえなかった。

あとは30分くらいのビデオを見て終了。エリアには上手い人もいて、ローパス(地面すれすれに飛ぶ)やスパイラル(らせん状に渦を巻きながら降下する)などを軽々とやっている。インストラクターに、風がよければ次回は飛びましょうといわれ、期待をふくらましつつ帰宅した。

プライベートLAN上のホストに対して、インターネット接続のための名前解決とプライベートLAN上の名前解決を提供する。外部からの(外向けの)名前解決はダイナミックDNS環境なので不要、というか出来ない。

CentOS5.0でDHCPサーバを作る

仮想サーバをちょこちょこコピーして増やしたりOSを再インストールしたりとネットワーク環境を頻繁にいじっていると、それぞれの機器にIPアドレスを重複しないように設定するのが面倒くさい。DHCPサーバを立ち上げて自動化しよう。

先日CLIで仮想サーバのインストールができないと書いたが、CentOS5.0でもCLIでやる方法があった。
[root@ml115 ~]# virt-install
Would you like a fully virtualized guest (yes or no)? This will allow you to run unmodified operating systems. no
What is the name of your virtual machine? storage2
How much RAM should be allocated (in megabytes)? 256
What would you like to use as the disk (path)? /var/lib/xen/images/storage2
How large would you like the disk (/var/lib/xen/images/storage2) to be (in gigabytes)? 2
Would you like to enable graphics support? (yes or no) no
What is the install location? http://ftp.jaist.ac.jp/pub/Linux/CentOS/5.0/os/x86_64/

Starting install...
この後kernelが起動してインストールが始まる。めでたしめでたし。

さんざんネタとして書いてきたが、ML115にCentOS5.0+Xenでサーバ環境が整ったため、自宅サーバをML115に切り替えた。インターネットゲートウェイもこれでまかなう。これまで熱暴走とメモリ不足であえいでいたCeleron機は晴れて引退となり、購入後わずか4ヶ月のATerm WR6650Sは無線APとして余生を送ることになった。

面白いのがXenによる仮想サーバ。今どきのマシンはCPU速度は十分なので、メモリさえ積めばそれなりに複雑なシステムも試すことができる。もちろんパフォーマンスは出ないが、それは個人サイトなので問題ない。

期待したMovable Typeの更新処理速度は、確かに速くなったがまだ遅いなぁと感じるレベル。これはもうMovable Typeの問題だな。

Linux BOXでインターネットに接続しているが、WWWサーバは別の仮想サーバで動いていてプライベートIP(192.168.0.100)しかもっていない。よってLinux BOX宛にきたHTTPのリクエストを仮想サーバへあて先NATして届けなくてはいけない。

あて先NATはルーティングの前に行われるので、-A PREROUTINGと付ける。また、あて先NATをした後の通信を許可するルールも必要。

[root@ml115 ~]#iptables -t nat -A PREROUTING -p tcp -i ppp0 --dport 80 -j DNAT --to-destination 192.168.0.100:80
[root@ml115 ~]#iptables -t nat -A PREROUTING -p tcp -i ppp0 --dport 443 -j DNAT --to-destination 192.168.0.100:443
[root@ml115 ~]#iptables -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp -d 192.168.0.100 --dport 80 -j ACCEPT
[root@ml115 ~]#iptables -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp -d 192.168.0.10 --dport 443 -j ACCEPT
[root@ml115 ~]#service iptables save

いろいろ整理して結局出来上がったルールは以下のとおり。

[root@ml115 ~]# cat /etc/sysconfig/iptables
# Generated by iptables-save v1.3.5 on Mon Oct 29 06:04:24 2007
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [791:91944]
:RH-Firewall-1-INPUT - [0:0]
-A INPUT -j RH-Firewall-1-INPUT
-A FORWARD -j RH-Firewall-1-INPUT
-A RH-Firewall-1-INPUT -i lo -j ACCEPT
-A RH-Firewall-1-INPUT -i eth0 -j ACCEPT
-A RH-Firewall-1-INPUT -i ppp0 -p icmp -m icmp --icmp-type any -j ACCEPT
-A RH-Firewall-1-INPUT -i ppp0 -p esp -j ACCEPT
-A RH-Firewall-1-INPUT -i ppp0 -p ah -j ACCEPT
-A RH-Firewall-1-INPUT -i ppp0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A RH-Firewall-1-INPUT -i ppp0 -p tcp -m state --state NEW -m tcp --dport 10022 -j ACCEPT
-A RH-Firewall-1-INPUT -d 192.168.0.100 -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A RH-Firewall-1-INPUT -d 192.168.0.100 -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited
COMMIT
# Completed on Mon Oct 29 06:04:24 2007
# Generated by iptables-save v1.3.5 on Mon Oct 29 06:04:24 2007
*nat
:PREROUTING ACCEPT [574:187784]
:POSTROUTING ACCEPT [13:676]
:OUTPUT ACCEPT [2:171]
-A PREROUTING -i ppp0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.0.100:80
-A PREROUTING -i ppp0 -p tcp -m tcp --dport 443 -j DNAT --to-destination 192.168.0.100:443
-A POSTROUTING -o ppp0 -j MASQUERADE
COMMIT
# Completed on Mon Oct 29 06:04:24 2007
[root@ml115 ~]#