そごうソフトウェア研究所

SOA、開発プロセス、ITアーキテクチャなどについて書いています。Twitterやってます@rsogo

JenkinsからWildFlyへのリモートデプロイ(pom.xmlの更新)

前回は、Jenkinsサーバーが乗っているDockerコンテナから、WildFlyが動作しているアプリケーションサーバー用Dockerコンテナへのコンテナ間接続をやりました。 begirama.hatenablog.com

JenkinsからWildFlyへのリモートデプロイはWildFly Maven Pluginというのがあって、MavenからWildFlyへのデプロイ、アンデプロイ、インスタンスの起動停止が行えるようです。

WildFly Maven Plugin - Plugin Documentation

deployに関する詳細なリファレンスは下記。 WildFly Maven Plugin - wildfly:deploy

公式サイトではないですが、リモートサーバーへデプロイする際のpom.xmlの例はこちら。 Configuring Maven WildFly plugin

実際のpom.xmlのデプロイ部分はこんな感じ。

<plugin>
  <groupId>org.wildfly.plugins</groupId>
  <artifactId>wildfly-maven-plugin</artifactId>
  <version>1.1.0.Alpha1</version>
  <executions>
    <execution>
        <id>deploy</id>
        <phase>install</phase>
        <goals>
            <goal>deploy</goal>
        </goals>
        <configuration>
            <hostname>apppot_runtime1.7</hostname>
            <port>9990</port>
            <name>apppot-1.7-ci-jenkins.war</name>
            <username>{username}</username>
            <password>{password}</password>
            <filename>apppot-1.7-ci-jenkins.war</filename>
        </configuration>
    </execution>
  </executions>
</plugin>

deployタスクのconfigurationとして、次を指定しています。

  • hostname: Docker Linkした結果、hostsに定義されたホスト名を指定します。apppot_runtime1.7
  • port: WildFlyの管理ポートを指定。アプリケーションサーバーコンテナで、管理ポートをexposeしています
  • name: デプロイする名前。warの拡張子を付けてないとだめ。付けてない場合、デプロイタスク自体は成功するけど、WildFly側でいろいろ認識されていなくて動かなかった。特にエラーもでないから調査に時間かかった。
  • username: WildFlyにログインするためのアカウント
  • password: WildFlyにログインするためのパスワード
  • filename: デプロイするwarファイルを指定しています

すごくはまったのは、[ERROR] JBREM000200: Remote connection failed: javax.security.sasl.SaslException: Authentication failed: the server presented no authentication mechanismsのエラー。 いろなサイトを参考にして、nameだけ指定して、usernameは使っていませんでした。この時に、上のエラーが発生していました。逆にusernameのみを指定しても同じエラーが発生しました。結局、usernameとnameの両方を指定することで、解消しました。参考にしたサイトの人たちはなんで成功していたんだろう・・・。 認証で、こけると何でもこのエラーになるみたいです。

2015/08/21追記

WildFlyの古いバージョンだと、ネイティブ用のポートを使ってデプロイしていて、それだとusernameが不要のようです。 最新のWildFlyだと管理ポートのプロトコルはHTTPで、その場合、usernameが必要なようです。 それで古い記事を参考にしていると駄目だったんだな。

JenkinsからWildFlyへのリモートデプロイ(DockerコンテナのLink)

自社製品のAppPotの開発、運用環境は次のような構成になっています。

  1. 自社クラウド本番環境:クラウド運用しているバージョンのみ
  2. 自社クラウドテスト環境:クラウド運用しているバージョンのみ
  3. 自社クラウド開発環境:クラウド運用しているバージョンのみ
  4. 自社CI環境:製品バージョンごとに存在
  5. 受託プロジェクト開発開発:プロジェクトごとに存在

バージョンごとに環境を立てるのは大変なので、自社CI環境と受託プロジェクト開発環境はDockerコンテナ上で運用しています。常にすごい負荷がかかっているわけではないので、小規模なさくらインターネットのサーバーで3〜5つくらいのコンテナが動作しています。

このうち、CI環境の一部だけはJenkinsを使ったビルド、デプロイ、テストのプロセスが自動で回っています。この一部というのは、Jenkinsと同居しているアプリケーションサーバーのみ。 なぜかというと、コンテナ間の連携をちゃんとやる時間が無かったから・・。

