お勉強のため、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では不要。
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を作成する。
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毎に作成するリソースである。
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を作成する。
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から環境変数を定義している。
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に接続する。
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_USER
とMYSQL_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を作成する。
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
ディレクトリーに配置する。
Libertyのserver.xml
は以下のようになる。MySQLへの接続情報は環境変数で渡すようにする。ローカルで稼働確認する際はserver.env
を使って環境変数を渡すとよい。
<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を作成する。
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を作成する。
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を作成する。
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コンテナをデプロイする。
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を作成する。
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:
となるかもしれない。
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
ログを確認する。
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$