4. ビルド・デプロイ手法

本節では、以下について説明します。

4.1. CIツールによるビルド

4.1.1. Jenkinsの利用

ここでは、代表的なCIツールであるJenkinsを利用します。

Jenkinsは、Javaで開発されたオープンソースツールで、あらゆるOSに対応しており、豊富なプラグインも提供されています。また、Jenkins 2.0より、複数のジョブを連携できるパイプライン機能を提供しており、後述する一連の処理をスクリプトで実装できます。

スクリプトで具体的な処理を記述するため、処理内容の確認が容易です。また、スクリプトファイルをソース管理システム(Gitなど)から読み込めるため、更新履歴も管理できます。

パイプラインスクリプト

また、パイプラインの流れは画面で可視化されるため、実行状況も容易に確認できます。

パイプライン画面

4.1.2. CIで行う処理

4.1.2.1. マイクロサービスプロファイル版
事前準備

次のような準備を行います。

  1. 開発環境
    1. 以下のMavenプロジェクトをGitに登録
パイプライン処理

マイクロサービスプロファイル版では、次の処理を行います。
各処理の実装については、 [ パイプラインでの実装方法 ] へのリンク先を参照してください。

  1. Gitの更新待ち
  2. ビルド環境をGitから取得
  3. WebOTX Uber JARのビルド
  4. コンテナイメージのビルド
  5. コンテナの評価
    1. コンテナの起動
    2. テストの実行
  6. コンテナイメージの登録
4.1.2.2. フルプロファイル版
事前準備
マイグレーションの場合

マイグレーションの場合、次のような準備を行います。

  1. 開発環境
    1. マイグレーションアシスタントでインポートファイルを生成
    2. 変換したJava EEアプリケーションのMavenプロジェクトをGitに登録
  2. ビルド環境
    1. コンテナ製品提供の準備スクリプトを最後まで実行
      • インポートファイルを引数に指定し、コンテナイメージを生成します。
    2. コンテナイメージの登録
    3. 成果物(Dockerfileなど)をコンテナビルド環境としてGitに登録

マイグレーションでは移行した時点でアプリケーションの更新が完結する場合もあると考えられますが、継続的な更新が想定される場合は、上記したようにアプリケーションのビルド環境もGitに登録します。

アプリケーションのEclipseプロジェクトをMavenプロジェクトに移行する手順については、 [ アプリケーション開発 > 開発環境の構築(WebOTX Developer) > Eclipseとは > Mavenプロジェクトへの移行 ] を参照してください。

新規構築/準備スクリプトを利用する場合

準備スクリプトを利用してDockerfileを生成する場合は、次のような準備を行います。

  1. 開発環境
    1. Java EEアプリケーションのMavenプロジェクトをGitに登録
  2. ビルド環境
    1. コンテナ製品提供の準備スクリプトを途中まで実行
      • コンテナイメージは作成しません。
    2. 成果物の更新(AP統合、設定、Dockerfileなど)
    3. コンテナイメージのビルド確認
    4. 成果物(設定、Dockerfileなど)をコンテナビルド環境としてGitに登録
新規構築/Dockerfileを自製する場合

公開されているコンテナイメージをベースにして、自由にApplication Server環境をカスタマイズするDockerfileを自製する場合は、次のような準備を行います。

  1. 開発環境
    1. Java EEアプリケーションのMavenプロジェクトをGitに登録
  2. ビルド環境
    1. Dockerfileの作成
      1. ベースイメージを指定
      2. 環境構築の処理を記述
      3. アプリケーションの配備処理を記述
    2. コンテナイメージのビルド確認
    3. 自製した成果物Dockerfileなど)をコンテナビルド環境としてGitに登録

例えば、アプリケーション配備(otxadmin deploy)と設定変更(otxadmin set)の処理を、次のようにDockerfileに記述します。

# WebOTX の公開イメージ名
FROM webotx/webotx-express-ubi8:11.11.00.00

# アプリケーション配備
COPY sample.war /tmp/
RUN /opt/WebOTX/bin/docker/start-domain-for-config.sh && \
    sleep 20 && \
    /opt/WebOTX/bin/otxadmin deploy --user admin --password adminadmin /tmp/sample.war && \
    /opt/WebOTX/bin/otxadmin set --user admin --password adminadmin server.〜 && \
    /opt/WebOTX/bin/docker/stop-domain-for-config.sh && \
    rm -rf /opt/WebOTX/domains/domain1/backup && \
    rm -rf /opt/WebOTX/domains/domain1/osgi-cache && \
    rm -f /opt/WebOTX/domains/domain1/config/ObjectBroker/namesv.ndf && \
    rm -f /tmp/sample.war

詳細については、 [ 構築・運用 > コンテナ型仮想化 > 公開イメージの利用 ] を参照してください。

パイプライン処理

フルプロファイル版では、次の処理を行います。
各処理の実装については、 [ パイプラインでの実装方法 ] へのリンク先を参照してください。

  1. Gitの更新待ち
  2. ビルド環境をGitから取得
  3. Java EEアプリケーションのビルド
  4. コンテナイメージのビルド
  5. コンテナの評価
    1. コンテナの起動
    2. テストの実行
  6. コンテナイメージの登録

4.1.3. パイプラインでの実装方法

Jenkinsパイプラインでの記述や必要な設定について説明します。

4.1.3.1. Git更新の待ち合わせ

Gitに登録されたソースファイルが更新されたことをトリガとしてパイプラインを実行する方法について、GitLabを例として説明します。

設定
Jenkins側

