Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JavaでやってみるThe 12 Factor App

Yu Watanabe
November 11, 2014

JavaでやってみるThe 12 Factor App

Japan Java Users Group Cross Community Conferrence 2014 Fall

Yu Watanabe

November 11, 2014
Tweet

More Decks by Yu Watanabe

Other Decks in Technology

Transcript

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

    View full-size slide

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

    View full-size slide

  3. hCp://12factor.net
    3

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  15. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    19

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    27

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  37. SpringBootなら折り込み済み
    37

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    40

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  44.    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  

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide