Slide 1

Slide 1 text

Javaでやってみる   The  Twelve  Factor  App JJUG-­‐CCC  2014  Fall   R1-­‐5   ベルサール西新宿   2014-­‐11-­‐15(Sat)

Slide 2

Slide 2 text

自己紹介 •  渡辺  祐   •  (株)ビズリーチ   •  @nabedge   •  hCp://mixer2.org   •  hCp://nabedge.blogspot.jp   2

Slide 3

Slide 3 text

hCp://12factor.net 3

Slide 4

Slide 4 text

このセッションのポイント 1.  12-­‐Factor  Appという論文に合わせ、   2.  妄信せず、現実と折り合いをつけ ながら、   3.  Java言語  +  α  でどう実現するか? 4

Slide 5

Slide 5 text

注意 •  12-­‐Factorの主張の是非はここでは議論しない。   •  1要素  ⇔  1ツール/ライブラリで解決ということはない。   •  12要素全部やらないとダメってことでもない。   •  12-­‐factorに書いてある通りにやるわけでもない   (臨機応変に解釈してアレンジ) 5

Slide 6

Slide 6 text

主に使う道具 •  Java7  or  higher   •  Spring  Framework  4.x   •  Spring  Boot   •  Tomcat-­‐embed  7  or  higher   •  maven  (gradle)   •  Sonatype  NEXUS   •  Jenkins 6

Slide 7

Slide 7 text

話の順序 VII  ポートバインディング   IX    廃棄容易性   XI    ログ   III    設定   V    ビルド、リリース、実行の分離   II    依存関係の明示的な宣言   VI    ステートレスなプロセス   最後に番外編 7

Slide 8

Slide 8 text

VII  『ポートバインディングを通じて サービスを公開せよ』 8

Slide 9

Slide 9 text

VII  ポートバインディング •  『Webアプリは自らポートを開いて ユーザーからのリクエストを待て。』   •  『RubyならThin,  JavaならJeCyが   いいかもね。』 9

Slide 10

Slide 10 text

Tomcatが好きなので 今回は下記の構成   1.  Tomcat  embed  8.x  (7.xでもよい)   2.  Spring  Boot  経由で起動   10

Slide 11

Slide 11 text

結論を先に •  [CATALINA_HOME]/webapp  に   foobar.warを置いてTomcatを   起動する     •  開発したアプリの中で、その   いち依存ライブラリたるTomcatが   ポートを開いてリクエストを待つ。 11

Slide 12

Slide 12 text

組み込みTomcatとは •  Tomcat  7.0.1x  (2011年初頭)くらいか ら安定リリース   •  tomcat-­‐embed-­‐core-­‐7.0.x.jar   •  tomcat-­‐embed-­‐logging-­‐log4j-­‐7.0.x.jar 12

Slide 13

Slide 13 text

そのまま使おうとすると 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

Slide 14

Slide 14 text

ここでSpring  Boot登場 14 2014年4月  1.0.0.RELEASE

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

