2014年12月8日月曜日

Force10にOpen Network Linuxをインストール

DELLのONIE版Force10Open Network Linux (ONL)を入れてみました。当然サポート対象外になりますので、ご自分の責任において実行しましょう。

ONIE版Force10だと、Cumulus Linuxを使っている人が一般的(?)かと思いますが、同じONIE準拠ならONLも入るんじゃね?と言われ試してみることに。Force10にはx86系を使ったS6000-ONとPowerPCを使ったS4810-ONがあります。ONLでプリビルドされて配布されているものはPowerPC用になるので、S4810-ONが対象です。

素の状態のONIE版Force10なら、最初に起動したときにONIEプロンプトに落ちるはずですが、一旦Cumulus Linuxをインストールしてしまうと、そちらからブートしてしまいます。まずはブートプロンプトに落とすため、U-Bootのイメージブート待ちカウントダウンの段階で、なにかキーを押してU-Bootプロンプトに落とします。

U-Bootには、ONIEを実行するための環境変数がいくつか事前に設定されているので、それを使ってONIEを起動します。

dni_7448-> run onie_bootcmd
(ONIEブートメッセージ)
ONIE:/ # 

ONIEプロンプトが出てきたら、ONLのインストール手順に従って作業を進めます。

ONIE:/ # wget http://opennetlinux.org/binaries/latest.installer
latest.installer 100% |*******************************| 188M 0:00:00 ETA
ONIE:/ # sh latest.installer
(インストールログメッセージ)
Partition Map for MMC device 0 -- Partition Type: DOS
Part Start Sector Num Sectors UUID Type
1 16 31280 00000000-01 83
2 31296 125056 00000000-02 83
3 156352 15883584 00000000-03 83
reading onl-loader
6775021 bytes read in 356 ms (18.1 MiB/s)
WARNING: adjusting available memory to 30000000
## Booting kernel from Legacy Image at 10000000 ...
Image Name:
Image Type: PowerPC Linux Multi-File Image (gzip compressed)
Data Size: 6774957 Bytes = 6.5 MiB
Load Address: 00000000
Entry Point: 00000000
Contents:
Image 0: 3384879 Bytes = 3.2 MiB
Image 1: 3382017 Bytes = 3.2 MiB
Image 2: 8041 Bytes = 7.9 KiB
Verifying Checksum ... OK
## Loading init Ramdisk from multi component Legacy Image at 10000000 ...
## Flattened Device Tree from multi component Image at 10000000
Booting using the fdt at 0x10674184
Uncompressing Multi-File Image ... OK
Loading Ramdisk to 2fcc6000, end 2ffffb01 ... OK
Loading Device Tree to 03ffb000, end 03ffff68 ... OK
setup_arch: bootmem
delta_7448_setup_arch()
arch: exit
Open Network Linux Loader [Open Network Linux 48f7842 (powerpc,2014.10.05.03.03,
48f7842bf909c43a4840e8d827e55edc113c299e)]
Open Network Linux installer [Open Network Linux 8f3e53e (powerpc.all,2014.11.04
.22.55,8f3e53ebcdcd5edea042e15ec852c904a6cafd6c)]

Press Control-C now to enter loader shell
Booting flash2:onl-powerpc.swi
FDT_ERR_NOSPACE: Unable to add reserve for cpu-release-addr!
Starting new kernel
setup_arch: bootmem
delta_7448_setup_arch()
arch: exit
INIT: version 2.88 booting
Using makefile-style concurrent boot in runlevel S.
Starting the hotplug events dispatcher: udevd.
Synthesizing the initial hotplug events...done.
Waiting for /dev to be fully populated...done.
Setting up block and net devices...done.
Setting kernel variables ...done.
Setting up sensors configuration...done.
Setting up resolvconf...done.
Configuring network interfaces...done.
Restoring persistent files...done.
Creating SSH2 RSA key...done.
Creating SSH2 DSA key...done.
Creating SSH2 ECDSA key...done.
INIT: Entering runlevel: 2
Using makefile-style concurrent boot in runlevel 2.
Not starting fancontrol; run pwmconfig first. ... (warning).
Starting enhanced syslogd: rsyslogd.
Starting Fault Agent: faultd.
Loading empty startup-config...failed.
Starting network management services: snmpd.
Starting OpenBSD Secure Shell server: sshd.
Open Network Linux 8f3e53e (powerpc.all,2014.11.04.22.24,8f3e53ebcdcd5edea042e1
5ec852c904a6cafd6c)
onl-powerpc login:
標準のブートイメージでは、ハードウェアに搭載されているスイッチポートは使えません。別途ライセンスを結ぶなどしてチップドライバーを組み入れる必要があります。素のONLをインストールした直後に見えているインターフェースは以下のものでした。

