開発プロジェクトのビルド
================================================================================

.. only:: html

 .. contents:: 目次
    :depth: 3
    :local:

開発プロジェクトのビルド
--------------------------------------------------------------------------------

アプリケーションサーバにデプロイするためのwarファイル、envモジュール(環境依存ファイルを格納するモジュール)のjarファイルを作成する方法を紹介する。

Maven Archetypeで作成したプロジェクトでは、warファイルを作成する方法として以下の2つの方法を提供している。

* :ref:`CreateWebApplicationProjectBuildWarExcludeEnvJar` (**推奨**)
* :ref:`CreateWebApplicationProjectBuildWarIncludeEnvJar`


.. note:: **推奨するビルド方法について**

    本ガイドラインでは、:ref:`CreateWebApplicationProjectBuildWarExcludeEnvJar` を推奨している。
    なお、ここで紹介するビルド方法は選択肢の一つであり、他のビルド方法を採用してもよい。

    ただし、**試験環境や商用環境にリリースするwarファイルとjarファイルは、EclipseなどのIDEが提供している機能を使って作成しないようにすること。**
    Eclipseなどの一部のIDEでは、開発用に最適化された独自のコンパイラを使ってクラスファイルを作成しており、
    コンパイラの違いが原因でアプリケーション実行時に予期しないエラーが発生するリスクが生まれる。

.. note:: **プロジェクト構成の原則**
    
    原則として下記のようなプロジェクト構造とする。

    1. 必ずマルチプロジェクト構成にする。
    2. 一つのプロジェクトに環境依存性のある設定ファイル(ex. logback.xml, jdbc.properties)をできるだけ集約する。 **以降、このプロジェクトを \*-env と表現する。**
    
      * ex. secure-login-env

    3. \*-env以外のプロジェクトには環境依存性のある設定値を一切持たせない。

      * もちろん、src/test/resources 配下などにテスト用の環境依存性設定ファイルを格納しておくことは許可される。

    4. 全てのソフトウェアのパッケージ済みバイナリをパッケージリポジトリ上に保管して管理する。

      * \*.jarファイルだけではなく\*.warファイルも成果物としてパッケージリポジトリにデプロイする。したがって、それらのjar/warファイルには環境依存性が含まれていてはならない。

    5. \*-env プロジェクトは下記のような構造にする。

      * 開発者のPC上での作業に必要な設定値をデフォルトとして src/main/resources 配下のファイルに格納する。
      * 試験サーバ、本番サーバ等、環境毎に異なる設定ファイルを src/main/resources 以外(ex. configs/test-server)のフォルダに格納し、mavenのprofile機能を使って環境毎に自動的に設定値を差し替えながら \*-env-x.y.z.jarファイルをビルドする。

    上記のような構造を取ることにより、ソフトウェアライフサイクルの全ての場面において、適切に開発をすることができるようになる。

    #. ローカル開発環境では、プロジェクト本体と\*-envプロジェクトの両方をチェックアウトし、envプロジェクトを本体プロジェクトのビルドパスに含めることによって、ローカル開発環境でのコーディングとテストを可能にする。
    #. CIサーバ上ではビルドツール(maven)によるテストの実行とパッケージングを行い、必要に応じてパッケージリポジトリにartifactをdeployする。
    #. 試験サーバ、本番サーバでは、パッケージリポジトリにあらかじめ保管しているプロジェクト本体に、リリース先環境にあわせてビルドした\*-envプロジェクトを追加してリリースすることにより、アプリケーションの動作が可能になる。

    詳細については\ `チュートリアル <https://github.com/Macchinetta/tutorial-apps/tree/1.8.3.RELEASE/secure-login-demo/secure-login>`_\ を参考にされたい。

.. warning:: **ビルド環境について**

    ここではWindows環境でビルドする例になっているが、Windows環境でビルドすることを推奨しているわけではない。
    本ガイドラインでは、**アプリケーションの実行環境と同じOSとJDKのバージョンを使ってビルドすることを推奨する。**

|

| Mavenを使ってビルドする場合は、環境変数「JAVA_HOME」にコンパイル時に使用するJDKのホームディレクトリが指定されていることを確認されたい。
| 環境変数が設定されていない場合や異なるバージョンのJDKのホームディレクトリが指定されている場合は、環境変数に適切なホームディレクトリを指定すること。

**[Windowsの場合]**

