Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

ICPにMySQLに接続するLibertyアプリケーションをデプロイ

More than 1 year has passed since last update.

お勉強のため、MySQLコンテナにアクセスするWebアプリケーション(WebSphere Liberty)コンテナを作成し、IBM Cloud Private CEにデプロイしてみたメモ。

IBM Cloud Private CEのインストールは以下の記事を参照。Kubernetes環境であればIKS(IBM Cloud Kubernetes Service)でもMinikubeでもDocker for Macでも何でもよいはず。

AWSにIBM Cloud Private-CE 2.1.0.3をインストールする

AWSにIBM Cloud Private-CE 3.1をインストールする

ClusterImagePolicyの作成

ICP 3.1ではデフォルトではイメージをPullできるレジストリーが制限されているため、DockerHubからのイメージのPullを許可する。ICP 2.1.0.3では不要。

コンテナー・イメージ・セキュリティーの適用

allow-dockerhub-image-policy.yaml
apiVersion: securityenforcement.admission.cloud.ibm.com/v1beta1
kind: ClusterImagePolicy
metadata:
  name: allow-dockerhub-image-policy
spec:
  repositories:
  # Docker hub Container Registry
  - name: "docker.io/*"
    policy:

Namespaceの作成

今回のアプリケーションはsugiというNamespaceに作成することにする。そのNamespaceを作成する。

kubectl create ns sugi

(オプション)
kubectlが操作するデフォルトのNamespaceを作成したNamespaceに変えておく。

ubuntu@icp31-single:~$ kubectl config current-context
mycluster-context
ubuntu@icp31-single:~$ kubectl config set-context mycluster-context --namespace=sugi
Context "mycluster-context" modified.
ubuntu@icp31-single:~$

MySQLコンテナのデプロイ

以下を参考にする。

Run a Single-Instance Stateful Application

PV/PVCの作成

今回は簡単に試すためPVとしてはhostPathで使用するので、ディレクトリーを用意する。NFSが利用できればその方が望ましい。

root@icp31-single:~# mkdir -p /data/mysql
root@icp31-single:~# ls -l /data
total 4
drwxr-xr-x 2 root root 4096 Oct 23 10:45 mysql
root@icp31-single:~#

MySQLから使用するPesistentVolumeを作成する。

mysql-pv.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
  name: mysql-pv
spec:
  storageClassName: mysql
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/data/mysql"
kubectl apply -f mysql-pv.yaml

PesistentVolumeClaimを作成する。なお、PVは全てのNamespaceで共通のリソースであるが、PVCはNamespace毎に作成するリソースである。

mysql-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  storageClassName: mysql
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
kubectl apply -f mysql-pvc.yaml -n sugi

PVCがBoundになったことを確認しておく。

ubuntu@icp31-single:~$ kubectl get pvc -n sugi
NAME        STATUS    VOLUME     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mysql-pvc   Bound     mysql-pv   10Gi       RWO            mysql          1m
ubuntu@icp31-single:~$

Secretの作成

MySQLのコンテナはrootパスワードを環境変数として渡す必要があるので、パスワードを保管するSecretを作成する。

パスワードをBase64でエンコードする。

ubuntu@icp31-single:~$ echo -n "password" | base64
cGFzc3dvcmQ=
ubuntu@icp31-single:~$

Secretを作成する。

mysql-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  root-password: cGFzc3dvcmQ=
kubectl apply -f mysql-secret.yaml -n sugi

Deploymentの作成

MySQLのデプロイメントを作成する。先ほど作成したSecretから環境変数を定義している。

mysql-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql:5.7
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: root-password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pvc
kubectl apply -f mysql-deployment.yaml -n sugi

Podが稼働したことを確認する。

ubuntu@icp31-single:~$ kubectl get po -n sugi
NAME                     READY     STATUS    RESTARTS   AGE
mysql-7c47657796-b7x48   1/1       Running   0          41s
ubuntu@icp31-single:~$

Serviceの作成

MySQLのServiceを作成する。アプリケーションはこのServiceに接続する。

