既存WebアプリケーションもJenkinsで自動デプロイしたい！（ビルド・デプロイ完結編）

先日の投稿の続きです。先日は次の投稿をしました。

- [既存WebアプリケーションもJenkinsで自動デプロイしたい！（概要編）](http://qiita.com/kurukurupapa@github/items/29f995360c09a3993a73)
 - Jenkinsで自動デプロイしてみたいシステムと、その問題点、自分なりの解決案の概要を書きました。
- [既存WebアプリケーションもJenkinsで自動デプロイしたい！（ビルド・デプロイ基礎編）](http://qiita.com/kurukurupapa@github/items/153e3557b2008ea8fa88)
 - 自分なりの解決案のうち、ビルド・デプロイに関する基礎的な部分を、具体的に記述しました。

今回は、解決案のうち、残りの部分を具体的に記述したいと思います。

# 今回の概要

ポイント

- ソースと、ビルド関連ファイルを別リポジトリで管理する。
- Jenkinsからテスト環境に配布するのは、変更のあったファイルのみとする。
- 設定ファイルは、配布先の環境に合わせて配布する。
- ただし、テスト環境で直接編集している設定ファイルは、配布しない。

前提

- Jenkinsは、開発環境（Windows）で起動する。
- テスト環境のTomcatには、Webアプリケーション（古いモジュール状態）がデプロイ済みで動作する環境となっている。

# プロジェクト構成
サンプルとして用意したWebアプリケーションのソースは、次のような構成です。特別なことはなく、Eclipseで動的Webプロジェクトとして作成し、JSP、Servlet、設定ファイル関連を追加しました。

![Tomcat4.1Project02_001.gif](https://qiita-image-store.s3.amazonaws.com/0/24511/ed7989d5-926a-a05b-9b60-4d6d9a5b1797.gif)

web.xmlは、環境に依存しない設定ファイルとして扱います。

messages.propertiesは、環境に依存する設定ファイルです。開発環境用のファイルはソース管理されていますが、テスト環境用のファイルはソース管理されておらず、テスト環境で適宜編集されている前提とします。自動デプロイ対象外とします。

jenkins_logo.pngは、環境に依存しない画像ファイルです。env_logo.pngは、環境に依存する画像ファイルです。

別管理とするビルド用ファイル類は、次のような構成です。テスト環境に配布する環境依存ファイルは「テスト環境」ディレクトリに配置してあります。詳細は、後ほど説明します。

![Tomcat4.1Project02_002.gif](https://qiita-image-store.s3.amazonaws.com/0/24511/5daa40f0-28e7-f90d-ced9-9678e7e3ca2b.gif)

# 手順（下準備）
## ビルド
ビルドを行うためのbuild.xmlを、前回投稿（[既存WebアプリケーションもJenkinsで自動デプロイしたい！（ビルド・デプロイ基礎編）](http://qiita.com/kurukurupapa@github/items/153e3557b2008ea8fa88)）と同様に用意します。

ただし、ソースのプロジェクトと、ビルド関連のプロジェクトを別にしていることを考慮します。

ソースのプロジェクトは「Tomcat4.1Project02」というディレクトリにチェックアウトされ、ビルド用プロジェクトは「Tomcat4.1Project02Build」というディレクトリにチェックアウトされているとします。ビルド用プロジェクト「Tomcat4.1Project02Build」のbuild.xmlから、ソースプロジェクト「Tomcat4.1Project02」をビルドするためには、次のようにprojectタグのbasedir属性でソースプロジェクトを指定しました。（この辺のやり方は色々あると思います。）

```xml
<project basedir="../Tomcat4.1Project02" default="build" name="Tomcat4.1Project02">
```

## デプロイ用モジュール収集
テスト環境へ配布しやすいように、テスト環境の構成に合わせて、モジュールを集めることにしました。次のようにbuild.xmlに追記します。

```xml
    <property name="env_dir" value="${BUILD_PROJECT_DIR}/テスト環境"/>
    <target name="make-deploy-files" depends="make-normal-files,make-env-files"/>
    <target name="make-normal-files">
        <mkdir dir="build/deploy"/>
        <copy todir="build/deploy">
            <fileset dir="WebContent"/>
        </copy>
        <copy todir="build/deploy/WEB-INF/classes">
            <fileset dir="build/classes"/>
        </copy>
    </target>
    <target name="make-env-files">
        <!-- 環境依存ファイルを上書き -->
        <copy todir="build/deploy" overwrite="true">
            <fileset dir="${env_dir}"/>
        </copy>
        <!-- リリース対象外ファイルの削除 -->
        <!-- ※サーバ側で手動更新されている可能性があるファイルは対象外とする。 -->
        <delete>
            <fileset dir="build/deploy" includes="**/*.conf,**/*.properties"/>
        </delete>
    </target>
```

make-normal-filesターゲットでは、環境に依存しないファイルを集めています。（ただし、開発環境に依存したファイルも含まれてしまいますが、make-env-filesターゲットで上書き/削除されます。）環境に依存しないファイルであるweb.xml、jenkins_logo.pngは、このターゲットの処理で収集されます。

make-env-filesターゲットでは、ソースとは別管理しているテスト環境用の環境依存ファイルを上書きしています。環境に依存するファイルであるenv_logo.pngは、このターゲットで収集されます。さらに、テスト環境に配布したくないファイルを削除しています。テスト環境配布対象外のmessages.propertiesは、ここで除外されます。

## モジュール配布
上記処理で収集したモジュールを、テスト環境へFTPアップロードします。前回投稿（[既存WebアプリケーションもJenkinsで自動デプロイしたい！（ビルド・デプロイ基礎編）](http://qiita.com/kurukurupapa@github/items/153e3557b2008ea8fa88)）と同様に用意します。

## Tomcat再起動
テスト環境のTomcatを再起動するための処理をbuild.xmlに追加します。前回投稿（[既存WebアプリケーションもJenkinsで自動デプロイしたい！（ビルド・デプロイ基礎編）](http://qiita.com/kurukurupapa@github/items/153e3557b2008ea8fa88)）と同様です。

## 差分抽出
変更のあったファイルのみをテスト環境に配布するため、差分を抽出します。

変更前のファイルは、Subversionのトランクやブランチなどで管理されていて、それを「Tomcat4.1Project02_before」という名前でチェックアウト済みの前提とします。次のように新規XML（diffbuild.xml）を作成しました。

```xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project basedir="." default="build" name="Tomcat4.1Project02Build_diffbuild">
    <property environment="env"/>
    <property name="BUILD_PROJECT_DIR" value="../Tomcat4.1Project02Build"/>
    <property name="BEFORE_PROJECT_DIR" value="../Tomcat4.1Project02_before"/>
    <property name="AFTER_PROJECT_DIR" value="../Tomcat4.1Project02"/>
    <property name="TOMCAT_HOME" value="../../apps/apache-tomcat-4.1.40"/>

    <!-- ================================================== -->
    <!-- ターゲット -->
    <!-- ================================================== -->

    <target name="init">
        <echo message="basedir: ${basedir}"/>
        <echo message="BUILD_PROJECT_DIR ${BUILD_PROJECT_DIR}"/>
        <echo message="BEFORE_PROJECT_DIR ${BEFORE_PROJECT_DIR}"/>
        <echo message="AFTER_PROJECT_DIR ${AFTER_PROJECT_DIR}"/>
        <mkdir dir="build/deploy"/>
    </target>

    <target name="clean">
        <delete dir="build/deploy"/>
    </target>
    <target depends="clean" name="cleanall"/>

    <target depends="build-subprojects,make-deploy-files" name="build"/>
    <target name="build-subprojects">
        <ant antfile="${BUILD_PROJECT_DIR}/build.xml" dir="${BEFORE_PROJECT_DIR}" target="build">
            <property name="TOMCAT_HOME" value="${TOMCAT_HOME}"/>
        </ant>
        <ant antfile="${BUILD_PROJECT_DIR}/build.xml" dir="${AFTER_PROJECT_DIR}" target="build">
            <property name="TOMCAT_HOME" value="${TOMCAT_HOME}"/>
        </ant>
    </target>

    <!-- デプロイ用モジュール収集 -->
    <target name="make-deploy-files">
        <exec executable="ruby.exe">
            <arg line="diffcopy.rb ${BEFORE_PROJECT_DIR}/build/deploy ${AFTER_PROJECT_DIR}/build/deploy ${BUILD_PROJECT_DIR}/build/deploy"/>
        </exec>
    </target>

    <!-- デプロイ -->
    <target name="deploy">
        <ant antfile="${BUILD_PROJECT_DIR}/build.xml" dir="${BUILD_PROJECT_DIR}" target="deploy"/>
    </target>
</project>
```

build-subprojectsターゲットで、変更前と変更後のプロジェクトの両方をビルドしています。ベースとなるディレクトリを切り替えながらbuild.xmlを呼び出すことでビルドしています。

一度にビルドすることで、classファイルが同じ環境で作成され、同一のソースからは同一のclassファイルが生成されるようになりました。（もし、変更前と変更後のプロジェクトを、バージョンの異なるJDKでビルドすると、同一のソースでも異なるclassファイルが生成されてしまいました。）

ビルド後には、変更前と変更後のプロジェクトの「build/deploy」ディレクトリに、テスト環境配布用のファイル構成が出来上がります。

make-deploy-filesターゲットで、テスト環境に配布する差分ファイルを抽出しています。自作したRubyスクリプトを使用して、変更前と変更後の「build/deploy」ディレクトリを比較し、異なるファイルのみを、ビルド用プロジェクトの「build/deploy」ディレクトリにコピーしています。Rubyスクリプトの詳細は、先日の投稿（[二つのディレクトリの差分を別ディレクトリにコピーするスクリプトを作ってみました](http://qiita.com/kurukurupapa@github/items/b58241946f14f3b36331)）を参照ください。

deployターゲットでは、build.xmlを呼び出して、ビルド用プロジェクトの「build/deploy」ディレクトリのファイルをテスト環境へ配布しています。

# 手順（Jenkins）
## ビルドジョブ
新規ジョブを追加して、上記で作成した処理を呼ぶことにします。ジョブの名前は「Tomcat4.1Project02_Build」とし、次のように設定を行いました。

「ソースコード管理」では、次のように設定しました。ソースプロジェクト（変更前）、ソースプロジェクト（変更後）、ビルド用プロジェクトをチェックアウトしています。

![Tomcat4.1Project02_101.gif](https://qiita-image-store.s3.amazonaws.com/0/24511/c4327abf-4c20-3247-de91-dd1f7ef53504.gif)

「ビルド」では、Antを次のようにして呼び出すことにしました。上記で作成したdiffbuild.xmlを呼び出すことで、変更前と変更後の両方のプロジェクトをビルドし、差分の抽出までしています。Eclipse環境と、Jenkinsの環境では、Tomcatのパスが異なることを考慮してあります。

![Tomcat4.1Project02_102.gif](https://qiita-image-store.s3.amazonaws.com/0/24511/8b8bf998-a103-1b58-e443-119f083d8421.gif)

「ビルド後の処理」では、抽出した差分を成果物として保存します。

![Tomcat4.1Project02_103.gif](https://qiita-image-store.s3.amazonaws.com/0/24511/8f219e45-c45a-9e4d-3641-a03761f2c675.gif)

## デプロイジョブ
新規ジョブを追加して、上記で作成した処理を呼ぶことにします。ジョブの名前は「Tomcat4.1Project02_Deploy」とし、次のように設定を行いました。

「ソースコード管理」では、次のように設定しました。ビルド用プロジェクトのみをチェックアウトしています。

![Tomcat4.1Project02_201.gif](https://qiita-image-store.s3.amazonaws.com/0/24511/a7118fd2-b287-d1ee-a2fd-fdca00875aab.gif)

「ビルド・トリガ」では、上記で作成したビルドジョブの後に起動されるようにしました。

![Tomcat4.1Project02_202.gif](https://qiita-image-store.s3.amazonaws.com/0/24511/dfaf306e-2bb9-ae0d-9dad-f214805b8336.gif)

「ビルド」では、必要なファイルを、ビルドジョブから、コピーします。

![Tomcat4.1Project02_203.gif](https://qiita-image-store.s3.amazonaws.com/0/24511/2ce496ff-9a3a-8ae2-ed04-3b5f261ef397.gif)

さらに、「ビルド」に、Ant呼び出しを追加し、モジュール配布とTomcat再起動を行えるようにします。FTPタスクを使用するため、ライブラリの設定を忘れずに行います。

![Tomcat4.1Project02_204.gif](https://qiita-image-store.s3.amazonaws.com/0/24511/4b3b0e98-84a1-020c-6037-95cba86e89b3.gif)

# ジョブ起動設定
上記までの設定で、ビルドジョブ（Tomcat4.1Project02_Build）のジョブ実行をワンクリックするだけで、最新ソースのチェックアウトから、ビルド、差分デプロイまで自動化できました。

さらに、ビルドジョブの「ビルド・トリガ」でSubversionを監視するようにすれば、ワンクリックも不要となり、完全自動化もできますね。

# 今回作成したファイル
上記で記述したファイル類は、次の場所に置いておきました。興味があればご覧ください。

- [ファイルツリー: TryJenkins/Tomcat4.1Project02/ (head) - ksandbox (svn) - Kurukurupapa SandBox - SourceForge.JP](http://sourceforge.jp/projects/ksandbox/scm/svn/tree/head/TryJenkins/Tomcat4.1Project02/)
- [ファイルツリー: TryJenkins/Tomcat4.1Project02_before/ (head) - ksandbox (svn) - Kurukurupapa SandBox - SourceForge.JP](http://sourceforge.jp/projects/ksandbox/scm/svn/tree/head/TryJenkins/Tomcat4.1Project02_before/)
- [ファイルツリー: TryJenkins/Tomcat4.1Project02Build/ (head) - ksandbox (svn) - Kurukurupapa SandBox - SourceForge.JP](http://sourceforge.jp/projects/ksandbox/scm/svn/tree/head/TryJenkins/Tomcat4.1Project02Build/)

# 動作確認環境

- 開発環境：Windows 8.1 64bit、Eclipse 4.2、Tomcat 4.1（Windows版）
- テスト環境：Ubuntu 8.04、Tomcat　4.1（Linux版）