.. code-block:: console

    echo %JAVA_HOME%
    set JAVA_HOME={Please set home directory of JDK}


**[Linux系の場合]**

.. code-block:: console

    echo $JAVA_HOME
    JAVA_HOME={Please set home directory of JDK}

.. note::

    環境変数「JAVA_HOME」は、ビルドを実行するOSユーザーのユーザー環境変数に設定しておくとよい。

|

.. _CreateWebApplicationProjectBuildWarExcludeEnvJar:

envモジュールのjarファイルをwarファイルに含めないビルド方法
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. _CreateWebApplicationProjectBuildWarExcludeEnvJarStepWar:

warファイルの作成
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

開発プロジェクトのルートディレクトリへ移動する。

.. code-block:: console

    cd C:\work\todo

|

| Mavenのプロファイル(\ ``-P``\ パラメータ)に\ ``warpack``\ を指定して、Maven installを実行する。

.. code-block:: console

    mvn -P warpack clean install

| Maven packageの実行が成功すると、webモジュールのtargetディレクトリの中に、envモジュールのjarファイルが含まれていないwarファイルが作成される。
| (例:\ ``C:\work\todo\todo-web\target\todo-web.war``\ )

.. note:: **指定するゴールについて**

    上記例ではゴールに\ ``install``\ を指定してwarファイルをローカルリポジトリへインストールしているが、

     * warファイルの作成のみ行う場合はゴールに\ ``package``\
     * Nexusなどのリモートリポジトリへデプロイする場合はゴールに\ ``deploy``\

    を指定すればよい。


|

.. _CreateWebApplicationProjectBuildWarExcludeEnvJarStepEnvJar:

envモジュールのjarファイルの作成
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

envモジュールのディレクトリへ移動する。

.. code-block:: console

    cd C:\work\todo\todo-env

|

Mavenのプロファイル(\ ``-P``\ パラメータ)に\ **環境を識別するプロファイルID**\ を指定して、Maven packageを実行する。

.. code-block:: console

    mvn -P test-server clean package

| Maven packageの実行が成功すると、envモジュールのtargetディレクトリの中に、指定した環境用のjarファイルが作成される。
| (例:\ ``C:\work\todo\todo-env\target\todo-env-1.0.0-SNAPSHOT-test-server.jar``\ )

.. note:: **環境を識別するプロファイルIDについて**

    Maven Archetypeで作成したプロジェクトでは、以下のプロファイルIDがデフォルトで定義されている。

     * \ ``local``\  : 開発者のローカル環境向け(IDE開発環境向け)のプロファイル (デフォルトのプロファイル)
     * \ ``test-server``\  : 試験環境向けのプロファイル
     * \ ``production-server``\  : 商用環境向けのプロファイル

    デフォルトで用意しているプロファイルは上記の3つだが、開発するシステムの環境構成にあわせて追加及び修正されたい。

|

.. _CreateWebApplicationProjectBuildWarIncludeEnvJar:

envモジュールのjarファイルをwarファイルに含めるビルド方法
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. _CreateWebApplicationProjectBuildWarIncludeEnvJarWar:

warファイルの作成
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

.. warning:: **envモジュールのjarファイルをwarファイルに含める場合の注意点**

    envモジュールのjarファイルをwarファイルに含めた場合、warファイルを他の環境にデプロイすることができないため、
    間違って他の環境(特に商用環境)にデプロイされないようにwarファイルを管理すること。

    また、環境毎にwarファイルを作成して各環境へリリースする方法を採用した場合、
    商用環境へリリースされるwarファイルが厳密にいうとテスト済みのwarファイルではないという点を意識してほしい。
    これは、商用環境用のwarファイルを作成する際にコンパイルをしなおすためである。
    warファイルを環境毎に作成してリリースする場合は、GitやSubversionなどのVCS(Version Control System)の機能(タグ機能など)を活用し、
    テスト済みのソースファイルを使用して商用環境や各種テスト環境へリリースするwarファイルを作成する仕組みを確立することが特に重要である。

|

開発プロジェクトのルートディレクトリへ移動する。

.. code-block:: console

    cd C:\work\todo

|

| Mavenのプロファイル(\ ``-P``\ パラメータ)に\ ``warpack-with-env``\ とenvモジュールの中で定義している\ **環境を識別するプロファイルID**\ を指定して、Maven packageを実行する。

.. code-block:: console

    mvn -P warpack-with-env,test-server clean package

