2012年4月22日日曜日

Virtual boxのNAT経由の外部接続について

かなり久しぶりの更新です。



私物のMacでWebアプリケーションの開発を行うことが多いのですが、MacにLAMP環境をいれたりすることに抵抗があるので、なるべくVirtual Boxを上で開発を行うようにしています。

Virtual Boxを使う際ですが、ネットワーク環境がかわっても接続できるように以下のような設定をしています。

 外部接続用  NATアダプタ
   内部接続用  host-onlyアダプタ

他にBridge接続というゲストOSにIPアドレスを割り当てる方法があるのですが、これを使う2つのIPアドレスを取得することになり、モバイルルーターなどで外で使う場合かなり不便します。特に一旦ブラウザで認証するような公衆無線Lan環境下ではゲストOS内でブラウザをたちあげる必要があり、x windowなどいれていないsever版などではかなり難儀したので使用を封印し、外部アクセスはNAT経由のみにしています。

NAT経由でもポートフォワードの設定をいれることで、ssh接続は設定すれば可能なのですがその設定が面倒なのとmysqlなどの接続時にわざわざポートフォワードするはめになり不便なので、ホストOSとゲストOSの通信はhost-onlyアダプタを利用しています。


NAT使って接続する 場合、本来であれば、家からオフィスに移動してもホストOSをルータに接続しにいくので、外部接続はゲストOSのネットワーク設定さえ切り替わっていればそのままつながるはずですが、時々つながらないことがありました。ネットワークを再起動すると名前解決できるようになるのですが、これではNATを使っている意味がありません。


面倒だなーと放置していたのですが、ちょっと調べてみると名前解決だけうまくいっていないことがわかりました。
/etc/resolvedをみたところ、ルータのアドレスを参照するようになっていました。


ホストOSが参照しているネームサーバーになっていたので、linuxのネームサーバをgoogle public DNSに変えたところ、名前解決できるようになりました。

わーい!


と思ったのつかのま再起動したらまたつながくなりました。


確認したところ、/etc/resolvedの記述が再びルータのアドレスになっていました。どうやらVMがホストOSが参照しているネームサーバに勝手に書き換えてしまうようです。


ホストOSのネットワーク設定も、ネームサーバをネットワークに依存しないものにしておく必要があるようです。(プロバイダからもらったネームサーバをちゃんと登録している方は、こんなことにはまらないかもしれません。)

というわけで、ホストOSのネームサーバをgoogle dnsに変更することにしました。


これで、VM再起動後も無事ネットワークが変わっても外にでれるようになりました。


同様の現象がおきている人は、ゲストOSのネームサーバーにGoogle Public DNSを足すと幸せになります。

2011年1月10日月曜日

Processing サブディスプレイでフルスクリーン

ながらく謎のままだったProcessingでサブディスプレイにフルスクリーンで表示する方法を調査してみした。ひとまず動いたので共有します。


import java.awt.*;

Rectangle monitor = new Rectangle();
boolean bSubdisplay = true;

void setup() { 
  GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
  GraphicsDevice[] gs = ge.getScreenDevices();  
  GraphicsDevice gd = gs[0];
  
  //サブディスプレイがある場合は上書き
  if (gs.length == 2 && bSubdisplay)
  {
    gd = gs[1];
  }
  
  GraphicsConfiguration[] gc = gd.getConfigurations();
  monitor = gc[0].getBounds();

  println(monitor.x + " " + monitor.y + " " + monitor.width + " " + monitor.height);
  size(monitor.width, monitor.height);
  background(0);
}

void draw() {
  frame.setLocation(monitor.x, monitor.y);
  frame.setAlwaysOnTop(true); 
  stroke(255);
  line(0,0,width,height);
}  

public void init() {
  frame.removeNotify();
  frame.setUndecorated(true);
  super.init();
} 

2010年1月17日日曜日

Virtual Boxの共有フォルダ

macbookのVirtual Boxにインストールし、Debian LennyをゲストOSとしていれてみた。

debian があまり使いなれていないのでソース編集はmac側でやりたい。
mac上のあるディレクトリを共有フォルダに設定し、ゲストOS側から参照。


mount -t vboxsf "virtualboxに設定した共有フォルダ名" "マウントポイント"