MainメソッドでSpringを起動 public  stadc  void  main(String[]  args)  {    SpringApplicadonBuilder  builder        =  new  SpringApplicadonBuilder();    builder.sources(WebMvcConfig.class);    ConfigurableApplicadonContext  context        =  builder.run(args);    context.registerShutdownHook();   16

Slide 17

Slide 17 text

main()メソッド起動ということは 17 これでローカル環境で   Tomcatが8080ポートを開き、   リクエストを待つ。   (本番環境でも同じこと)

Slide 18

Slide 18 text

プラグインは、もう、いらない。 18 Sysdeo  Tomcat  Plugin WTP  Plugin

Slide 19

Slide 19 text

Tomcatのバージョンアップもお手軽    org.apache.tomcat.embed              tomcat-­‐embed-­‐core              7.0.56        org.apache.tomcat.embed              tomcat-­‐embed-­‐logging-­‐log4j              7.0.56   19

Slide 20

Slide 20 text

APサーバという固定観念を捨てよう •  Linuxマシンを用意して、Tomcat/GlassFishをイ ンストールして...ビルドジョブを書いて... アプリをデプロイして...   20

Slide 21

Slide 21 text

IX  『廃棄容易性』    −  高速な起動と      グレースフルなシャットダウンを      心がけよ  − 21

Slide 22

Slide 22 text

高速な起動? あきらめよう •  理想: 一ケタ秒   •  現実:  20秒〜30秒   – サンプルアプリ程度なら10秒以内   •  Web●ogicよりは速かろう...   22

Slide 23

Slide 23 text

グレースフルなシャットダウン? •  意訳:「中途半端な残タスクや   ゴミ掃除を終えてからアプリを終了さ せましょう」   •  きちんとShutdownHookを   指定すればいい。 23

Slide 24

Slide 24 text

@PreDestroy   public  void  lazyUpdate()  {    //  例:DB操作を遅延実行するメソッド   }     @Bean(destroyMethod=“close”)   public  DataSource  dataSource()  {    //  例:DBのデータソース生成メソッド   } 24

Slide 25

Slide 25 text

public  stadc  void  main(String[]  args)  {    SpringApplicadonBuilder  builder        =  new  SpringApplicadonBuilder();    builder.sources(WebMvcCfg.class);    ConfigurableApplicadonContext  context        =  builder.run(args);  //  ここで起動    context.registerShutdownHook();   } 25 Springならメソッド1個呼ぶだけ

Slide 26

Slide 26 text

30秒ほどCMと休憩 1.  水を飲む   2.  時間を確認:15分くらい 26 Javaな人、絶賛採用中 hCp://www.bizreach.co.jp/recruit/  

Slide 27

Slide 27 text

IX  『ログをイベントストリーム      として扱え』   27

Slide 28

Slide 28 text

Twelve-­‐Factor  Appはアプリケーションの出力ス トリームの送り先やストレージについて一切関 知しない。 アプリケーションはログファイルに書 き込んだり管理しようとするべきではない。代わ りに、それぞれの実行中のプロセスはイベント ストリームをstdout(標準出力)にバッファリング せずに書きだす。ローカルでの開発中、開発者 はこのストリームをターミナルのフォアグラウン ドで見ることで、アプリケーションの挙動を観察 する。 28

Slide 29

Slide 29 text

とにかくやることはひとつ 「すべてのログを    標準出力に集めよ」 29

Slide 30

Slide 30 text

アプリはどこで動く? •  Windows7  +  Eclipse   •  OracleVirtualBox  +  CentOS   •  Dockerコンテナ   •  AWSのEC2   •  Heroku   •  オンプレミス   30

Slide 31

Slide 31 text

31 すべての状況に対応しうるのは   標準出力しかない

Slide 32

Slide 32 text

32 •  自作アプリのログ   •  ライブラリ/フレームワーク のログ(Tomcat含む)   標準出力 Fluentd TreasureData   GoogleBigQuery rsyslog /dev/null ElasdcSearch

Slide 33

Slide 33 text

※  SYSLOGに中継したい場合 •  Logback(Log4jも)のSyslogAppenderはUDPを 使うのでログのロストが怖い   •  Java  Service  Wrapper提供のラッパーのログ 中継機能が便利   – Linux,Win,MacOS用の各バイナリあり   – 詳しくは  hCp://wrapper.tanukisowware.com/ 33

Slide 34

Slide 34 text

34 ログの集約は、   ロギングライブラリの集約から。

Slide 35

Slide 35 text

•  Spring  Framework    commons-­‐logging   •  Tomcat    log4j  または java.udl.logging   •  他のライブラリ    slf4j、commons-­‐logging、log4j   •  自分のライブラリ    slf4j 35

Slide 36

Slide 36 text

Slf4jのブリッジライブラリで集約 36 log4j log4j-­‐over-­‐slf4j commons   -­‐logging jcl-­‐over-­‐slf4j Slf4j-­‐api logback ConsoleAppender 従来型ライブラリは   すべて依存関係から除 外(exclusion)しておく!

Slide 37

Slide 37 text

SpringBootなら折り込み済み 37

Slide 38

Slide 38 text

logbackの設定 •  すべてConsoleAppender   •  以下二つは変数化して外部から調整可能に しておく。   – ログのレベル(DEBUG  /  INFO)   – タイムスタンプの有無   •  例:ローカル環境で開発中はタイムスタンプ有り   •  例:本番環境では、ログ集約システムの側で   タイムスタンプを付加する 38

Slide 39

Slide 39 text

ところで、GCログどうする? •  フォーマットが独特すぎて   他のログと混ぜると….   •  どうしようもないかもしれない。   ログの先頭に任意の固定プレフィクスでも   付けられればいいんですが…   •  -­‐Xloggc:/var/log/gc.log..  とかはもうやめて、 JMX経由でGC状況をモニタリング?   39

Slide 40

Slide 40 text

III  『設定はOS環境変数に      格納せよ』   40

Slide 41

Slide 41 text

41 「設定ファイルもソースコードも   同じツリーでVCSに入れて管理し、   ビルドのたびにjar(war)に含めて いますが、何か?」 本番DBのパスワードも   そんな管理でいいの?

Slide 42

Slide 42 text

42 「本番用の設定ファイルだけは別 のVCSで管理しています。」 1.  面倒くさい   2.  そもそも言語/ライブラリ/   フレームワークによって   フォーマットが異なる

Slide 43

Slide 43 text

だから「OS環境変数」 1.  LinuxでもWindowsでも   OS環境変数の設定方法はほとんど同じ。   2.  気の利いたライブラリの多くはOS環境変 数からの設定値読み込みに対応してい る。   3.  対応していなくても起動時のコマンドライ ン引数にOS環境変数をあてるとか。   4.  どうせ ansible/chef/puppet  で自動設定 するし。 43

Slide 44

Slide 44 text

  44 上の“$AP_LOG_LEVEL”  変数の優先順位   1.   logback.xml上のproperty値   2.   Javaシステムプロパティ        -­‐DAP_LOG_LEVEL=INFO   3.   OS環境変数        export  AP_LOG_LEVEL=INFO   4.   上記のどこにも無い場合にはDEBUG  

Slide 45

Slide 45 text

45 自作するアプリ自体の設定値を   どうやって可変にするか?

Slide 46

Slide 46 text

SpringBoot流 設定値の埋め込み方 @Component   public  class  Foo  {      @Value(“foo.bar”)    private  String  bar  =  “hoge”;  //  default値       } 46

Slide 47

Slide 47 text

さっきの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

Slide 48

Slide 48 text

II  『依存関係を明示的に    宣言し分離せよ』   V  『ビルド/リリース/実行は    厳密に分離せよ』 48

Slide 49

Slide 49 text

49 それはCM②のあとで 1.  水を飲む   2.  時間を確認:30分くらい

Slide 50

Slide 50 text

50 Scalaな人も大歓迎 hCp://www.bizreach.co.jp/recruit/  

Slide 51

Slide 51 text

II  『依存関係を明示的に    宣言し分離せよ』   V  『ビルド/リリース/実行は    厳密に分離せよ』 51

Slide 52

Slide 52 text

まずはビルドツール • バイナリ間の依存関係管理機能 のあるビルドツールを使う   Maven   Gradle   – 以上、終わり…でもない(後述) 52

Slide 53

Slide 53 text

一方、これもある意味NGらしい •  「サーバにリリースだ!」   1.  ソースをチェックアウト   2.  設定ファイル差し替え   3.  mvn  compile  package   4.  app.warの完成   5.  scpして   6.  sshでAPサーバ再起動 53

Slide 54

Slide 54 text

54 ビルド、リリース、実行を、分離せよ。

Slide 55

Slide 55 text

ビルドという作業 55 VCS checkout mvn        compile      package jar mvn        deploy   パッケージ   リポジトリ GOAL

Slide 56

Slide 56 text

ポイント •  「ビルド」の結果はjar(war)という   バイナリ   •  バイナリは   パッケージリポジトリサーバ   (以下PKGリポジトリ)にdeploy(格納)   しておくものである   •  MavenもGradleもバイナリ間の依存性 解決にはPKGリポジトリの存在が必須 56

Slide 57

Slide 57 text

PKGリポジトリを構築しておく •  Sonatype  NEXUS   •  Ardfactory   – Bintray?   •  Apache  +  mod_webdav   (おすすめできない) 57

Slide 58

Slide 58 text

ビルドという作業(再掲) 58 VCS checkout mvn        compile      package jar mvn        deploy   パッケージ   リポジトリ GOAL

Slide 59

Slide 59 text

リリースという作業 59 PKGリポジトリ 1.  mvn  copy-­‐dependencies   2.  zip   3.  scp   サーバ上でunzip •  自分が開発したアプリjar   •  依存ライブラリjar GOAL

Slide 60

Slide 60 text

実行という作業 60 $  java  \    –cp  “jar群の展開dir/*”  \    com.example.MyAppMainClass ※設定値はOS上に環境変数として保存済み “*”(ワイルドカー ド指定)でおk   (java6以降)

Slide 61

Slide 61 text

1. Javaアプリはバイナリ(jar)の集合体   2. 自分で書いたソースもビルドすれば   バイナリ(jar)になる   3. バイナリの間に依存関係がある   4. すべてのバイナリはPKGリポジトリ に格納して管理する   (VCSに入れるな!)   61

Slide 62

Slide 62 text

5.  リリース作業では依存関係を   たどってバイナリ(群)をPKGリポジ トリから取得してサーバに配置   6.  設定はOS環境変数に書いてある   7.  よって、どのサーバにも同じバイナ リを配置して使い回し可能   62

Slide 63

Slide 63 text

63 II      依存関係の管理   III    設定   V      ビルド、リリース、実行の分離 Javaアプリでは、下の4つ全てが絡み合って   3要素が成立   1.   ビルドツール   2.   PKGリポジトリ   3.   OS環境変数(chef/puppet/ansible)   4.   CIツール  

Slide 64

Slide 64 text

VI  『アプリケーションをステートレスな プロセスとして実行せよ』 64

Slide 65

Slide 65 text

65 しつこいようですがCMです 時間を確認:45分くらい

Slide 66

Slide 66 text

66 CTO  トップライブ 11/30(Sun) hCp://www.bizreach.co.jp/recruit/event   ちょっとくらい興味あるかもという方に −  キャリア採用イベント  −

Slide 67

Slide 67 text

VI  『アプリケーションをステートレスな プロセスとして実行せよ』 67

Slide 68

Slide 68 text

ポイント 「ステートレスなプロセス」   ≒  sdckyセッション禁止 68

Slide 69

Slide 69 text

いろいろ難しいので •  Sdckyセッション +  ELB  でいいのでは。   •  Tomcatのセッションストアプラグイン (keyValue,  RDBMS)は   serialize/deserialize  がらみでいろいろトラブル   •  今回は、いくつかのプランの紹介のみ 69

Slide 70

Slide 70 text

プランA:  Stateless  Session  Cookie •  セッション情報自体を暗号化してCookie の値に埋め込む手法   •  Play  Frameworkが採用   •  大きな情報をセッションに格納できない   70

Slide 71

Slide 71 text

プランB:  Memcached •  memcached-­‐session-­‐manager   – Tomcatのvalveとして使うプラグイン   – SpringFrameworkとは無関係に動かせる   •  あくまで個人的な検証結果:   – SpringMVC  +  SpringSecurity  +  FlashScope変数を 組み合わせるとserialize失敗の例外が出やすい 71

Slide 72

Slide 72 text

プランC:  Spring-­‐Session •  Spring-­‐session   •  Spring-­‐session-­‐redis   •  どちらも正式リリース前   •  未検証(だれか人柱頼む) 72

Slide 73

Slide 73 text

73 番外編   -­‐  12-­‐Factorには書いてないけれど  -­‐

Slide 74

Slide 74 text

*.war,  web.xml,  JSP禁止 •  Servlet3.xでGO   •  src/main/webapp  すら無しの方向で   •  ビューはThymeleafかMixer2で。   – src/main/resources/templates  に配置   •  こうすると、もうwarに固める必要なし。   •  *.jar群をクラスパスに入れてjavaコマンドで 起動(単純!)   –  SpringBootの独自one-­‐jar形式は、、、 74 あくまでも個人的な意見です

Slide 75

Slide 75 text

まとめ、、、ている時間は   たぶんないだろう 75

Slide 76

Slide 76 text

ありがとうございました! 76