mysql-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
  - port: 3306
  selector:
    app: mysql
kubectl apply -f mysql-service.yaml -n sugi

MySQLコンテナの初期化

MySQLコンテナにユーザーを作成し、テーブルを作成し、初期データをロードする。
本来はJobで実行するのが望ましいかもしれない。ここではkubectl execで実施する。

(追記)
Jobでやる場合は以下の記事を参照。
Kubernetes JobでMySQLへデータをロードする

(補足)
環境変数MYSQL_DATABASEや、MYSQL_USERMYSQL_PASSWORDにより、コンテナの初回起動時にデータベースを1つ作成したり、ユーザーをひとり作ることも可能。また、/docker-entrypoint-initdb.d/ディレクトリーにスクリプトを配置して、コンテナの初回起動時に初期化処理を行う事も可能。

2.5.8.2 More Topics on Deploying MySQL Server with Docker

MySQLのPodを確認する。

kubectl get po -n sugi

Podにログインする。

kubectl exec -it -n sugi <Pod名> bash

mysqlクライアントを実行する。パスワードは環境変数から取得。

mysql -uroot -p${MYSQL_ROOT_PASSWORD}

mydbデータベースを作成する。

create database mydb;

libertyユーザーを作成する。

create user 'liberty' identified by 'liberty';

libertyユーザーにmydbへの全権限を付与する。

grant all privileges on mydb.* to 'liberty';

一度抜けてlibertyユーザーで入り直す。パスワードはliberty

quit;
mysql -u liberty -p

mydbにmemberテーブルを作成する。

use mydb;
DROP TABLE IF EXISTS member;
CREATE TABLE `member` (
  id int NOT NULL AUTO_INCREMENT,
  name varchar(255) NOT NULL,
  created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
);

テストデータを挿入する。

INSERT INTO member (name) VALUES ('user1'),('user2'),('user3');
INSERT INTO member (name) VALUES ('user4'),('user5'),('user6');

データを確認。

SELECT * from member;

(実行例)

mysql> SELECT * from member;
+----+-------+---------------------+---------------------+
| id | name  | created             | updated             |
+----+-------+---------------------+---------------------+
|  1 | user1 | 2018-10-23 11:18:48 | 2018-10-23 11:18:48 |
|  2 | user2 | 2018-10-23 11:18:48 | 2018-10-23 11:18:48 |
|  3 | user3 | 2018-10-23 11:18:48 | 2018-10-23 11:18:48 |
|  4 | user4 | 2018-10-23 11:18:48 | 2018-10-23 11:18:48 |
|  5 | user5 | 2018-10-23 11:18:48 | 2018-10-23 11:18:48 |
|  6 | user6 | 2018-10-23 11:18:48 | 2018-10-23 11:18:48 |
+----+-------+---------------------+---------------------+
6 rows in set (0.00 sec)

mysql>

終了する。

quit;
exit

Libertyコンテナのデプロイ

MySQLに接続して取得したデータを表示するアプリケーションを乗せたLibertyコンテナを作成する。

アプリケーションの作成

簡単なWebアプリケーションを作成する。以下のコマンドでWarファイルを抽出して先に進んでもよい。

docker run --rm -v $(pwd):/data sotoiwa540/hellomysql:1.0 cp /config/dropins/hellomysql.war /data/

アプリケーションの作成は本筋から外れるため、ここでは要点のみ記載。

Eclipseで「Dynamic Web Project」を作成し、以下のServletを作成する。

HelloServlet.java
package com.example;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

/**
 * Servlet implementation class HelloServlet
 */
@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * Default constructor.
     */
    public HelloServlet() {
        // TODO Auto-generated method stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html; charset=SJIS");
        PrintWriter writer = response.getWriter();

        DataSource dataSource = null;
        Connection conn = null;

        try {
            Context context = new InitialContext();
            dataSource = (DataSource) context.lookup("jdbc/mydb");
        } catch (NamingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            throw new ServletException(e);
        }

        try {
            conn = dataSource.getConnection();

            PreparedStatement statement = conn.prepareStatement("select name from member");
            ResultSet result = statement.executeQuery();
            while (result.next()) {
                writer.println(result.getString(1));
                System.out.println(result.getString(1));
            }

        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
            }
        }

        writer.append("Served at: ").append(request.getContextPath());
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

