SlideShare a Scribd company logo
Javaでやってみる	
The	Twelve	Factor	App	
JJUG-CCC	2014	Fall	
R1-5	
ベルサール西新宿	
2014-11-15(Sat)
自己紹介	
•  渡辺	祐	
•  (株)ビズリーチ	
•  @nabedge	
•  hCp://mixer2.org	
•  hCp://nabedge.blogspot.jp	
2
hCp://12factor.net	
3
このセッションのポイント	
1.  12-Factor	Appという論文に合わせ、	
2.  妄信せず、現実と折り合いをつけ
ながら、	
3.  Java言語	+	α	でどう実現するか?	
4
注意	
•  12-Factorの主張の是非はここでは議論しない。	
•  1要素	⇔	1ツール/ライブラリで解決ということはない。	
•  12要素全部やらないとダメってことでもない。	
•  12-factorに書いてある通りにやるわけでもない	
(臨機応変に解釈してアレンジ)	
5
主に使う道具	
•  Java7	or	higher	
•  Spring	Framework	4.x	
•  Spring	Boot	
•  Tomcat-embed	7	or	higher	
•  maven	(gradle)	
•  Sonatype	NEXUS	
•  Jenkins	
6
話の順序	
VII 	ポートバインディング	
IX	 	廃棄容易性	
XI	 	ログ	
III	 	設定	
V 	 	ビルド、リリース、実行の分離	
II 	 	依存関係の明示的な宣言	
VI	 	ステートレスなプロセス	
最後に番外編	 7
VII	『ポートバインディングを通じて
サービスを公開せよ』	
8
VII	ポートバインディング	
•  『Webアプリは自らポートを開いて
ユーザーからのリクエストを待て。』	
•  『RubyならThin,	JavaならJeCyが	
いいかもね。』	
9
Tomcatが好きなので	
今回は下記の構成	
1.  Tomcat	embed	8.x	(7.xでもよい)	
2.  Spring	Boot	経由で起動	
10
結論を先に	
•  [CATALINA_HOME]/webapp	に	
foobar.warを置いてTomcatを	
起動する	
	
