nginxによる動的リバースプロキシサーバー
以前、LXCの勉強会で知ったNginxとRedisを使った動的なプロキシサーバーに興味をそそられて、「これは素晴らしい!」といまさら影響を受け、この辺の資料や記事を漁ってみたもののLinux系の情報は多いのですがなかなかSolaris系の情報が少なかったため、「では、Solarisでやってみましょう」ということでやってみましたやりたいこと
今回のサンプル環境でやりたいことは、URLに含まれるディレクトリが、Redisへ登録されている場合だけ静的コンテンツを表示するwebサーバーへ(server3)転送し、それ以外は動的コンテンツを表示するwebサーバー(server1、server2)へ転送するという処理をnginxで処理させます。構成
環境として、愛しのGentoo Linuxへインストールしたvmware player上のSolaris11で構築しました、こんな感じです
作成するZone
- ngx
- nginx + Lua + Redis
- server1
- server2
- apache + PHP + ZendFramework(動的コンテンツ出力用)
- server3
- apache(静的コンテンツ出力用)
- iichiko-spec
- パッケージサーバー(IPS)
インストール
まず、全部パッケージをビルドするのは面倒なので、パッケージサーバーを作成しそこからインストールします。このパッケージは私がビルドしたものなので、ご利用の際は自己責任でお願いします、検証のために作成したためテストなどは一切行っておりませんのでご注意ください。iichiko-specゾーンの作成
パッケージインストール用zoneの作成、これは他のzoneで代用しても構いません。iichiko-spec.cfg
sol11 ~ # cat iichiko-spec.cfg create -b set brand=solaris set zonepath=/rpool/zones/iichiko-spec set autoboot=false set ip-type=shared add net set address=192.168.254.102/24 set configure-allowed-address=true set physical=net0 endiichiko-specゾーンの構築
sol11 ~ # zonecfg -z iichiko-spec -f iichiko-spec.cfg sol11 ~ # zoneadm -z iichiko-spec install sol11 ~ # zoneadm -z iichiko-spec boot sol11 ~ # zlogin -C iichiko-specパッケージサーバーを設定
こでで、iichiko-specからnginxとredisなどの必要パッケージをインストールすることが出きるようになります。
root@iichiko-spec:~# zfs create -p -o mountpoint=/var/pkglocal rpool/pkglocal root@iichiko-spec:~# svccfg -s application/pkg/server setprop pkg/inst_root=/var/pkglocal root@iichiko-spec:~# pkgsend -s file:///var/pkglocal create-repository --set-property publisher.prefix=iichiko-spec root@iichiko-spec:~# svccfg -s pkg/server setprop pkg/port=80 root@iichiko-spec:~# svccfg -s svc:/application/pkg/server setprop pkg/readonly=true root@iichiko-spec:~# svcadm refresh pkg/server root@iichiko-spec:~# wget http://www.karky7.com/files/ips-2014.02.22.zfs.img.gz root@iichiko-spec:~# gunzip < ips-2014.02.22.zfs.img.gz | zfs recv -F rpool/pkglocal root@iichiko-spec:~# svcadm enable pkg/server
http://192.168.254.102にアクセスしてこんな画面がでればOKです