ってな感じで、Debian から共有フォルダをマウントする。

cakephpは、cakeapp/app/tmp/*の所有者権限をApacheユーザにする必要があるのだけど、
マウントした共有フォルダは所有者がrootのなっており、かつ所有者権限の変更がきない。

なぜだろうと思ったら、mountする際に所有者権限設定するみたいだった。


mount -t vboxsf "virtualboxに設定した共有フォルダ名" "マウントポイント" -o uid="所有者のuid"


-o uid=にwwwユーザを設定して、とりあえず解決しました。

2010年1月16日土曜日

ApacheログをDBに保存するperlスクリプト

Apache Logを解析するためにMySQLに保存したいなーと思ったのでスクリプトを書いてみた。
DBIを利用するのが初めて、perlの理解もいまいちだったので苦労した・・

携帯サイト用なので一応uidも考慮。docomoのuidはパラメータしか取得できないのでちょっと面倒。

テーブルはこんな感じ。とりあえずつくったので、けっこう適当です。
======
CREATE TABLE `ap_log` (
`id` int(11) NOT NULL auto_increment,
`lb` varchar(10) default NULL,
`a_datetime` datetime default NULL,
`remote_host` varchar(256) default NULL,
`remote_user` varchar(256) default NULL,
`x_docomo_uid` varchar(20) default NULL,
`x_up_subno` varchar(256) default NULL,
`x_jphone_uid` varchar(20) default NULL,
`request` varchar(1024) default NULL,
`last_status` int(4) default NULL,
`responsesize` int(10) default NULL,
`response_time` int(10) default NULL,
`recv_size` int(10) default NULL,
`send_size` int(10) default NULL,
`referer` varchar(256) default NULL,
`user_agent` varchar(256) default NULL,
`a_host` varchar(256) default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM
=====

perlスクリプトはこんな感じ。カラムが多くすぎてINSERTのところは意味不明。

アパッチログのパースは、Apache Combined Log を効率的にパースする正規表現メモ を参考にさせて頂きました。おかげで高速に動作しました。ありがとうございます。

(.*)よりも最短マッチの(.*?)のほうが早いそうです。自分では試してはいません(^^;
最短マッチを使わなかった場合、テキストを最後まで読んでしまうから遅くなるのかも。

=====
#!/usr/bin/perl -w
use DBI;

# データソース
my $dsn = 'DBI:mysql:apache_log';
# ユーザ名
my $db_user = 'apachelog';
# パスワード
my $db_password = 'xxxxx';

# データベースへ接続
my $dbh = DBI->connect($dsn, $db_user, $db_password,
{ RaiseError => 1});

if (@ARGV <>
{
die "USAGE: analizelog.pl apachelog\n"
}


my $filename=$ARGV[0];
my $line;
#idはauto incrementのためNULL
my $sth = $dbh->prepare("INSERT INTO ap_log (id,lb,a_datetime,remote_host,remote_user,x_docomo_uid,x_up_subno,x_jphone_uid,request,last_status,responsesize,response_time,recv_size,send_size,referer,user_agent,a_host) VALUES (NULL,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");

open( FH , "$filename" ) || die "Error: $filename $!\n";

while () {
chop;
my ($lb,$datetime,$remote_host,$remote_user,$x_up_subno,$x_jphone_uid,$request,$last_status,$responsesize,$response_time,$recv_size,$send_size,$referer,$user_agent,$host) = /^(.*?) (.*? .*?) (.*?) (.*?) (.*?) (.*?) "(.*?)" (.*?) (.*?) (.*?) (.*?) (.*?) "(.*?)" "(.*?)" (.*?)/;

#docomoのuidはrequestパスから取得。ここも?つけたほうが高速になるような気がする。
if ($request =~ /.*uid=(\w{12})/)
{
$docomo_uid=$1;
}else{
$docomo_uid="-";

}

$sth->execute($lb,$datetime,$remote_host,$remote_user,$docomo_uid,$x_up_subno,$x_jphone_uid,$request,$last_status,$responsesize,$response_time,$recv_size,$send_size,$referer,$user_agent,$host);
}

$dbh->disconnect();
=====

uidを1カラムにすればよかったなー。いつかやろう。
あとリクエストパスとreferも、もうちょっと細分化しないと、
満足な分析には使えないかも。