| Maven packageの実行が成功すると、webモジュールのtargetディレクトリの中に、envモジュールのjarファイルを含んだwarファイルが作成される。
| (例:\ ``C:\work\todo\todo-web\target\todo-web.war``\ )

|


.. _CreateWebApplicationProjectBuildDeploy:

デプロイ
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. _CreateWebApplicationProjectBuildDeployToTomcat:

Tomcatへのデプロイ
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

WebアプリケーションをTomcat 8.5およびTomcat 9上にリリースする場合は次のような手順をとる。 

1. リリース対象のAPサーバ環境にあわせてmavenのprofileを指定し、 \*-env プロジェクトを ビルドする。
2. 上記でビルドした\*-env-x.y.z.jarファイル をあらかじめ決定したAPサーバ上のフォルダに設置する。 ex. /etc/foo/bar/abcd-env-x.y.z.jar
3. あらかじめパッケージリポジトリにデプロイ済みの\*.warファイルを [CATALINA_HOME]/webapps 配下にコピーする。
4. Tomcatのリソース機能を使用して、 /etc/foo/bar/\*.jar をクラスパスに追加する。

 * [CATALINA_HOME]/conf/Catalina/localhost/[contextPath].xmlファイルに下記の定義を追加する。
 * 詳しくは、 `The Resources Component <https://tomcat.apache.org/tomcat-9.0-doc/config/resources.html>`_\ と `atrs-envのconfigsフォルダ <https://github.com/Macchinetta/atrs/tree/1.8.3.RELEASE/atrs-env/configs>`_\ を参考されたい。
 * リソースの設定例:
   
  .. code-block:: xml

   <Resources className="org.apache.catalina.webresources.StandardRoot">
     <PreResources className="org.apache.catalina.webresources.DirResourceSet"
                   base="/etc/foo/bar/"
                   internalPath="/"
                   webAppMount="/WEB-INF/lib" />
   </Resources>

.. note::

 * Catalina以外のエンジン、およびlocalhost以外のホストを利用する場合は、[contextPath].xmlを[CATALINA_HOME]/conf/[enginename]/[hostname]に配置する。

|

.. _CreateWebApplicationProjectBuildDeployContinuedDeployment:

継続的なデプロイ
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

プロジェクト(ソースコードツリー)の構造、バージョン管理、インスペクションとビルド作業、ライフサイクル管理の工程を恒常的にループさせることによって目的のソフトウェアをリリースし続けることが、継続的デプロイメントである。

開発の途中では、SNAPSHOTバージョンのソフトウェアをパッケージリポジトリや開発用APサーバにリリースし、テストを実施する。
ソフトウェアを正式にリリースする場合には、バージョン番号を固定したうえでVCSのソースコードツリーに対してタグづけを行う必要がある。
このように、スナップショットリリースの場合と正式リリースの場合で、ビルドとデプロイのフローが少し異なる。

また、Webサービスを提供するAPサーバにアプリケーションをデプロイする場合には、スナップショットバージョンか正式リリースバージョンかに関わらず、
デプロイ先のAPサーバ環境に合わせた環境依存性設定ファイル群と*.warファイルをセットでデプロイする必要がある。

そこで、環境依存性設定を持たない状態のライブラリ(jar,war)をmavenリポジトリに登録する作業と、
それらを実際にAPサーバにデプロイする作業を分離することによって、デプロイ作業を簡潔に実施可能にする。

.. note::

 mavenの世界では、pom.xml上の<version>タグの内容によってそれがSNAPSHOTバージョンなのかRELEASEバージョンなのかが自動的に判別される。

 * 末尾が -SNAPSHOT である場合にSNAPSHOTとみなされる。例:<version>1.0-SNAPSHOT</version>
 * 末尾が -SNAPSHOT ではない場合はRELEASEとみなされる。例:<version>1.0</version>

 また、mavenパッケージリポジトリにはsnapshotsリポジトリとreleaseリポジトリの2種類があり、いくつかの制約があることに注意する。

 * SNAPSHOTバージョンのソフトウェアをreleaseリポジトリに登録することはできない。その逆も不可能。
 * releaseリポジトリには、同一のGAV情報を持つartifactは1回しか登録できない。(GAV=groupId,artifactId,version)
 * snapshotリポジトリには、同一のGAV情報を持つartifactを何度でも登録しなおすことができる。

SNAPSHOTバージョンの運用
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