nginxをソースからビルドする場合
今回のnginxへ組み込んだモジュールは
- nginx-1.5.8
- ngx_http_redis-0.3.7
- lua_nginx_module-0.9.5rc2
$ wget http://nginx.org/download/nginx-1.5.8.tar.gz $ tar -xzvf nginx-1.5.8.tar.gz $ cd nginx-1.5.8 $ ./condifgure \ --add-module=../ngx_http_redis-0.3.7 \ --add-module=../lua_nginx_module-0.9.5rc2 ... ...
ngxゾーンの構築
ngx.cfgcreate -b set brand=solaris set zonepath=/rpool/zones/ngx set autoboot=false set ip-type=shared add net set address=192.168.254.200/24 set configure-allowed-address=true set physical=net0 endngxゾーンのインストール
sol11 ~ # zonecfg -z ngx -f ngx.cfg sol11 ~ # zoneadm -z ngx installngxゾーンへアプリケーションのインストール
sol11 ~ # zlogin ngx root@ngx:~# pkg set-publisher -g http://192.168.254.102 iichiko-spec必要なアプリケーションをインストール
root@ngx:~# pkg install pkg://iichiko-spec/service/redis-28 root@ngx:~# pkg install pkg://iichiko-spec/web/server/nginx root@ngx:~# pkg install pkg://iichiko-spec/library/lua/resty-redis root@ngx:~# pkg install pkg://iichiko-spec/library/lua/jit root@ngx:~# pkg install runtime/lua root@ngx:~# svcadm enable svc:/application/database/redis_28:default_64bit
nginxからRedisへアクセスする設定
Redisへサンプルとして使うデータをセットする、イメージ的にはこんな感じです「static1」、「static2」、「static3」へアクセスした場合だけ、静的なコンテンツを出力するwebサーバーへ転送します。
root@ngx:~# redis-cli 127.0.0.1:6379> 127.0.0.1:6379> RPUSH "www.samohan.jp" "static1" (integer) 1 127.0.0.1:6379> RPUSH "www.samohan.jp" "static2" (integer) 2 127.0.0.1:6379> RPUSH "www.samohan.jp" "static3" (integer) 3 127.0.0.1:6379>
nginx + luaの設定を作成
nginxからlua経由でRedisへアクセスするための設定をnginx.confへ書いておきます。細かい設定は調整してください、私自身も細かいところまで解ってません 笑...
upstream の部分がzendが動いているserver1、server2へ振る設定です、access_by_luaの部分がluaの部分でRedisへアクセスするコードです。luaがライブラリにアクセス出きるようにlua_package_pathの設定を忘れずに書いておいてください。
# /etc/nginx/nginx.conf #user nobody; worker_processes 1; # error_log logs/error.log; #error_log logs/error.log notice; # ここをコメントアウトするとINFOレベルのログの出力が止まります error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; lua_package_path "/usr/lib/lua/?.lua;;"; upstream zend { server 192.168.254.201:80; server 192.168.254.202:80; } server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { set $target ''; access_by_lua ' local domain_name = ngx.var.host local path = ngx.var.uri ngx.log(ngx.INFO, "Get domain_name: ", domain_name) ngx.log(ngx.INFO, "Get path: ", path) local redis = require "resty.redis" local red = redis:new() red:set_timeout(1000) -- 1 second local ok, err = red:connect("127.0.0.1", 6379) if not ok then ngx.log(ngx.ERR, "failed to connect to redis: ", err) return ngx.exit(500) end local klen, err = red:llen(domain_name) if klen == 0 then ngx.log(ngx.ERR, "failed to llen redis key: ", err) return ngx.exit(500) end local maxindex = klen - 1 ngx.log(ngx.INFO, "Get maxindex: ", maxindex) local t = {} local find = false local m = nil for i = 0, maxindex do t[i] = red:lindex(domain_name, i) m = string.match(path, "^\/" .. t[i] .. "\/") if m ~= nil then ngx.log(ngx.INFO, "Found : ", m) find = true break end ngx.log(ngx.INFO, "Get data: ", t[i]) end if find == true then ngx.var.target = "192.168.254.203" else ngx.var.target = "zend" end '; proxy_pass http://$target; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } # another virtual host using mix of IP-, name-, and port-based configuration # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias; # location / { # root html; # index index.html index.htm; # } #} # HTTPS server # #server { # listen 443 ssl; # server_name localhost; # ssl_certificate cert.pem; # ssl_certificate_key cert.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # location / { # root html; # index index.html index.htm; # } #} }設定ができましたらnginxを再起動してください
root@ngx:~# svcadm enable nginx root@ngx:~# svcs -xv root@ngx:~#
server1、server2、server3ゾーンの構築
server1とserver2は同じものを作成する、動的なページの生成で利用する、server3は静的ページを表示するために利用。server1.cfg
sol11 ~ # cat server1.cfg create -b set brand=solaris set zonepath=/rpool/zones/server1 set autoboot=false set ip-type=shared add net set address=192.168.254.201/24 set configure-allowed-address=true set physical=net0 endserver2.cfg
sol11 ~ # cat server2.cfg create -b set brand=solaris set zonepath=/rpool/zones/server2 set autoboot=false set ip-type=shared add net set address=192.168.254.202/24 set configure-allowed-address=true set physical=net0 endserver3.cfg
sol11 ~ # cat server3.cfg create -b set brand=solaris set zonepath=/rpool/zones/server3 set autoboot=false set ip-type=shared add net set address=192.168.254.203/24 set configure-allowed-address=true set physical=net0 endゾーン作成
sol11 ~ # zonecfg -z server1 -f server1.cfg sol11 ~ # zonecfg -z server2 -f server2.cfg sol11 ~ # zonecfg -z server3 -f server3.cfg sol11 ~ # zoneadm -z server1 install sol11 ~ # zoneadm -z server2 clone server1 sol11 ~ # zoneadm -z server3 clone server1最終的なゾーンはこの様な形になります
sol11 ~ # zoneadm -z list -vc ID NAME STATUS PATH BRAND IP 0 global running / solaris shared 10 iichiko-spec running /rpool/zones/iichiko-spec solaris shared 14 ngx running /rpool/zones/ngx solaris shared 15 server1 running /rpool/zones/server1 solaris shared 16 server2 running /rpool/zones/server2 solaris shared 17 server3 running /rpool/zones/server3 solaris shared
server1、server2へZendFrameworkをインストール
server2も同じ構成でインストールしてくださいsol11 ~ # zlogin server1 root@server1:~# pkg install pkg:/web/server/apache-22 root@server1:~# pkg install pkg:/web/server/apache-22/module/apache-php52 root@server1:~# wget http://packages.zendframework.com/releases/ZendFramework-1.12.3/ZendFramework-1.12.3.tar.gz root@server1:~# mkdir -p /usr/local/share/php root@server1:~# tar -xzvf ZendFramework-1.12.3.tar.gz root@server1:~# cp -rf ZendFramework-1.12.3/library/Zend/ /usr/local/share/php/php.iniの設定
root@server1:~# emacs /etc/php/5.2/php.ini
include_path = ".:/var/php/5.2/pear:/usr/local/share/php"ZendFrameworkの設定
server1とserver2へ展開してください
root@server1:~# cd / root@server1:/# wget http://www.karky7.com/files/zend_sample.tar.gz root@server1:/# tar -xzvf zend_sample.tar.gz root@server1:/# chown -R webservd:webservd web root@server1:/# tree /web /web ├── application │ ├── controllers │ │ ├── ErrorController.php │ │ ├── IndexController.php │ │ └── SampleController.php │ └── views │ ├── index │ │ └── index.phtml │ └── sample │ └── sample.phtml └── www └── index. root@server1:/#続いてhttpd.confの設定
root@server1:~# diff /etc/apache2/2.2/httpd.conf /etc/apache2/2.2/httpd.conf.ORG 113c113 < DocumentRoot "/web/www" --- > DocumentRoot "/var/apache2/2.2/htdocs" 140c140 < <Directory "/web/www"> --- > <Directory "/var/apache2/2.2/htdocs"> 153c153 < Options All --- > Options Indexes FollowSymLinks 160c160 < AllowOverride All --- > AllowOverride None
server3の構築
server3は普通の静的ファイルを返すだけのapacheサーバーとして構築するsol11 ~ # zlogin server3 root@server3:~# pkg install pkg:/web/server/apache-22
アクセスしてみる
最後に、ドメイン経由でブラウザからアクセスしたいので /etc/hostsへドメインを追加する(DNS立てれないからね)、ちなみにここで言うhostsファイルは、ブラウザでアクセスするホストの奴です、僕で言うとGentooのhostsフィルです。192.168.254.200はngxゾーンのIPです。
192.168.254.200 www.samohan.jpブラウザから以下のURLへアクセスしてみますと、Redisへ登録されているstatic1、static2、static3へのアクセスはserver3へ転送され、それ以外はserver1、server2へ転送される。
- http://www.samohan.jp/ ・・・ zendサーバーへ、server1、server2
- http://www.samohan.jp/static1/ ・・・ server3へ
- http://www.samohan.jp/static2/ ・・・ server3へ
- http://www.samohan.jp/static3/ ・・・ server3へ
- http://www.samohan.jp/static4/ ・・・ zendサーバーへ転送されErrorControllerで捕まる
こんな感じで、Redisに保存されている情報を元に色々振り分ける事ができます。
これは素晴らしい。
この他にもnginxって色々使えそうでビックリしてる所です、今後、適材適所でnginxを利用していこう思います。
書きすぎでまとまりがありませんが、間違いがありましたら指摘していただければ幸です
最後に謝辞
この度、パッケージングで作成したnginxは @ftnk 先生のspecをカスタマイズして利用させていただきました、ブログからで申し訳ございませんがお礼を申し上げます、ありがとうございました。また色々お世話になると思いますのでよろしくお願いします。