というわけで、コンテナ間の連携、JenkinsからのWildFlyへのリモートデプロイをできるようにするのが、本エントリの目標です。

Dockerコンテナ間連携

まだしばらく同一サーバー内でのコンテナ間連携で行けそうなので、--linkを使います。

https://docs.docker.com/docker/userguide/dockerlinks/#communication-across-links

今回の場合はJenkinsサーバーコンテナから、アプリケーションサーバーコンテナへリンクします。

アプリケーションサーバーの起動

--nameオプションで、apppot_runtime1.7という名前でコンテナを起動させています。

docker run -it --expose 9181 -p 9181:8080 -p 9991:9990 --name apppot_runtime1.7 rsogo/wildfly8:v1 /bin/bash

Jenkinsサーバーコンテナの起動

--linkオプションで、apppot_runtime1.7という名前のコンテナをリンクさせています。

docker run -it --expose 8081 -p 8081:8080 --name jenkins --link apppot_runtime1.7:apppot_runtime1.7 rsogo/jenkins:v5 /bin/bash

コンテナIDでもリンクで指定することはできますが、コンテナIDはコンテナの起動の度に変わります。 上のような起動スクリプトはシェルとして用意しておきたいと思いますので、コンテナIDより、コンテナ名を定義しておいた方が便利です。

Jenkinsサーバーコンテナでのhostsファイル、環境変数の確認

apppot_runtime1.7がhostsファイルに追加されていることが分かります。

# cat /etc/hosts
172.17.0.71 cfc8c054ccf8
127.0.0.1   localhost
172.17.0.69 apppot_runtime1.7 9b5ee14ff469

envコマンドを実行した結果、環境変数アプリケーションサーバーコンテナが公開しているポートごとに次のような環境変数が定義されています。

APPPOT_RUNTIME1.7_PORT_8080_TCP_ADDR=172.17.0.69
APPPOT_RUNTIME1.7_PORT=tcp://172.17.0.69:22
APPPOT_RUNTIME1.7_PORT_22_TCP_PORT=22
APPPOT_RUNTIME1.7_PORT_22_TCP_ADDR=172.17.0.69
APPPOT_RUNTIME1.7_PORT_22_TCP=tcp://172.17.0.69:22
APPPOT_RUNTIME1.7_PORT_9181_TCP_PORT=9181
APPPOT_RUNTIME1.7_PORT_22_TCP_PROTO=tcp
APPPOT_RUNTIME1.7_PORT_8080_TCP_PORT=8080
APPPOT_RUNTIME1.7_PORT_9990_TCP=tcp://172.17.0.69:9990
APPPOT_RUNTIME1.7_PORT_9080_TCP_PORT=9080
APPPOT_RUNTIME1.7_PORT_9181_TCP_PROTO=tcp
APPPOT_RUNTIME1.7_PORT_8080_TCP=tcp://172.17.0.69:8080
APPPOT_RUNTIME1.7_PORT_8080_TCP_PROTO=tcp
APPPOT_RUNTIME1.7_PORT_9080_TCP_PROTO=tcp
APPPOT_RUNTIME1.7_PORT_9990_TCP_ADDR=172.17.0.69
APPPOT_RUNTIME1.7_PORT_9080_TCP_ADDR=172.17.0.69

この状態で、Jenkinsサーバーコンテナから以下のコマンドを実行することで、JenkinsサーバーからWildFlyのポートにアクセスできることを確認できます。

# curl http://apppot_runtime1.7:8080
<!--
  ~ JBoss, Home of Professional Open Source.
  ~ Copyright (c) 2011, Red Hat, Inc., and individual contributors
略

次は、JenkinsサーバーからWildFlyへリモートデプロイします。

Mule ESBまとめ

本ブログ内のMule ESBについてのまとめです。

Mule ESBはオープンソースのESB製品です。 オープンソースのCommunity Editionでも、基本的な機能やプロトコルに対応しています。

コネクタの一覧は下記のサイトから調べることができます。 Anypoint Exchange

