Ch3 : Play command & build & deploy

[Introduce]
Play本身的建置是用sbt工具來建置環境,sbt的設定檔build.sbt,可以對自身的專案做版本的控管,也可以協助你,引用其他專案相關的library。在Play的環境下的建置,我們使用的是activator關鍵字再加上指令.來讓我們去建置專案。以下就來介紹Play建置部署與常用指令。


Learning a new technical. you must be practice , practice , and more practice.


[build.sbt]
build.sbt本身可以用來定義該專案的名稱與版本,當我們使用Play去建置時,會產出相關的jar檔可以使用,也可以使用其他專案或別人的library(jar)來幫助自己的專案開發與使用。下面是簡單的範例,可以參考與使用。

 name := "myFirstApp"           <-專案名稱

 version := "1.0.0-SNAPSHOT"    <-專案版本

 libraryDependencies ++= Seq(   <-這個意思是,我們專案所需要相依性的library,會依照下面的順序,依據尋找
   // javaJdbc,
   // javaEbean,
   cache,     <-play的/repository/cache目錄,裡面存放play相關的lib
   filters,   <-play內建的filters,可以支援gzip的網站回覆資訊
   "com.typesafe.play" % "play-json_2.11" % "2.3.4", <-這邊是範例,我們可以自定義要使用的lib來使用
 )

 play.Project.playJavaSettings <-這個宣告定義很重要,主要讓我們play專案所引用的基本lib是以java為基準

 resolvers ++= Seq( <-這個意思是,當相關lib找不到時,會再依序照你定義的目錄或網址,抓取相關的lib
     "Local Maven Repository" at "file:C:\.m2",          <-如果你有mvn專案,可以設定路徑可以使用
     "Spy Repository" at "http://files.couchbase.com/maven2"  <-線上mvn的lib下載
 )

 // 這是sbt的註解寫法

 // play支援轉換專成Maven repository的lib格式,以下兩個寫法是要把專案推播到哪個Maven repository網站上
 publishTo := Some( 
     "My resolver" at "https://mycompany.com/repo"
 )
 // 稍微不太一樣是, 後面可以設定該 mvn Repo 網站的帳號與密碼
 credentials += Credentials(
     "Repo", "https://mycompany.com/repo", "admin", "admin123"
 )
)

[play command]
指令部分,大部份是sbt內建的指令,少部分play新增的。我只介紹基本常使用的指令,若想要瞭解更多,而sbt官方有更完整的介紹。當我們要建置環境時,首先要切到專案的目錄之後,才可以下相關的指令,記得前面的關鍵字需要用activator
ex command : activator compile

- clean   
刪除專案target目錄產出的編譯檔案。偶爾Play專案會發生compile錯誤,而本身專案設定卻沒有錯誤時,可以藉由這指令,清除target產出的資料,再重新compile一次,減少問題發生。

- update   
下載這個專案所設定需要的library,是根據build.sbt來設定所下載的。update下來的library通常會放在play Framework的目錄下。
ex path : c:/playFramework/xxxxxx/repository/cache/

- compile   
編譯Play專案,產出專案需要的檔案,通常會在專案下的target目錄。  

- eclipse   
eclipse的指令用處,可以讓eclipse IDE 所匯入專案,與辨認Play的程式碼,在使用eclipse指令之前,請記得要先compile才能使用,直接使用,若直接輸入eclipse指令,會導致eclipse失敗。   

- run   
啟動Play專案成為一個網站服務,後面可以雙引號設定要啟動服務的port。ex : activator "run 8888"。快捷鍵ctrl + D,可中斷Play的網頁服務執行。 

- publish   
產生專案本身,可呼叫與使用的jar檔,可以放到設定好的遠端函式庫。若在build.sbt有設定的話,可以把專案編譯成MVN格式的library後,放到設定好的Maven repository網站上。

- publish-local   
產生專案本身,可呼叫與使用的jar檔,放到本機play的repository/local目錄下。   
ex path : c:/playFramework/xxxxxx/repository/local