root@onl-powerpc:~# ifconfig -a
dummy0    Link encap:Ethernet HWaddr XX:XX:XX:XX:XX:XX
          BROADCAST NOARP MTU:1500 Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1 Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING MTU:65536 Metric:1
          RX packets:6 errors:0 dropped:0 overruns:0 frame:0
          TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:456 (456.0 B) TX bytes:456 (456.0 B)

ma1       Link encap:Ethernet HWaddr XX:XX:XX:XX:XX:XX
          BROADCAST MULTICAST MTU:1500 Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
          Base address:0xa000

sit0      Link encap:IPv6-in-IPv4
          NOARP MTU:1480 Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

ひとまず起動はしたということで。

2014年4月16日水曜日

OpenStackでNative VXLANテナントを使う

久方ぶりの更新でBloggerの使い方も忘れてるくらいの勢いです。

しばらく前からOpenStackなどが流行っているようですが、すっかり流れに乗り遅れてしまいました。諸般の事情により、最近ようやくOpenStackに触り始めています。とはいうものの、いまさらOpenStackの導入とか書いてもネットの海に埋もれるだけです。なので、まだあまり見かけないNative VXLANをテナントネットワークとして使う設定を、自分のメモという意味も含めて記録しておこうと思います。

ここではOpenStackの導入については「全く」述べません。そのあたりは、巷に溢れているブログなりを参考にしていただければと思います。もっとも、公式のドキュメントがかなりよくできているので、ゼロから一歩一歩導入を試したい人はそちらをご覧になることをお勧めします。簡単に導入したい人向きにはRed Hat Inc.のRDOなども人気が高いようです。

Native VXLAN (以後、単にVXLANと呼びます) をテナントネットワークとして使うためには、いくつか準備が必要です。

  • iproute2がVXLANに対応している
  • NeutronでML2プラグインが使え、かつML2プラグインがVXLANに対応している
以上の条件を整えます。ML2プラグインは最新のOpenStackなら設定するだけで使えるはずです。ML2プラグインへの切り替えについては、あまり情報がないので、簡単にメモを残します。

まず、/etc/neutron/neutron.confでML2プラグインを利用するように設定します。

core_plugin = neutron.plugins.ml2.plugin.Ml2Plugin
service_plugins = neutron.services.l3_router.l3_router_plugin.L3RouterPlugin


続いて、/etc/default/neutron-serverneutron-serverが起動時に読み込む設定ファイルをML2プラグインにします。(Ubuntu 12.04の場合)

NEUTRON_PLUGIN_CONFIG="/etc/neutron/plugins/ml2/ml2_conf.ini"

これらの設定は、今後OpenStackでは標準設定になっていくと思われます。Icehouse以降では設定不要になっているかもしれません。

VXLANでテナントネットワークを構成するためには、L2エージェントとしてLinux Bridgeエージェントを使う必要があります。世にある情報の多くは、Open vSwitchエージェントとGREトンネルによるテナントネットワークの構成例となっているようですので、NeutornのL2エージェントを導入する際に気をつけてください。

ML2プラグインの設定ファイル/etc/neutron/plugins/ml2/ml2_conf.iniは以下のようになります。

[ml2]
tenant_network_types = vxlan,flat
type_drivers = vxlan,flat
mechanism_drivers = linuxbridge

[ml2_type_flat]
flat_networks = public0

[ml2_type_vxlan]
vni_ranges= 1000:2000

[securitygroup]

firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver

Linux Bridgeエージェントの設定ファイル/etc/neutron/plugins/linxbridge_conf.iniは以下のようになります。

[linux_bridge]
physical_interface_mappings = public0:eth0
[vxlan]
enable_vxlan = True
local_ip = (ノードのIPアドレス)
[securitygroup]
firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver

なお、ML2プラグインの設定はneutron-serverが動作するノード (通常は管理ノード) のみで大丈夫です。またLinux Bridgeエージェントの[linux_bridge]セクションの設定はゲートウェイとなるノード (L3エージェントやDHCPエージェントを動作させているノード) で設定するだけで大丈夫です。eth0はゲートウェノードのインターネット側の物理インターフェース名です。コンピュートノードには[vxlan]セクションの設定だけを入れておきます。