パッケージ製品用のアダプターを使いたい、GUIで開発したいという場合にはEnterprise Editionが用意されています。

起動

begirama.hatenablog.com

Groovyスクリプト

begirama.hatenablog.com

Database Connector

begirama.hatenablog.com

begirama.hatenablog.com

begirama.hatenablog.com

フロー定義

begirama.hatenablog.com

begirama.hatenablog.com

サンプル

begirama.hatenablog.com

古い記事

有償版についている、Anypoint Studioを使ったエントリ。

begirama.hatenablog.com

Mule ESB 3.7のDatabase Connectorを試す2(INSERT)

先日、Muleを使ってOracle Databaseにアクセスするための設定の記事を書きました。

begirama.hatenablog.com

今回は、JSONで受け取って、Oracle DBにInsertするまでを書きます。

まず、メインのmule-config.xml

gist.github.com

前回のSELECTだけやるフローを改良しています。

まず、HTTPメソッドに応じて動かすフローを分けています。

GETメソッドで動かすフロー

  <flow name="GetFlow">
    <http:listener config-ref="HTTP_Listener_Configuration" path="/" doc:name="Recieve HTTP request" allowedMethods="GET"/>

中身は前回のフローとほぼ同様で、データベースに対してSELECT文を発行して、結果をJSONにして返します。

レスポンスのサンプルはこんな感じ。

[
  {
    "VALUE": "foo",
    "NAME": "SATO"
  },
  {
    "VALUE": "bar",
    "NAME": "SUZUKI"
  }
]

POSTメソッドで動かすフロー

  <flow name="PostFlow" doc:name="PostFlow">
    <http:listener config-ref="HTTP_Listener_Configuration" path="/" doc:name="Recieve HTTP request" allowedMethods="POST"/>

中身の処理は

デバッグ用にTransformerの前後でPayloadの中身をログにダンプ

<logger doc:name="Log the payload" level="INFO" message="About to echo #[message.payload]"/>

変換前後のログの出力結果はこんな感じ。

INFO  2015-08-06 08:51:47,892 [[database_update].HTTP_Listener_Configuration.worker.01] org.mule.api.processor.LoggerMessageProcessor: About to echo org.glassfish.grizzly.utils.BufferInputStream@386d562
INFO  2015-08-06 08:51:47,973 [[database_update].HTTP_Listener_Configuration.worker.01] org.mule.api.processor.LoggerMessageProcessor: About to echo [{VALUE=foo, NAME=SATO}, {VALUE=bar, NAME=SUZUKI}]

JSONをObjectに変換

この時の変換先のクラスはjava.util.ArrayListということを指定しています。 今回は、この後でループ処理をやるためにArrayListに変換していますが、<byte-array-to-string-transformer doc:name="Convert Byte Array to String"/>とかで、一つのStringオブジェクトに変換してもOK。

<json:json-to-object-transformer returnClass="java.util.ArrayList" doc:name="JSON to Object"/>

INSERTの発行

リクエストに含まれる件数分ループで回しつつ、Insert文を発行。

