OpenShiftによるJava EEアプリケーションのモダナイゼーションをやってみた。

# はじめに 
IBM CloudのOpenShiftのマネージドサービスである「 Red Hat OpenShift on IBM Cloud 」を使った「OpenShiftによるJava EEアプリケーションのモダナイゼーション」の記事を寄稿しました。
https://www.atmarkit.co.jp/ait/articles/1911/15/news002.html

その記事で使用している「 Red Hat OpenShift on IBM Cloud 」は有料サービスのため、たくさんの人に記事の手順を試してもらうのは難しいと思います。　そこで、**無料で利用できるMiniShiftを使って、気軽にOpenShiftでJava EEアプリケーションのモダナイゼーションを体感してもらえるように、リライトしました。**

**今回はアプリケーション・データベース共に全てコンテナ化するケースを試したいと思います。記事を読んでいただいた方は、記事の内容に加えて複数コンテナの連携(アプリケーションとデーターベース接続）について学べるようになってます。** 記事では、データベースはIBM Cloudのマネージドサービス「 Compose for MySQL 」を利用しました。
<img width="５00" alt="example-health-archtecture-0.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/d752183c-110d-3c74-d627-0892febfa9e0.png">

## (1)から(5)までシリーズ化してます。
- （この投稿）「[OpenShiftによるJava EEアプリケーションのモダナイゼーションをやってみた](https://qiita.com/daihiraoka/items/23cfaed7662d36ccc7ab)」- ビジネスロジック用のOpen Libertyで実行されているJava EEアプリケーションのモダナイゼーション

- 「[OpenShiftによるJava EEアプリケーションのモダナイゼーションをやってみた(2)](https://qiita.com/daihiraoka/items/d27cf3b3281ddc5ce8f1)」- 患者向けUI（ユーザーインターフェイス）のNode.jsアプリケーションのモダナイゼーション

- 「 [OpenShiftによるJava EEアプリケーションのモダナイゼーションをやってみた(3)](https://qiita.com/daihiraoka/items/be786115f1ca0b7fcdc0)」- 健康記録管理者用のPHPアプリケーション機能追加のモダナイゼーション

- 「 [OpenShiftによるJava EEアプリケーションのモダナイゼーションをやってみた(4)](https://qiita.com/daihiraoka/items/9ee24492737fb769abef)」- OpenShiftの標準的な機能のみを使ったDevOpsやCI/CD（継続的インテグレーション/継続的デリバリー）

- 「 [OpenShiftによるJava EEアプリケーションのモダナイゼーションをやってみた(5)](https://qiita.com/daihiraoka/items/a18e75487ec16f71fa88)」- Jenkinsを使ったDevOpsやCI/CD（継続的インテグレーション/継続的デリバリー）

# OpenShiftによるJava EEアプリケーションのモダナイゼーション  
[IBM Code Patterns](https://developer.ibm.com/jp/patterns/) に「 [Java EE と Open Liberty を使用した架空の医療アプリ内にマイクロサービスをデプロイする](https://developer.ibm.com/jp/patterns/jee-app-modernization-with-openshift/) 」というコードパターンがあります。これからこのコードパターンを使って実際に手を動かしてJava EEアプリケーションのモダナイゼーションを体感したいと思います。この一連の流れはオンプレミスシステムからクラウドへの移行の手順に相当するとご想像いただくとイメージしやすいでしょうか。これから皆さんはソリューションアーキテクトになりきって、これからクラウドで広がるモダナイゼーションの旅を体感しましょう。

## Example Healthのユースケース
Example Healthは架空の医療会社です。この会社には歴史があり、数十万の患者記録があります。もともと、Example Healthはアプリケーションにモノリシックアプリケーション構造を使用していました。それらのアプリケーション構造は、メインフレーム上のDb2データベースに接続されたWebSphereで実行されるフルスタックのJavaアプリケーションでした。Example Healthの元のアーキテクチャは次の通りです。
<img width="300" alt="example-health-archtecture-1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/06ee21d5-3794-2e28-c39b-d2a0f9dd1e93.png">
最近、Example Healthはアプリケーションをモダナイズし、マイクロサービスに分割することを決定しました。彼らはビジネスロジック用のOpen Libertyで実行されているJava EEアプリケーションと患者UI用のNode.jsアプリケーションに接続されたSQLデータベース(MySQL)に移動することを決定したのです。さらに、Example Healthはこれらのアプリケーション、SQLデータベースを全てコンテナ化し「 Red Hat OpenShift on IBM Cloud」上で動かすことを決定しました。 Example Healthの新しいアーキテクチャは次の通りです。
<img width="300" alt="example-health-archtecture-3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/22f479d7-5a30-2877-b19b-86d7a3fdc4b3.png">

「 Red Hat OpenShift on IBM Cloud 」に移行した結果、Example Healthは容易に機能拡張できるようになりました。間もなく、健康記録管理用アプリケーションと分析アプリケーションを含む新しいマイクロサービスが含まれるようになるのです。

- [健康記録管理用アプリケーション](https://developer.ibm.com/jp/patterns/app-modernization-php-s2i-openshift/)
- [分析アプリケーション](https://developer.ibm.com/patterns/creating-a-health-data-analytics-app-with-legacy-mainframe-code-and-cloud/)

## MiniShiftの準備

Qiitaの別投稿を参考に、MiniShiftを準備してください。

> 注:MiniShiftを起動するホストのDockerのバージョンは17.09以降をインストールしてください。 Docker CE（コミュニティエディション)の最新をインストールすると良いでしょう。後ほど使用するDockerfileの中にDocker 17.09からサポートするADD/COPY --chownフラグでファイルのオーナーを変える構文が使われているためです。　MiniShiftの仮想マシン(VM)で動作するDockerのバージョンが1.13なので、面倒なことになってます。ちなみにDockerfileを--chownフラグを使わないようにすれば、メンドくさいことから回避されますが、今回はコードパターンのリソースは変更せずにやっていきます。


- [ESXi上のCentOS7にOpenShift(MiniShift)をインストール](https://qiita.com/daihiraoka/items/f04ce27d4ddaff1734e0)

- [公式サイト - https://docs.okd.io/latest/minishift/getting-started/installing.html](https://docs.okd.io/latest/minishift/getting-started/installing.html)

手順の前半ではMiniShiftは使用しません。必要になる時までMiniShiftを停止してください。

```console
# minishift stop
```

MiniShiftを起動した後に「 # eval $(minishift docker-env) 」コマンドを実行している場合は、
「 docker push 」する際に、MiniShiftの仮想マシン(VM)で動作するDockerにイメージを登録します。


![minishift-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/ccc36aa1-7de9-17cd-f7b5-8f9ea86f7fa2.png)

今回は、作業ホストのMiniShiftを起動するホストのDockerにイメージを登録したいので、「 # env | grep DOCKER 」コマンドを実行してDOCKER_HOST、DOCKER_TLS_VERIFY、DOCKER_CERT_PATHに値が入っている場合は、下記コマンドで環境変数を空にしてください。

```console
export DOCKER_TLS_VERIFY=""
export DOCKER_HOST=""
export DOCKER_CERT_PATH=""
```

## 手順 

>(筆者が試した環境)CentOS 7.7 最小構成

### 1. Maven (Mavenの依存関係でJDKもインストールされる） 

```console
# yum install maven
```

### 2. Dockerデーモンの起動確認
後ほどDockerビルドするのでDockerでデーモンが起動していることを確認

```console
# systemctl status docker
```
> Dockerfileの中に、Docker 17.09 からサポートするADD/COPY --chownでファイルのオーナーを変える構文が使われているため、 CentOSでサポートする　Dockerでは、構文がわからないためエラーになります。 Dockerのバージョンを17.09以上にするか、Dockerfileを--chownの箇所を 別行(別レイヤー）でchownコマンドで処理するなど回避してください。


### 3. GitHubのプロジェクトをCloneします。Cloneするとexample-health-jee-openshiftフォルダが作成されます。

```console
# git clone https://github.com/daihiraoka/example-health-jee-openshift.git
Cloning into 'example-health-jee-openshift'...
remote: Enumerating objects: 263, done.
remote: Counting objects: 100% (263/263), done.
remote: Compressing objects: 100% (175/175), done.
remote: Total 263 (delta 108), reused 204 (delta 53), pack-reused 0
Receiving objects: 100% (263/263), 17.82 MiB | 5.57 MiB/s, done.
Resolving deltas: 100% (108/108), done.
# cd example-health-jee-openshift
# ls
example-health-api  generate  LICENSE  readme_images  README.md  screenshots
```

### 4. Java EEアプリケーションをビルドします。

```console
# cd example-health-api/
# mvn package
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building health-api 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-resources-plugin/2.5/maven-resources-plugin-2.5.pom
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-resources-plugin/2.5/maven-resources-plugin-2.5.pom (7 KB at 7.4 KB/sec)
<<------------------------------------省略------------------------------------>>
[INFO] Building war: /root/example-health-jee-openshift/example-health-api/target/health-api.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 34.656s
[INFO] Finished at: Thu Oct 17 13:58:55 JST 2019
[INFO] Final Memory: 14M/143M
[INFO] ------------------------------------------------------------------------
```

### 5. Java EE アプリケーションのDockerイメージをビルドします。

```console
# docker build -t ol-example-health:1 .
Sending build context to Docker daemon  13.48MB
Step 1/10 : FROM openliberty/open-liberty:javaee8-ubi-min
javaee8-ubi-min: Pulling from openliberty/open-liberty
bdb299bbb0dd: Pull complete 
22b1a8fa1ec0: Pull complete 
bccea9526f92: Pull complete 
ca821998be76: Pull complete 
7d738fac7181: Pull complete 
2356e9fc5285: Pull complete 
048ba391e9fe: Pull complete 
347eb7134a38: Pull complete 
94456b65cdbb: Pull complete 
Digest: sha256:1f08f83c3076aaec7a7d3639864ca06998a779cecad6ad1452d501008c56f63b
Status: Downloaded newer image for openliberty/open-liberty:javaee8-ubi-min
 ---> fc55e2d66c27
Step 2/10 : ENV INSTALL_DIR /opt/ol/wlp/
 ---> Running in 45aaeaaa0c92
Removing intermediate container 45aaeaaa0c92
 ---> 27fe222d05be
Step 3/10 : ENV CONFIG_DIR /opt/ol/wlp/usr/servers/defaultServer/
 ---> Running in 395e839afb7f
Removing intermediate container 395e839afb7f
 ---> 8632cfb62026
Step 4/10 : ADD --chown=default:root https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.16/mysql-connector-java-8.0.16.jar  ${INSTALL_DIR}lib/mysql-connector-java-8.0.16.jar
Downloading [==================================================>]  2.293MB/2.293MB

 ---> 61898c26bdb1
Step 5/10 : RUN chmod 644 ${INSTALL_DIR}lib/mysql-connector-java-8.0.16.jar
 ---> Running in 8011b3b50bac
Removing intermediate container 8011b3b50bac
 ---> 5909218a689a
Step 6/10 : COPY liberty-mysql/mysql-driver.xml ${CONFIG_DIR}configDropins/defaults/
 ---> f42f5684e5b0
Step 7/10 : COPY liberty/server.xml $CONFIG_DIR
 ---> 67938badab11
Step 8/10 : COPY liberty/jvm.options $CONFIG_DIR
 ---> 60c3c494f5ef
Step 9/10 : COPY target/health-api.war /opt/ol/wlp/usr/servers/defaultServer/apps
 ---> 1bcb2f837df9
Step 10/10 : EXPOSE 9080
 ---> Running in eba84e894ddc
Removing intermediate container eba84e894ddc
 ---> aa91da14cf12
Successfully built aa91da14cf12
Successfully tagged ol-example-health:1
```

### 6. Dockerビルドが成功するとベースイメージのopenliberty/open-libertyと今回作成したol-example-healthイメージが出力されます。

```console
# docker images
REPOSITORY                 TAG                 IMAGE ID            CREATED             SIZE
ol-example-health          1                   aa91da14cf12        48 seconds ago      348MB
openliberty/open-liberty   javaee8-ubi-min     fc55e2d66c27        16 hours ago        343MB
```


**Note:**
DockerfileのFROM句で指定しているOpen LibertyのベースイメージにはRed Hat UBI(Red Hat Universal Base Image)のRHEL7を使用しています。Red Hat UBIはRed Hatの品質管理を経て提供されるコンテナイメージで無償で、自由に再配布することができます。
Red Hat UBIベースで作成したコンテナイメージは、「 Red Hat OpenShift on IBM Cloud 」上で動作させる時は、サポートを受けることができます。OpenShiftを使用しない環境では、サポートを受けることはできませんが、無償でRHELのコンテナイメージが使えるメリットがあります。
企業の中でコンテナを運用していると、それぞれの部門からCentOS、Ubuntuなど出所のよく分からないコンテナを渡されてセキュリティ的に大丈夫なのか判断が必要な場合があります。でも様々な理由で使うしかなく不安を抱えて運用することもありました。Red Hat UBIだとRed Hatの品質管理を経て提供されるのでその不安は解消されます。もし、今CentOSやUbuntuのコンテナイメージを使っている方は、Red Hat UBIを使ってみたらいかがでしょうか？

Red Hat UBI(Red Hat Universal Base Image)
https://access.redhat.com/containers/#/search/ubi

### 7. Docker HubにJava EEアプリケーションのDockerイメージ「 ol-example-health 」を登録します。

   - 事前にDocker Hubのアカウントを作成してください。
   - daihiraokaの箇所をDocker Hubのアカウント名に置き換えて実行してください。

ol-example-healthイメージを 「 Docker Hubのアカウント名/イメージ名:タグ名 」の形式でタグ付けします。

```
# docker tag ol-example-health:1 daihiraoka/ol-example-health:1
```

Dockerイメージの一覧を出力するとdaihiraoka/ol-example-healthイメージが作成されているのが確認できます。

```
# docker images
REPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE
daihiraoka/ol-example-health   1                   901666e26ca5        27 minutes ago      450MB
ol-example-health              1                   901666e26ca5        27 minutes ago      450MB
openliberty/open-liberty       javaee8-ubi-min     bb992680821b        17 hours ago        445MB
```

Docker Hubにログインし、Docker Hubのリポジトリにdaihiraoka/ol-example-healthイメージを登録します。

```
# docker login -u daihiraoka
Login Succeeded

# docker push daihiraoka/ol-example-health:1
```
イメージの登録が完了するとDocker Hubのリポジトリにdaihiraoka/ol-example-healthが表示されます。
<img width="400" alt="dockerhub-01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/c27602ab-7fa3-ec73-f779-229e2d85d852.png">

```
Note:
今回はCode Patternsの手順でDocker Hubを使いましたが、IBM CloudにはContainer Registryのサービスがあります。通常、商用利用ではIBM Cloud Container Registryを使ってコンテナイメージを管理します。

・IBM Cloud Container Registry の概要
https://cloud.ibm.com/docs/services/Registry?topic=registry-registry_overview&locale=ja

```

### 8. MiniShiftの起動 

```console
# minishift start
-- Starting profile 'minishift'
-- Check if deprecated options are used ... OK
-- Checking if https://github.com is reachable ... OK
-- Checking if requested OpenShift version 'v3.11.0' is valid ... OK
-- Checking if requested OpenShift version 'v3.11.0' is supported ... OK
-- Checking if requested hypervisor 'kvm' is supported on this platform ... OK
Server Information ...
OpenShift server started.
<img width="400" alt="dockerhub-01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/d24a8d74-9aca-898e-1066-86395168ba48.png">

The server is accessible via web console at:
    https://192.168.42.138:8443/console
```

- MiniShiftの環境変数の適用

```console
# eval $(minishift oc-env)    <- ocコマンドのPATH定義
# eval $(minishift docker-env) <- MiniShiftのVMで動作するDockerへの接続設定
# source <(oc completion bash) <-コマンドとリソースのシェル補完
```

minishift oc-envを実行してみると ocコマンドのPATHを通すためコマンドが出力される。

```console
# minishift oc-env
export PATH="/root/.minishift/cache/oc/v3.11.0/linux:$PATH"
# Run this command to configure your shell:
# eval $(minishift oc-env)

# ls -1 /root/.minishift/cache/oc/v3.11.0/linux
oc
```

minishift docker-envを実行すると、下記のように KVM上で動作しているMiniShiftのVMで動作しているDockerへの接続情報が出力されます。　この環境変数を定義することでローカルのDockerレジストリではなくMiniShiftのVMのDockerレジストリでコンテナイメージを取り扱います。

```console
# minishift docker-env
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.42.138:2376"
export DOCKER_CERT_PATH="/root/.minishift/certs"
```

### 9. OpenShiftのCLIにユーザー名をdeveloperでログインします。
(MiniShiftではパスワードは何でも通るので任意の文字列を使用してください。)

```console
# oc login -u developer
Logged into "https://192.168.42.138:8443" as "developer" using existing credentials.

You have one project on this server: "myproject"

Using project "myproject".
```

### 10. Example Health用のプロジェクトを作成します。
これにより、新しいプロジェクトが作成され、Pod(コンテナ）がデプロイされる作業プロジェクトとして設定されます。

```console
# oc new-project health
Now using project "health" on server "https://192.168.42.138:8443".

You can add applications to this project with the 'new-app' command. For example, try:

    oc new-app centos/ruby-25-centos7~https://github.com/sclorg/ruby-ex.git

to build a new example application in Ruby.
```

### 11. MySQLのカタログを探すためにOpenShiftプロジェクトのImageStream(is)の一覧を出力します。

```console
# oc get is -n openshift
NAME         DOCKER REPO                            TAGS                         UPDATED
dotnet       172.30.1.1:5000/openshift/dotnet       2.0,latest                   16 hours ago
httpd        172.30.1.1:5000/openshift/httpd        2.4,latest                   16 hours ago
jenkins      172.30.1.1:5000/openshift/jenkins      2,latest,1                   16 hours ago
mariadb      172.30.1.1:5000/openshift/mariadb      10.1,10.2,latest             16 hours ago
mongodb      172.30.1.1:5000/openshift/mongodb      2.6,3.2,3.4 + 3 more...      16 hours ago
mysql        172.30.1.1:5000/openshift/mysql        latest,5.5,5.6 + 1 more...   16 hours ago
nginx        172.30.1.1:5000/openshift/nginx        1.10,1.12,1.8 + 1 more...    16 hours ago
nodejs       172.30.1.1:5000/openshift/nodejs       4,6,8 + 4 more...            16 hours ago
perl         172.30.1.1:5000/openshift/perl         5.20,5.24,5.26 + 2 more...   16 hours ago
php          172.30.1.1:5000/openshift/php          7.1,latest,5.5 + 2 more...   16 hours ago
postgresql   172.30.1.1:5000/openshift/postgresql   9.4,9.5,9.6 + 3 more...      16 hours ago
python       172.30.1.1:5000/openshift/python       3.5,3.6,latest + 3 more...   16 hours ago
redis        172.30.1.1:5000/openshift/redis        3.2,latest                   16 hours ago
ruby         172.30.1.1:5000/openshift/ruby         2.2,2.3,2.4 + 3 more...      16 hours ago
wildfly      172.30.1.1:5000/openshift/wildfly      11.0,12.0,13.0 + 5 more...   16 hours ago
```

mysqlが今回使用するコンテナイメージのImageStreamです。一覧で表示されるnodejsやdotnetは、下記画像のWebコンソールのカタログと同じです。OpenShiftはCLIでも簡単にアプリケーションをデプロイする仕組みを用意しています。

<img width="400" alt="s2i-1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/f8eb2b89-51b3-b0e3-04b5-38b4a11c09b2.png">

### 12. OpenShiftのS2I（Source to Image）を使ってMySQLデータベースのコンテナを作成します。   

```console
# oc new-app \
-e MYSQL_USER=admin \
-e MYSQL_PASSWORD=password \
-e MYSQL_DATABASE=health \
--name=mysql \
openshift/mysql:5.7~https://github.com/daihiraoka/example-health-jee-openshift.git
```
 
「 -e 」で環境変数を定義します。

| パラメーター                         |       概要          |
|:----------------------------------|:------------------:|
| -e MYSQL_USER                     |  MySQLのユーザー名      |
| -e MYSQL_PASSWORD                 |  MySQLのパスワード       |
| -e MYSQL_DATABASE                 |  データベース名       |
| --name                            |  コンテナ名        |
| openshift/mysql:5.7               |  openshift/mysql:5.7はベースとなるコンテナイメージのImageStream名(openshiftプロジェクトのmysql:5.7)      |
| ~https://github.com(省略)          | ~(チルダ)で挟んで右側が、ソースコードリポジトリを指定  |

> 今回は、データベースのデータを保存する永続ストレージについては省略しています。Pod(コンテナ）に永続ストレージの設定をしていない場合は、 Pod(コンテナ)が停止すると登録したデーターは全て消えてしまいます。
今回の場合は、新たにPod(コンテナ）が起動すると、空っぽで、SQLスキーマのインポートから再開しないといけません。

実行結果

```console
--> Found image f83a293 (6 days old) in image stream "openshift/mysql" under tag "5.7" for "openshift/mysql:5.7"

    MySQL 5.7 
    --------- 
    MySQL is a multi-user, multi-threaded SQL database server. The container image provides a containerized packaging of the MySQL mysqld daemon and client application. The mysqld server daemon accepts connections from clients and provides access to content from MySQL databases on behalf of the clients.

    Tags: database, mysql, mysql57, rh-mysql57

    * A source build using source code from https://github.com/daihiraoka/example-health-jee-openshift.git will be created
      * The resulting image will be pushed to image stream tag "mysql:latest"
      * Use 'start-build' to trigger a new build
    * This image will be deployed in deployment config "mysql"
    * Port 3306/tcp will be load balanced by service "mysql"
      * Other containers can access this service through the hostname "mysql"

--> Creating resources ...
    imagestream.image.openshift.io "mysql" created
    buildconfig.build.openshift.io "mysql" created
    deploymentconfig.apps.openshift.io "mysql" created
    service "mysql" created
--> Success
    Build scheduled, use 'oc logs -f bc/mysql' to track its progress.
    Application is not exposed. You can expose services to the outside world by executing one or more of the commands below:
     'oc expose svc/mysql' 
    Run 'oc status' to view your app.
```

しばらくすると mysqlのPod [ mysql-1-hktv2 ] が起動します。


```console
# oc get pod
NAME            READY     STATUS      RESTARTS   AGE
mysql-1-build   0/1       Completed   0          3m
mysql-1-hktv2   1/1       Running     0          2m
```

### 13. MySQLコンテナにデーターベーススキーマーを作成 
MySQLにデーターベースのスキーマーを作成するために、 oc rshコマンドでコンテナにログインします。

```console
# oc rsh mysql-1-hktv2
```

rshでログインするとgithubでディレクトリ構造がコンテナの中にあることがわかります。

```console
sh-4.2$ ls
LICENSE  README.md  example-health-api	generate  readme_images  screenshots
```

患者の健康記録データのSQLスキーマをインポートします ファイル名： example-health-api/samples/health_schema.sql 

```console
sh-4.2$ mysql -u admin -ppassword health < ./example-health-api/samples/health_schema.sql 
mysql: [Warning] Using a password on the command line interface can be insecure.
```

healthデータベースのテーブル一覧を出力します。SQLスキーマのインポートが正常に終了していると出力結果のテーブルが表示されます。

```console
sh-4.2$ mysql -u admin -ppassword health -e "show tables;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------------+
| Tables_in_health |
+------------------+
| Allergies        |
| Appointments     |
| MESSAGE          |
| Observations     |
| Organizations    |
| Patients         |
| Prescriptions    |
| Providers        |
| SEQUENCE         |
+------------------+
```

データベースの作成が終わったのでコンテナから「 exit 」コマンドで抜けます。

```console
sh-4.2$ exit
exit
```
### 14. ビジネスロジック用のJava EE アプリケーションとMySQLのコンテナ間通信設定

作業ホストに戻って「 pwd 」を打つと「 example-health-jee-openshift/example-health-api 」フォルダにいるはずです。

```console
# pwd
/root/example-health-jee-openshift/example-health-api
# ls
create-secrets.sh  Dockerfile  kubernetes-openshift.yaml  liberty  liberty-mysql  pom.xml  samples  src  target
```

ビジネスロジック用のJava EE アプリケーションとMySQLを接続するために、まずは MySQLのサービス名を調べます。

```console
# oc get svc
NAME      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
mysql     ClusterIP   172.30.88.187   <none>        3306/TCP   9m
```

Pod間の通信は、サービス名で行います。　サービス名は次の手順で使うので覚えておいてください。


example-health-api/create-secrets.shスクリプトを使ってMySQLの接続情報を設定します。

```console
cat create-secrets.sh
#!/bin/bash
oc create secret generic db-secrets    \
     --from-literal=db_username=admin        \
     --from-literal=db_password=password       \
#    --from-literal=db_host="jdbc:mysql://サービス名:ポート番号/データベース名?sessionVariables=sql_mode=''"
     --from-literal=db_host="jdbc:mysql://mysql:3306/health?sessionVariables=sql_mode=''"

```

>注: 2019年10月時点ではcreate-secrets.shには「 DB名/?sessionVariables 」と「 DB名 」と「 ? 」の間に「 / 」が書かれています。JDBCで接続する時は「 / 」もDB名の文字列に含まれるため、接続エラーが発生します。そのため「 / 」を削除してください。

OpenShiftではパスワードなど認証情報はsecretsという機密情報を保持するメカニズムをもつオブジェクトに保持します。
そしてMySQの接続情報はPod(コンテナ)の中で環境変数として利用します。環境変数として使うためには次の手順のkubernetes-openshift.yamlでPod(コンテナ)のデプロイを定義するDeploymentオブジェクトの中で、環境変数とsecretsの紐付けを行います。

- kubernetes-openshift.yamlのenv(環境変数)を定義する箇所を抜粋

```
env:
- name: ENV_MYSQL_UR
  valueFrom:
    secretKeyRef:
      name: db-secrets
      key: db_host
- name: ENV_MYSQL_USER
  valueFrom:
    secretKeyRef:
      name: db-secrets
      key: db_username
- name: ENV_MYSQL_PWD
  valueFrom:
    secretKeyRef:
      name: db-secrets
      key: db_password
``` 

そしてOpen LibertyのDataSource設定では、上記で定義した環境変数を使用してデータベース接続のパラメータを設定します。

- example-health-api/liberty/server.xmlのDataSourceを定義する箇所を抜粋

```
<dataSource id="DefaultDataSource" jndiName="jdbc/health-api" jdbcDriverRef="mysql-driver"
           type="javax.sql.ConnectionPoolDataSource" transactional="true">

   <properties url="${ENV_MYSQL_URL}"
               databaseName="${ENV_MYSQL_DB_NAME}"
               user="${ENV_MYSQL_USER}"
               password="${ENV_MYSQL_PWD}"/>
```
 
> 注: 上記には未定義の環境変数:ENV_MYSQL_DB_NAMEがありますが、環境変数:ENV_MYSQL_URLの中でデータベース名が定義しているためです。ここでは元のCode Patternsのコードをそのまま表示しています。
 
スクリプトを実行してsecretsをOpenShiftに作成します。作成後「 oc get secrets 」コマンドでsecretsの一覧を出力すると「 db-secrets 」という名前で作成されているのが確認できます。

```
#  ./create-secrets.sh 
secret/db-secrets created

# oc get secrets
NAME                       TYPE                                  DATA      AGE
db-secrets                 Opaque                                3         2d
```

### 15. Java EE アプリケーションのデプロイ

ファイル: example-health-api/kubernetes-openshift.yamlを編集して、containersセクションのimageキーをDocker HubにpushしたJava EE アプリケーションのDockerイメージに変更します。 
	- daihiraokaの箇所をDockerHubのアカウント名に置き換えてください。
	- ol-example-healthのタグをlatestから1に置き換えてください。

(変更前) 

```
  containers:
  - name: example-health-api
    image: ykoyfman/ol-example-health:latest
```

(変更後)

```
  containers:
  - name: example-health-api
    image: daihiraoka/ol-example-health:1
```

Java EE アプリケーションをクラスターにデプロイします。

```
# oc create -f kubernetes-openshift.yaml
service/example-health-api created
deployment.apps/example-health-api created
```

example-health-api/kubernetes-openshift.yamlの中には、Open LibertyのPod(コンテナ）をデプロイするための定義が記述されているDeployment、Open LibertyのPod(コンテナ）のEndPoint(IP)にアクセスするためのServiceが記述されています。このyamlを実行することによって、OpenShiftにOpen LibertyのPod(コンテナ）が起動し、Serviceを使ってOpen LibertyのPod(コンテナ)に接続できるようになります。


しばらく時間が経過するとOpen LibertyのPod(コンテナ）が起動します。「 oc get pod 」コマンドを実行してPod(コンテナ)の一覧を出力すると「 example-health-api-<任意の英数字> 」のPod(コンテナ)のSTATUSが 「 Running 」になります。

```console
# oc get pod
NAME                                  READY     STATUS      RESTARTS   AGE
example-health-api-7fcb786fb6-l5kx9   1/1       Running     0          1m
mysql-1-build                         0/1       Completed   0          22m
mysql-1-hktv2                         1/1       Running     0          21m
```

### 16. Java EE アプリケーションをインターネットに公開するためのOpenShiftのオブジェクトであるRouteを作成します。

```console
# oc expose svc example-health-api
route.route.openshift.io/example-health-api exposed
```

Java EE アプリケーションが機能していることを確認します。まず、Routeに割り当てられたホスト名を取得します。

```console
# oc get route
NAME                 HOST/PORT                                         PATH      SERVICES             PORT      TERMINATION   WILDCARD
example-health-api   example-health-api-health.192.168.42.138.nip.io             example-health-api   http                    None
```

この場合は最初のNAMEのexample-health-apiがRoute名で、次のHOST/PORTのFQDNが生成されたホスト名です。RouteにアクセスがあるとSERVICESのexample-health-apiを通って、Open LibertyのPod(コンテナ）のEndPointのIPアドレスにアクセスします。

### 17. ブラウザでJava EEアプリケーションの動作確認

ブラウザウィンドウで、<Routeで作成されたFQDN>/openapi/ui/に移動します。Java EEアプリケーションでサポートされるOpenAPIのエンドポイントと仕様が表示されます。 例) http://example-health-api-health.192.168.42.138.nip.io/openapi/ui/

<img width="929" alt="スクリーンショット 2019-10-17 14.52.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/9cbe5d5b-99d5-d14f-c7c4-1765218a5c17.png">

これで、ビジネスロジックがRed Hat OpenShift on IBM Cloud上で起動しました。現時点ではデータベースにはSQLのスキーマーは作成されていますがデータがありません。次の手順で患者の健康記録テストデータをUSERが①の経路でREST APIを使って登録します。
<img width="750" alt="business-logic-architecture.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/7077fbe0-6ec4-b885-a101-517a9c36c98f.png">

### 18. 患者の健康記録テストデータ生成プログラムの準備

- 患者の健康記録テストデータを作成するgenerate.shを実行してテストデータをREST APIでMySQLに登録します。generate.shの中では合成された現実的な（ただし実際ではない）患者データと関連する健康記録をさまざまな形式で出力することができる [synthea](https://github.com/synthetichealth/synthea) と呼ばれるプログラムが使用されています。

    - スクリプト名: example-health-jee-openshift/generate/generate.sh

- generate.shを実行するのに必要なNode.jsのcsvtojsonをインストールします。

```console
# ls
example-health-api  generate  LICENSE  readme_images  README.md  screenshots
# cd generate/
# ls
generate.sh  package.json  README.md
# pwd
/root/example-health-jee-openshift/generate
# yum install npm
Installing:
 npm                      x86_64                   1:3.10.10-1.6.17.1.1.el7                    epel                   2.5 M
Installing for dependencies:
 libuv                    x86_64                   1:1.30.1-1.el7                              epel                   138 k
 nodejs                   x86_64                   1:6.17.1-1.el7                              epel                   4.7 M
# npm install csvtojson
synthea-generate@1.0.0 /root/example-health-jee-openshift/generate
└─┬ csvtojson@2.0.10 
  ├── bluebird@3.7.1 
  ├── lodash@4.17.15 
  └─┬ strip-bom@2.0.0 
    └── is-utf8@0.2.1 

# pwd
/root/example-health-jee-openshift/generate

- csvtojsonが使える様にPATHを通します。
# PATH=$PATH:/root/example-health-jee-openshift/generate/node_modules/csvtojson/bin
```

### 19. Routeのデフォルトタイムアウト値変更

前の手順で作成したRoute名: example-health-api のデフォルトタイムアウト値を60分に変更します。USERがgenerate.shを実行するとOpenShiftのアプリケーションロードバランサー(ALB)のrouterを通ってOpen LibertyのPod(コンテナ)をREST APIで呼出します。OpenShiftのrouterのデフォルトのタイムアウトは30秒のため、デフォルト値ではテストデータを投入する様な長時間実行されるREST API呼出しには短すぎるためタイムアウト値を長く設定する必要があります。 

```
# oc annotate route example-health-api --overwrite haproxy.router.openshift.io/timeout=60m
  route.route.openshift.io/example-api annotated
```

変更した結果は「 oc describe route <route名> 」コマンドで確認できます。  

```console
# oc describe route example-health-api 
Name:			example-health-api
Namespace:		health
Created:		13 minutes ago
Labels:			app=example-health-api
Annotations:		haproxy.router.openshift.io/timeout=60m
			openshift.io/host.generated=true
Requested Host:		example-health-api-health.192.168.42.138.nip.io
			  exposed on router router 13 minutes ago
Path:			<none>
TLS Termination:	<none>
Insecure Policy:	<none>
Endpoint Port:		http

Service:	example-health-api
Weight:		100 (100%)
Endpoints:	172.17.0.10:9080
```

### 20. 患者の健康記録テストデータプログラムの実行

それでは実行します。generate.shのオプションは -p は人口、-u は routeで公開したホスト名です。今回は150人のデータを登録します。

```console
# ./generate.sh -p 150 -u http://example-health-api-health.192.168.42.138.nip.io
Cloning into 'synthea'...
remote: Enumerating objects: 38, done.
remote: Counting objects: 100% (38/38), done.
remote: Compressing objects: 100% (28/28), done.
remote: Total 31698 (delta 7), reused 21 (delta 2), pack-reused 31660
Receiving objects: 100% (31698/31698), 605.79 MiB | 9.81 MiB/s, done.
Resolving deltas: 100% (18183/18183), done.
Checking out files: 100% (663/663), done.

BUILD SUCCESSFUL in 30s
4 actionable tasks: 2 executed, 2 up-to-date
```

BUILD SUCCESSFULが表示された後から登録完了まで数分で終わりました。途中の状況を確認したい場合は、Open LibertyのPod(コンテナ）のログを「 oc logs -f example-health-api-<任意の英数字> 」コマンドを実行して確認してください。

### 21. 登録した患者の健康記録データの確認

患者の一覧を取得するAPI「 /resources/v1/getInfo/patients 」を使って、患者の健康記録データが登録されているか確認します。curlでURLにホスト名/resources/v1/getInfo/patientsを指定して実行すると事前に登録した件数と同じ150人分の患者のデータが取得できます。

```console

# curl -X GET "http://example-health-api-health.192.168.42.138.nip.io/resources/v1/getInfo/patients" -H "accept: */*"
{"ResultSet Output":[{"CA_DOB":"1962-10-
<<<省略>>>
09","CA_FIRST_NAME":"Sergio","CA_GENDER":"M","CA_LAST_NAME":"Castellanos"},{"CA_DOB":"1988-06-06","CA_FIRST_NAME":"Lorraine","CA_GENDER":"F","CA_LAST_NAME":"Ledner"},{"CA_DOB":"2018-01-29","CA_FIRST_NAME":"Shemika","CA_GENDER":"F","CA_LAST_NAME":"Terry"},{"CA_DOB":"1954-03-26","CA_FIRST_NAME":"Clyde","CA_GENDER":"M","CA_LAST_NAME":"Ferry"},{"CA_DOB":"1946-03-25","CA_FIRST_NAME":"Bobby","CA_GENDER":"M","CA_LAST_NAME":"Krajcik"}],"StatusCode":200,"StatusDescription":"Execution Successful"}
```

### 22. まとめ

これでExample HealthはモノリシックなJava EE アプリケーション構造からビジネスロジック部分を分割し、MiniShiftのOpenShift上で動作するOpen Libertyで実行されているビジネスロジック用のJava EE アプリケーションとして稼働させることに成功しました。実際に患者の健康管理テストデータ生成プログラム(generater.sh)を使ってREST API を使用してMySQLデータベースに患者の健康管理テストデータを取り込み、Java EE アプリケーションからそのデータにアクセスする方法も実行することができました。

ここまでのステップでモダナイゼーションの旅も一山越えた感じですが、このままでは、REST APIでしか呼応できないため、サービスとしては不十分です。次のステップからモノリシックなJava EEアプリケーションから分割したもう一つの患者用UIのNode.jsアプリケーションをOpenShiftにデプロイして、今回作成したビジネスロジック用のJava EEアプリケーションと結合したいと思います。

続きは、「 [OpenShiftによるJava EEアプリケーションのモダナイゼーションをやってみた(2)](https://qiita.com/daihiraoka/items/d27cf3b3281ddc5ce8f1)」　の投稿に続きます。