VXLANを使う上で注意しなければならないことは、VXLANのカプセル化のため、ペイロードが50バイト小さくなることです。Linuxで普通にVXLAN仮想インターフェースを構成すると、MTUが1450になっていると思います。このままだと、OpenStackの仮想ブリッジ内でMTU 1500のインターフェースと1450のインターフェースが混じることになり、パケットが通らない場合が発生します。これを回避するため、ゲートウェイノードとコンピュートノードが通信する物理インターフェースのMTUをあらかじめ1550に設定しておく必要があります。

テナント共用となる外部ネットワークを作成する場合、外部ネットワークをflatタイプで構成します。以下は外部ネットワーク名をexternal1として、external1-subnet1というサブネットに172.16.0.0/24が割り当てられている場合の構成例です。

neutron net-create external1 \
        --tenant-id ${SERVICE_TENANT_ID} \
        --provider:network_type flat \
        --provider:physical_network public0 \
        --router:external=True
neutron subnet-create external1 172.16.0.0/24 \
        --name external1-subnet1 \
        --tenant-id ${SERVICE_TENANT_ID} \
        --gateway 172.16.0.1 \
        --allocation-pool start=172.16.0.64,end=172.16.0.254 \
        --disable-dhcp \
        --dns-nameserver 172.16.0.1

テナントネットワークはVXLANで構成します。外部ネットワークが作成されていれば、テナントネットワークはDashboardからも作成できますが、コマンドラインで実行する場合は、例えば下のようになります。以下の例は、テナントネットワークとしてdemo-private1を構成し、demo-private1-subnet1という名前で10.0.0.0/24を割り当てる場合の構成例です。

neutron net-create demo-private1 \
        --tenant-id ${TENANT_ID} \
        --provider:network_type vxlan \
        --provider:segmentation_id 1000
neutron subnet-create demo-private1 10.0.0.0/24 \
        --name demo-private1-subnet1 \
        --tenant-id ${TENANT_ID}


2010年12月24日金曜日

App Inventorを使ってみた

Google Japan Developer Relations BlogでApp Inventorが公開βになったと紹介されていたので使ってみました。ちょうど、最近ブログの更新もさぼっていたし。

とりあえず、加速度センサーの値を表示させるアプリを作ってみます。iPhoneでも昔作ったけど、まぁそれなりに手間のかかるコーディングが必要でした。App Inventorでは、なるほど広告通り、あっという間にアプリが出来上がります。一昔前に流行った(いや、流行り損ねた?)Java Beansを彷彿とさせるプログラミング。

まず手元のコンピュータに必要なツール類をインストールする必要があります。ツールはApp Inventor Setupページからダウンロードしましょう。今のところ、Mac、Linux、Windowsをサポートしているようです。あと、Java環境も必要です。SetupページにJava環境のチェックができるページへのリンクが張られているので、手元のコンピュータのJava環境を整備しておきます。

次にAndroid端末の設定をします。エミュレータも提供されているようですが、ちょうど手元にNexus Oneがあるので、これを使うことにします。端末側の設定としては、「提供元不明のアプリ」を許可し、「USBデバッグ」モードをオン、「スリープモードにしない」をオンに設定するだけです。なお、コンピュータと接続中にUSBストレージモードになっているとうまく動作しないため、接続直後にストレージモードになる設定をしている場合は、コンピュータに接続後に手動でストレージモードをオフにする必要があります。

あとは、App Inventorホームでプログラム開始です。とりあえず加速度センサーの値が表示されればいいので、以下のような画面をデザインしました。



テーブルビューを配置して、その中にラベルを6つはめ込んだだけです。あと、不可視コンポーネントとしてAccelerometerSensor1を追加しています。

次に、これらの間の関係を定義するために、画面右上の(ちょっと切れていますが)Open the Blocks Editorをクリックしてブロックエディタを起動します。ここでビジュアルにプログラムするのですが、途中は省略して、最終的に以下のようなブロックダイアグラムを作ります。



AccelerometerSensor1.AccelerationChangedは、加速度センサーの値が変更されたときに実行されるモジュールですので、その中で、センサーの値を表示している3つのラベル(X、Y、Z軸)に各軸のセンサーの値を設定するだけです。