<foreach collection="#[message.payload]" doc:name="For Each">
    <db:insert config-ref="Oracle_Configuration" doc:name="Database">
        <db:parameterized-query><![CDATA[INSERT INTO TEST(NAME, VALUE)
              VALUES (#[payload.NAME], #[payload.VALUE])]]></db:parameterized-query>
    </db:insert>
</foreach>

マニュアル

あんまり読んで無いけど、JDBC周りのリファレンス。

JDBC Transport Reference - Current Mule Documentation

HTTPリスナでリクエストを受け付けるところはこのマニュアルを読んでおけばOK。

HTTP Listener Connector - Current Mule Documentation

Payloadからの値の取り方について

あと、これも参考にした。

JSON Payload ingested into MySQL database using Mule ESB - Stack Overflow

Mule ESB 3.7 メッセージ変換

使えるメッセージ変換の機能は下記のマニュアルを参照。

  • 用意されている変換機能

Objectと、JSONXMLの変換なんかは自動でやってくれる。 いざとなったらJavaやGroovyも呼び出せる。

Transformers - Current Mule Documentation

MEL (Mule Expression Language)

MELというXMLベースの独自言語が用意されていて、メッセージの要素にアクセスしたり、値を評価しての条件分岐とか書ける。

概要はこっちのマニュアルを読んで、

Mule Expression Language MEL - Current Mule Documentation

どんな機能が用意されているからは、こっちのリファレンスを見ればOK。 Mule Expression Language Reference - Current Mule Documentation

後はサンプルを見て、感じをつかむのが早い。

デプロイすると、No suitable driver foundが原因のjava.sql.SQLExceptionが発生する。 Muleを再起動すると解消する。DB接続が絡んでいない場合は、起動中のホットデプロイができているので、DB接続がらみで何かあるのかも知れない。要調査。

org.mule.module.db.internal.domain.connection.ConnectionCreationException: java.sql.SQLException: Cannot get connection for URL jdbc:oracle:thin:CMN/CMDB01@localhost:1521:aaa : No suitable driver found for jdbc:oracle:thin:aaa/aaa@localhost:1521:aaa (java.sql.SQLException). Message payload is of type: LinkedHashMap

Mule ESB 3.7のDatabase Connectorを試す1(設定とSELECT)

デプロイ

mule-config.xmlをappsの下に作ったdatabaseフォルダに置きます。

$ pwd
/Users/rsogo/work/mule-standalone-3.7.0/apps/database
$ ls
mule-config.xml

gist.github.com

デプロイ時ログ

おぉ、成功。

*******************************************************************************************************
*            - - + APPLICATION + - -            *       - - + DOMAIN + - -       * - - + STATUS + - - *
*******************************************************************************************************
* default                                       * default                        * DEPLOYED           *
* database                                      * default                        * DEPLOYED           *
*******************************************************************************************************

JDBC Driverの配置

  • Database Driverになにもやってない状態でhttp://localhost:8081/にアクセスすると次のようなエラーがでた。
org.mule.module.db.internal.domain.connection.ConnectionCreationException: java.sql.SQLException: Error trying to load driver: oracle.jdbc.Driver : oracle.jdbc.Driver (java.sql.SQLException). Message payload is of type: NullPayload

OracleからJDBC Driverをダウンロードする。

Oracle Database 12c Release 1 JDBC Driver Downloads

自分の環境はJDK1.7を使っているので、ojdbc7.jar

{MULE_HOME}/lib/user/配下に置く。

$ ls lib/user/
README.txt          mule-tests-functional-3.7.0.jar xmlunit-1.5.jar
junit-4.11.jar          ojdbc7.jar

StackOverflowかどこかに{MULE_HOME}/lib/mule/に置けって言っている人がいるけど、それだと動かなかった。

  • DriverはOKで、コネクションが確立できない場合のログ。
org.mule.module.db.internal.domain.connection.ConnectionCreationException: java.sql.SQLException: Cannot get connection for URL jdbc:oracle:thin:{User}/{Password}@localhost:{SID} : No suitable driver found for jdbc:oracle:thin:{User}/{Password}@localhost:{SID} (java.sql.SQLException). Message payload is of type: NullPayload

実行

Muleを実行しているマシンのhttp://locahost:8081/にアクセスしてみる。 上手く行っていると、データベースに検索した結果がJSONに変換されたレスポンスが見られる。

続きを次のエントリで書いています。 begirama.hatenablog.com

Mule ESB 3.7起動

以前、OSX上でMule 3.6を動かしました。

Mule ESB 3.6起動 - そごうソフトウェア研究所

Mule 3.7がリリースされているので、そちらを試してみたいと思います。

Mule 3.7のダウンロード

以前のエントリでは、Enterprise版のダウンロードページにしか行けずに、そちらで検証していました。 Enterprise版ではトライアル期間が終わると次のようなエラーが出て、起動できなくなります。

ERROR 2015-08-04 16:22:59,527 [main] com.mulesource.licm.impl.TrueLicenseHelper: Couldn't validate license key!
Invalid license

Community Editionのダウンロードはこちらで行けそう。

developer.mulesoft.com

Muleの起動

ダウンロードしたファイルを解凍。

$ unzip mule-standalone-3.7.0.zip

実行ファイルがあるところまで移動して、

$ cd mule-standalone-3.7.0/bin/
$ ls
additional.groovy   launcher.bat        mule
launcher        launcher.conf       mule.bat

muleコマンドを実行

$ ./mule 

起動ログ

$ ./mule 
MULE_HOME is set to /Users/rsogo/work/mule-standalone-3.7.0
Running in console (foreground) mode by default, use Ctrl-C to exit...
MULE_HOME is set to /Users/rsogo/work/mule-standalone-3.7.0
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
Running Mule...
--> Wrapper Started as Console
Launching a JVM...
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
Starting the Mule Container...
Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org
  Copyright 1999-2006 Tanuki Software, Inc.  All Rights Reserved.


WARNING - Unable to load the Wrapper's native library because none of the
          following files:
            libwrapper-macosx-x86-64.dylib
            libwrapper-macosx-universal-64.dylib
            libwrapper.dylib
          could be located on the following java.library.path:
            /Users/rsogo/work/mule-standalone-3.7.0/bin/%LD_LIBRARY_PATH%
            /Users/rsogo/work/mule-standalone-3.7.0/lib/boot
          Please see the documentation for the wrapper.java.library.path
          configuration property.
          System signals will not be handled correctly.

INFO  2015-08-04 16:46:04,937 [WrapperListener_start_runner] org.mule.module.launcher.MuleContainer: 
**********************************************************************
* Mule ESB and Integration Platform                                  *
* Version: 3.7.0 Build: 725cbc8a                                     *
* MuleSoft, Inc.                                                     *
* For more information go to http://www.mulesoft.org                 *
*                                                                    *
* Server started: 15/08/04 16:46                                     *
* JDK: 1.7.0_71 (mixed mode)                                         *
* OS: Mac OS X (10.10.4, x86_64)                                     *
* Host: Ryohei-no-MacBook-Pro.local (192.168.11.5)                   *
**********************************************************************
INFO  2015-08-04 16:46:04,941 [WrapperListener_start_runner] org.mule.module.launcher.coreextension.DefaultMuleCoreExtensionManager: Initializing core extensions
INFO  2015-08-04 16:46:04,941 [WrapperListener_start_runner] org.mule.module.launcher.coreextension.DefaultMuleCoreExtensionManager: Starting core extensions
INFO  2015-08-04 16:46:04,955 [WrapperListener_start_runner] org.mule.module.launcher.DefaultArchiveDeployer: ================== New Exploded Artifact: default
INFO  2015-08-04 16:46:04,963 [WrapperListener_start_runner] org.mule.module.launcher.MuleSharedDomainClassLoader: Using domain dir /Users/rsogo/work/mule-standalone-3.7.0/domains/default for domain default
INFO  2015-08-04 16:46:05,013 [WrapperListener_start_runner] org.mule.module.launcher.MuleDeploymentService: 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ Started domain 'default'                                 +
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
INFO  2015-08-04 16:46:05,020 [WrapperListener_start_runner] org.mule.module.launcher.DefaultArchiveDeployer: ================== New Exploded Artifact: default
INFO  2015-08-04 16:46:05,044 [WrapperListener_start_runner] org.mule.module.launcher.application.DefaultMuleApplication: 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ New app 'default'                                        +
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
INFO  2015-08-04 16:46:09,459 [WrapperListener_start_runner] org.mule.module.launcher.MuleDeploymentService: 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ Started app 'default'                                    +
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
INFO  2015-08-04 16:46:09,462 [WrapperListener_start_runner] org.mule.module.launcher.DeploymentDirectoryWatcher: 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ Mule is up and kicking (every 5000ms)                    +
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
INFO  2015-08-04 16:46:09,533 [WrapperListener_start_runner] org.mule.module.launcher.StartupSummaryDeploymentListener: 
**********************************************************************
*              - - + DOMAIN + - -               * - - + STATUS + - - *
**********************************************************************
* default                                       * DEPLOYED           *
**********************************************************************

*******************************************************************************************************
*            - - + APPLICATION + - -            *       - - + DOMAIN + - -       * - - + STATUS + - - *
*******************************************************************************************************
* default                                       * default                        * DEPLOYED           *
*******************************************************************************************************