•  開発したアプリの中で、その	
いち依存ライブラリたるTomcatが	
ポートを開いてリクエストを待つ。	
11
組み込みTomcatとは	
•  Tomcat	7.0.1x	(2011年初頭)くらいか
ら安定リリース	
•  tomcat-embed-core-7.0.x.jar	
•  tomcat-embed-logging-log4j-7.0.x.jar	
12
そのまま使おうとすると	
public	stadc	void	main(String[]	args)	{	
	Tomcat	tomcat	=	new	Tomcat();	
	tomcat.setPort(8080);	
	tomcat.addWebapp("/”,	
	 	new	File(“/var/webAppDir)	
	 	 	.getAbsolutePath());	
	tomcat.start();	
	tomcat.getServer().await();	
}	
13
ここでSpring	Boot登場	
14	
2014年4月	1.0.0.RELEASE
SpringのBeanとしてTomcatを定義	
@Configuradon	
public	class	WebMvcConfig	extends	WebMvcConfigurerAdapter	{	
	@Bean	
	public	EmbeddedServletContainerFactory	
embeddedServletContainerFactory()	{	
	 	TomcatEmbeddedServletContainerFactory	factory		
	 	 	=	new	TomcatEmbeddedServletContainerFactory();	
	 	factory.setPort(8080);	
	 	factory.setUriEncoding(“UTF-8”);	
	 	factory.setContextPath("");	
}	
15
MainメソッドでSpringを起動	
public	stadc	void	main(String[]	args)	{	
	SpringApplicadonBuilder	builder		
	 	=	new	SpringApplicadonBuilder();	
	builder.sources(WebMvcConfig.class);	
	ConfigurableApplicadonContext	context		
	 	=	builder.run(args);	
	context.registerShutdownHook();	
16
main()メソッド起動ということは	
17	
これでローカル環境で	
Tomcatが8080ポートを開き、	
リクエストを待つ。	
(本番環境でも同じこと)
プラグインは、もう、いらない。	
18	
Sysdeo	Tomcat	Plugin	
WTP	Plugin
Tomcatのバージョンアップもお手軽	
<dependency>	
	<groupId>org.apache.tomcat.embed</groupId>	
						<ardfactId>tomcat-embed-core</ardfactId>	
						<version>7.0.56</version>	
</dependency>	
<dependency>	
	<groupId>org.apache.tomcat.embed</groupId>	
						<ardfactId>tomcat-embed-logging-log4j</ardfactId>	
						<version>7.0.56</version>	
</dependency>	
19
APサーバという固定観念を捨てよう	
•  Linuxマシンを用意して、Tomcat/GlassFishをイ
ンストールして...ビルドジョブを書いて...
アプリをデプロイして...	
20
IX	『廃棄容易性』	
	−	高速な起動と	
	 	グレースフルなシャットダウンを	
	 	心がけよ	−	
21
高速な起動? あきらめよう	
•  理想: 一ケタ秒	
•  現実:	20秒〜30秒	
– サンプルアプリ程度なら10秒以内	
•  Web●ogicよりは速かろう...	
22
グレースフルなシャットダウン?	
•  意訳:「中途半端な残タスクや	
ゴミ掃除を終えてからアプリを終了さ
せましょう」	
•  きちんとShutdownHookを	
指定すればいい。	
23
@PreDestroy	
public	void	lazyUpdate()	{	
	//	例:DB操作を遅延実行するメソッド	
}	
	
@Bean(destroyMethod=“close”)	
public	DataSource	dataSource()	{	
	//	例:DBのデータソース生成メソッド	
}	
24
public	stadc	void	main(String[]	args)	{	
	SpringApplicadonBuilder	builder		
	 	=	new	SpringApplicadonBuilder();	
	builder.sources(WebMvcCfg.class);	
	ConfigurableApplicadonContext	context		
	 	=	builder.run(args);	//	ここで起動	
	context.registerShutdownHook();	
}	
25	
Springならメソッド1個呼ぶだけ
30秒ほどCMと休憩	
1.  水を飲む	
2.  時間を確認:15分くらい	
26	
Javaな人、絶賛採用中	
hCp://www.bizreach.co.jp/recruit/
IX	『ログをイベントストリーム	
	 	として扱え』	
	
27
Twelve-Factor	Appはアプリケーションの出力ス
トリームの送り先やストレージについて一切関
知しない。 アプリケーションはログファイルに書
き込んだり管理しようとするべきではない。代わ
りに、それぞれの実行中のプロセスはイベント
ストリームをstdout(標準出力)にバッファリング
せずに書きだす。ローカルでの開発中、開発者
はこのストリームをターミナルのフォアグラウン
ドで見ることで、アプリケーションの挙動を観察
する。	
28
とにかくやることはひとつ	
「すべてのログを	
	標準出力に集めよ」	
29
アプリはどこで動く?	
•  Windows7	+	Eclipse	
•  OracleVirtualBox	+	CentOS	
•  Dockerコンテナ	
•  AWSのEC2	
•  Heroku	
•  オンプレミス	
30
31	
すべての状況に対応しうるのは	
標準出力しかない
32	
•  自作アプリのログ	
•  ライブラリ/フレームワーク
のログ(Tomcat含む)	
標準出力	
Fluentd	
TreasureData	
GoogleBigQuery	
rsyslog	
/dev/null	
ElasdcSearch
※	SYSLOGに中継したい場合	
•  Logback(Log4jも)のSyslogAppenderはUDPを
使うのでログのロストが怖い	
•  Java	Service	Wrapper提供のラッパーのログ
中継機能が便利	
– Linux,Win,MacOS用の各バイナリあり	
– 詳しくは	hCp://wrapper.tanukisowware.com/	
33
34	
ログの集約は、	
ロギングライブラリの集約から。
•  Spring	Framework	
	commons-logging	
•  Tomcat	
	log4j	または java.udl.logging	
•  他のライブラリ	
	slf4j、commons-logging、log4j	
•  自分のライブラリ	
	slf4j	
35
Slf4jのブリッジライブラリで集約	
36	
log4j	 log4j-over-slf4j	
commons	
-logging	
jcl-over-slf4j	
Slf4j-api	
logback	
ConsoleAppender	
従来型ライブラリは	
すべて依存関係から除
外(exclusion)しておく!
SpringBootなら折り込み済み	
37
logbackの設定	
•  すべてConsoleAppender	
•  以下二つは変数化して外部から調整可能に
しておく。	
– ログのレベル(DEBUG	/	INFO)	
– タイムスタンプの有無	
•  例:ローカル環境で開発中はタイムスタンプ有り	
•  例:本番環境では、ログ集約システムの側で	
タイムスタンプを付加する	
38
ところで、GCログどうする?	
•  フォーマットが独特すぎて	
他のログと混ぜると….	
•  どうしようもないかもしれない。	
ログの先頭に任意の固定プレフィクスでも	
付けられればいいんですが…	
•  -Xloggc:/var/log/gc.log..	とかはもうやめて、
JMX経由でGC状況をモニタリング?	
39
III	『設定はOS環境変数に	
	 	格納せよ』	
	
40
41	
「設定ファイルもソースコードも	
同じツリーでVCSに入れて管理し、	
ビルドのたびにjar(war)に含めて
いますが、何か?」	
本番DBのパスワードも	
そんな管理でいいの?
42	
「本番用の設定ファイルだけは別
のVCSで管理しています。」	
1.  面倒くさい	
2.  そもそも言語/ライブラリ/	
フレームワークによって	
フォーマットが異なる
だから「OS環境変数」	
1.  LinuxでもWindowsでも	
OS環境変数の設定方法はほとんど同じ。	
2.  気の利いたライブラリの多くはOS環境変
数からの設定値読み込みに対応してい
る。	
3.  対応していなくても起動時のコマンドライ
ン引数にOS環境変数をあてるとか。	
4.  どうせ ansible/chef/puppet	で自動設定
するし。	
43
<logger	name=”com.example.myapp"		
	level="${AP_LOG_LEVEL:-DEBUG}"	/>	
44	
上の“$AP_LOG_LEVEL”	変数の優先順位	
1. 	logback.xml上のproperty値	
2. 	Javaシステムプロパティ	
	 	 	-DAP_LOG_LEVEL=INFO	
3. 	OS環境変数	
	 	 	export	AP_LOG_LEVEL=INFO	
4. 	上記のどこにも無い場合にはDEBUG
45	
自作するアプリ自体の設定値を	
どうやって可変にするか?
SpringBoot流 設定値の埋め込み方	
@Component	
public	class	Foo	{	
	
	@Value(“foo.bar”)	
	private	String	bar	=	“hoge”;	//	default値		
	
}	
46
さっきのfoo.barの値の変え方	
1.  コマンドライン引数	
java	–cp	…	--foo.bar=xxxxx	//ハイフン2個	
2.  OS環境変数	
3.  コマンドラインで指定した位置にある	
”applicadon.properdes”	
4.  クラスパス直下のapplicadon.properdes	
5.  ソースコード上の値	
47	
実際はもう少し細かいので詳細は	
hCp://docs.spring.io/spring-boot/docs/1.1.7.RELEASE/reference/html/boot-features-external-config.html
II	『依存関係を明示的に	
	宣言し分離せよ』	
V	『ビルド/リリース/実行は	
	厳密に分離せよ』	
48
49	
それはCM②のあとで	
1.  水を飲む	
2.  時間を確認:30分くらい
50	
Scalaな人も大歓迎	
hCp://www.bizreach.co.jp/recruit/
II	『依存関係を明示的に	
	宣言し分離せよ』	
V	『ビルド/リリース/実行は	
	厳密に分離せよ』	
51
まずはビルドツール	
• バイナリ間の依存関係管理機能
のあるビルドツールを使う	
Maven	
Gradle	
– 以上、終わり…でもない(後述)	
52
一方、これもある意味NGらしい	
•  「サーバにリリースだ!」	
1.  ソースをチェックアウト	
2.  設定ファイル差し替え	
3.  mvn	compile	package	
4.  app.warの完成	
5.  scpして	
6.  sshでAPサーバ再起動	
53
54	
ビルド、リリース、実行を、分離せよ。
ビルドという作業	
55	
VCS	
checkout	
mvn		
		compile	
		package	
jar	
mvn		
		deploy	
パッケージ	
リポジトリ	
GOAL
ポイント	
•  「ビルド」の結果はjar(war)という	
バイナリ	
•  バイナリは	
パッケージリポジトリサーバ	
(以下PKGリポジトリ)にdeploy(格納)	
しておくものである	
•  MavenもGradleもバイナリ間の依存性
解決にはPKGリポジトリの存在が必須	
56
PKGリポジトリを構築しておく	
•  Sonatype	NEXUS	
•  Ardfactory	
– Bintray?	
•  Apache	+	mod_webdav	
(おすすめできない)	
57
ビルドという作業(再掲)	
58	
VCS	
checkout	
mvn		
		compile	
		package	
jar	
mvn		
		deploy	
パッケージ	
リポジトリ	
GOAL
リリースという作業	
59	
PKGリポジトリ	
1.  mvn	copy-dependencies	
2.  zip	
3.  scp	
サーバ上でunzip	
•  自分が開発したアプリjar	
•  依存ライブラリjar	
GOAL
実行という作業	
60	
$	java		
	–cp	“jar群の展開dir/*”		
	com.example.MyAppMainClass	
※設定値はOS上に環境変数として保存済み	
“*”(ワイルドカー
ド指定)でおk	
(java6以降)
1. Javaアプリはバイナリ(jar)の集合体	
2. 自分で書いたソースもビルドすれば	
バイナリ(jar)になる	
3. バイナリの間に依存関係がある	
4. すべてのバイナリはPKGリポジトリ
に格納して管理する	
(VCSに入れるな!)	
61
5.  リリース作業では依存関係を	
たどってバイナリ(群)をPKGリポジ
トリから取得してサーバに配置	
6.  設定はOS環境変数に書いてある	
7.  よって、どのサーバにも同じバイナ
リを配置して使い回し可能	
62
63	
II			依存関係の管理	
III		設定	
V			ビルド、リリース、実行の分離	
Javaアプリでは、下の4つ全てが絡み合って	
3要素が成立	
1. 	ビルドツール	
2. 	PKGリポジトリ	
3. 	OS環境変数(chef/puppet/ansible)	
4. 	CIツール
VI	『アプリケーションをステートレスな
プロセスとして実行せよ』	
64
65	
しつこいようですがCMです	
時間を確認:45分くらい
66	
CTO	トップライブ 11/30(Sun)	
hCp://www.bizreach.co.jp/recruit/event	
ちょっとくらい興味あるかもという方に	
−	キャリア採用イベント	−
VI	『アプリケーションをステートレスな
プロセスとして実行せよ』	
67
ポイント	
「ステートレスなプロセス」	
≒	sdckyセッション禁止	
68
いろいろ難しいので	
•  Sdckyセッション +	ELB	でいいのでは。	
•  Tomcatのセッションストアプラグイン
(keyValue,	RDBMS)は	
serialize/deserialize	がらみでいろいろトラブル	
•  今回は、いくつかのプランの紹介のみ	
69
プランA:	Stateless	Session	Cookie	
•  セッション情報自体を暗号化してCookie
の値に埋め込む手法	
•  Play	Frameworkが採用	
•  大きな情報をセッションに格納できない	
70
プランB:	Memcached	
•  memcached-session-manager	
– Tomcatのvalveとして使うプラグイン	
– SpringFrameworkとは無関係に動かせる	
•  あくまで個人的な検証結果:	
– SpringMVC	+	SpringSecurity	+	FlashScope変数を
組み合わせるとserialize失敗の例外が出やすい	
71
プランC:	Spring-Session	
•  Spring-session	
•  Spring-session-redis	
•  どちらも正式リリース前	
•  未検証(だれか人柱頼む)	
72
73	
番外編	
-	12-Factorには書いてないけれど	-
*.war,	web.xml,	JSP禁止	
•  Servlet3.xでGO	
•  src/main/webapp	すら無しの方向で	
•  ビューはThymeleafかMixer2で。	
– src/main/resources/templates	に配置	
•  こうすると、もうwarに固める必要なし。	
•  *.jar群をクラスパスに入れてjavaコマンドで
起動(単純!)	
–  SpringBootの独自one-jar形式は、、、	
74	
あくまでも個人的な意見です
まとめ、、、ている時間は	
たぶんないだろう	
75
ありがとうございました!	
76

More Related Content

Javaでやってみる The Twelve Factor App JJUG-CCC 2014 Fall 講演資料