まつざきの技術メモ

エンジニアの私的な技術メモです。


コメントする

VAIO Pro 11にDebianをインストール

VAIO Pro 11にDebianをインストールした時のメモ。

手順は以下のとおり。

  1. まずは普通にWheezyをインストール
  2. sidにアップデート
  3. 最新カーネル(3.11-rc2)をビルドしてインストール

 

Wheezyそのままだと無線LANデバイスを認識しませんでした。Intelの7260ってやつが付いてるみたいです。
このブログエントリーによると、最新カーネルの3.11だとモジュールが入っているみたいなので、
今日時点の最新(3.11-rc2)をインストールしました。
カーネルだけ最新にするのもなんかイヤなので、ついでにsidにしています。

上記リンクのブログエントリーでは、Arch Linuxをインストールしていますが、同じ手順でOKです。

  1. 最新firmwareのダウンロード
  2. 最新カーネルソースのダウンロード
  3. intel_pstate.cにパッチを当てる
  4. カーネルコンパイル
  5. 出来上がったカーネルヘッダーとカーネルイメージのdebパッケージをdpkgコマンドでインストール

 

カーネルのコンパイルとインストールはこのブログエントリーを参考にさせてもらいました。
カーネルをコンパイルする時にプロンプトが沢山出て来ましたが、全てデフォルトにしました。

 

2013/07/23追記
Ubuntu 13.10 (Saucy Salamander) Daily Build でも同じように
最新firmwareと最新カーネルをインストールすれば動きました。
Ubuntu 13.10はリリース時にはカーネルが3.11になるようです。

広告


コメントする

GlassFishが付加したExpiresヘッダを上書きする

Apache + GlassFishの環境で稼働中のアプリで、
アプリ内のjsファイルを修正しても、内容がクライアントに反映されなかった件の対応メモ。

GlassFishが静的ファイルにExpiresヘッダを付加するのが原因だったので、
(webapp/resourcesに配置したファイルだけ?)
今回はその前段に配置しているApacheのmod_expiresモジュールで対応しました。

GlassFishで設定出来そうな気がしますが、設定項目を見つけきれませんでした。
ご存知の方がいらっしゃれば教えて下さい><

■バージョン
OS: Scientific Linux 6.3 x86_64
Apache: 2.2.15
GlassFish: 3.1.2.2

■手順
Apacheはyumでインストール済なので、
ビルドしたRPMファイルからモジュールファイルを取り出して差し替えました。

1. 依存パッケージをインストール
2. 作業ディレクトリを作成
3. SRPMをダウンロード
4. mod_expiresのパッチファイルを作成
5. specファイルを修正
6. .rpmmacrosファイルを作成
7. RPMファイルをビルド
8. RPMファイルを解凍して、モジュールファイル「mod_expires.so」を取り出す
9. モジュールファイルを差し替え

SRPMの作成は必ず一般ユーザで行なうようにしてください。

# yum install rpm-build apr-devel apr-util-devel pcre-devel

$ mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}

$ cd ~/rpmbuild/SRPMS

$ yumdownloader --source httpd

$ rpm -ivh httpd-2.2.15-28.sl6.src.rpm

$ cat << EOF > ~/rpmbuild/SOURCES/httpd-2.2.15-mod_expires.patch
--- httpd-2.2.17.orig/modules/metadata/mod_expires.c    2008-11-12 04:59:22.000000000 +0900
+++ httpd-2.2.17/modules/metadata/mod_expires.c 2011-01-20 11:47:03.000000000 +0900
@@ -472,6 +472,11 @@
         expiry = apr_table_get(r->headers_out, "Expires");
         t = r->headers_out;
     }