コンピュータに実端末を接続している場合は、ブロックエディタでConnect to Deviceをクリックすると、自動的にプログラムが走り始めます。

プログラムに問題がなければ、App Inventorのページに戻って、Package for Phoneをクリックすると、今作ったプログラムが端末に転送、インストールされます。

まぁ、とても簡単なのですが、果たしてこれ、どれくらいまで細かい内容をプログラムできるのか、もうちょっと遊んでみないと分からないですね。

2010年4月13日火曜日

IPv4 to IPv6, IPv6 to IPv4 translator

ちょっとした必要に迫られて、IPv4とIPv6のプロトコル変換プログラムを作りました。動作は至ってシンプルで、あるひとつのIPv6アドレスを、別のユニークなIPv4アドレスに変換(また、その逆変換)を行うものです。最近流行っている、NAT64のような、複数のIPv6ノードがひとつのIPv4アドレスを共有して通信するものとは異なります。

そもそもの目的は、IPv6のみを使って構築運用されているネットワークの内部ノードを、外部に公開することでした。もちろん、IPv6を使えば、普通に外部からアクセスできるのですが、まだまだIPv6の利用が一般的ではない現在、IPv4での公開も考えなければなりません。こうした目的の場合、一般的にはIPv4とIPv6のデュアルスタック環境にするところです。しかしながら、必ずしもすべてのIPv6ノードがIPv4でアクセスできる必要はありません。運用されているIPv6ノードの中で、サーバとして公開されるものは極わずかであり、多くのノードはそのサーバのサポートをしているだけだからです。そのようなノードに、貴重なIPv4アドレスを割り当てるのはもったいないですし、またデュアルスタックにすることで運用のコストも大きくなりかねません。

そこで、公開サーバの数を収容するために必要十分なIPv4アドレスを用意して、単純に1対1で対応させてしまおう、ということになります。言ってみれば、IPv6への移行が完了するまでの、つなぎの技術ですね。

仕組み自体はNAT64とDNS64のものとほとんど変わりません。違いはトランスポート層のポート番号の変換処理が必要かどうかです。アドレスを1対1で対応させる場合、ポート番号を処理する必要がないので、変換サーバがNATのような状態を持つ必要がなくなります。状態を持たなくてよいので、負荷分散あるいは耐障害性の向上のために、簡単に多重化できるという利点があります。欠点はNAT64に比べてたくさんのIPv4アドレスが必要になることです。なにせ1対1対応ですから。

実装はtunデバイスを使っています。最近のOSなら標準でサポートしているものも多いのではないでしょうか。tunデバイスを使えば、read(2)システムコールとwrite(2)システムコールで生のIPパケットを読み書きできるので、今回のような目的にぴったりです。ユーザ空間で実装できるので、開発やデバッグも簡単になります。当然、転送速度は遅くなると思いますが、開発の簡単さ、もともとの目的がつなぎの技術であることを考えると、そう悪い選択でもないでしょう。

動作はちょっと複雑です。まず、IPv6ノードがIPv4ノードにアクセスする場合から考えてみます。IPv6ノードはIPv4アドレスを持っていないため、まずIPv4アドレスとIPv6アドレスの対応を定義します。ここでは例として、IPv6ネットワークのプレフィックスを2001:db8:0:0::/64、IPv4グローバルアドレス空間を192.0.2.0/24と仮定しましょう。以下のようなアドレスの対応を定義します。

  • 192.0.2.1 <=> 2001:db8:0:0::100

つまり、外部のIPv4ノードが2001:db8:0:0::100と通信したいと思ったときは、192.0.2.1に対して接続すればよいということになります。192.0.2.1に届いたIPv4パケットは、IPv6に変換されて2001:db8:0:0::100に転送されます。このとき、変換後のIPv6パケットの始点アドレスには、通信相手のIPv4アドレスが識別できるよう、IPv6アドレスの一部にIPv4アドレスを埋め込んでおきます。始点アドレスとして使うIPv6プレフィックスはなんでもよいのですが、仮に64::/64を使うとしましょう。外部のIPv4ノードのアドレスが202.214.86.196だった場合、変換後の始点アドレスは64::cad6:56c4となります。IPv4アドレス4バイト分が、IPv6アドレスの下4バイトに埋め込まれた形になります。