GitLabプラグインを利用し、GitLabに設定するためのトリガの通知先URLとトークンを生成します。

  1. [Jenkinsの管理]−[プラグインの管理]で、GitLabプラグインをインストールします。
  2. [Jenkinsの管理]−[Gitlab]
    1. 項目[Enable authentication for '/project' end-point]にチェックを入れます。
  3. パイプラインジョブの設定
    1. [ビルドトリガ]
      1. 項目[Build when a change is pushed to GitLab. GitLab webhook URL: http://<IPアドレス>:<ポート番号>/project/<ジョブ名>]にチェックを入れます。
      2. [高度な設定]を開き、[Secret token]の[Generate]でトークンを生成します。
    2. 設定を保存します。
GitLab側

通知対象のGitプロジェクトに以下を設定します。

  1. 通知対象のGitプロジェクトを開きます。
  2. 左ペインの[Settings]−[Webhooks]
    項目
    URL 通知先URL
    ※Jenkinsの認証情報も含める (*1)
    SecretToken トークン
    Trigger [Push events]をチェック
    Enable SSL verification JenkinsのエンドポイントのTLSに応じてチェック

    (*1) http://admin:admin@<IPアドレス>:<ポート番号>/project/<ジョブ名>

  3. [Add webhook]を押下して追加します。
4.1.3.2. Gitからの取得

ビルド環境(Mavenプロジェクト)や、デプロイ環境(マニフェストファイル)をGitから取得する方法について説明します。

設定
  1. JenkinsビルドマシンにGitをインストールします。
  2. [Jenkinsの管理]
    1. [プラグインの管理]で、Git clientプラグインをインストールします。
    2. [Global Tool Configuration]−[Git]で、[Git追加]を押下してインストール済みGitを登録します。
    3. [Security]−[Manaage Credentials]で、任意ドメインの[Add credentials]を押下して認証情報を登録します。
パイプライン記述

Gitからクローンするには、次のように記述します。

stage('Checkout application') {
    steps {
        git(url: 'http://gitlab.example.com/root/sample-app.git',credentialsId: 'gitlab-user-pass')
    }
}

指定している情報は以下です。

項目 説明
url GitリポジトリのURL
credentialsId Jenkinsに登録した認証情報のID
4.1.3.3. 任意コマンドの実行

任意コマンドをshで実行するには、次のように記述します。 Jenkinsビルドマシンにインストールされていれば、どのコマンドも実行できます。

stage('Run any command') {
  steps {
    dir('sample-app/src') {
      sh 'ls -la'
    }
  }
}

この例では、dirで実行時のディレクトリを指定しています。

パイプラインで実行するjavaのテストプログラムやシェルスクリプトの実行を含め、以降のMavenやDocker/Podmanのコマンドにも汎用的に利用できます。

4.1.4. Mavenコマンドの実行

アプリケーションやWebOTX Uber JARのMavenプロジェクトをビルドする場合、JenkinsビルドマシンにMaven環境を構築しておき、パイプラインではmvnコマンドをshで実行するように記述します。

stage('Build application') {
  steps {
    dir('sample-app') {
      sh 'mvn clean package'
    }
  }
}

この例では、Mavenプロジェクトのディレクトリ配下で、mvn clean installコマンドを実行しています。

4.1.4.1. Docker/Podmanコマンドの実行

コンテナイメージのビルドや実行などdocker/podmanコマンドを使用する場合、JenkinsビルドマシンにDocker/Podmanの環境を構築しておき、パイプラインではdocker/podmanコマンドをshで実行するように記述します。

stage('Build docker image') {
  steps {
    dir('sample-app/target/webotx-ms-package') {
      sh 'docker build -t registry.sample.com:5000/uberjar/webotx-as-exp:11.1 .'
    }
  }
}

この例では、WebOTX Uber JARのマイクロサービスパッケージが出力されるディレクトリ配下で、docker buildコマンドを実行しています。

4.1.4.2. パイプライン定義例

Jenkinsのパイプラインに定義内容を直接記述するか、以下の定義ファイル(GROOVY)をGitに登録して取り込むことができます。

このパイプラインでは、 [ 構築・運用 > コンテナ環境の開発から運用まで > アプリケーションの開発手順 > 新規アプリケーションの開発 ] で構築したUber JARのMavenプロジェクトを使用します。
構築後のMavenプロジェクトを固めた、以下のアーカイブファイルをGitに登録してください。ここでは、sample-appというプロジェクトに登録しています。

パイプライン定義例の内容を以下に示します。
変数定義のホスト名など、<>で囲まれた情報は環境にあわせてください。

//--------------------------------------
// 変数定義
//--------------------------------------
// WebOTX Uber JARプロジェクトのGitリポジトリURL
uberjarProjectRepoURL = 'http://<Gitサーバホスト>:<Gitサーバポート>/<PATH>/sample-app.git'

// Git認証情報の登録識別子
uberjarProjectRepoCredentialId = 'gitlab-user-pass'

// WebOTX Uber JARプロジェクトの展開先ディレクトリ
uberjarProjectRootDir = 'sample-app'

// WebOTXマイクロサービスパッケージの出力ディレクトリ
uberjarProjectTargetDir = 'sample-app/target/webotx-ms-package'

// WebOTX Uber JARのjarファイル名
uberjarFileName = 'sample-app-1.0-SNAPSHOT-micro.jar'

// 単体起動時のヘルスチェックURL
uberjarHealthCheckURL = 'http://localhost:18080/health'

// コンテナビルド時の引数(プロキシ定義など)
dockerBuildArgs = '--build-arg http_proxy=http://<Proxyサーバホスト>:<Proxyサーバポート>/ --build-arg https_proxy=http://<Proxyサーバホスト>:<Proxyサーバポート>/-build-arg no_proxy=127.0.0.1,localhost,<Proxy除外ホスト>'

// コンテナ名
dockerContainerName = 'uberjar-exp'

// コンテナイメージのタグ
dockerContainerTag = '<dockerレジストリサーバホスト>:<dockerレジストリサーバポート>/uberjar/webotx-as-exp:11.1'

// コンテナ起動時のオプション(ポートフォワードなど)
dockerRunOptions = '-p 28080:18080 OTX_LOG_TO_STDIO=true'

// コンテナ起動時のヘルスチェックURL
dockerHealthCheckURL = 'http://localhost:28080/health'


//--------------------------------------
// パイプライン定義
//--------------------------------------
pipeline {
    agent any
    // ツール定義
    tools {
        // Global Tool Configurationに登録したGit環境の定義名
        git '<定義名>'
    }

    stages {
        //--------------------------------------------------------------
        // WebOTX Uber JARのビルド(単体起動したUberJARの評価も実行)
        //--------------------------------------------------------------
        stage('Source Checkout and Build') {
            steps {
                dir(uberjarProjectRootDir){
                    // GitからWebOTX Uber JARのMavenプロジェクトを展開
                    // ※認証情報はJenkinsに登録済み
                    git(url: uberjarProjectRepoURL, credentialsId: uberjarProjectRepoCredentialId)

                    // テスト用のバッチファイルをシェルスクリプトに変更
                    sh 'chmod 555 *.sh'
                    sh 'sed -i -e "s/.bat/.sh/g" pom.xml'

                    // mavenビルド
                    sh 'mvn clean package'
                }
            }
        }

        //--------------------------------------------------------------
        // コンテナイメージのビルド
        //--------------------------------------------------------------
        stage('build docker image') {
            steps {
                dir(uberjarProjectTargetDir) {
                    // dockerビルド
                    sh 'docker build ' + dockerBuildArgs + ' . -t ' + dockerContainerTag
                }
            }
        }

        //--------------------------------------------------------------
        // コンテナ起動
        //--------------------------------------------------------------
        stage('run docker image') {
            steps {
                // コンテナの起動
                // ポートは18080→28080にフォワード
                sh 'docker run -itd --name ' + dockerContainerName + ' ' + dockerRunOptions + ' ' + dockerContainerTag

                // Application Serverの起動待ち合わせ
                waitForStartUp("docker-as")
            }
        }

        //--------------------------------------------------------------
        // コンテナの評価
        //--------------------------------------------------------------
        //stage('External test to Docker container') {
        //    steps {
        //      // 省略
        //    }
        //}

        //--------------------------------------------------------------
        // コンテナイメージのpush
        //--------------------------------------------------------------
        stage('Push Docker container') {
            steps {
                // Kubernetesが参照するリポジトリにpush
                sh 'docker push ' + dockerContainerTag
            }
        }
    }

    //--------------------------------------------------------------
    // パイプラインの後処理
    //--------------------------------------------------------------
    post{
        // 正常 / 異常に関わらず、終了時に実行
        always{
            // コンテナの停止
            sh 'docker stop ' + dockerContainerName

            // コンテナの削除
            sh 'docker rm ' + dockerContainerName

            // コンテナイメージの削除
            sh 'docker rmi ' + dockerContainerTag

            // workspaceのクリア
            cleanWs()
        }
    }
}

//--------------------------------------------------------------
// 起動待ち合わせ
//--------------------------------------------------------------
def waitForStartUp(String platform) {
    // 起動確認のためのコマンドを定期的に実行して正常終了するのを待ち合わせる。
    env.DOCKER_HEALTHCHECK_URL = dockerHealthCheckURL
    def messageAndCommands = readJSON text: '{\
        "docker-as": {\
            "errMessage": "dockerコンテナが120秒以内に起動しませんでした",\
            "command": "curl -kLI $DOCKER_HEALTHCHECK_URL -o /dev/null -w \'%{http_code}\' -s"\
        }\
    }'
    def waitCount = 0
    def isStarted = sh(script: messageAndCommands[platform]["command"], returnStatus: true)
    while(isStarted != 0){
        if (waitCount > 11) {
            echo messageAndCommands[platform]["errMessage"]
            sh 'exit 1'
        }
        sleep 10
        isStarted = sh(script: messageAndCommands[platform]["command"], returnStatus: true)
        waitCount ++
    }
}

4.2. デプロイ操作

ステージング/本番環境となる、コンテナオーケストレーションツール環境へのデプロイは、WebOTX Operatorを介して行われるため、事前に当該環境で稼働させておく必要があります。

4.2.1. 事前準備

4.2.1.1. WebOTX Operatorの環境構築

WebOTX Operatorの環境(コンテナイメージ、マニフェストファイル)は、2通りの準備方法があります。

両者のコンテナイメージは基本的に同じであり、通常はビルドが不要な後者が利便性が高いといえます。

Caution
新しいバージョンのコンテナイメージがDocker Hubで公開されると、その時点から旧バージョンの更新は行われない点に注意してください。脆弱性対処などで、OperatorのベースイメージとなっているOSを更新する場合は、前者の方法で対応します。

WebOTX Operatorの詳細については、以下を参照してください。

インストールして準備する方法

WebOTX Operatorをインストールしてコンテナイメージを作成し、対象となるコンテナオーケストレーションツール環境にデプロイする全体の流れは以下となります。

  1. ビルド環境

    1. Operatorをインストール
    2. コンテナイメージのビルド
    3. コンテナイメージの登録
    4. 成果物(Dockerfile、マニフェストファイル)をデプロイ環境としてGitに登録
      • Operatorデプロイ環境
        • カスタムリソース定義 (webotx_crd.yaml)
        • デプロイメント (operator.yaml)
      • Application Serverデプロイ環境
        • ConfigMap (configmap.yaml)
        • カスタムリソース (webotx_cr.yaml)
  2. ステージング/本番環境

    1. Operatorデプロイ環境を展開
      • Gitから取得、もしくはファイル転送など
    2. 操作環境の準備
      1. (Amazon EKSの場合)
        • aws/eksctl/kubectlコマンド環境を準備して以降の操作を行います。
      2. (OpenShiftの場合)
        • ocコマンド環境を準備し、OpenShiftにログインして移行の操作行います。
    3. 環境依存のコンテナレジストリへの登録
      1. (Amazon EKSの場合)
        • ビルド環境から、コンテナイメージをAmazon ECRに登録します。
      2. (OpenShiftの場合)
        • OpenShift環境でコンテナイメージをビルドし、内部レジストリに登録します。
    4. Operatorの設定 (operator.yaml)
      • コンテナイメージ名を指定
    5. 名前空間の作成
    6. 各種マニフェストの適用
      • カスタムリソース定義 (webotx_crd.yaml)
      • ConfigMap/デプロイメント (operator.yaml)
    7. (Operator稼働)
    8. 動作確認
      • OperatorのPodのSTATUSがRunningであることを確認します。
      • コンテナのログにエラーが記録されていないことを確認します。
公開物件を利用する方法

Docker Hubで公開されるWebOTX Operatorのコンテナイメージと、GitHubで公開されるマニフェストファイルを利用して、対象となるコンテナオーケストレーションツール環境にデプロイする全体の流れは以下となります。

  1. ビルド環境 (作業なし)

  2. ステージング/本番環境

    1. Operatorデプロイ環境を展開
      • GitHubからマニフェストファイルを取得
    2. 操作環境の準備
      1. (Amazon EKSの場合)
        • aws/eksctl/kubectlコマンド環境を準備して以降の操作を行います。
      2. (OpenShiftの場合)
        • ocコマンド環境を準備し、OpenShiftにログインして移行の操作を行います。
    3. Operatorの設定 (operator.yaml)
      • コンテナイメージ名を指定
    4. 名前空間の作成
    5. 各種マニフェストの適用
      • カスタムリソース定義 (webotx_crd.yaml)
      • ConfigMap/デプロイメント (operator.yaml)
    6. (Operator稼働)
    7. 動作確認
      • OperatorのPodのSTATUSがRunningであることを確認します。
      • コンテナのログにエラーが記録されていないことを確認します。
4.2.1.2. WebOTX Application Serverの設定

WebOTX OperatorがデプロイするWebOTX Application Serverの設定は、WebOTX Operatorが提供するマニフェストファイルに対して行います。

  1. 開発環境/ビルド環境
    1. Application Serverデプロイ環境をGitから取得
    2. Application Serverの設定 (operator.yaml)
      • ConfigMapの更新 (configmap.yaml)
      • カスタムリソースの更新 (webotx_cr.yaml)
    3. 更新内容をGitに反映

詳細については、以下を参照してください。

4.2.2. コンテナオーケストレーション環境でのデプロイ

WebOTX Operatorを介して、WebOTX Application Serverをコンテナオーケストレーションツール環境にデプロイする全体の流れは以下となります。

  1. ステージング/本番環境
    1. 操作環境の準備
      1. (Amazon EKSの場合)
        • aws/eksctl/kubectlコマンド環境を準備して以降の操作を行います。
      2. (OpenShiftの場合)
        • ocコマンド環境を準備し、OpenShiftにログインして移行の操作を行います。
    2. Application Serverデプロイ環境の展開
      • Gitから取得、もしくはファイル転送
    3. Application Serverの設定 (webotx_cr.yaml)
      • コンテナイメージ名を指定
    4. (OpenShiftの場合)サービスの公開
      1. SCC(Security Context Constraints)の設定
    5. 各種マニフェストの適用
      • ConfigMap (configmap.yaml)
      • カスタムリソース (webotx_cr.yaml)
    6. (OpenShiftの場合)サービスの公開
      1. Route定義
    7. (Application Server稼働)
    8. 動作確認
      • Application ServerのPodのSTATUSがRunningであることを確認します。
      • webotx-asコンテナのログにエラーが記録されていないことを確認します。

詳細については、以下を参照してください。