+    if ( apr_table_get(r->subprocess_env, "override_expires") ) {
+        expiry = NULL;
+        apr_table_unset(t,"Expires");
+        apr_table_unset(t,"Cache-Control");
+    }
     if (expiry == NULL) {
         /*
          * No expiration has been set, so we can apply any managed by
EOF

$ emacs ~/rpmbuild/SPECS/httpd.spec

$ cat << EOF > ~/.rpmmacros
%_topdir %(echo $HOME)/rpmbuild
%_builddir %{_topdir}/BUILD
%_rpmdir %{_topdir}/RPMS
%_sourcedir %{_topdir}/SOURCES
%_specdir %{_topdir}/SPECS
%_srcrpmdir %{_topdir}/SRPMS
%debug_package %{nil}
EOF

$ rpmbuild -ba ~/rpmbuild/SPECS/httpd.spec

$ cd ~/rpmbuild/RPMS/x86_64/

$ rpm2cpio httpd-2.2.15-28.sl6.x86_64.rpm | cpio -id

 

~/rpmbuild/SPECS/httpd.specとして保存するファイルはここに置いています。
変更箇所は以下です。

$ diff ~/rpmbuild/SPECS/httpd.spec{,.org}
105,108d104
<
< # my patch
< Patch212: httpd-2.2.15-mod_expires.patch
<
261,263d256
< # my patch
< %patch212 -p1 -b .mod_expires
<

 

モジュールのコピーはrootかsudoで行なってください。

# cp -i ~rpmbuilder/rpmbuild/RPMS/x86_64/usr/lib64/httpd/modules/mod_expires.so /usr/lib64/httpd/modules/mod_expires.so

 

あとは、httpd.confに以下のような設定をすればOKです。
この例では、画像のみ1ヶ月キャッシュして、
それ以外はすべてキャッシュしないようにしています。

SetEnv override_expires 1

<IfModule mod_expires.c>
    ExpiresActive on
    ExpiresByType image/png "access plus 1 months"
    ExpiresByType image/jpeg "access plus 1 months"
    ExpiresByType image/jpg "access plus 1 months"
    ExpiresByType image/gif "access plus 1 months"
    ExpiresDefault A0
</IfModule>

 

以下のブログエントリを参考にさせて頂きました。
ありがとうございますm(_ _)m

@kazeburoさん 
mod_expiresでExpiresとCache-Controlを上書きする
mod_expiresのパッチファイルは@kazeburoさんのそのまま使わせて頂いてます><

@tnmtさん 
いまさら聞けないrpmbuildことはじめ


コメントする

nginxをリバースプロキシにしてGlassFishでクラスタリング

GlassFishクラスタ構成を作った時のメモです。

バージョンは、
OS: Scientific Linux 6.3 x86_64
nginx: 1.2.6
GlassFish: 3.1.2.2
Java: Java SE 7u11
いずれも今日時点の最新安定バージョンです。

アプリはJavaEE6で作ってます。
ステートフルなアプリなので、スティッキーセッションとセッションレプリケーションが必要です。

 

構成はこんな感じ。
DAS(ドメイン管理サーバ)がクラスタを管理します。
# 今回はGlassFishクラスタの話なので、「nginxとDASの冗長化は?」というツッコミは無しでお願いします:)

GlassFishのレプリケーション方式はインメモリレプリケーションです。
# 昔のGlassFishではHigh-Availability Database (HADB)という方式があったようですが、
# もう無くなったみたいですね。

レプリケーションについてはこのページがわかりやすいです。
Clustering in GlassFish Version 3.1

では、クラスタ構成の手順です。
このブログエントリーを参考にさせて頂きました。ありがとうございます!
Glassfish 3.1の自己増殖クラスタを試す

1. ノード準備
※この手順だけはDASではなく、各ノードで行います。

  • glassfishユーザ作成(GlassFishはglassfishユーザで実行する事にします)
  • GlassFishインストールディレクトリ作成
  • GlassFishインストールディレクトリのオーナーをglassfishに変更
  • Javaインストール
groupadd glassfish
useradd -g glassfish glassfish
mkdir /usr/local/glassfish3
chown glassfish:glassfish /usr/local/glassfish3
rpm -ivh /path/to/JDKのrpmファイル

2. クラスタ作成

asadmin create-cluster cluster1

※EC2環境で稼働させる場合、マルチキャストが使えないため以下のように明示的にノードを列挙してください。
詳しくはこのページを参照。
Discovering a Cluster When Multicast Transport Is Unavailable
@yoshioteradaさんに教えて頂きました。ありがとうございます!

※同一ノードにインスタンスを複数立ててクラスタを複数作る場合は、ポートが被らないように注意しましょう。

asadmin create-cluster --properties GMS_DISCOVERY_URI_LIST=tcp'\\:'//glassfish01,tcp'\\:'//glassfish02,tcp'\\:'//glassfish03:GMS_LISTENER_PORT=9090 cluster1

3. DASからノードへのssh接続設定

echo "AS_ADMIN_SSHPASSWORD=ノードのglassfishユーザのパスワード" > /tmp/password
asadmin --passwordfile=/tmp/password --interactive=false setup-ssh --sshuser glassfish --generatekey=true glassfish01
asadmin --passwordfile=/tmp/password --interactive=false setup-ssh --sshuser glassfish --generatekey=true glassfish02
asadmin --passwordfile=/tmp/password --interactive=false setup-ssh --sshuser glassfish --generatekey=true glassfish03
rm /tmp/password

4. DASからsshでノードのjavaコマンドが使えるか確認

ssh glassfish01 java -version
ssh glassfish02 java -version
ssh glassfish03 java -version

5. ノードにGlassFishをインストール

asadmin install-node --installdir /usr/local/glassfish3 --sshuser glassfish --sshkeyfile ~/.ssh/id_rsa glassfish01
asadmin install-node --installdir /usr/local/glassfish3 --sshuser glassfish --sshkeyfile ~/.ssh/id_rsa glassfish02
asadmin install-node --installdir /usr/local/glassfish3 --sshuser glassfish --sshkeyfile ~/.ssh/id_rsa glassfish03

6. DASにノードを追加

asadmin create-node-ssh --nodehost glassfish01 --sshuser glassfish --sshkeyfile ~/.ssh/id_rsa --installdir /usr/local/glassfish3 glassfish01
asadmin create-node-ssh --nodehost glassfish02 --sshuser glassfish --sshkeyfile ~/.ssh/id_rsa --installdir /usr/local/glassfish3 glassfish02
asadmin create-node-ssh --nodehost glassfish03 --sshuser glassfish --sshkeyfile ~/.ssh/id_rsa --installdir /usr/local/glassfish3 glassfish03

7. ノードにインスタンスを追加

asadmin create-instance --node glassfish01 --cluster cluster1 instance1
asadmin create-instance --node glassfish02 --cluster cluster1 instance2
asadmin create-instance --node glassfish03 --cluster cluster1 instance3

8. スティッキーセッションのためのプロパティ設定
この設定を行うと、Cookieの末尾にインスタンス識別子が付加され、
リクエストが振り分けられるインスタンスが固定されます。

asadmin create-system-properties --target instance1 INSTANCE=i1
asadmin create-system-properties --target instance2 INSTANCE=i2
asadmin create-system-properties --target instance3 INSTANCE=i3
asadmin create-jvm-options --target cluster1 -DjvmRoute=\${INSTANCE}

9. クラスタを起動
※OS起動時のクラスタの自動起動がわかりませんでした。ご存知の方教えて下さい><

asadmin start-cluster cluster1

GlassFishの設定はここまで。
次はnginxのインストールと設定です。

nginxは標準でスティッキーセッションの機能がありませんが、
モジュールを作ってくれている方がいらっしゃるので、ありがたく使わせて頂きます。

1. nginxインストール

ソースからインストールするので、ユーザを作ります。

groupadd nginx
useradd -g nginx nginx

依存ライブラリのインストール

yum install pcre-devel

ソースと追加モジュールのダウンロード

cd /usr/local/src
wget http://nginx.org/download/nginx-1.2.6.tar.gz
svn checkout http://nginx-sticky-module.googlecode.com/svn/trunk/ nginx-sticky-module-read-only

インストール
※各種パスとモジュールの指定は適宜読み替えてください。

tar xvf nginx-1.2.6.tar.gz
cd nginx-1.2.6
./configure \
  --prefix=/var/www \
  --user=nginx \
  --group=nginx \
  --sbin-path=/usr/local/sbin/nginx \
  --conf-path=/etc/nginx/nginx.conf \
  --error-log-path=/var/log/nginx/error.log \
  --http-log-path=/var/log/nginx/access.log \
  --pid-path=/var/run/nginx/nginx.pid \
  --lock-path=/var/lock/subsys/nginx.lock \
  --with-http_ssl_module \
  --with-http_realip_module \
  --with-http_gzip_static_module \
  --with-http_stub_status_module \
  --add-module=../nginx-sticky-module-read-only
make
make install

2. 設定ファイル修正
nginxのconfigureの時に–conf-pathで指定したパスに設定ファイルが出来ています。
以下、設定例です。
※スティッキーセッションに必要な設定は、upstreamのstickyだけです。

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log debug;

pid        /var/run/nginx/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" '
                      '$upstream_response_time';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;

    tcp_nopush      off;

    keepalive_timeout  65;

    gzip  off;

    server_tokens off;

    upstream cluster1 {
        sticky;
        server glassfish01:28080 max_fails=2 fail_timeout=10m;
        server glassfish02:28080 max_fails=2 fail_timeout=10m;
        server glassfish03:28080 max_fails=2 fail_timeout=10m;
    }

    server {
        listen       80;

        proxy_set_header Host               $host;
        proxy_set_header X-Real-IP          $remote_addr;
        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;

        error_page  404              /404.html;
        error_page  500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        location / {
            root   /var/www/html;
            index  index.html index.htm;
        }

        location /favicon.ico {
            root   /var/www/html;
        }

        location /warファイルコンテキスト名/ {
            proxy_pass    http://cluster1;
        }
    }
}

以上で環境は出来ました。
動作確認してみます。

1. 確認用ソース
以下をsession.jspという名前で保存して、warファイルを作成します。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="java.net.InetAddress" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.util.Date" %>
<%@ page import="javax.servlet.http.Cookie" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">
<!--
body
{
	font-family: 'MS ゴシック';
	font-size: 9pt;
}

table
{
	border-collapse: collapse;
	border-left: 1px;
	border-right: 1px;
	border-top: 1px;
	border-bottom: 1px;
	border-style: solid;
	border-color: #000000;
}

table.border
{
	border-left: 0px;
	border-right: 0px;
	border-top: medium solid;
	border-bottom: 0px;
	border-color: #000000;
}

td
{
	border-left: 0px;
	border-right: 1px;
	border-top: 0px;
	border-bottom: 1px;
	border-style: solid;
	border-color: #000000;
	margin: 2px;
	padding: 2px;
}

td.title-left
{
	background-color: #a3bacd;
	font-weight: bold;
	text-align: left;
}

td.title-center
{
	background-color: #a3bacd;
	font-weight: bold;
	text-align: center;
}
-->
</style>
</head>
<body>
<h1><font color="red">Session Info</font></h1>
<table align="center" border="0" width="800">
	<tr>
		<td class="title-left" width="120">Server</td>
		<td><%= InetAddress.getLocalHost().getHostName() %></td>
	</tr>
	<tr>
		<td class="title-left" width="120">Session ID</td>
		<td><%= session.getId() %></td>
	</tr>
	<tr>
		<td class="title-left" width="120">Created on</td>
		<td>
<%
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
			out.print(sdf.format(new Date(session.getCreationTime())));
%>
		</td>
	</tr>
	<tr>
		<td class="title-left" width="120">Request Count</td>
		<td>
<%
			if (session.getAttribute("count") == null) {
				session.setAttribute("count", new Integer(0));
			}
			int count = ((Integer)session.getAttribute("count")).intValue() + 1;
			session.setAttribute("count", new Integer(count));
			out.print(count);
%>
		</td>
	</tr>
</table>

<br/>
<table border="0" width="100%" class="border">
	<tr>
		<td width="80%"></td>
	</tr>
</table>

<h1><font color="red">Cookie Info</font></h1>
<table align="center" border="0" width="800">
	<tr>
		<td class="title-center">Name</td>
		<td class="title-center">Value</td>
		<td class="title-center">Domain</td>
		<td class="title-center">Path</td>
		<td class="title-center">MaxAge</td>
		<td class="title-center">Comment</td>
		<td class="title-center">Secure</td>
		<td class="title-center">Version</td>
	</tr>
<%
	Cookie[] cookies=request.getCookies();
	if (cookies != null) {
		for (int i=0; i<cookies.length; i++) {
			Cookie cookie = cookies[i];
			out.print("<tr>"  + "\r\n");
			out.print("<td>"  + cookie.getName()    + "</td>" + "\r\n");
			out.print("<td>"  + cookie.getValue()   + "</td>" + "\r\n");
			out.print("<td>"  + cookie.getDomain()  + "</td>" + "\r\n");
			out.print("<td>"  + cookie.getPath()    + "</td>" + "\r\n");
			out.print("<td>"  + cookie.getMaxAge()  + "</td>" + "\r\n");
			out.print("<td>"  + cookie.getComment() + "</td>" + "\r\n");
			out.print("<td>"  + cookie.getSecure()  + "</td>" + "\r\n");
			out.print("<td>"  + cookie.getVersion() + "</td>" + "\r\n");
			out.print("</tr>" + "\r\n");
		}
	}
%>
</table>

</body>
</html>

2. デプロイ
Jenkinsを使ってビルドからデプロイまで自動化するのが良いと思います。

asadmin --host=glassfish00 --port=4848 --passwordfile=/path/to/.glassfishpasswd deploy --target=cluster1 --contextroot=warファイルコンテキスト名 --force=true --property java-web-start-enabled=false:preserveAppScopedResources=true /path/to/warファイル

3. ブラウザで確認
http://nginxホスト名/warファイルコンテキスト名/session.jsp
を表示して、リクエストの度に「Request Count」の値がカウントアップされる事、
「JSESSIONID」の値が変わらない事を確認します。

4. GlassFishのWeb管理コンソールから、テスト中のセッションを処理しているノードを停止します。

5. もう一度ブラウザで確認
http://nginxホスト名/warファイルコンテキスト名/session.jsp
を再度表示して、「Request Count」の値が初期化されずにカウントアップされる事、
「JSESSIONID」の値はインスタンス識別子の部分だけ変わる事を確認します。

以上で完了です。

最後に
nginx + GlassFishの組み合わせは情報が少なかったです。
昔からApacheを使うのが当たり前ではありますが、(マニュアルにも載ってるし)
個人的には、nginxの方が設定がわかりやすくパフォーマンスも優れていると思います。


コメントする

第4回インフラ勉強会@福岡 Fluentdハンズオンを開催しました

9/22(土)に「第4回 インフラ勉強会@福岡 Fluentdハンズオン」を開催しました。

ご参加頂いた方々、ありがとうございました!!

第4回 インフラ勉強会@福岡 Fluentdハンズオン

今回のハンズオン内容は、

  1. Fluentdの簡単な説明と事例紹介
  2. 自分が使いたいデータストア(MySQL, PostgreSQL, MongoDB)をインストール
  3. Fluentdとプラグインのインストール
  4. 僕が準備したconfigの説明
  5. Apacheのログを収集してみる
  6. 自作プラグインを動かしてみる

といった内容で行いました。

GrowthForecastでグラフ書いたり、ikachan経由でIRCサーバに通知したりしたかったんですが、
準備が間に合わなくて出来ませんでした。すみません。。。

 

今回初めてFluentdを使うという方が結構いらっしゃったので、
きっかけとしては良かったかなぁと思いました。
個人的にFluentdすごく好きなので、福岡でも興味を持つ人がもっと増えたら嬉しいです!

 

以下、ハンズオンで使った資料とスライドです。

configと自作プラグインのサンプルなど一式
※GitHubに置いてます

 

最後にお礼です。

@frsyukiさん、@GedowFatherさん、@mikedaさん、@hotchpotchさん、@repeatedlyさん、@tagomorisさん、@riywoさん、@taka84u9さん

のスライド、ブログ、SoftwareDesignの特集記事、ソースなどを、参考・紹介させて頂きました。

ありがとうございますm(_ _)m


コメントする

第3回 インフラ勉強会@福岡でLTしてきました

 

第3回 インフラ勉強会@福岡でLTしてきました。

第3回 インフラ勉強会@福岡

ご参加いただいた皆さん、LTしてくださった@ToshiChanさん、
@minimum2scpさん、ありがとうございました。

@minimum2scpさんのスライドはこちら

第1回 福岡Debian勉強会、7/28(土) に仮決定だそうです。
Debian使いではないですけど、楽しみです!

 

みなさん、次回もご都合があえば、ぜひご参加ください!

僕のスライドはこちら。
継続的デリバリーという本の内容から、インフラに関係ある事をお話しました。


1件のコメント

MySQL Casual Talks @gumi福岡でLTしてきました

 

あのMySQL Casual Talksが福岡でも行われるという事で、BKA JOINについてLTさせてもらいました。

主催者の@Spring_MTさん、会場をご提供いただいたgumiさん、参加された皆さん、ありがとうございました。

MySQL Casual Talks @gumi福岡

勉強を初めたばかりの初学者にも関わらず、ソースも読んでみましましたが、
マニュアルなどに書いてある仕様やアルゴリズムがどういう風に実装されているのか、
少しずつでもわかり始めると非常に面白くなってきます。
OSSのソースコードリーディングはお薦めです。

参加した感想ですが、「MySQLすげぇ!」の一言です。
特に5.6は凄い!Oracleさんの本気を感じました。

規模や要件に合わせて色んな構成が組めるし、実案件でのノウハウもみなさんオープンにされているし、
他のデータベースにはない文化があるなぁと感じました。

もっとMySQLを勉強したくなりました。
MySQL (・∀・)イイネ!!

# Vol2.もあるといいなぁ。


1件のコメント

hktstudy #01でLTしてきました

 

先日開催されたhktstudy #01に参加して、
「JVM監視」という、あまり需要がなさそうな内容でLTさせてもらいました><

主催者の@zabbiozabbioさん、参加された皆さん、ありがとうございました。

hktstudy #01 ~恋せよ乙女~

# 「恋せよ乙女」ってWANDSですか?

今回はZabbix2.0しか試さなかったんですが、僕がやりたい事が全部出来そうなので、
現在業務で使っている監視ツールをZabbix2.0置き換えて行こうと思います。

hktstudyは初心者エンジニアに優しい勉強会なので、皆さんもぜひご参加ください。

数ヶ月前までは福岡ではインフラ関係の勉強会が一切なく、
インフラに携わる者としては寂しい限りだったのですが、
最近は色んな方が勉強会を主催されて非常に盛り上がってきてます。

皆さん、インフラも楽しいよ!!