こういうものが欲しいなと思いました。
- vagrant upしたら外部にWebサーバが公開できる
- グローバルIPアドレスの利用量は最小限にしたい
- vagrant up, vagrant destroyはカジュアルにやりたい
vagrantで起動されるVirtual BoxのVMはデフォルトでNATされるので、もともとグローバルIPアドレスは無駄になりません。でもそのままだとポートフォワードをしないといけないので手間がかかるのと、複数のVMが起動しているときにポート番号を変えないといけないのはある程度の規則が必要になります。そもそもURLにデフォルトではないポート番号が書かれているのはダサい。
よって、なんらかのリバースプロキシを利用して80/tcpで公開しつつ、Virtual Hostで複数のVMにアクセスを振り分けることにします。次に問題となるのはVirtual BoxのNAT。Virtual BoxのNATはよくあるLANを覆うタイプではなく、VM個別にインスタンス(と言えばいいのかな)が存在していて、すべてのVMに同じIPアドレスが割り振られます。つまりVM同士の通信はNATに接続されたインタフェースを通じて行うことはできず、たとえリバースプロキシを用意してもVirtual BoxのNATにいる限り無駄になります。
今回はbr0をホスト上に作成して、各VMの2つ目のNICをここにブリッジ接続させることにしました。br0は物理NICには接続していません。内部ネットワークとしてだけ使いますが、ホストマシンからも通信できるようにするために、Virtual Boxのinternal networkではなくてホストのブリッジにしました。vagrantの設定上はpublic_networkとしてbr0を:bridgeに指定するだけなので、とても簡単。1つ目のNICはそのままVirtual BoxのNATに接続したままにします。vagrant upしたあとにsshの転送設定がここに向かうのでそれを生かしたままとするためです。
br0に接続したVMとしてVyattaを1つ用意します。各VMが外に出て行く時はこのVyattaがNATするようにします。それからDHCPもこのVyattaにやらせます。vagrant upしてVirtual BoxのNATからIPアドレスが割り当てられたあと、このVyattaからDHCPでもうひとつのIPアドレスと、デフォルトゲートウェイを受け取るので、実際の通信はこちらに向きますが、vagrant sshだけはVirtual BoxのNAT側から直接接続できる状態になります。ここでは、br0に接続するVMは172.16.100.0/24に属することとし、Vyattaが適当な範囲でIPアドレスを払い出すことにします。
次にbr0に接続するVMをもう一つつくってnginxをインストールします。外部公開するためには2つのNICを用意して一方は例えばeth0にブリッジしてグローバルIPアドレス、もう一方はbr0にブリッジして適当な固定のプライベートIPアドレスを振ります。
公開用のグローバルIPアドレスに対して適当なcatch allのホスト名を設定します。たとえば*.rp1.kawataso.net IN A 10.0.0.100みたいな感じです。例なのでプライベートアドレスを指定しています。
nginxのVirtual Hostを設定するserver_nameのパラメータは正規表現を使うことができ、更に一部をキャプチャして他の設定から参照することができます。
こういう設定を書いてやることで、vNNN.rp1.kawataso.netにアクセスすることで172.16.100.NNNにアクセスが振り分けられるようになります。あたまにvをつけているのは、なんとなく数字で始まるホスト名よりはマシかなと思った程度の理由です。
server { listen 80; server_name ~^v(?<num>\d+)\.rp1\.kawataso\.net$; location / { proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://172.16.100.$num:80; } }
これで、vagrant upしてhttpサーバが起動すれば、外部からすぐにアクセスできるようになります。vagrant destroyしてvagrant upするとIPアドレスが変わっちゃうのでVyattaのDHCPリースを確認するとかvagrant sshしてIPアドレスを確認する必要はありますが、いずれにしてもその確認だけできれば、URLの頭を変えれば追従できます。それも本当は手抜きをしたいので、Vyatta側で新規のDHCPリースがあったら何か適当な方法で通知するとか、vagrantのBoxを作りこんで起動時に取得したアドレスを通知するみたいなことができればいいですね。Boxに依存しない方法のほうがいいなと思うのでVyatta側でなんとかしたいところです。あるいはサブネット全体にhttpの死活監視をすれば起動したサーバのhttpステータスがOKになるという通知で代用もできそうですが、監視ツールをそうやって使うのはちょっと違うような。
さて、作業記録としてとりあえず書いてみたのですが、これは図が必要ですね。そのうち書こうとおもいます。
2013-08-12: 図を描きました。描いてみればシンプルなものです。
あと設定の引用で
server_name ~^v(?\d+)\.rp1\.kawataso\.net$;
は間違っていたので以下のように修正しています。
server_name ~^v(?\d+)\.rp1\.kawataso\.net$;