逆方向の通信には、上記の手順を逆に適用します。2001:db8:0:0::100から64::cad6:56c4に対してパケットを送信すると、変換サーバでIPv6宛先アドレスの下4バイトからIPv4宛先アドレス202.214.86.196を取り出します。また、あらかじめ定義されたIPv4とIPv6アドレスの対応表から、始点アドレスとして使うIPv4アドレス(この場合は192.0.2.1)を取り出し、IPv4パケットとして転送するのです。

コードはgithubで公開しています。興味のある方は http://github.com/keiichishima/map646 にアクセスしてみてください。forkも大歓迎です。

2009年11月20日金曜日

自分で作るネットワークストレージ (2)

ファイルシステムを作ると言っても、OSネイティブのファイルシステムを作るのは大変です。しかしながら、最近はFUSE (Filesystem in Userspace)を使って手軽にファイルシステムを試作できるようになりました。以前だったら躊躇していたところですが、気軽に試せそうです。

FUSEはOS内部で発生したファイルシステムイベントをユーザー空間のプログラムに通知し、そこで必要な操作を代行させることでOSネイティブのファイルシステムと同様の操作性をファイルシステム利用者に提供しています。イベントの処理といっても、実際はイベントに対応したコールバック関数を記述する形になりますから、特に実装が複雑なわけではありません。FUSEでは様々なイベントに対応するコールバック関数が定義されていますが、すべての関数を実装しなければならないわけではありません。たとえば、シンボリックリンクをサポートしないのであれば、シンボリックリンクに関係する関数を実装する必要はありません。とりあえず今回対応するのは以下の関数です。試作にMacOS XのXcodeテンプレートを使うので、関数名がCocoa APIっぽく書かれていますが、簡単に読み替えることができると思います。

  • ディレクトリ一覧 (contentsOfDirectoryAtPath:error:, opendir(2), readdir(2)など)
  • ファイル情報取得 (attributesOfItemAtPath:userData:error:, stat(2))
  • ファイル情報設定 (setAttributes:ofItemAtPath:userData:error:, chmod(2)など)
  • ファイルオープン (openFileAtPath:mode:userData:error:, open(2))
  • ファイルクローズ (releaseFileAtPath:userData:, close(2))
  • ファイル読み込み (readFileAtPath:userData:buffer:size:offset:error:, read(2))
  • ファイル書き込み (writeFileAtPath:userData:buffer:size:offset:error:, write(2))
  • 新規ディレクトリ作成 (createDirectoryAtPath:attributes:error:, mkdir(2))
  • 新規ファイル作成 (createFileAtPath:attributes:userData:error:, open(2))
  • ファイル移動 (moveItemAtPath:toPath:error:, rename(2))
  • ディレクトリ削除 (removeDirectoryAtPath:error:, rmdir(2))
  • ファイル削除 (removeItemAtPath:error:, unlink(2))

FUSEで読み書き可能なファイルシステムを作る場合、上記の関数を実装すればとりあえず動きます。あとは、これらのイベントの裏で、適切に版管理システムと連携させてあげればよいわけです。版管理システムが提供するインターフェースは以下のようなものになるでしょう。

  • チェックアウト (checkout)
  • 更新 (update)
  • 追加 (add)
  • 複製 (copy)
  • 移動 (move)
  • 削除 (delete)
  • コミット (commit)

今回、版管理システムとしてSubversionを念頭に置いています。ですが、Subversionと同様の概念で構築されているシステムであれば、上記のような抽象化された版管理インターフェースと実際の動作を対応させることで、差し替えもできるのではないかと思います。

FUSEが提供するファイル操作と、版管理システムが提供するファイル操作をじっと見比べてみると、お互いの機能が似ていることがわかります。FUSE側に存在せず、版管理側に存在する操作としてチェックアウトとコミット、逆にFUSEには存在し、版管理システムに存在しない操作としてはファイルのオープンやクローズ、ファイル情報の操作などがあります。これらの差を埋めれば二つのシステムが相互に繋がりそうです。Subversionを前提にがっつり実装してもよいのですが、将来の拡張性を考えて、版管理抽象層を定義し、以下のAPIを版管理抽象層からFUSEファイルシステム側に提供することにしました。

  • 初期化 (revisionControlSetup:)
  • チェックアウト (revisionControlSetup:)
  • 追加 (revisionControllAdd:)
  • 削除 (revisionControlRemove:)
  • 複製 (revisionControlCopy:)
  • 更新 (revisionControlUpdate:)
  • コミット (revisionControlCommit:)
  • タッチ (revisionControlTouch:)
  • 終了処理 (revisionControlCleanup:)
  • 実パス名取得 (revisionControlRealPathForPath:)
  • 制限ファイル名取得 (revisionControlNameIsReservedAtPath:)

