yamasaki0's diary

IT勉強会や技術的なメモなどを書いていきたいと思います。

Vimでxdebugを使ってphpをトレース実行する

概要

Vimを使ってIDEのようにphpをトレース実行出来るらしいので試してみた。


 

環境準備

xdebugのインストール

ubuntu 12.04 ですが、 php5-xdebugを入れるだけ

aptitude install php5-xdebug

xdebugの設定

/etc/php5/conf.d/xdebug.ini に
xdebug.remote_enable=On
xdebug.remote_host=localhost
を書き足す。

zend_extension=/usr/lib/php5/20090626+lfs/xdebug.so
xdebug.remote_enable=On
xdebug.remote_host=localhost


apacheは再起動すること。

vimの準備

NeoBundle を使ってインストールします。
(NeoBundleについては、http://vim-users.jp/2011/10/hack238/ こちらで)

.vimrcに

NeoBundle 'git://github.com/joonty/vim-xdebug.git'

を記載して、

:NeoBundleInstall

を実行するだけ。

トレース実行

ブレークポイント設定およびリモートデバッグ待ち受けの開始

vimphpソースコードを開く
ブレイクしたいところで
:Bp
するとブレークポイントとして行の色が反転する
その[F5]を押してから、

Waiting for a connection (this message will self-destruct in 30 seconds...)

と表示されるので、その間にブラウザで対象ページに
パラメータ「XDEBUG_SESSION_START」を付けて開く

http://localhost/test.php?XDEBUG_SESSION_START

操作方法

phpページを上記のようなURLでアクセスすると、vimデバッグモードになる。

操作方法は下の通り

[ Function Keys ]                 |                       
  <F1>   resize                   | [ Normal Mode ]       
  <F2>   step into                |   ,e  eval            
  <F3>   step over                |                       
  <F4>   step out                 |                       
  <F5>   run                      | [ Command Mode ]      
  <F6>   quit debugging           | :Bp toggle breakpoint 
                                  | :Up stack up          
  <F11>  get all context          | :Dn stack down        
  <F12>  get property at cursor   |                       

phpコマンドライン実行のデバッグ方法

以下の環境変数をセットして実行するとよい

XDEBUG_CONFIG="idekey=DBGP" XDEBUG_SESSION_START=DBGP php test.php

distccを使ってEC2で分散ビルドを試す。

EC2は並列ビルドと相性がよさそうだ思ったので試してみた。

  • 環境
    • c1.medium Amazon Linux 32bit x最大8台まで
  • ターゲット
    • php5.4

distccをすべてのホストにインストールする必要がある。
しかしAWSなら簡単にスナップショットを取って複製マシンが作れるので凄くお手軽です。

distccのインストール

残念なことにAmazon Linuxのyumではdistccが見つからなかったので、ソースからビルドすることに。

wget http://distcc.googlecode.com/files/distcc-3.1.tar.bz2
tar xvjf distcc-3.1.tar.bz2
sudo yum install -y python-devel
cd distcc-3.1
./autogen.sh 
./configure
make
sudo make install

distccdの起動

/etc/init.dに/usr/local/share/doc/distcc/example/initをコピーして起動時に有効になるようにする。

sudo cp /usr/local/share/doc/distcc/example/init /etc/init.d/distcc
sudo chmod 755 /etc/init.d/distcc

/usr/local/etc/distcc/clients.allow 等がインストールされるのだが、
exampleのinitファイルではそれらを読むようになっていないので意味が無かった。
しかたなく、/etc/init.d/distccの中身を変更

start() {
    echo -n $"Starting $SERVICE: "
    daemon /usr/local/bin/$SERVICE --daemon
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$SERVICE
    return $RETVAL
}

の --daemonの後ろに "--allow=10.0.0.0/8 --allow=127.0.0.1"を追加

sudo chkconfig --add distcc
sudo /etc/init.d/distcc start

psで起動していることを確認する。
distccについてはいったんこれで終わり

実際にphp5.4をビルドしてみる

参考までに手元のマシンでのビルド結果
Hyper-VのVMで4GBメモリとCPU1コアを割り当てている(CPUは、Intel(R) Xeon(R) CPU L3426 @ 1.87GHz boost時3.2GHz)
ubuntu11.10

/usr/bin/time make
394.53user 24.84system 8:05.51elapsed 86%CPU (0avgtext+0avgdata 1274768maxresident)k
2296inputs+625480outputs (16major+19995025minor)pagefaults 0swaps

そして下がc1.mediumの普通のmake

/usr/bin/time make
247.98user 142.63system 6:29.62elapsed 100%CPU (0avgtext+0avgdata 979264maxresident)k
2256inputs+535168outputs (2major+15762296minor)pagefaults 0swaps

とりあえず1台のままdistccを試してみる。
/usr/local/etc/distcc/hosts へ 127.0.0.1 とだけ書き入れる

/usr/bin/time make -j10 CC="distcc gcc" CXX="distcc g++"
57.70user 147.89system 4:17.03elapsed 79%CPU (0avgtext+0avgdata 265200maxresident)k
0inputs+629400outputs (0major+14121531minor)pagefaults 0swaps

自分に対してdistccしても効果があるようだw

期待を膨らませつつ、
この状態のスナップショットを起動したまま取る。
(そのまえにsyncを実行)

webUIからポチポチとスナップショットをとってそこからイメージを作成
スナップショットもすぐに取れるのでお手軽です。早いときは数秒でスナップショット完了する。

作ったAMIで3台分追加で起動してみた。
ポチポチと。この辺はコマンドでやった方がいいんだろうけど・・。まあ3台程度であればWebからでもいいかなと。
ただし、セキュリティーグループは適切に設定する必要がある。
TCP3632を開けておくこと。

これで、まったく同じマシンが4台になったので、どのマシンからでも良いのだけど、
先ほど作業していた元のマシンで作業を続けます。
/usr/local/etc/distcc/hostsに追加起動したマシンのIPを追記


4台に増やしたから-j40に変更して実行しました。

/usr/bin/time make -j40 CC="distcc gcc" CXX="distcc g++"
57.75user 153.72system 2:29.77elapsed 141%CPU (0avgtext+0avgdata 265200maxresident)k
0inputs+620368outputs (0major+13968821minor)pagefaults 0swaps

早くなりました!

どこまで早くなるか試すためにさらに4台追加して試しました。

/usr/bin/time make -j80 CC="distcc gcc" CXX="distcc g++"
58.47user 157.69system 2:29.25elapsed 144%CPU (0avgtext+0avgdata 265216maxresident)k
0inputs+639544outputs (0major+14120097minor)pagefaults 0swaps

かわらねーw すでに4台のところで頭打ちだったようです。(-j15とか適当に減らしてもかわらない状態)

色々試した結果、hostsからlocalhost消して、別の2台のIPを追加した状態が
一番効率がよいという結果になりました。

57.74user 154.76system 2:25.63elapsed 145%CPU (0avgtext+0avgdata 265216maxresident)k
0inputs+622056outputs (0major+14116877minor)pagefaults 0swaps

このあたりはビルドするターゲットによって色々違うだろうとは思います。

distccにpumpモードというのがあるようなのでそちらも試したかったのですが、今日はここまで。

Ubuntu ufwでのiptablesの設定

ufwについて

ubuntuにはiptablesでの設定を簡単に行えるようにしたufwというツールがあり、
iptablesを生で使うより簡単に設定が行えるようになっている。
また、iptablesで設定する基本的なルールがある程度用意されているようである。
GUIの設定ツールなどもある。

設定ファイル

/etc/ufw:
sysctl.conf    -> IPフォワーディング等のkernelパラメータの設定
ufw.conf        -> ufwの有効化やログレベルの設定
before.rules    -> おそらくカスタムルールの前に評価するチェーンなどの登録設定
before6.rules   -> 上記と同じ、ipv6用
after.rules     -> おそらくカスタムルールの後に評価するチェーンなどの登録設定
after6.rules    -> 上記と同じ、ipv6用
applications.d  -> アプリケーション名に応じた使用ポート等の情報が入っている。
                   おそらくパッケージを入れるとここにファイルが追加される形であろう。

/etc/ufw/applications.d:
openssh-server  -> OpenSSHが利用するポートが書かれている

/lib/ufw:
user.rules      -> ユーザーのカスタムルールが格納される
user6.rules     -> 上記と同じ、ipv6用

ルールの追加

$ sudo ufw allow ssh
とすると、/etc/ufw/user.rulesに

### tuple ### allow any 22 0.0.0.0/0 any 0.0.0.0/0 in
-A ufw-user-input -p tcp --dport 22 -j ACCEPT
-A ufw-user-input -p udp --dport 22 -j ACCEPT

と追加された。

/etc/ufw/applications.dに設定が入っているアプリケーションであれば以下のように登録出来る
$ sudo ufw allow OpenSSH

### tuple ### allow tcp 22 0.0.0.0/0 any 0.0.0.0/0 OpenSSH - in
-A ufw-user-input -p tcp --dport 22 -j ACCEPT -m comment --comment 'dapp_OpenSSH'

ルールの削除

追加時に入れたオプション文字列の先頭にを追加するだけ
$ sudo ufw delete allow ssh
$ sudo ufw delete allow OpenSSH

Firewall ON/OFF

$ sudo ufw enable
$ sudo ufw disable
で ON/OFF 出来ます。
sshのルールを追加していることを確認してから実行

$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? 

脅しが入ります。yで進むと適用されます。

Firewall is active and enabled on system startup

$ sudo iptables -L -v
するとルールが表示されますが長すぎて読む気になりませんw

$ sudo ufw status verbose
するとわかりやすいです。

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp (OpenSSH)           ALLOW IN    Anywhere

しかしこのルールの一覧はufw enableにしていないと見れないので注意


こんな使い方をする
$ sudo ufw allow from 10.0.0.0/8 to any app OpenSSH
と入れると

### tuple ### allow tcp 22 0.0.0.0/0 any 10.0.0.0/8 OpenSSH - in
-A ufw-user-input -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT -m comment --comment 'dapp_OpenSSH'

と設定が追加されるようです。

リモートからiptablesを設定するときに失敗して「あー繋がらなくなった」ってことにならないためのスクリプト

よくあるんですよね、リモートでちょっとiptablesスクリプトをいじってみたら、

あら・・繋がらなくなったよ!現地に行くしかない 

みたいなのが・・。
そんなことが無いようにiptables-applyというスクリプトがあるようなのですが、
これは、iptables-saveとiptables-restoreを使って、
ルール適用後にキー入力を待って、タイムアウトした場合は、
元の適用前のルールをrestoreしてくれるんです。
かなり便利なんですが、
iptables-restoreで読める形式でルールを書かないといけないのが難点で、
シェルスクリプトで書いたルールと比べると可読性がかなりよろしくない。

そこで、シェルスクリプトでかいたルールでも、同じようにキー入力を待って
からタイムアウトで元のルールをrestoreするスクリプトを書いてみました。

利用方法

使い方は、こいつ自身を直接実行するのではなく、
以下のような感じでルールスクリプトを書く形です。

$ cat filter_ruleset.sh
#!/bin/bash

# スクリプトを読み込む(先頭に「.」が必要な点に注意
. ./iptables-ruleupdater

# 変数等をセット
mynetwrok=10.10.10.0/24
myhost=10.10.10.12

#ルールを書く
rule_set () {
    iptables -F
    iptables -t nat -F
    iptables -P INPUT ACCEPT
    iptables -P FORWARD DROP
    iptables -P OUTPUT ACCEPT

    # any -> ppp0:ssh accept
    iptables -A INPUT  -i ppp0 -d $myhost -p tcp -m state --state NEW,ESTABLISHED,RELATED --dport 22 -j ACCEPT
    iptables -A OUTPUT -o ppp0 -s $myhost -p tcp --sport 22 -j ACCEPT
    
    # 以下略

    iptables -A OUTPUT -j LOG
}

apply
# ↑上記のルールを適用したりチェックしたり分岐処理するファンクション

実行方法

# ./filter_ruleset.sh
 * Usege: filter_ruleset.sh {check|try|status|start}
  • check
    • スクリプトの文法的エラーがないかどうか確認します。
    • 中では実際にiptablesでルールを適用し、すべてルール適用が終わったらすぐさま直前のルールをrestoreします。
    • エラーがあった場合はそのスクリプト中の行数を表示し停止します。
  • try
    • ルールを適用した後、キーに入力を待ち、10秒まってもキー入力が無い場合は直前のルールをrestoreします。
  • start
    • ルールを普通に適用します(確認なし)

追記

id:bitwalkerhttp://d.hatena.ne.jp/bitwalker/20090111/1244874627 に同じようなことを簡単なスクリプトで実現されているのを見つけました。(ただ、この方法だとオールクリア状態に戻ってしまうので、ちょこっと更新とかは厳しいかも)