SNAPSHOTバージョンのソフトウェアのデリバリーフローは下図のように簡潔である。

.. figure:: ./images/ContinuousDelivery-snapshot.png
   :alt: Continuous delivery for SNAPSHOT version.
   :width: 600px

1. 開発用trunkからソースコードをチェックアウトする。
2. コンパイル、コードメトリクスの測定、テストを実行する。

 * コンパイルエラー、コードメトリクスでの一定以上のviolationの発生、テストの失敗の場合、以降の作業を中止する。

3. mavenパッケージリポジトリサーバにartifact(jar,warファイル)をアップロード(mvn deploy)する。

|

RELEASEバージョンの運用
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

正式なリリースの場合、バージョン番号の付与作業が必要なため、SNAPSHOTリリースよりもやや複雑なフローとなる。

.. figure:: ./images/ContinuousDelivery-release.png
   :alt: Continuous delivery for RELEASE version.
   :width: 600px

1. リリースに与えるバージョン番号を決定する。(例:1.0.1)
2. 開発用trunk(またはリリース用branch)からソースコードをチェックアウトする。
3. pom.xml上の<version>タグを変更する。(例:<version>1.0.1</version>)
4. VCS上にtagを付与する。(例: tags/1.0.1)
5. コンパイル、コードメトリクスの測定、テストを実行する。

 * コンパイルエラー、コードメトリクスでの一定以上のviolationの発生、テストの失敗の場合、以降の作業を中止する。
 * 失敗した場合はVCS上のtagを削除する。

6. mavenパッケージリポジトリサーバにartifact(jar,warファイル)をアップロード(mvn deploy)する。

.. note::

 pom.xmlファイルの<version>タグの変更は `versions-maven-plugin <https://www.mojohaus.org/versions-maven-plugin/>`_ で可能である。
 
 .. code-block:: bash
 
  mvn versions:set -DnewVersion=1.0.0
 
 上記のようなコマンドで、pom.xml内のversionタグを<version>1.0.0</version>のように編集することができる。

アプリケーションサーバへのリリース
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Webサービスを提供するAPサーバにアプリケーションをリリースする場合、
あらかじめmavenパッケージリポジトリに登録済みのwarファイルと、
リリース先のAPサーバ環境に合わせた環境依存性設定ファイル群とを、セットでリリースする。
これはスナップショットリリースか正式リリースかに関わらず同じフローとなる。

.. figure:: ./images/ContinuousDelivery-apserver.png
   :alt: Continuous delivery for webapp to application server.
   :width: 600px

1. リリース対象バージョンのwarファイルをmavenパッケージリポジトリからダウンロードする
2. \*-resourcesプロジェクト(環境依存性設定ファイルを集約しているプロジェクト)をVCSからチェックアウトする
3. mavenのprofileを機能によって、リリース先の環境に合わせた設定ファイル群で内容を差し替えてresourcesプロジェクトをパッケージし、\*-resources-x.y.z.jarを生成する。
4. 生成した\*-resources-x.y.z.jarファイルを、warファイル内のWEB-INF/libフォルダ配下に追加する。

 * Tomcatの場合は、\*-resources-x.y.z.jarをwarファイル内部に追加するのではなく、Tomcatサーバ上の任意のパスにコピーし、そのパスをVirtualWebappLoaderの拡張クラスパスに指定する。

5. warファイルをアプリケーションサーバにデプロイする。

.. note::

 mavenパッケージリポジトリからのwarファイルのダウンロードは、maven-dependency-pluginのcopyゴールで可能である。

 .. code-block:: bash

  mvn org.apache.maven.plugins:maven-dependency-plugin:3.2.0:copy^
   -Dartifact=com.example:mywebapp:0.0.1-SNAPSHOT:war^
   -DoutputDirectory=target

 これで、targetというディレクトリ配下にmywebapp-0.0.1-SNAPSHOT.warファイルがダウンロードされる。
 
 さらに、下記のようなコマンドで環境依存設定ファイルのパッケージをmywebapp-0.0.1-SNAPSHOT.warファイル内に追加することができる。

 .. code-block:: bash

  mkdir -p $WORKSPACE/target/WEB-INF/lib
  cd $WORKSPACE/target
  cp ./mywebapp-resources*.jar WEB-INF/lib
  jar -ufv mywebapp-0.0.1-SNAPSHOT.war WEB-INF/lib



.. _CreateProjectCustomize:

.. raw:: latex

   \newpage