いくつか、版管理システムの操作一覧にないAPIを追加しています。初期化と終了処理はよいとして、タッチ、実パス名取得、制限ファイル名取得は、手元の作業コピーでの操作と版管理されているデータを結びつけるために必要となります。

今回、版管理システムを基礎としてファイルシステムを構築するので、ファイルへの操作はオリジナルのファイルではなく、手元に作られた作業コピーに対して行われます。作業結果は、最終的に版管理システムにコミットしなければならないので、どのファイルが操作されたのか履歴を記録しておく必要があります。タッチAPIは、作業コピーで修正されたファイルを版管理抽象層に通知します。

実パス名取得APIは、版管理システム内で使われているパス名を、作業コピー上でのパス名に変換するためのAPIです。今回の試作では、版管理システム内のディレクトリ構造を、手元のPCの特定ディレクトリにマウントして使うことを想定しています。FUSEから通知されるパスはマウントされたディレクトリからの総体パスになりますが、実際に操作できるファイルは作業コピーとして取り出したファイルパスになります。作業コピーを取り出した場所は版管理抽象層しか知らないので、実際のファイルパス名を知りたい場合に抽象層に問い合わせるAPIが必要になります。

制限ファイル名取得APIは、ファイルシステムとして利用できないファイル名を判断するためのAPIです。たとえば、版管理システムとしてSubversionを使う場合、.svnという名前のファイル名、ディレクトリ名は使えません。このAPIを通じて、後ろで使われている版管理システムで禁止されているファイル名を取得します。

とりあえずFUSE関数を上述の版管理抽象層APIで実装してみると、以下のようになります。

  • (FUSE初期化関数)
    • 初期化
    • チェックアウトあるいは更新
  • ディレクトリ一覧
    • 更新
  • ファイル情報取得
    • (作業コピーのファイル情報を取得)
  • ファイル情報設定
    • (作業コピーのファイル情報を取得)
  • ファイルオープン
    • タッチ
  • ファイルクローズ
    • コミット
  • ファイル読み込み
    • (作業コピーのファイルを読み込み)
  • ファイル書き込み
    • (作業コピーのファイルに書き込み)
  • 新規ディレクトリ作成
    • (作業コピーにディレクトリ作成)
    • 追加
  • 新規ファイル作成
    • (作業コピーにファイル作成)
    • 追加
  • ファイル移動
    • (移動元を移動先に)複製
    • (移動元を)削除
  • ディレクトリ削除
    • 削除
  • ファイル削除
    • 削除
  • (FUSE終了関数)
    • コミット
    • 終了処理

まぁ、いろいろと問題はあるのですが、一応動くものにはなります。ソースコードsourceforgeに公開していますので、興味のある人は覗いてみてください。sourceforgeに登録しているコードは、上記以上の機能も実装していますが、それはまた別の機会に。

次回に続きます。

2009年11月11日水曜日

自分で作るネットワークストレージ (1)

ネットワークストレージという考え方は昔からありましたが、それが単体サービスとして有償で提供されるようになったのはここ数年でしょうか。Dropboxなどに代表されるネットワークストレージサービスには一定の利用者がいるようで、解説記事もよく見るようになりました。

データをサーバに保持しておいて、ネットワーク経由でどこからでもアクセスするという考え方は新しいものではありません。ただ、そういったサービスを構築するには、高度なサーバ設定、ネットワーク設定の知識が必要だったため、一般の人が手軽に始めるというわけにはいきませんでした。近年のネットワークストレージサービスは、サーバ設定をサービス提供者側に分離し、クライアントとネットワークの設定を専用アプリケーションにすることでその敷居を下げ、技術者以外の利用者の取り込みに成功したのだと思います。

さて、特に昔からコンピュータネットワークを使っている人には共感してもらえると思いますが、自分のデータを自分の管理の行き届かない場所に預けるのは心配なものです。便利なネットワークストレージサービスですが、大切なデータをそこに保存しても大丈夫なのかどうか、つい考えてしまいます。そうはいっても便利なサービスは使いたい、ということで、自分で運用できないものかと考えるのは技術者として自然なことです。

