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

[前回投稿](http://qiita.com/kurukurupapa@github/items/29f995360c09a3993a73)の続きです。

前回は、Jenkinsで自動デプロイしてみたいシステムと、その問題点、自分なりの解決案の概要を書きました。
今回は、解決案のうち、ビルド・デプロイに関する基礎的な部分を、具体的に記述してみたいと思います。

# 今回の目標
次のような流れをJenkinsで自動化します。Subversionからソースを取得し、ビルドして、FTPでモジュールを配布し、Tomcatを再起動する。

ポイント

- ファイルの配布は、AntのFTPタスクを使用する。
- Tomcatの再起動は、TomcatのAntタスクを使う。

前提

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

# プロジェクト構成
サンプルとして用意したWebアプリケーションのソースは、次のような構成です。特別なことはなく、Eclipseで動的Webプロジェクトで作成した構成です。

![無題.png](https://qiita-image-store.s3.amazonaws.com/0/24511/86b3bdf0-b33c-7e8a-83e0-08318c3a0b93.png)

# 手順（下準備）
## ビルド
まず、ビルドを行うためのbuild.xmlを作成します。Eclipseで、プロジェクトを選択して、右クリックのメニューの「エクスポート」から、build.xmlを作成しました。多少、Tomcatのパス設定などを手直しして次のようになりました。

```xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project basedir="." default="build" name="Tomcat4.1Project01">
    <property environment="env"/>
    <property name="TOMCAT_HOME" value="../../apps/apache-tomcat-4.1.40"/>
    <property name="debuglevel" value="source,lines,vars"/>
    <property name="target" value="1.4"/>
    <property name="source" value="1.4"/>
    <path id="Apache Tomcat v4.1 [Apache Tomcat v4.1].libraryclasspath">
        <pathelement location="${TOMCAT_HOME}/common/lib/activation.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/lib/ant-launcher.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/lib/ant.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/lib/commons-collections-3.2.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/lib/commons-dbcp-1.2.2.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/lib/commons-logging-api-1.1.1.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/lib/commons-pool-1.4.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/lib/jasper-compiler.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/lib/jasper-runtime.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/lib/jdbc2_0-stdext.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/lib/jta.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/lib/mail.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/lib/naming-common.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/lib/naming-factory.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/lib/naming-resources.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/lib/servlet.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/endorsed/xercesImpl.jar"/>
        <pathelement location="${TOMCAT_HOME}/common/endorsed/xml-apis.jar"/>
    </path>
    <path id="Web App ライブラリー.libraryclasspath"/>
    <path id="EAR ライブラリー.libraryclasspath"/>
    <path id="Tomcat4.1Project01.classpath">
        <pathelement location="build/classes"/>
        <path refid="Apache Tomcat v4.1 [Apache Tomcat v4.1].libraryclasspath"/>
        <path refid="Web App ライブラリー.libraryclasspath"/>
        <path refid="EAR ライブラリー.libraryclasspath"/>
    </path>
    <target name="init">
        <mkdir dir="build/classes"/>
        <copy includeemptydirs="false" todir="build/classes">
            <fileset dir="src">
                <exclude name="**/*.launch"/>
                <exclude name="**/*.java"/>
            </fileset>
        </copy>
    </target>
    <target name="clean">
        <delete dir="build/classes"/>
    </target>
    <target depends="clean" name="cleanall"/>
    <target depends="build-subprojects,build-project" name="build"/>
    <target name="build-subprojects"/>
    <target depends="init" name="build-project">
        <echo message="${ant.project.name}: ${ant.file}"/>
        <javac debug="true" debuglevel="${debuglevel}" destdir="build/classes" includeantruntime="false" source="${source}" target="${target}">
            <src path="src"/>
            <classpath refid="Tomcat4.1Project01.classpath"/>
        </javac>
    </target>
    <target description="Build all projects which reference this project. Useful to propagate changes." name="build-refprojects"/>
</project>
```

コマンドラインから、次のように実行して、ビルドが行われることを確認しました。

```bat
ant
```

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

```xml
    <target name="make-deploy-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>
```

コマンドラインから、次のように実行して、処理が行われることを確認しました。

```bat
ant make-deploy-files
```

## モジュール配布
上記処理で収集したモジュールを、テスト環境へFTPアップロードします。これもAntで実現することにしました。

AntのFTPタスクを使うためには、Apache Commons Netが必要となりますので、次のサイトから、「commons-net-3.3.jar」をダウンロードしました。

- [Apache Commons Net - Overview](http://commons.apache.org/proper/commons-net/)

build.xmlに、次を追加しました。

```xml
    <property name="server" value="xxxxx"/>
    <property name="ftp_userid" value="xxxxx"/>
    <property name="ftp_password" value="xxxxx"/>

    <target name="deploy-ftp">
        <echo message="デプロイ先サーバ： ${server}"/>
        <ftp server="${server}" userid="${ftp_userid}" password="${ftp_password}" remotedir="webapps/${ant.project.name}" verbose="true">
            <fileset dir="build/deploy">
                <include name="**/*"/>
            </fileset>
        </ftp>
    </target>
```

コマンドラインから、次のように実行して、処理が行われることを確認しました。

```bat
ant -lib build_lib\commons-net-3.3.jar deploy-ftp
```

## Tomcat再起動
今回知ったのですが、Tomcatには、AntからTomcatを再起動するためのライブラリが用意されているのですね。さっそく使うことにしました。

次の記述をbuild.xmlに追加しました。

```xml
    <property name="tomcat_ant_jar" value="${TOMCAT_HOME}/server/lib/catalina-ant.jar" />

    <!-- Configure the context path for this application -->
    <property name="path"     value="/${ant.project.name}"/>

    <!-- Configure properties to access the Manager application -->
    <property name="url"      value="http://${server}:8080/manager"/>
    <property name="username" value="xxxxx"/>
    <property name="password" value="xxxxx"/>

    <!-- Configure the custom Ant tasks for the Manager application -->
    <taskdef name="deploy"    classname="org.apache.catalina.ant.DeployTask" classpath="${tomcat_ant_jar}"/>
    <taskdef name="install"   classname="org.apache.catalina.ant.InstallTask" classpath="${tomcat_ant_jar}"/>
    <taskdef name="list"      classname="org.apache.catalina.ant.ListTask" classpath="${tomcat_ant_jar}"/>
    <taskdef name="reload"    classname="org.apache.catalina.ant.ReloadTask" classpath="${tomcat_ant_jar}"/>
    <taskdef name="remove"    classname="org.apache.catalina.ant.RemoveTask" classpath="${tomcat_ant_jar}"/>
    <taskdef name="resources" classname="org.apache.catalina.ant.ResourcesTask" classpath="${tomcat_ant_jar}"/>
    <taskdef name="roles"     classname="org.apache.catalina.ant.RolesTask" classpath="${tomcat_ant_jar}"/>
    <taskdef name="start"     classname="org.apache.catalina.ant.StartTask" classpath="${tomcat_ant_jar}"/>
    <taskdef name="stop"      classname="org.apache.catalina.ant.StopTask" classpath="${tomcat_ant_jar}"/>
    <taskdef name="undeploy"  classname="org.apache.catalina.ant.UndeployTask" classpath="${tomcat_ant_jar}"/>

    <target name="tomcat-reload">
        <reload url="${url}" username="${username}" password="${password}" path="${path}"/>
    </target>
```

コマンドラインから、次のように実行して、処理が行われることを確認しました。

```bat
ant -lib build_lib\commons-net-3.3.jar tomcat-reload
```

FTPとTomcat再起動をまとめて実施できるように、build.xmlを追記しました。

```xml
    <target name="deploy" depends="deploy-ftp,tomcat-reload"/>
```

## プロジェクト構成
ここまでで、次のようなプロジェクト構成になりました。Subversionにコミットしておきます。

![無題.png](https://qiita-image-store.s3.amazonaws.com/0/24511/a82a2ea5-3234-c7e3-b871-1a37e06bf47a.png)

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

「ソースコード管理」では、次のように設定しました。特別なことは無いと思います。

![無題3.gif](https://qiita-image-store.s3.amazonaws.com/0/24511/66b098a5-fad7-3a5f-58f6-42085171016c.gif)

build.xmlを次のようにして呼び出すことにしました。Eclipse環境と、Jenkinsの環境では、Tomcatのパスが異なることを考慮してあります。

![無題4.gif](https://qiita-image-store.s3.amazonaws.com/0/24511/92f71e58-5fcf-cf44-2c67-513c7fa04b1b.gif)

成果物を保存します。テスト環境に配布するモジュールと、配布するためのbuild.xmlなどを含んでいます。

![無題5.gif](https://qiita-image-store.s3.amazonaws.com/0/24511/b3eb3249-1092-9256-4e3c-25a0cfd62fba.gif)

ジョブを実行し、正常に動作することを確認しました。

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

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

![無題6.gif](https://qiita-image-store.s3.amazonaws.com/0/24511/1032aa6f-9ecc-0a19-f24e-4de44ad4a81d.gif)

モジュール配布とTomcat再起動を行うためAntを呼び出します。FTPタスクを使用するため、ライブラリの設定を行っています。

![無題7.gif](https://qiita-image-store.s3.amazonaws.com/0/24511/b3373adb-e794-0d6a-f362-715b68f2164d.gif)

ジョブを実行し、正常に動作することを確認しました。

# ジョブ起動設定
デプロイジョブ（Tomcat4.1Project01_Deploy）は、ビルドジョブ（Tomcat4.1Project01_Build）の終了後に起動されるように「ビルド・トリガ」を設定します。これで、ビルドジョブのジョブ実行をワンクリックするだけで、最新ソースのチェックアウトから、ビルド、デプロイまで自動化できました。

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

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

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

# 動作確認環境

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