社内の開発環境とローカルの開発環境の連携方法
どんな時に便利か?
全てのサービスをローカル環境として構築できれば良いのですが
それがあまり現実的ではなく、基本は外部のアプリを利用して
一部アプリだけローカルのアプリを利用したいとい時に便利です。
ローカル環境構成図
PAC(Proxy Access-Control)ファイルを利用して
まずは、ローカルとそれ以外へのアクセスを振り分けています。
ローカルでは、nginxがアクセスを集約しています。
これは、80番や443番ポートを複数のアプリで利用するためで
ホスト名によって各アプリへリクエストの振り分けをしています。
PACファイル
開発環境用に社内プロキシが無い場合は、設定不要です。
JavaScriptの文法で、proxyの設定が書けるファイルです。
Firefoxだと、下記の場所からから設定できます。
オプション > ネットワーク > 接続設定 > 自動プロキシ設定スクリプト URL
proxyを通さない場合(今回はローカル環境)は、"DIRECT"という文字列を返しておきます。
ドメイン名に"hatena.ne.jp"が入る場合は、開発環境用のproxyを通したい。という場合は、
組み込みのshExpMatch関数を使い、host名とマッチングをかけ、PROXYのIPとポートを返します。
セミコロンでproxyもしくは、"DIRECT"をつなげると、順番に接続を試みてくれます。
function FindProxyForURL(url, host) { if (isInNet(host, "127.0.0.1", "255.255.255.255")) { return "DIRECT"; } else if (isDevHost(host)) { // dev.proxy:9999 return "PROXY 172.16.0.2:9999"; } // default.proxy:9999 return "PROXY 172.16.0.3:9999; DIRECT"; } function isDevHost(host) { return shExpMatch(host, "*.hatena.ne.jp"); }
hostsの設定
isInNet(host, "127.0.0.1", "255.255.255.255")でローカル環境として判定をさせるために
/etc/hosts で、ローカルアプリのドメインのIPを、127.0.0.1として登録しておきます。
# local env 127.0.0.1 d.hatena.ne.jp
これで、http://d.hatena.ne.jp/とアクセスした場合は、127.0.0.1:80へのアクセスに
それ以外のはてなドメインは、172.16.0.2:9999のproxy経由でのアクセスが可能になりました。
nginxの設定
ほぼ、デフォルトの設定のままですが、肝はinclude文です。
これで、各アプリに振り分けるようの設定を読み込んでいます。
error_log /usr/local/var/logs/nginx/error.log; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include params/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 /usr/local/var/logs/nginx/access.log main; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; keepalive_timeout 65; sendfile on; gzip on; include /usr/local/var/nginx/conf/extra/backends/*.conf; }
/usr/local/var/nginx/conf/extra/backends/d-hatena-ne-jp.confの場合
d.hatena.ne.jp用のtomcatアプリが、8080ポートで動いている場合は
以下のような設定になります。
server { listen 80; server_name d.hatena.ne.jp; location / { proxy_pass http://127.0.0.1:8080; } }
アプリを増やしたい場合は、hostsファイルへの追記とconfファイルの新規作成で簡単に行えます。
魔術でデプロイ
1文字に飽きたら、詠唱でも
準備
# ホームディレクトリへ移動 function I(){ cd ~/ } # バックアップ function Steel(){ cp /usr/local/tomcat/webapps/UBW.war ./UBW.war } # リリースファイルをSTGサーバから取得 function Unknown(){ scp stg:UBW.war ~/UBW.war } # tomcat停止 function Nor(){ sudo -u tomcat /usr/local/tomcat/bin/shutdown -force } # アプリ削除 function Have(){ sudo -u tomcat rm -rf /usr/local/tomcat/webapps/UBW } # warファイル入れ替え function Yet,(){ sudo -u tomcat cp ./UBW.war /usr/local/tomcat/webapps/UBW.war } # tomcat開始 function So(){ sudo -u tomcat /bin/sh usr/local/tomcat/bin/startup.sh }
詠唱
I am the bone of my sword. Steel is my body, and fire is my blood. I have created over a thousand blades. Unknown to Death. Nor known to Life. Have withstood pain to create many weapons. Yet, those hands will never hold anything. So as I pray, unlimited blade works.
1文字シリーズ
毎日、毎日タイプするコマンドならば、タイプ数を減らすに限るよね。
抜けてるところには、何を入れよう?
1文字alias
alias a="sudo aptitude" alias b="" alias c="cat" alias d="diff" alias e="echo" alias f="find . -type f -name" alias g="grep" alias h="head" alias i="/sbin/ifconfig" alias j="" alias k="" alias l="ls -ltrah" alias m="" alias n="node -e" alias o="" alias p="perl -wnl -e" alias q="" alias r="reset" alias s="sqlplus user_name/password@host[:port][/service_name]" alias t="tail -f" alias u="" alias v="view" alias x="xargs" alias y="" alias z=""
1文字変数
aliasよりさらにネタが無いな
export a="access_`date +%Y%m%d`.log" export b="" export c="" export d="`date +%d`" export e="error_`date +%Y%m%d`.log" export f="" export g="" export h="" export i="" export j="" export k="" export l="" export m="`date +%m`" export n="" export o="" export p="" export q="" export r="" export s="" export t="" export u="" export v="" export w="" export x="" export y="`date +%Y`" export z=""
node.jsでsocket通信
みんな大好きエコーサーバ
Install websocket server module
% npm install websocket-server
Server side
httpとwsプロトコルで、返す値を変えられる。
サーバの監視用にする、クライアント側のコードを返すなどの利用方法が考えられる。
var http = require('http'); var ws = require('websocket-server'); // http server = http.createServer(function(req, res){ res.writeHead(200, {'Content-Type': 'text/html'}); res.end("<html><body><h1>It's Works!</h1></body></html>"); }); server.listen(10003); // WebSocket var socket = ws.createServer({'server': server}); socket.on('connection', function(conn){ conn.on('message', function(msg){ conn.send(msg); }); conn.on('close', function(){ console.log('closed'); }) });
Client side
今回は、サーバのコードとは分けてあるので、httpでアクセスできる場所に適当に置く。
ローカルファイル(file://)だと、セキュリティに引っかかりWebSocket通信ができない。
<script> var ws = new WebSocket('ws://127.0.0.1:10003/'); ws.onopen = function() { ws.send('hello world'); } ws.onmessage = function(evt) { console.log(evt.data); } ws.onclose = function() { console.log('closed'); } </script>
カスタムfindコマンド
alias f="find"
でも、そこそこ便利だけれど
.gitディレクトリを、検索対象外にしたいときに
f . -name .git -prune -print
となり、長いし忘れやすいので
#!/bin/bash case $# in 1) path='.' name=$1 ;; 2) path=$1 name=$2 ;; esac #echo "find \"$path\" -name .git -prune -o -name \"$name\" -print" find "$path" -name .git -prune -o -name "$name" -print
デフォルトで、.gitディレクトリを抜いてfindさせるシェルスクリプトを作成。
引数が1つの場合は、カレントディレクトリから引数で与えられたnameを検索。
引数が2つの場合は、第一引数のディレクトリから、第二引数のnameを検索。
node.jsを使ってWebページからテキストを取得
jsdomモジュール使うと、http周りの記述しなくて良いから楽だね。
レスポンスヘッダもしくは、メタ要素で指定された文字コード見てUTF-8に変換すれば
もうちょっとましになりそう。
ソース
// getText.js var jsdom = require('jsdom'); function removeElements(list) { for (var i = 0, l = list.length; i < l; i++) { var elem = list[i]; elem.parentNode.removeChild(elem); } } jsdom.env(process.argv[2], function(errors, window) { var body = window.document.body; removeElements(body.getElementsByTagName('script')); removeElements(body.getElementsByTagName('style')); console.log(body.textContent); });
使い方
% node getText.js http://d.hatena.ne.jp/TakiTake/
JSON形式の設定ファイルに対する変更をリアルタイムに反映する方法
JSON形式の設定ファイルに変更があったら動的に変更を読み込みたいな
ということで、
var fs = require('fs'); var conf = null; var filepath = '/path/to/file'; // 設定ファイルを再読み込みする関数 // 第二引数で、同期か非同期かを選べる function reload(filepath, sync) { if (sync) { conf = JSON.parse(fs.readFileSync(filepath, 'utf8')); } else { fs.readFile(filepath, 'utf8', function(err, data) { if (err) { throw err; } conf = JSON.parse(data); }) } } // 設定ファイルを監視するロジック // watchFileして、更新日時が新しかったら再読み込みする fs.watchFile(filepath, function(curr, prev) { if (curr.mtime > prev.mtime) { reload(filepath); } });
デバッグレベルを切り替えてみたり、上限や下限値を変更したりと
アプリを再起動するまでも無い変更には便利かと