MySQLのJDBCドライバーのjarファイルをダウンロードして、Libertyの${server.config.dir}/resources/mysqlディレクトリーに配置する。

https://dev.mysql.com/downloads/connector/j/

Libertyのserver.xmlは以下のようになる。MySQLへの接続情報は環境変数で渡すようにする。ローカルで稼働確認する際はserver.envを使って環境変数を渡すとよい。

server.xml
<server description="new server">
  <!-- Enable features -->
  <featureManager>
    <feature>webProfile-7.0</feature>
    <feature>localConnector-1.0</feature>
  </featureManager>
  <!-- To access this server from a remote client add a host attribute to 
        the following element, e.g. host="*" -->
  <httpEndpoint host="*" httpPort="9080" httpsPort="9443" id="defaultHttpEndpoint" />
  <library id="MySQLLib">
    <fileset dir="${server.config.dir}/resources/mysql" includes="*.jar" />
  </library>
  <dataSource jndiName="jdbc/mydb" transactional="false">
    <jdbcDriver libraryRef="MySQLLib" />
    <properties databaseName="mydb" serverName="${env.MYSQL_SERVERNAME}" portNumber="${env.MYSQL_PORTNUMBER}" user="${env.MYSQL_USER}" password="${env.MYSQL_PASSWORD}" />
  </dataSource>
  <!-- Automatically expand WAR files and EAR files -->
  <applicationManager autoExpand="true" />
  <applicationMonitor updateTrigger="mbean" />
</server>

ローカルで稼働確認する場合、以下のコマンドでDockerでMySQLを起動することができる。

docker run --name mysql -e MYSQL_ROOT_PASSWORD=password -d -p 3306:3306 mysql:5.7

起動後は以下のコマンドでコンテナの中に入り、先ほどと同様にユーザーやデータを作る。

docker exec -it mysql bash

Libertyイメージのビルド

Dockerfileを作成する。

Dockerfile
FROM websphere-liberty:webProfile7
COPY server.xml /config/
RUN installUtility install --acceptLicense defaultServer
COPY mysql-connector-java-8.0.13.jar /config/resources/mysql/
COPY hellomysql.war /config/dropins/

同じディレクトリーに必要なファイルを配置する。

$ tree .
.
├── Dockerfile
├── hellomysql.war
├── mysql-connector-java-8.0.13.jar
└── server.xml

0 directories, 4 files
$

このディレクトリーでDockerビルドを実行し、DockerHubにPushする。

docker build -t sotoiwa540/hellomysql:1.0 .
docker push sotoiwa540/hellomysql:1.0

Secretの作成

MySQLに接続するユーザーのパスワードを格納するためのSecretを作成する。

パスワードをBase64でエンコードする。

$ echo -n "liberty" | base64
bGliZXJ0eQ==

Secretを作成する。

liberty-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: liberty-secret
type: Opaque
data:
  liberty-password: bGliZXJ0eQ==
kubectl apply -f liberty-secret.yaml -n sugi

ConfigMapの作成

パスワード以外のMySQLへの接続情報を格納したConfigMapを作成する。

liberty-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: liberty-config
data:
  mysql-servername: "mysql"
  mysql-portnumber: "3306"
  mysql-user: "liberty"
kubectl apply -f liberty-config.yaml -n sugi

Libertyコンテナのデプロイ

Libertyコンテナをデプロイする。