- stage   
這個指令是把專案建置成可部署Play的服務檔案,建置後會放在以下路徑裡。
ex path : [project]/target/universal/stage/bin/myFirstApp

Play指令的使用時機,可以按照以下的說明,選擇自己需要執行的指令。

-會先清除專案產生出來的target資料,之後會下載專案要使用的library,最後編譯Play專案。
activator clean update compile   

-編譯整個專案,以及讓專案可以使Eclipse匯入。
activator clean update compile eclipse

-讓play專案能成為一個可服務的網站。
activator "run 8888"   

-編譯整個專案,並且把編譯過的jar檔放到相關的Repository網站或目錄。
activator clean update compile publish (publish-local)   

-編譯整個專案,以及建置可部署Play的檔案。
activator clean update compile stage

[Play deploy and build]
Play本身主打就是各種形式的網站服務,這一小節,來介紹怎樣部署我們的Play專案以及可以設定的地方。如果你機器上有多個服務的時候,可以使用nginxApache來管理我們的Http server,最後我會是以常見的nginxApache來說明,PlayHttp server應該要怎樣設定。

當我們使用下指令後。
activator clean update compile stage

會把可執行的Play檔案放在以下路徑。當你想要在一個全新的環境裡想要啟用Play服務時,最低的執行需求是最少要安裝Java8的編譯程式(JDK)。
path : target/universal/stage/bin/[project-name]
ex path : target/universal/stage/bin/myFirstApp

Play啟動網站服務時可以增加參數化指令可以讓Play的服務更符合我們所期望的結果。

設定檔/conf
Play專案使用設定檔時,有時候需要分測試環境與正式環境的設定檔,我們也可以自定義設定檔,做其他用途。設定檔會放在專案的conf目錄下。test.conf通常意指測試的設定檔,prod.conf意指正式環境的設定檔。

-這樣設定會吃到play專案本身自己的conf檔,設定檔通常建議會是放在專案的conf/目錄下。
/path/to/bin/<project-name> -Dconfig.resource=prod.conf

-當然我們也可以使用專案外部的設定檔案。
/path/to/bin/<project-name> -Dconfig.file=c:/playFramework/playConf/prod.conf

Http Server
Play網站服務啟動時,我們可以特別去定義我們要使用的urlip address跟想要使用port

/path/to/bin/<project-name> -Dhttp.port=1234 -Dhttp.address=127.0.0.1