では、自分にとってネットワークストレージサービスに必要な機能は何か、と考えてみると、以下のような要求がでてきました。

  1. 自分で運用できる
  2. ファイルシステムとして操作できる
  3. ネットワークに接続していなくてもある程度操作できる

要求1は、そもそもの発端なので当然です。要求2は利便性を確保するために重要です。ネットワーク上にデータを保存できても、それを直接ローカルアプリケーションで操作できなければ面倒です。OSのファイルシステムの一部として見えている、もしくは同等の操作性が提供されている必要があります。要求3も、現実の環境を考えると必須といえます。ネットワーク環境は日々向上しているものの、ネットワークに接続できない場所は必ずあるものです。その間、フル機能ではないにせよ、ある程度の操作ができないと使い勝手が落ちてしまいます。

これらの条件を満たすもので、現状一番近いものは版管理システムです。旧くはRCSやCVS、その後現れたSubversion、最近使われる事が多いGitなどが有名です。これらの版管理システムは一種のファイルシステム機能を提供しています。ただ、元々プログラムのソースコードの改変履歴を記録する目的で設計されたシステムですから、OSのファイルシステムと同様には操作できません。ファイルを更新しようとした場合、まず版管理システムに保存されているデータを、通常のファイルシステム上に複製(チェックアウト)し、その複製に対して編集を行い、編集完了後に書き戻し(チェックイン)といった、通常のファイル操作とは異なる粒度でのファイル操作が必要になります。

それならば、その部分をうまく隠蔽し、通常のOSレベルでのファイル操作と同等のインターフェースを提供できれば、自分の欲しいネットワークストレージになるのではないか、しかも版管理機能のおまけ付き、という考えが浮かびます。

実際、そういう試みは過去にありました。かなり古いプロジェクトですが、CVSサーバをNFSマウントするVirtual CVS Filesystemというソフトウェアがsourceforgeに登録されています。ただし、プロジェクトが活動停止してからかなり時間が経っているようです。また、FUSEを用いたSVNレポジトリアクセス用ファイルシステムSvnFSというのもあります。こちらは開発が継続しているようです。ただ、どちらも読み取り専用ファイルシステムで、ネットワークストレージとしては中途半端な状態です。ここはやはり、読み書きできるストレージシステムが欲しいところではないでしょうか。

ということで次回に続きます。

2009年7月22日水曜日

FUSEオペレーションの可視化

FUSE (Filesystem in Userspace) はvfs/vnode APIをユーザ空間のプログラムから利用できるようにするための機構で、OSでサポートされないファイルシステムを容易に追加できます。sshサーバ上のディレクトリにアクセスするためにsshfs-fuseを使っている人も多いのではないでしょうか。

vfs/vnodeアクセスがユーザ空間から見えるので、それを利用すればファイルシステムへのアクセスの様子が見えるはず、ということでUbiGraphを使ってsshfs-fuseのアクセスを可視化してみました。

まずは、sshfs-fuseでマウントしたディレクトリ上で、次のスクリプトを実行してみました。

cd /sshfs
for i in 0 1 2 3 4 5 6 7 8 9 10
do
mkdir $i
cd $i
for j in a b c d e f g
do
mkdir $j
done
done
sleep 2
cd /sshfs
rm -rf 0


11レベルの階層ディレクトリを作り、それぞれの階層に7個のディレクトリを作成した後、すべてのディレクトリを削除しています。各ノードは、ファイル/ディレクトリの実体に最初にアクセスされた段階で描画されます。ですから、初期状態では、トップディレクトリにあるオブジェクトしか見えていません。グラフのノードはファイルかディレクトリを表しており、緑色のノードがディレクトリ、青いノードがファイルです。アクセスされたオブジェクトは、色が赤くなるとともに、そのオブジェクトのファイル名/ディレクトリ名が表示されます。

続いて、sshfs-fuseでマウントしたディレクトリ上で、wgetをコンパイルしてみました。

cd work
tar zxf wget-1.11.tar.gz
cd wget-1.11
sh configure
make
make distclean
cd ..
rm -rf wget-1.11

wget-1.11.tar.gzを展開すると、ファイルの生成に合わせてディレクトリ木が徐々に伸びていくのが分かります。



configureの過程ではwget-1.11を展開したディレクトリ直下のファイルが頻繁にアクセスされており、makeが始まると進み具合に応じて各ディレクトリのファイルが順次アクセスされていくのが見えます。

単にアーカイブを展開、コンパイル、削除しただけですが、可視化することでまた違った感じがします。