liberty-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: liberty
spec:
  selector:
    matchLabels:
      app: liberty
  replicas: 1
  template:
    metadata:
      labels:
        app: liberty
    spec:
      containers:
      - name: liberty
        image: sotoiwa540/hellomysql:1.0
        imagePullPolicy: Always
        ports:
        - containerPort: 9080
        env:
        - name: MYSQL_SERVERNAME
          valueFrom:
            configMapKeyRef:
              name: liberty-config
              key: mysql-servername
        - name: MYSQL_PORTNUMBER
          valueFrom:
            configMapKeyRef:
              name: liberty-config
              key: mysql-portnumber
        - name: MYSQL_USER
          valueFrom:
            configMapKeyRef:
              name: liberty-config
              key: mysql-user
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: liberty-secret
              key: liberty-password
kubectl apply -f liberty-deployment.yaml -n sugi

Podが稼働したことを確認する。

ubuntu@icp31-single:~/hellomysql$ kubectl get po -n sugi
NAME                       READY     STATUS      RESTARTS   AGE
liberty-74fd798747-pwghp   1/1       Running     0          11s
mysql-7c47657796-bkc67     1/1       Running     0          4m
ubuntu@icp31-single:~/hellomysql$

Serviceの作成

Serviceを作成する。

liberty-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: liberty
spec:
  type: ClusterIP
  selector:
    app: liberty
  ports:
  - protocol: TCP
    port: 9080
kubectl apply -f liberty-service.yaml -n sugi

Ingressの作成

Ingressを作成する。
Minikubeの場合はアノテーションがnginx.ingress.kubernetes.io/rewrite-target:となるかもしれない。

liberty-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: liberty
  annotations:
    ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host:
    http:
      paths:
      - path: /liberty
        backend:
          serviceName: liberty
          servicePort: 9080
kubectl apply -f liberty-ingress.yaml -n sugi

稼働確認

ブラウザで以下のURLにアクセスし、アプリケーションがMySQL内のデータを取得して表示することを確認する。

https://<ICPのProxyのVIP>/liberty/hellomysql/HelloServlet

image.png

ログを確認する。

ubuntu@icp31-single:~/hellomysql$ kubectl logs liberty-74fd798747-pwghp -n sugi
Launching defaultServer (WebSphere Application Server 18.0.0.3/wlp-1.0.22.cl180320180905-2337) on IBM J9 VM, version 8.0.5.22 - pxa6480sr5fp22-20180919_01(SR5 FP22) (en_US)
[AUDIT   ] CWWKE0001I: The server defaultServer has been launched.
[AUDIT   ] CWWKE0100I: This product is licensed for development, and limited production use. The full license terms can be viewed here: https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/wasdev/license/base_ilan/ilan/18.0.0.3/lafiles/en.html
[AUDIT   ] CWWKG0093A: Processing configuration drop-ins resource: /opt/ibm/wlp/usr/servers/defaultServer/configDropins/defaults/keystore.xml
[AUDIT   ] CWWKZ0058I: Monitoring dropins for applications.
[AUDIT   ] CWWKS4104A: LTPA keys created in 3.087 seconds. LTPA key file: /opt/ibm/wlp/output/defaultServer/resources/security/ltpa.keys
[AUDIT   ] CWPKI0803A: SSL certificate created in 7.370 seconds. SSL key file: /opt/ibm/wlp/output/defaultServer/resources/security/key.jks
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://liberty-74fd798747-pwghp:9080/hellomysql/
[AUDIT   ] CWWKZ0001I: Application hellomysql started in 0.994 seconds.
[AUDIT   ] CWWKF0012I: The server installed the following features: [localConnector-1.0].
[AUDIT   ] CWWKF0011I: The server defaultServer is ready to run a smarter planet.
user1
user2
user3
user4
user5
user6
ubuntu@icp31-single:~/hellomysql$
sotoiwa
私の投稿する内容は個人の見解であり、所属団体を代表するものではありません。
aws-professional-services
AWSプロフェッショナルサービスは、お客様がクラウドのイノベーティブな活用によりビジネス価値を生み出すことを支援し、加速させるための有償のコンサルティングチームです。Twitterで情報発信しています。https://twitter.com/awscloud_jp
https://aws.amazon.com/jp/careers/teams/professionalservices/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away