既にご存知の方も多いかと思いますが、株式会社SRAを退職いたしました。
SRAには2004年に新卒として入社、以後7年間に渡りIAサーバを中心に、システム構築および運用サービスに従事しておりました。サーバの構築には学生時代から興味をもって取り組んでいたものの、ビジネスとして取り組むITは非常に新鮮で、同社社員、およびお客様方から大変多くのことについて学ぶことができました。自分にとって忘れられない7年間になりました。ありがとうございました。
在籍期間中、職場の同僚やマネージャ陣には大変お世話になりました。直接の業務ではないXen徹底入門の執筆、また、昨年に公開した仮想マシンのしくみの解説スライドなどのプロジェクトに必要な時間をやりくりして来られたのは、職場や上司の理解があり、時には、少なからずのバックアップいただけたという事情もあり、同社の社員としてこれまで業務に取り組めた事をありがたく、大変誇りに思っております。
6/1からの三日間はLinuxCon JAPAN 2011にアテンドさせていただきました。日本中、世界中のエンジニアとまた新たなつながりができました。会期中に受けた刺激で充電し、これから自分がどのようにITインフラストラクチャに関わっていけるかを考えていきたいと思っております。
SRA在職中は、多くの方々に大変お世話になりました。今後も引き続きご指導のほど、よろしくお願いいたします。
Takeshi HASEGAWA aka hasegaw
2011年6月4日土曜日
2011年5月30日月曜日
#ssmjp に参加してきました。
5月26日(水)に開催されたささみの会(#ssmjp、新橋勉強会とか別の名前が色々あるようですが)にてプロジェクトマネジメント的観点からプレゼンテーションをさせていただきました。ちょっと私のスケジュールがテンパっていた都合、事実上私の都合に合わせて開催していただいたような感じで……。 @togakushi さんには大変ご迷惑おかけしました。
さて、プロジェクトマネジメントというと、普通は限られた予算・時間・リソース内でいかに仕事を片付けるかという話が一般的にされるわけですが、今回はそれとはちょっと違います。本業における私の立場では、プロジェクトマネジメントというよりはプロジェクトをリードする立場で、いかにプロジェクトが円滑に回るように、最短で片付くように、という観点から支援していく立場にあります。この立場で仕事をしているうちに思ったことなどを資料にまとめて 30 分ほどお話しさせていただきました。
前日の夜、酔いつぶれた状態で資料を作り始め、途中でやめて寝てしまうという事件があったため(wあまり内容がまとまっていない、私の私見と独断ベースの「仲間と一緒に戦うための心得」みたいな感じになってしまいましたが……。
某社の新人さんも何名かいらっしゃっていたようで……もし、私の話を聞いて、今後、より主体的に仕事に取り組んでくれるような若手になってくれたら ——— この夜の目的としては達成と言えるのかな、とか、そんなことを思っています。
さて、プロジェクトマネジメントというと、普通は限られた予算・時間・リソース内でいかに仕事を片付けるかという話が一般的にされるわけですが、今回はそれとはちょっと違います。本業における私の立場では、プロジェクトマネジメントというよりはプロジェクトをリードする立場で、いかにプロジェクトが円滑に回るように、最短で片付くように、という観点から支援していく立場にあります。この立場で仕事をしているうちに思ったことなどを資料にまとめて 30 分ほどお話しさせていただきました。
前日の夜、酔いつぶれた状態で資料を作り始め、途中でやめて寝てしまうという事件があったため(wあまり内容がまとまっていない、私の私見と独断ベースの「仲間と一緒に戦うための心得」みたいな感じになってしまいましたが……。
某社の新人さんも何名かいらっしゃっていたようで……もし、私の話を聞いて、今後、より主体的に仕事に取り組んでくれるような若手になってくれたら ——— この夜の目的としては達成と言えるのかな、とか、そんなことを思っています。
東京OpenSolaris勉強会 2011.05に参加してきました。
5月28日(土)に開催された、東京OpenSolaris勉強会 2011.05に参加してきました。
@nslope さんに「自宅ZFSで盛り上がろうず!」とお声がけをいただいたので、構成的にヘンタイな我が家のZFS環境について簡単に紹介させていただきました。
OpenSolaris 界隈の方はマニアックな方々ばかりなので今頃私が ZFS 自体の話をしても全然面白くなりませんし、ということで、あくまでもZFS的に非一般的な我が家のZFS環境についての紹介とさせていただきました。
私の自宅では、 CentOS 5 の Xen 環境において OpenSolaris の開発版スナップショットが動いており、 ZFS ファイルサーバとして利用しています。こうしてある理由としてはファイルサーバとしてZFSの最新機能を活用しつつ Linux とのコンソリデーションを実現する、またOpenSolarisに対応できないような安価なハードウェアでもZFSの恩恵を得るために、そういった構成にしています。
ZFSのオイシイところは、信頼性と管理性だと思います。Linuxのmdraidなどは意図せぬ停電やカーネルパニックでアレイの不整合などが起きると大変です。しかし、ZFSの場合は書き込み操作がトランザクション保護されており、中途半端な書き込み操作が多少起きたぐらいではデグレードしません。仮にデグレードしても、 End-to-end checksum による確認が可能なので、デグレ中や復旧作業後にデータが維持できているかどうかを判断できる点も魅力です。また、(喩えれば水と油を1つのバケツに溜めておける、と私はZFSを紹介することが多いのですが)データの管理が非常にフレキシブルなのもポイントです。
私は基本的には「重要なデータは持たない」(データを持つと管理コストが生じるので)という方針にしていますので、仮に手元のデータがロスしても精々数日ヘコむぐらいで済むよう心の覚悟をいつもしている(つもりな)のですが、これまで3年以上の運用期間中に2回のデグレが発生しても、嬉しいことに、データロスにまでは至っていません。また、これまでの経験から、使い始めた当初は色々と罠があった ZFS ですが、だいたいイケるところが見えてきたので、これからも ZFS を使っていくつもりです。
青山のオラクルさんのビルにて Linux の上に乗った OpenSolaris の話をしたり、リプレース時のOS候補は FreeBSD-current だとか話をしたりとかなり KY でしたがニヤニヤしながら聞いてくださった参加者の皆さん、ありがとうございました。
@nslope さんに「自宅ZFSで盛り上がろうず!」とお声がけをいただいたので、構成的にヘンタイな我が家のZFS環境について簡単に紹介させていただきました。
OpenSolaris 界隈の方はマニアックな方々ばかりなので今頃私が ZFS 自体の話をしても全然面白くなりませんし、ということで、あくまでもZFS的に非一般的な我が家のZFS環境についての紹介とさせていただきました。
私の自宅では、 CentOS 5 の Xen 環境において OpenSolaris の開発版スナップショットが動いており、 ZFS ファイルサーバとして利用しています。こうしてある理由としてはファイルサーバとしてZFSの最新機能を活用しつつ Linux とのコンソリデーションを実現する、またOpenSolarisに対応できないような安価なハードウェアでもZFSの恩恵を得るために、そういった構成にしています。
ZFSのオイシイところは、信頼性と管理性だと思います。Linuxのmdraidなどは意図せぬ停電やカーネルパニックでアレイの不整合などが起きると大変です。しかし、ZFSの場合は書き込み操作がトランザクション保護されており、中途半端な書き込み操作が多少起きたぐらいではデグレードしません。仮にデグレードしても、 End-to-end checksum による確認が可能なので、デグレ中や復旧作業後にデータが維持できているかどうかを判断できる点も魅力です。また、(喩えれば水と油を1つのバケツに溜めておける、と私はZFSを紹介することが多いのですが)データの管理が非常にフレキシブルなのもポイントです。
私は基本的には「重要なデータは持たない」(データを持つと管理コストが生じるので)という方針にしていますので、仮に手元のデータがロスしても精々数日ヘコむぐらいで済むよう心の覚悟をいつもしている(つもりな)のですが、これまで3年以上の運用期間中に2回のデグレが発生しても、嬉しいことに、データロスにまでは至っていません。また、これまでの経験から、使い始めた当初は色々と罠があった ZFS ですが、だいたいイケるところが見えてきたので、これからも ZFS を使っていくつもりです。
青山のオラクルさんのビルにて Linux の上に乗った OpenSolaris の話をしたり、リプレース時のOS候補は FreeBSD-current だとか話をしたりとかなり KY でしたがニヤニヤしながら聞いてくださった参加者の皆さん、ありがとうございました。
qpstudy 06 の懇親会に参加してきました。
5月28日(土)に開催された qpstudy 06 の懇親会に参加してきました。 qpstudy は IT インフラストラクチャを扱うエンカイチックな勉強会で、 qpstudy 03 の頃から、都合がつけばできる限り参加するようにしています。これまで勉強会の参加記録などは blog には書いてなかったんですが、折角 trackback 企画があるのでチャレンジ!
(本当は本編にも参加したかったんだけど、東京 OpenSolaris 勉強会 2011.05でテーマとして ZFS を扱うということで、 @nslope さんに私の都合を考慮して(??)日程を決めていただいていた事もあり……昼過ぎ〜夕方には東京 OpenSolaris 勉強会@外苑前、それが終わってから割と急いで大森のニフティさんにハシゴするという感じに……)
本編では @sho7650 さんのリードにより、普段の宴会チックな qpstudy とは全く雰囲気が違う勉強会になっているなーというのを Twitter のタイムライン越しに感じていたのですが、残念ながらそれが終わった頃にやっとこ現地到着。あ、通用口まで迎えにきてくださった @ysaotome さん、ありがとうございます。
懇親会は例によってピザとビールを囲んでの LT 大会です。折角なので私も LT やらせていただきました。
本当は別のネタを仕込んでいたのですが、このスライドのほうが、勉強会本編のテーマにも沿ってるかも知れなくてGoodかな?と思い、セレクト。簡単にご紹介すると、明治35年に行われた八甲田山の雪中行軍のお話をベースに、プロジェクトを円滑を進めるためには以下のような点が重要だよね?という感じでまとめさせていただきました。
今あらためて見るとヘボいスライドだなぁ……
◇
後、もう一本。ちょっと時間が余っているということだったので、 LT で @masudaK さんが発表されていた「海外MLに積極的に出ようよ!」という内容に共感したので、全くの突然でしたが、カーネル/VM探検隊向けに作成した LT 資料でも簡単に発表させてもらいました。
なお、 LT の発表時間実績が 5 分 0 秒ジャストだったのは、、、、、偶然ですw
(本当は本編にも参加したかったんだけど、東京 OpenSolaris 勉強会 2011.05でテーマとして ZFS を扱うということで、 @nslope さんに私の都合を考慮して(??)日程を決めていただいていた事もあり……昼過ぎ〜夕方には東京 OpenSolaris 勉強会@外苑前、それが終わってから割と急いで大森のニフティさんにハシゴするという感じに……)
本編では @sho7650 さんのリードにより、普段の宴会チックな qpstudy とは全く雰囲気が違う勉強会になっているなーというのを Twitter のタイムライン越しに感じていたのですが、残念ながらそれが終わった頃にやっとこ現地到着。あ、通用口まで迎えにきてくださった @ysaotome さん、ありがとうございます。
懇親会は例によってピザとビールを囲んでの LT 大会です。折角なので私も LT やらせていただきました。
本当は別のネタを仕込んでいたのですが、このスライドのほうが、勉強会本編のテーマにも沿ってるかも知れなくてGoodかな?と思い、セレクト。簡単にご紹介すると、明治35年に行われた八甲田山の雪中行軍のお話をベースに、プロジェクトを円滑を進めるためには以下のような点が重要だよね?という感じでまとめさせていただきました。
- スコープを把握する
- 問題を見つけたら対策をとる。判断を先送りしない
- 主体的・積極的に問題に取り組む。他人まかせにしない
今あらためて見るとヘボいスライドだなぁ……
◇
後、もう一本。ちょっと時間が余っているということだったので、 LT で @masudaK さんが発表されていた「海外MLに積極的に出ようよ!」という内容に共感したので、全くの突然でしたが、カーネル/VM探検隊向けに作成した LT 資料でも簡単に発表させてもらいました。
なお、 LT の発表時間実績が 5 分 0 秒ジャストだったのは、、、、、偶然ですw
2011年4月28日木曜日
Xen Meets virtio
開発版バージョンである xen-unstable と最新の qemu を組み合わせることによって virtio-net が Xen でも使えるようになってきたので紹介したいと思います。
■ 必要なもの
■ 設定方法
ドメイン定義ファイルで vif 行を下記イメージで記述します。
またドメインの作成には xl コマンドを使ってください。 xm コマンドだと新しい QEMU に対応できない可能性があります。
■ ゲストOS側の留意事項
Xen と QEMU の割り込み関係の相性が悪いのか、 MSI(-X) による割り込み通知が正しく inject されないようです。現時点の回避策として、ゲスト OS として Linux を起動する際に下記のカーネルパラメータを付けると問題を回避できます。
■ 参考
QEMUUpstream - Xen Wiki
■ 必要なもの
- xen-unstable をレポジトリからひっぱってくる
- qemu を git://xenbits.xen.org/people/aperard/qemu-dm.git から引っ張ってくる。ブランチ qemu-dm-v14 をチェックアウト。
- QEMU のクラッシュを防ぐ vmport パッチ http://ysr.jp/~hasegaw/upstream-qemu_vmport.patch
(vmportにアクセスしてくるような最近のdistroを動かす際に必要) - virtio対応のゲストOS
■ 設定方法
ドメイン定義ファイルで vif 行を下記イメージで記述します。
vif = [ 'type=ioemu, bridge=br0,mac=00:16:3e:09:ac:cd,model=virtio' ]
またドメインの作成には xl コマンドを使ってください。 xm コマンドだと新しい QEMU に対応できない可能性があります。
■ ゲストOS側の留意事項
Xen と QEMU の割り込み関係の相性が悪いのか、 MSI(-X) による割り込み通知が正しく inject されないようです。現時点の回避策として、ゲスト OS として Linux を起動する際に下記のカーネルパラメータを付けると問題を回避できます。
pci=nomsi
■ 参考
QEMUUpstream - Xen Wiki
2011年4月5日火曜日
iptables+xinetdで強引トンネル
久々に変なことしたのでブログネタに。
一定期間、 192.168.10.200/24 のサーバを 192.168.20.200/24 のセグメントに移設することになりました。でもこのサーバは利用者がいるので、なくなると困ります。
この絵だとDNSで名前を付け直せばいいという話もありますが、今回はそういう手を使うわけにはいかなかったので、隣にいる Linux サーバ、 192.168.10.100/24 に 192.168.10.200 のホストも兼ねさせることにしました。
いちばんまっとうな手としては 192.168.10.100/24 のマシンに 192.168.10.200 のアドレスを振って、各アドレスごとに別のデーモンを立ち上げることです。でも、できるだけ既存サーバの 192.168.10.100 には手を加えたくなかったので、 192.168.20.200 の目的のポートへ通信がきたときに redirect するようにしました。(酷
そして、ネットワーク上から 192.168.10.200:22 にアクセスすると、 192.168.10.100:50022 に TCP 接続されるようになりました。今度は、 192.168.10.100:50022 にアクセスが来たら、それを xinetd の TCP リダイレクションでネットワークの果てにある 192.168.20.200:22 に飛ばします。
かなり酷い手ではありますが、とりあえず期間限定なのでOK!
実際には、これをインターネット越しに SSH, HTTP, その他のプロトコルを stunnel で保護しながらトンネルしました。
一定期間、 192.168.10.200/24 のサーバを 192.168.20.200/24 のセグメントに移設することになりました。でもこのサーバは利用者がいるので、なくなると困ります。
この絵だとDNSで名前を付け直せばいいという話もありますが、今回はそういう手を使うわけにはいかなかったので、隣にいる Linux サーバ、 192.168.10.100/24 に 192.168.10.200 のホストも兼ねさせることにしました。
# ifconfig eth0:1 inet 192.168.10.200 netmask 255.255.255.255
いちばんまっとうな手としては 192.168.10.100/24 のマシンに 192.168.10.200 のアドレスを振って、各アドレスごとに別のデーモンを立ち上げることです。でも、できるだけ既存サーバの 192.168.10.100 には手を加えたくなかったので、 192.168.20.200 の目的のポートへ通信がきたときに redirect するようにしました。(酷
# iptables -t nat -A PREROUTING -p tcp --dest 192.168.10.200 --dport 22 -j REDIRECT --to-port 50023
そして、ネットワーク上から 192.168.10.200:22 にアクセスすると、 192.168.10.100:50022 に TCP 接続されるようになりました。今度は、 192.168.10.100:50022 にアクセスが来たら、それを xinetd の TCP リダイレクションでネットワークの果てにある 192.168.20.200:22 に飛ばします。
service hoge-ssh { disable = no socket_type = stream protocol = tcp wait = no user = daemon group = sys redirect = 192.168.20.200 22 }
# echo "hoge-ssh 50022/tcp" >> /etc/services
かなり酷い手ではありますが、とりあえず期間限定なのでOK!
実際には、これをインターネット越しに SSH, HTTP, その他のプロトコルを stunnel で保護しながらトンネルしました。
2011年1月28日金曜日
国際版Galaxy Sに日本語フォント追加
ついカッとなってGalaxy Sに日本語フォントを追加しました。一時的にSuperOneClickでuid=0に昇格して作業。
事前に /sdcard/ に下記ファイルをコピーしておく。
here we go:
メーカー提供データがはいった読み取り専用ファイルシステム/systemを書き換えるので、実際には作業前にファイルシステムレベルで事前にダンプしました。
Androidは初心者なので、難しいこと私には聞かないでね(テヘ
事前に /sdcard/ に下記ファイルをコピーしておく。
- busybox
- DroidSansJapanese.ttf (自分の好きなTrueTypeフォント)
here we go:
- SuperOneClickでuid=0に昇格(Shell root)
- コマンドラインから adb.exe で端末内のシェルを開く
adb shell - dd if=/sdcard/busybox of=/mnt/asec/mount
- chmod 755 /mnt/asec/mount
- /mnt/asec/mount -o remount,rw /system
- dd if=/sdcard/DroidSansJapanese.ttf of=/system/fonts/DroidSansJapanese.ttf
- sync
- 端末を再起動
メーカー提供データがはいった読み取り専用ファイルシステム/systemを書き換えるので、実際には作業前にファイルシステムレベルで事前にダンプしました。
Androidは初心者なので、難しいこと私には聞かないでね(テヘ
2011年1月5日水曜日
FreeBSD VIMAGEを使ったTCP/IPのルーティング デモンストレーション
こんにちわ。 @hasegaw です。あけましておめでとうございます。今年もよろしくお願いいたします!
本日は カーネル/VM Advent Calendar 私の当番!ということで、 FreeBSD 8.0-RELEASE から標準装備になった VIMAGE がどんなモノで、どういう使い方ができるかについて軽く紹介したいと思います。
■ バックグラウンド: 新人研修で「ネットワークを教えることになったが……」
実は2010年4月、弊社の新人研修の一環として、丸1日かけてネットワークの基本について教えることになりました。
新人研修には、これまでコンピュータなどを専攻してきた新人もいますが、まったく違う分野からやってきた人たちもいます。そこで、インターネットを使うとどうして世界中のコンピュータと通信できるのか、ルーティングの動きを体験してもらおうと思いました。
INTEROP で NICT の nictorを度々見かけていたので、これぐらいかっこいいのを作ろう(嘘)と思いました。
さて、どうやって作ろう? VMware 等でたくさんのゲスト OS を用意したりするのもアリですが、それだと、それなりなスペックの PC なども必要になります。できれば私が普段常用しているノートパソコンで全てが完結するレベルで作りたい……と思い、「ああ、いいのが有るじゃないか」。デモ環境のベースとして、久々に VIMAGE を使ってみることにしたのです。
■ VIMAGE とはなんぞや
FreeBSD で利用できる VIMAGE という機能ですが、これは FreeBSD のネットワークスタックを多重化するための機能です。ひとつの FreeBSD カーネル上で複数のネットワークスタックを動かすことができ、それらは全て独立した形で動きます。IPアドレスなどの情報はもちろん、ルーティングテーブルも独立したものになるため、 1 つの FreeBSD カーネルで複数のノードを再現できます。しかも多重化されるのはネットワークスタックと動作中のプロセスだけ。10ノード分程度のエミュレーションならメモリ128MBのちいさなFreeBSD環境をVMware上で動かしてあげれば十分なので、大きさ的にも、今回のデモには最適です。
ところで、 FreeBSD では、 UNIX の世界で広く使われている chroot によるリソースアクセス制御のほかにも jail と呼ばれるコンテナ技術が(たしか) 4.0-RELEASE の頃から実装されています。これは、 jail 内で動作するプロセスは、その jail 内にあるプロセスしか見えなくなるというタイプのもので、今思えば Linux でいう Virtuozzo のような技術に先駆けて実装された PC UNIX 向けの仮想化技術でありました。とはいえ、 jail はあくまでも「関係のないプロセスが見えなくなる」ものであって、ネットワークスタックなどがパーティションされているわけではありませんでした。
話を VIMAGE に戻しましょう。これは元々 FreeBSD Network Stack Virtualization Project にてネットワークの研究目的で実装されたもので、 FreeBSD ベースのシステム上で複数の仮想ルータや仮想サーバを構築できます。また、 GUI 上でネットワークトポロジを作ることによって、1 台の FreeBSD Box の中で、普通にはひとつのカーネルでは構築できないような複雑なトポロジを実現し、試すことができる、というものです。
VIMAGE は当初 4.11-RELEASE 向けに実装されたコードがあり、私自身も 2005 年頃に見つけて色々と遊んでいたのですが、それが、ついに FreeBSD のメインツリーに取り込まれたという形になります。
なお VIMAGE は FreeBSD jail の機能の一部として実装されています。これまでの jail によるプロセス隔離機能、および VIMAGE によるネットワークスタックの多重化を組み合わせることによって、ひとつの FreeBSD Box の中で Virtuozzo のようなパーティションが可能になったのです。
VIMAGE について、 FreeBSD 8.0-RELEASE リリース当初に後藤大地さんがマイコミジャーナルの記事にて解説されているので、こちらも併せてご覧いただくとよいかと思います。
■ VIMAGE を使うための下準備
さて、VIMAGE を使うには、色々と準備をしなければいけません。特にカーネルですが GENERIC カーネルではなく VIMAGE が有効化されたカーネルを自分で作らないといけません。
また VIMAGE は jail の機能の一部であり、 jail が使えるようなイメージの準備をしておかないといけません。平たく言えば chroot 利用時のように、ファイルシステム上のどこかに jail 環境のルートディレクトリとなるディレクトリを準備しなければいけません。(ただ試すだけなら、 FreeBSD box の / を使うこともできます。この場合は、プロセス間の干渉などはできませんが、当然 jail 間でファイルは自由にアクセスできてしまいます)
FreeBSD では jail 環境は現状 /usr/jails/$JAIL_NAME/ というパスで作るのが一般的?なようです。 ports コレクションにある ezjail などを利用すると jail 環境を割と簡単に作れるみたいです。私も ezjail を使ってテスト用 jail 環境を作りました(が、一度デモで使うだけのやっつけ環境だったので後から強引に各 jail 内の構成をごりごり弄りました)。
■ VMAGE jail を起動する
あらかじめ準備した jail 用ツリーを使って、 VIMAGE jail を起動するために下記のスクリプトを書きました。本当は ezjail などの管理機能に任せるのが正しいのでしょうが、作業した時点の ezjail は VIMAGE を正しく扱えなかったため断念したように思います。
上記スクリプトが何をしているかは、見ていただければ判ると思いますが
これで各 VIMAGE Jail で sshd, routed が起動した状態となりました。
■ VIMAGE Jail にネットワークインターフェイスを
ただ、この状態ではまだ各 VIMAGE Jail はループバックインターフェイスしか持っていません。 jexec コマンドを使って VIMAGE Jail 内に入ることはできますが、たとえ親環境からでも TCP/IP 的に到達することはできません。
続けて、ネットワークインターフェイスを各 VM に割り当てていきます。各 VIMAGE 間を接続するために epair インターフェイスを作成し、それを各 VM に割り当てていきます。
これで、 vm1~9 に Peer to Peer な経路がいくつか設定されました。
各 VIMAGE Jail の中では routed が動いていますので、 routed が自動的に隣接ノードを見つけて、ルーティングテーブルを作成してくれます。
■ VIMAGE Jail 内から PING してみる
各 jail の中はクローズドな FreeBSD 環境になっています。もちろん PING などの操作が可能です。
■ VIMAGE Jail 内から traceroute... あれれ?
しかし残念ながら VMAGE jail 内の traceroute は(8.0-RELEASEの段階では)正しく?動作しませんでした。 traceroute がソースアドレスを決定しようとする際に VIMAGE Jail 内でエラーになる処理をするのが原因でした。 traceroute 時に毎回ソースアドレスを指定すれば問題なく動くのですが、新人研修用のテスト環境で traceroute が動かないとなると、それではちょっとアレです。
というわけで、当時ググりまくったら、この問題を改善するパッチが send-pr されていたため、 traceroute にパッチをあててコンパイルし直すと、普通に traceroute できるようになりました。このパッチですが、すでに -STABLE にも入っていると思いますので、 8.1-RELEASE 以降であれば問題は発生しないでしょう。
参考情報: kern/139454: [jail] traceroute does not work inside jail
http://www.freebsd.org/cgi/query-pr.cgi?pr=139454
■ 一度 VIMAGE のことは忘れて……デモグラフィックをどうやって作るか
さて、ここまで動けばとりあえず最低限のデモはできるでしょう。でも、もっと視覚的に訴えるようなモノを作りたいと思っていたので、どうやって実現するかについて考え始めました。もちろん目標は nicter です。(まだ言うか
どうやってアニメーションさせるかを色々考えたのですが(Delphi + Canvasで描くとかDelphi + OpenGLで描くとか)、せいぜい30分も使わないであろうデモのためにあまり時間をかけるわけにはいきません。そこで、このデモを作ろうと思った頃に話題となっていた、 HTML5 Canvas を使ってお手軽に作ってみることにしました。
…描けました。 nicter ほど格好良くないですが、上等です!さらに、出発点、中継点、終点を渡すとアニメーションを開始するための関数、定期的に画面を更新しアニメーションを進めるための関数も書いて、なんなく動き始めました。
■ VIMAGE と デモをどうやって連携させるか……? すみません、フェイクです
さて、ここまでできたら、あとはパケットの流れをもとにアニメーションにどう反映させるか、です。本当なら送信元ホスト、送信先ホストを調べて、ルーティングテーブルなどを解析して、どのようにルーティングするかをシミュレーションするべきでしょう。しかし、どうせ30分使うかどうかのデモにそこまでの時間をかけるのはちょっと厳しいので、tracerouteの出力を解析することにしました。 :p
/usr/sbin/traceroute を実はスクリプトにおきかえて、 traceroute された時にはその内容を同時に各 jail 環境の /tmp/log/traceroute_log.$$ に吐き出すようにしておきます。こうしておけば traceroute するたびにログファイルが生成されるので、それを親環境側の Perl プロセスが回収し、どこからどこに traceroute されたかを確認して、先の HTML 5 Canvas な JavaScript に食わせるデータを生成することにしました。
続いて ping コマンド。これは traceroute と違って途中の経路情報が表示されません。困った。
よし、これでOK (w /tmp/log/配下にログがどんどん溜まっていきます。さらに、誰の traceroute(ping) かは uid を見れば判断できそうです。この情報を使って、 ping/traceroute の実行者が誰なのかわかるようにします。
Perl で作ったログ回収&出力デーモンには、パケットを発射する関数を叩く Javascript を生成させて、それを HTML 5 Canvas な Javascript が差分ダウンロードしてはひたすら eval するクソ仕様としました。本当なら JSON などを使うべきでしょうが。
■ 完成!
実際の動作デモ
http://ysr.jp/~doggie/routedemo/
よし!完成です。あまり見た目とか良くないですが、新人に、このデモ環境に実際にログインしてもらい、思い思いのホストに ping したり traceroute したりしてもらいました。 HTML5 Canvas の Javascript は会場のスクリーンに投影し、誰がどこからどこへパケットを飛ばしているかがわかるようにセッティングして、しばらく遊んでもらいました。
また、これまでの流れのとおり routed が動いているので、途中で経路をダウンさせるとそのうちに違う経路にルーティングが変更されることも確認でき、動的ルーティングというものがどういうものなのかを新人に説明しました。
作業量的には、 VMware 上の FreeBSD を立ち上げるのに手こずったのと(構築環境とデモ環境で VMware のバージョンが違ってハマった)、 VIMAGE の traceroute まわりでハマったのと Javascript は普段書き慣れていないのとで、結局数日かかってしまったのですが、割と面白いおもちゃができたかなという感じです。
■ まとめ
さて、そんなわけで、 FreeBSD のネットワーク仮想化機能である VIMAGE の利用例として 、ひとつの FreeBSD で 9 台分のノードをたてて、 TCP/IP のルーティングをデモンストレーションした事例を紹介しました。あまり広く使われていない機能だと思いますが、このように FreeBSD の VIMAGE を利用すると、OSのインスタンスひとつで、ほぼ最小限のリソースだけでも、いろんなネットワークトポロジを再現できるようになっています。これを使って、いわゆる Virtual Router 的なものを作ってもよいでしょうし、色々と楽しめる機能です。
ただ、 8.0-RELEASE からリリースにはいったばかりの機能であることもあり、以下の点には注意が必要です。
まだ私が気づかなかった問題点などもあるのでしょうか、VIMAGEの機能が今後どのように発展しているのかは興味深く思っており、今後とも注視していきたいと思って居ます。
最後に、カーネル/VM Advent Calendar に誘ってくださった @syuu1228 さん、ありがとうございました。おかげで久々に真面目にテキストを書いた気がします。^^;
本日は カーネル/VM Advent Calendar 私の当番!ということで、 FreeBSD 8.0-RELEASE から標準装備になった VIMAGE がどんなモノで、どういう使い方ができるかについて軽く紹介したいと思います。
■ バックグラウンド: 新人研修で「ネットワークを教えることになったが……」
実は2010年4月、弊社の新人研修の一環として、丸1日かけてネットワークの基本について教えることになりました。
新人研修には、これまでコンピュータなどを専攻してきた新人もいますが、まったく違う分野からやってきた人たちもいます。そこで、インターネットを使うとどうして世界中のコンピュータと通信できるのか、ルーティングの動きを体験してもらおうと思いました。
INTEROP で NICT の nictorを度々見かけていたので、これぐらいかっこいいのを作ろう(嘘)と思いました。
さて、どうやって作ろう? VMware 等でたくさんのゲスト OS を用意したりするのもアリですが、それだと、それなりなスペックの PC なども必要になります。できれば私が普段常用しているノートパソコンで全てが完結するレベルで作りたい……と思い、「ああ、いいのが有るじゃないか」。デモ環境のベースとして、久々に VIMAGE を使ってみることにしたのです。
■ VIMAGE とはなんぞや
FreeBSD で利用できる VIMAGE という機能ですが、これは FreeBSD のネットワークスタックを多重化するための機能です。ひとつの FreeBSD カーネル上で複数のネットワークスタックを動かすことができ、それらは全て独立した形で動きます。IPアドレスなどの情報はもちろん、ルーティングテーブルも独立したものになるため、 1 つの FreeBSD カーネルで複数のノードを再現できます。しかも多重化されるのはネットワークスタックと動作中のプロセスだけ。10ノード分程度のエミュレーションならメモリ128MBのちいさなFreeBSD環境をVMware上で動かしてあげれば十分なので、大きさ的にも、今回のデモには最適です。
ところで、 FreeBSD では、 UNIX の世界で広く使われている chroot によるリソースアクセス制御のほかにも jail と呼ばれるコンテナ技術が(たしか) 4.0-RELEASE の頃から実装されています。これは、 jail 内で動作するプロセスは、その jail 内にあるプロセスしか見えなくなるというタイプのもので、今思えば Linux でいう Virtuozzo のような技術に先駆けて実装された PC UNIX 向けの仮想化技術でありました。とはいえ、 jail はあくまでも「関係のないプロセスが見えなくなる」ものであって、ネットワークスタックなどがパーティションされているわけではありませんでした。
話を VIMAGE に戻しましょう。これは元々 FreeBSD Network Stack Virtualization Project にてネットワークの研究目的で実装されたもので、 FreeBSD ベースのシステム上で複数の仮想ルータや仮想サーバを構築できます。また、 GUI 上でネットワークトポロジを作ることによって、1 台の FreeBSD Box の中で、普通にはひとつのカーネルでは構築できないような複雑なトポロジを実現し、試すことができる、というものです。
VIMAGE は当初 4.11-RELEASE 向けに実装されたコードがあり、私自身も 2005 年頃に見つけて色々と遊んでいたのですが、それが、ついに FreeBSD のメインツリーに取り込まれたという形になります。
なお VIMAGE は FreeBSD jail の機能の一部として実装されています。これまでの jail によるプロセス隔離機能、および VIMAGE によるネットワークスタックの多重化を組み合わせることによって、ひとつの FreeBSD Box の中で Virtuozzo のようなパーティションが可能になったのです。
VIMAGE について、 FreeBSD 8.0-RELEASE リリース当初に後藤大地さんがマイコミジャーナルの記事にて解説されているので、こちらも併せてご覧いただくとよいかと思います。
■ VIMAGE を使うための下準備
さて、VIMAGE を使うには、色々と準備をしなければいけません。特にカーネルですが GENERIC カーネルではなく VIMAGE が有効化されたカーネルを自分で作らないといけません。
options VIMAGE nooptions SCTP
また VIMAGE は jail の機能の一部であり、 jail が使えるようなイメージの準備をしておかないといけません。平たく言えば chroot 利用時のように、ファイルシステム上のどこかに jail 環境のルートディレクトリとなるディレクトリを準備しなければいけません。(ただ試すだけなら、 FreeBSD box の / を使うこともできます。この場合は、プロセス間の干渉などはできませんが、当然 jail 間でファイルは自由にアクセスできてしまいます)
FreeBSD では jail 環境は現状 /usr/jails/$JAIL_NAME/ というパスで作るのが一般的?なようです。 ports コレクションにある ezjail などを利用すると jail 環境を割と簡単に作れるみたいです。私も ezjail を使ってテスト用 jail 環境を作りました(が、一度デモで使うだけのやっつけ環境だったので後から強引に各 jail 内の構成をごりごり弄りました)。
■ VMAGE jail を起動する
あらかじめ準備した jail 用ツリーを使って、 VIMAGE jail を起動するために下記のスクリプトを書きました。本当は ezjail などの管理機能に任せるのが正しいのでしょうが、作業した時点の ezjail は VIMAGE を正しく扱えなかったため断念したように思います。
#!/usr/local/bin/bash sysctl -w security.jail.socket_unixiproute_only=0 sysctl -w security.jail.allow_raw_sockets=1 for i in 1 2 3 4 5 6 7 8 9; do jail -c vnet host.hostname=vm${i} name=vm${i} path=/usr/jails/vm${i} persist jexec vm${i} sysctl -w net.inet.ip.forwarding=1 jexec vm${i} ifconfig lo0 127.0.0.1/24 up jexec vm${i} /etc/rc.d/sshd onestart jexec vm${i} routed -s -m cp /root/master.passwd /usr/jails/vm${i}/etc/master.passwd jexec vm${i} pwd_mkdb /etc/master.passwd jexec vm${i} pwd_mkdb -p /etc/master.passwd done
上記スクリプトが何をしているかは、見ていただければ判ると思いますが
- VIMAGE Jail 「vmX 」を作成
- TCP/IPのルーティングを許可(ルータ化)
- とりあえず強引にループバックデバイスを立ち上げる
- OpenSSHのサーバを立ち上げる
- 動的ルーティングデーモン(routed)を立ち上げる
- 親環境の /etc/master.passwd ファイルを jail 内にコピーし、パスワードデータベースを更新する
これで各 VIMAGE Jail で sshd, routed が起動した状態となりました。
netdemo# ps -auxww | grep J root 1032 0.0 1.5 6676 3680 ?? IsJ 9:27AM 0:00.00 /usr/sbin/sshd root 1034 0.0 0.5 3348 1368 ?? SsJ 9:27AM 0:00.64 routed -s -m root 1047 0.0 1.6 6676 4000 ?? IsJ 9:27AM 0:00.01 /usr/sbin/sshd root 1049 0.0 0.5 3348 1368 ?? SsJ 9:27AM 0:00.32 routed -s -m root 1062 0.0 1.6 6676 4000 ?? IsJ 9:27AM 0:00.00 /usr/sbin/sshd root 1064 0.0 0.5 3348 1368 ?? SsJ 9:27AM 0:00.17 routed -s -m root 1077 0.0 1.6 6676 4008 ?? IsJ 9:27AM 0:00.00 /usr/sbin/sshd root 1079 0.0 0.5 3348 1360 ?? SsJ 9:28AM 0:00.11 routed -s -m root 1092 0.0 1.6 6676 3996 ?? IsJ 9:28AM 0:00.00 /usr/sbin/sshd root 1094 0.0 0.5 3348 1360 ?? SsJ 9:28AM 0:00.16 routed -s -m root 1107 0.0 1.6 6676 3996 ?? IsJ 9:28AM 0:00.00 /usr/sbin/sshd root 1109 0.0 0.5 3348 1360 ?? SsJ 9:28AM 0:00.16 routed -s -m root 1122 0.0 1.6 6676 3996 ?? IsJ 9:28AM 0:00.00 /usr/sbin/sshd root 1124 0.0 0.5 3348 1360 ?? SsJ 9:28AM 0:00.18 routed -s -m root 1137 0.0 1.6 6676 4000 ?? IsJ 9:28AM 0:00.00 /usr/sbin/sshd root 1139 0.0 0.5 3348 1360 ?? SsJ 9:28AM 0:00.17 routed -s -m root 1152 0.0 1.6 6676 3996 ?? IsJ 9:28AM 0:00.00 /usr/sbin/sshd root 1154 0.0 0.5 3348 1360 ?? SsJ 9:28AM 0:00.17 routed -s -m
■ VIMAGE Jail にネットワークインターフェイスを
ただ、この状態ではまだ各 VIMAGE Jail はループバックインターフェイスしか持っていません。 jexec コマンドを使って VIMAGE Jail 内に入ることはできますが、たとえ親環境からでも TCP/IP 的に到達することはできません。
続けて、ネットワークインターフェイスを各 VM に割り当てていきます。各 VIMAGE 間を接続するために epair インターフェイスを作成し、それを各 VM に割り当てていきます。
# vm1 - vm2 ifconfig epair create ifconfig epair0a vnet vm1 ifconfig epair0b vnet vm2 jexec vm1 ifconfig epair0a 10.0.10.1/24 up jexec vm2 ifconfig epair0b 10.0.10.2/24 up # vm1 - vm3 ifconfig epair create ifconfig epair1a vnet vm1 ifconfig epair1b vnet vm3 jexec vm1 ifconfig epair1a 10.0.20.1/24 up jexec vm3 ifconfig epair1b 10.0.20.2/24 up # vm2 - vm3 ifconfig epair create ifconfig epair2a vnet vm2 ifconfig epair2b vnet vm3 jexec vm2 ifconfig epair2a 10.0.30.1/24 up jexec vm3 ifconfig epair2b 10.0.30.2/24 up # vm1 - vm4 ifconfig epair create ifconfig epair3a vnet vm1 ifconfig epair3b vnet vm4 jexec vm1 ifconfig epair3a 10.0.40.1/24 up jexec vm4 ifconfig epair3b 10.0.40.2/24 up # vm1 - vm5 ifconfig epair create ifconfig epair4a vnet vm1 ifconfig epair4b vnet vm5 jexec vm1 ifconfig epair4a 10.0.50.1/24 up jexec vm5 ifconfig epair4b 10.0.50.2/24 up # vm2 - vm6 ifconfig epair create ifconfig epair5a vnet vm2 ifconfig epair5b vnet vm6 jexec vm2 ifconfig epair5a 10.0.60.1/24 up jexec vm6 ifconfig epair5b 10.0.60.2/24 up # vm2 - vm7 ifconfig epair create ifconfig epair6a vnet vm2 ifconfig epair6b vnet vm7 jexec vm2 ifconfig epair6a 10.0.70.1/24 up jexec vm7 ifconfig epair6b 10.0.70.2/24 up # vm3 - vm8 ifconfig epair create ifconfig epair7a vnet vm3 ifconfig epair7b vnet vm8 jexec vm3 ifconfig epair7a 10.0.80.1/24 up jexec vm8 ifconfig epair7b 10.0.80.2/24 up # vm3 - vm9 ifconfig epair create ifconfig epair8a vnet vm3 ifconfig epair8b vnet vm9 jexec vm3 ifconfig epair8a 10.0.90.1/24 up jexec vm9 ifconfig epair8b 10.0.90.2/24 up
これで、 vm1~9 に Peer to Peer な経路がいくつか設定されました。
各 VIMAGE Jail の中では routed が動いていますので、 routed が自動的に隣接ノードを見つけて、ルーティングテーブルを作成してくれます。
netdemo# jexec vm1 netstat -r Routing tables Internet: Destination Gateway Flags Refs Use Netif Expire 10.0.10.0 link#2 U 1 0 epair0 vm1 link#2 UHS 0 0 lo0 10.0.20.0 link#3 U 1 0 epair1 vm1 link#3 UHS 0 0 lo0 10.0.30.0 vm2 UG 0 0 epair0 10.0.40.0 link#4 U 1 0 epair3 vm1 link#4 UHS 0 0 lo0 10.0.50.0 link#5 U 1 0 epair4 vm1 link#5 UHS 0 0 lo0 10.0.60.0 vm2 UG 0 0 epair0 10.0.70.0 vm2 UG 0 0 epair0 10.0.80.0 vm3 UG 0 0 epair1 10.0.90.0 vm3 UG 0 0 epair1 localhost link#1 UH 0 0 lo0 Internet6: (省略)
■ VIMAGE Jail 内から PING してみる
各 jail の中はクローズドな FreeBSD 環境になっています。もちろん PING などの操作が可能です。
netdemo# jexec vm1 ping -c 3 vm5 Version 1.4a12+FreeBSD Usage: traceroute [-adDeFInrSvx] [-f first_ttl] [-g gateway] [-i iface] [-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr] [-t tos] [-w waittime] [-A as_server] [-z pausemsecs] host [packetlen] PING vm5 (10.0.50.2): 56 data bytes 64 bytes from 10.0.50.2: icmp_seq=0 ttl=64 time=1.204 ms 64 bytes from 10.0.50.2: icmp_seq=1 ttl=64 time=0.438 ms 64 bytes from 10.0.50.2: icmp_seq=2 ttl=64 time=0.147 ms --- vm5 ping statistics --- 3 packets transmitted, 3 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.147/0.596/1.204/0.446 ms
■ VIMAGE Jail 内から traceroute... あれれ?
しかし残念ながら VMAGE jail 内の traceroute は(8.0-RELEASEの段階では)正しく?動作しませんでした。 traceroute がソースアドレスを決定しようとする際に VIMAGE Jail 内でエラーになる処理をするのが原因でした。 traceroute 時に毎回ソースアドレスを指定すれば問題なく動くのですが、新人研修用のテスト環境で traceroute が動かないとなると、それではちょっとアレです。
というわけで、当時ググりまくったら、この問題を改善するパッチが send-pr されていたため、 traceroute にパッチをあててコンパイルし直すと、普通に traceroute できるようになりました。このパッチですが、すでに -STABLE にも入っていると思いますので、 8.1-RELEASE 以降であれば問題は発生しないでしょう。
参考情報: kern/139454: [jail] traceroute does not work inside jail
http://www.freebsd.org/cgi/query-pr.cgi?pr=139454
netdemo# jexec vm1 traceroute vm6 traceroute to vm6 (10.0.60.2), 64 hops max, 40 byte packets 1 vm2 (10.0.10.2) 1.274 ms 0.294 ms 0.214 ms 2 vm6 (10.0.60.2) 1.919 ms 0.404 ms 0.438 ms
■ 一度 VIMAGE のことは忘れて……デモグラフィックをどうやって作るか
さて、ここまで動けばとりあえず最低限のデモはできるでしょう。でも、もっと視覚的に訴えるようなモノを作りたいと思っていたので、どうやって実現するかについて考え始めました。もちろん目標は nicter です。(まだ言うか
どうやってアニメーションさせるかを色々考えたのですが(Delphi + Canvasで描くとかDelphi + OpenGLで描くとか)、せいぜい30分も使わないであろうデモのためにあまり時間をかけるわけにはいきません。そこで、このデモを作ろうと思った頃に話題となっていた、 HTML5 Canvas を使ってお手軽に作ってみることにしました。
…描けました。 nicter ほど格好良くないですが、上等です!さらに、出発点、中継点、終点を渡すとアニメーションを開始するための関数、定期的に画面を更新しアニメーションを進めるための関数も書いて、なんなく動き始めました。
■ VIMAGE と デモをどうやって連携させるか……? すみません、フェイクです
さて、ここまでできたら、あとはパケットの流れをもとにアニメーションにどう反映させるか、です。本当なら送信元ホスト、送信先ホストを調べて、ルーティングテーブルなどを解析して、どのようにルーティングするかをシミュレーションするべきでしょう。しかし、どうせ30分使うかどうかのデモにそこまでの時間をかけるのはちょっと厳しいので、tracerouteの出力を解析することにしました。 :p
vm1# cat /usr/sbin/traceroute #!/bin/sh export PATH=/usr/sbin/orig:$PATH # mkdir -p /tmp/log LOG=/tmp/log/traceroute_log.$$ traceroute $* | tee $LOG
/usr/sbin/traceroute を実はスクリプトにおきかえて、 traceroute された時にはその内容を同時に各 jail 環境の /tmp/log/traceroute_log.$$ に吐き出すようにしておきます。こうしておけば traceroute するたびにログファイルが生成されるので、それを親環境側の Perl プロセスが回収し、どこからどこに traceroute されたかを確認して、先の HTML 5 Canvas な JavaScript に食わせるデータを生成することにしました。
続いて ping コマンド。これは traceroute と違って途中の経路情報が表示されません。困った。
vm1# cat /sbin/ping #!/bin/sh export PATH=/usr/sbin/orig:$PATH # mkdir -p /tmp/log LOG=/tmp/log/traceroute_log.$$ ( traceroute $* > $LOG ) & ping $*
よし、これでOK (w /tmp/log/配下にログがどんどん溜まっていきます。さらに、誰の traceroute(ping) かは uid を見れば判断できそうです。この情報を使って、 ping/traceroute の実行者が誰なのかわかるようにします。
$ cd /tmp/log $ ls -l total 8 -rw-r--r-- 1 root wheel 0 Dec 29 00:54 traceroute_log.1436 -rw-r--r-- 1 root wheel 50 Dec 29 00:55 traceroute_log.1453 -rw-r--r-- 1 root wheel 50 Dec 29 00:58 traceroute_log.1458 -rw-r--r-- 1 root wheel 100 Dec 29 00:58 traceroute_log.1461 -rw-r--r-- 1 hasegaw wheel 100 Dec 29 01:36 traceroute_log.1584
Perl で作ったログ回収&出力デーモンには、パケットを発射する関数を叩く Javascript を生成させて、それを HTML 5 Canvas な Javascript が差分ダウンロードしてはひたすら eval するクソ仕様としました。本当なら JSON などを使うべきでしょうが。
■ 完成!
実際の動作デモ
http://ysr.jp/~doggie/routedemo/
よし!完成です。あまり見た目とか良くないですが、新人に、このデモ環境に実際にログインしてもらい、思い思いのホストに ping したり traceroute したりしてもらいました。 HTML5 Canvas の Javascript は会場のスクリーンに投影し、誰がどこからどこへパケットを飛ばしているかがわかるようにセッティングして、しばらく遊んでもらいました。
また、これまでの流れのとおり routed が動いているので、途中で経路をダウンさせるとそのうちに違う経路にルーティングが変更されることも確認でき、動的ルーティングというものがどういうものなのかを新人に説明しました。
作業量的には、 VMware 上の FreeBSD を立ち上げるのに手こずったのと(構築環境とデモ環境で VMware のバージョンが違ってハマった)、 VIMAGE の traceroute まわりでハマったのと Javascript は普段書き慣れていないのとで、結局数日かかってしまったのですが、割と面白いおもちゃができたかなという感じです。
■ まとめ
さて、そんなわけで、 FreeBSD のネットワーク仮想化機能である VIMAGE の利用例として 、ひとつの FreeBSD で 9 台分のノードをたてて、 TCP/IP のルーティングをデモンストレーションした事例を紹介しました。あまり広く使われていない機能だと思いますが、このように FreeBSD の VIMAGE を利用すると、OSのインスタンスひとつで、ほぼ最小限のリソースだけでも、いろんなネットワークトポロジを再現できるようになっています。これを使って、いわゆる Virtual Router 的なものを作ってもよいでしょうし、色々と楽しめる機能です。
ただ、 8.0-RELEASE からリリースにはいったばかりの機能であることもあり、以下の点には注意が必要です。
- カーネルの再コンパイルが必要(GENERICカーネルではサポートされない)
- 一部コマンドが期待通りに動作しない可能性がある(今回であれば traceroute )
まだ私が気づかなかった問題点などもあるのでしょうか、VIMAGEの機能が今後どのように発展しているのかは興味深く思っており、今後とも注視していきたいと思って居ます。
最後に、カーネル/VM Advent Calendar に誘ってくださった @syuu1228 さん、ありがとうございました。おかげで久々に真面目にテキストを書いた気がします。^^;
登録:
投稿 (Atom)