PID
Play服務啟動是有自己的PID(prcess ID),我們可以設定在想要的地方,方便之後需要砍掉服務時,可以到設定的目錄直接刪除它,這邊範例是以Linux or MacOS作業系統為主。
console(命令與提示字元/終端機) : ``Play server process ID is 2534```

-Pid設定
/path/to/bin/<project-name> -Dpidfile.path=/var/run/play.pid

-如果要砍掉服務時可以使用該指令去砍掉服務(ps:只能使用在Linux or MacOSX 等環境)
kill $(cat /var/run/play.pid)

-如果你想要讓Play自己自動產生自己的pid號碼,你可以在application.conf所設定。
pidfile.path = "/dev/null"


Log設定檔路徑
專案建立之後,會有一個log設定檔的參考範本可以看,路徑是在conf/logBack.xml。當Play執行時,可以根據指令,來去指定對應的logFile

- 這是讀取專案內的log設定檔   
/path/to/bin/<project-name> -Dlogger.resource=conf/prod-logger.xml   

- 這是讀取專案外部的log設定檔
/path/to/bin/<project-name> -Dlogger.file=c:/playFramework/playConf/prod-logger.xml

- 這是讀取專案的網站log設定檔
/path/to/bin/<project-name> -Dlogger.url=http://conf.mycompany.com/logger.xml

Log設定檔
專案建立之後,會有一個log設定檔的參考範本可以看,路徑在conf/logBack.xmlLog檔可以說是檢查服務跟找問題的好幫手。主要是它可以監控Play,我們可以自行印出Play程式的輸入輸出結果。如果一些出問題或出錯時時,還可以額外設定,該寄出錯誤訊息給相關者,方便開發者去尋找程式問題。

在專案內的log設定檔,以下是官方設定檔的參考範本。

 <!-- https://www.playframework.com/documentation/latest/SettingsLogger -->
 <configuration>

   <conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel" />
   <!-- 這邊預設寫入專案內的logs目錄下的application.log檔案-->
   <appender name="FILE" class="ch.qos.logback.core.FileAppender">
     <file>${application.home:-.}/logs/application.log</file>
     <encoder>
       <pattern>%date [%level] from %logger in %thread - %message%n%xException</pattern>
     </encoder>
   </appender>

   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
     <encoder>
       <pattern>%coloredLevel %logger{15} - %message%n%xException{10}</pattern>
     </encoder>
   </appender>

   <appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
     <appender-ref ref="FILE" />
   </appender>

   <appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
     <appender-ref ref="STDOUT" />
   </appender>
   <!--play相關程式,info等級以上-->
   <logger name="play" level="INFO" />
   <logger name="application" level="DEBUG" />

   <!-- Off these ones as they are annoying, and anyway we manage configuration ourselves -->
   <logger name="com.avaje.ebean.config.PropertyMapLoader" level="OFF" />
   <logger name="com.avaje.ebeaninternal.server.core.XmlConfigLoader" level="OFF" />
   <logger name="com.avaje.ebeaninternal.server.lib.BackgroundThread" level="OFF" />
   <logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF" />
   <!--root這邊表示是全域等級的,只要發生Warn等級以上訊息,都會寫入log記錄檔-->
   <root level="WARN">
     <appender-ref ref="ASYNCFILE" />    <!-- 會根據ref指定log設定名稱,去記錄相關記錄-->
     <appender-ref ref="ASYNCSTDOUT" />
   </root>

 </configuration>

若想要額外再專案外部使用log設定檔,以下是官方設定檔的參考範本。這邊我多新增寄信的設定,要請您注意就是,需要有mail server協助才會順利寄出log信件。

 <configuration>

     <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
         <file>${user.dir}/web/logs/application.log</file> 
          <!-- 這邊是要擺放application.log記錄檔的路徑,用途是會記錄我們Play自己的相關記錄 ex path : C:/playFrameWork/playLogs -->
         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
             <!-- 隔一天的紀錄,會被壓縮成.gz減少使用空間,若伺服器量不大,可以把副檔名修改成原始的.log名稱 -->
             <fileNamePattern>application-log-%d{yyyy-MM-dd}.gz</fileNamePattern>
             <!-- 這邊可以設定,記錄最久時間 -->
            <maxHistory>30</maxHistory>
         </rollingPolicy>
         <encoder> <!-- log印出前, 會增加前面的時間訊息與log等級-->
             <pattern>%date{yyyy-MM-dd HH:mm:ss ZZZZ} [%level] from %logger in %thread - %message%n%xException</pattern>
         </encoder>
     </appender>
     <!-- 這邊是要擺放access log記錄檔的路徑,用途是會記錄下請求的對方相關資訊 ex path : C:/playFrameWork/playLogs -->
     <appender name="ACCESS_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
         <file>${user.dir}/web/logs/access.log</file>
         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
             <!-- daily rollover with compression -->
             <fileNamePattern>access-log-%d{yyyy-MM-dd}.gz</fileNamePattern>
             <!-- keep 1 week worth of history -->
             <maxHistory>7</maxHistory>
         </rollingPolicy>
         <encoder>
             <pattern>%date{yyyy-MM-dd HH:mm:ss ZZZZ} %message%n</pattern>
             <!-- this quadruples logging throughput -->
             <immediateFlush>false</immediateFlush>
         </encoder>
     </appender>


     <!-- 這邊可以設定嚴重錯誤時,可以寄信給相關人員-->
     <appender name="email" class="ch.qos.logback.classic.net.SMTPAppender">
       <smtpHost>test.test.com.tw</smtpHost>
       <to>[email protected],[email protected]</to>   <!-- 多人的寄信,可以使用逗點區隔。 -->
       <from>playServiceError</from>   <!-- 可以設定從哪裡寄送出來的。 -->
       <subject>[playServiceError] Log Message Host: %X{host} IP: %X{ip} Account:devuser</subject>
       <layout class="ch.qos.logback.classic.html.HTMLLayout">
           <pattern>%d{yyyy/MM/dd HH:mm:ss.SSS}%thread%level%c%X{abbreviateInfo}%X{remoteAddress}%msg</pattern>
       </layout>
   </appender>

     <!-- additivity=false 是只保留access log 的紀錄而不會有其他記錄-->
     <logger name="access" level="INFO" additivity="false">
         <appender-ref ref="ACCESS_FILE" />  
     </logger>

     <root level="INFO">
         <appender-ref ref="FILE"/> <!-- 會根據ref指定log設定名稱,去記錄相關記錄-->
     </root>
     <!-- 當程式發生有ERROR等級的錯誤訊息時,可以依據ref的寄信設定,寄給相關人員-->
     <root level="ERROR">
         <appender-ref ref="email"/> 
     </root>

 </configuration>


front end HTTP server
當我們線上有多個服務啟動的時候,通常會使用nginxApache來管理相關的線上服務。而想要把Play的服務加入到線上啟用的機器時,我們需要設定好Play的服務給nginxApache知道,我們的Play就可以被呼叫的到了,以下簡單介紹PlaynginxApache的設定。

nginx設定檔如下,通常需要修改/etc/nginx/nginx.conf的設定檔。當外部使用 www.mysite.com/ 網址呼叫服務時,會導向到設定檔所指定的Play服務。

worker_processes  1;

events {
    worker_connections  1024;
}

http {
  include       mime.types;
  default_type  application/octet-stream;

  sendfile        on;
  keepalive_timeout  65;

  proxy_buffering    off;
  proxy_set_header   X-Real-IP $remote_addr;
  proxy_set_header   X-Forwarded-Proto $scheme;
  proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header   Host $http_host;
  proxy_http_version 1.1;

  # 這邊是我們Play服務的設定
  upstream my-backend {
     server 127.0.0.1:9000;
  }

  # 當發現 location是 / 把服務導向到我們的Play
  server {
    listen       80;
    server_name www.mysite.com;
    location / {
       proxy_pass http://my-backend;
    }
  }
}


apache設定如下。對外網址會是port是80,當使用 www.loadbalancedapp.com/ 網址呼叫服務時,會導向到設定檔所指定的Play服務。

<VirtualHost *:80>
  ProxyPreserveHost On
  ServerName www.loadbalancedapp.com
  ProxyPass  /excluded !
  ProxyPass / http://127.0.0.1:9000/
  ProxyPassReverse / http://127.0.0.1:9000/
</VirtualHost>



[Final]
呼! 以上就是本章節想要說明的部分,前半部分是說明Play常用的指令,需要先了解一番,後半部的部分都是Play部署相關的說明,這部分可以等到需要把程式上線到要部署的環境時,再好好研究即可,下個章節,會終於開始進入正題,如何寫Play程式。(這章節特別難寫啊~~~)


[Refernece]

1.The build system
網址 : https://www.playframework.com/documentation/2.5.x/Build

2.SBT官方教學
網址 : http://www.scala-sbt.org/0.13/docs/Getting-Started.html

3.sbt Command Line Reference
http://www.scala-sbt.org/0.13/docs/Command-Line-Reference.html

4.I can not import filters in playframework 2.3.0
http://stackoverflow.com/questions/24257288/i-can-not-import-filters-in-playframework-2-3-0

5.Deploying
https://www.playframework.com/documentation/2.5.x/Deploying

6.Using Play in production
https://www.playframework.com/documentation/2.5.x/Production

7.SettingsLoggern
https://www.playframework.com/documentation/2.5.x/SettingsLogger

results matching ""

    No results matching ""