MySQL as Kubernetes Service, Access from WildFly Pod
Java EE 7 and WildFly on Kubernetes using Vagrant (Tech Tip #71) explained how to run a trivial Java EE 7 application on WildFly hosted using Kubernetes and Docker. The Java EE 7 application was the hands-on lab that have been delivered around the world. It uses an in-memory database that is bundled with WildFly and allows to understand the key building blocks of Kubernetes. This is good to get you started with initial development efforts but quickly becomes a bottleneck as the database is lost when the application server goes down. This tech tip will show how to run another trivial Java EE 7 application and use MySQL as the database server. It will use Kubernetes Services to explain how MySQL and WildFly can be easily decoupled.
Lets get started!
Make sure to have a working Kubernetes setup as explained in Kubernetes using Vagrant.
The complete source code used in this blog is available at github.com/arun-gupta/kubernetes-java-sample.
Start MySQL Kubernetes pod
First step is to start the MySQL pod. This can be started by using the MySQL Kubernetes configuration file:
kubernetes> ./cluster/kubectl.sh create -f ../kubernetes-java-sample/mysql.json KUBE_MASTER_IP: 10.245.1.2 Running: ./cluster/../cluster/vagrant/../../_output/dockerized/bin/darwin/amd64/kubectl --auth-path=/Users/arungupta/.kubernetes_vagrant_auth create -f ../kubernetes-java-sample/mysql.json mysql
The configuration file used is at github.com/arun-gupta/kubernetes-java-sample/blob/master/mysql.json.
Check the status of MySQL pod:
kubernetes> ./cluster/kubectl.sh get pods KUBE_MASTER_IP: 10.245.1.2 Running: ./cluster/../cluster/vagrant/../../_output/dockerized/bin/darwin/amd64/kubectl --auth-path=/Users/arungupta/.kubernetes_vagrant_auth get pods POD IP CONTAINER(S) IMAGE(S) HOST LABELS STATUS mysql 10.246.1.3 mysql mysql:latest 10.245.1.3/10.245.1.3 name=mysql Pending
Wait till the status changes to “Running”. It will look like:
KUBE_MASTER_IP: 10.245.1.2 Running: ./cluster/../cluster/vagrant/../../_output/dockerized/bin/darwin/amd64/kubectl --auth-path=/Users/arungupta/.kubernetes_vagrant_auth get pods POD IP CONTAINER(S) IMAGE(S) HOST LABELS STATUS mysql 10.246.1.3 mysql mysql:latest 10.245.1.3/10.245.1.3 name=mysql Running
It takes a few minutes for MySQL server to be in that state, so grab a coffee or a quick fast one miler!
Start MySQL Kubernetes service
Pods, and the IP addresses assigned to them, are ephemeral. If a pod dies then Kubernetes will recreate that pod because of its self-healing features, but it might recreate it on a different host. Even if it is on the same host, a different IP address could be assigned to it. And so any application cannot rely upon the IP address of the pod.
Kubernetes services is an abstraction which defines a logical set of pods. A service is typically back-ended by one or more physical pods (associated using labels), and it has a permanent IP address that can be used by other pods/applications. For example, WildFly pod can not directly connect to a MySQL pod but can connect to MySQL service. In essence, Kubernetes service offers clients an IP and port pair which, when accessed, redirects to the appropriate backends.
Lets start MySQL service.
kubernetes> ./cluster/kubectl.sh create -f ../kubernetes-java-sample/mysql-service.json KUBE_MASTER_IP: 10.245.1.2 Running: ./cluster/../cluster/vagrant/../../_output/dockerized/bin/darwin/amd64/kubectl --auth-path=/Users/arungupta/.kubernetes_vagrant_auth create -f ../kubernetes-java-sample/mysql-service.json mysql
The configuration file used is at github.com/arun-gupta/kubernetes-java-sample/blob/master/mysql-service.json. In this case, only a single MySQL instance is started. But multiple MySQL instances can be easily started and WildFly Pod will continue to refer to all of them using MySQL Service.
Check the status/IP of the MySQL service:
kubernetes> ./cluster/kubectl.sh get services KUBE_MASTER_IP: 10.245.1.2 Running: ./cluster/../cluster/vagrant/../../_output/dockerized/bin/darwin/amd64/kubectl --auth-path=/Users/arungupta/.kubernetes_vagrant_auth get services NAME LABELS SELECTOR IP PORT kubernetes component=apiserver,provider=kubernetes <none> 10.247.0.2 443 kubernetes-ro component=apiserver,provider=kubernetes <none> 10.247.0.1 80 mysql name=mysql name=mysql 10.247.202.104 3306 skydns k8s-app=skydns k8s-app=skydns 10.247.0.10 53
Start WildFly Kubernetes Pod
WildFly Pod must be started after MySQL service has started. This is because the environment variables used for creating JDBC resource in WildFly are only available after the service is up and running. Specifically, the JDBC resource is created as:
data-source add --name=mysqlDS --driver-name=mysql --jndi-name=java:jboss/datasources/ExampleMySQLDS --connection-url=jdbc:mysql://$MYSQL_SERVICE_HOST:$MYSQL_SERVICE_PORT/sample?useUnicode=true&characterEncoding=UTF-8 --user-name=mysql --password=mysql --use-ccm=false --max-pool-size=25 --blocking-timeout-wait-millis=5000 --enabled=true
$MYSQL_SERVICE_HOST
and $MYSQL_SERVICE_PORT
environment variables are populated by Kubernetes as explained here.
This is shown at github.com/arun-gupta/docker-images/blob/master/wildfly-mysql-javaee7/customization/execute.sh#L44.
Start WildFly pod:
kubernetes> ./cluster/kubectl.sh create -f ../kubernetes-java-sample/wildfly.json KUBE_MASTER_IP: 10.245.1.2 Running: ./cluster/../cluster/vagrant/../../_output/dockerized/bin/darwin/amd64/kubectl --auth-path=/Users/arungupta/.kubernetes_vagrant_auth create -f ../kubernetes-java-sample/wildfly.json wildfly
The configuration file used is at github.com/arun-gupta/kubernetes-java-sample/blob/master/wildfly.json.
Check the status of pods:
KUBE_MASTER_IP: 10.245.1.2 Running: ./cluster/../cluster/vagrant/../../_output/dockerized/bin/darwin/amd64/kubectl --auth-path=/Users/arungupta/.kubernetes_vagrant_auth get pods POD IP CONTAINER(S) IMAGE(S) HOST LABELS STATUS mysql 10.246.1.3 mysql mysql:latest 10.245.1.3/10.245.1.3 name=mysql Running wildfly 10.246.1.4 wildfly arungupta/wildfly-mysql-javaee7:knetes 10.245.1.3/10.245.1.3 name=wildfly Pending
Wait until WildFly pod’s status is changed to Running. This could be a few minutes, so may be time to grab another quick miler!
Once the container is up and running, you can check /opt/jboss/wildfly/standalone/configuration/standalone.xml in the WildFly container and verify that the connection URL indeed contains the correct IP address. Here is how it looks on my machine:
[jboss@wildfly ~]$ grep 3306 /opt/jboss/wildfly/standalone/configuration/standalone.xml <connection-url>jdbc:mysql://10.247.202.104:3306/sample?useUnicode=true&characterEncoding=UTF-8</connection-url>
The updated status (after the container is running) would look like as shown:
kubernetes> ./cluster/kubectl.sh get pods KUBE_MASTER_IP: 10.245.1.2 Running: ./cluster/../cluster/vagrant/../../_output/dockerized/bin/darwin/amd64/kubectl --auth-path=/Users/arungupta/.kubernetes_vagrant_auth get pods POD IP CONTAINER(S) IMAGE(S) HOST LABELS STATUS mysql 10.246.1.3 mysql mysql:latest 10.245.1.3/10.245.1.3 name=mysql Running wildfly 10.246.1.4 wildfly arungupta/wildfly-mysql-javaee7:knetes 10.245.1.3/10.245.1.3 name=wildfly Running
Access the Java EE 7 Application
Note down the HOST IP address of the WildFly container and access the application as:
curl http://10.245.1.3:8080/employees/resources/employees
to see the output as:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><collection><employee><id>1</id><name>Penny</name></employee><employee><id>2</id><name>Sheldon</name></employee><employee><id>3</id><name>Amy</name></employee><employee><id>4</id><name>Leonard</name></employee><employee><id>5</id><name>Bernadette</name></employee><employee><id>6</id><name>Raj</name></employee><employee><id>7</id><name>Howard</name></employee><employee><id>8</id><name>Priya</name></employee></collection>
Or viewed in the browser as:
Debugging Kubernetes and Docker
Login to the Minion-1 VM:
kubernetes> vagrant ssh minion-1 Last login: Tue Feb 10 23:20:13 2015 from 10.0.2.2
Log in as root:
[vagrant@kubernetes-minion-1 ~]$ su - Password: [root@kubernetes-minion-1 ~]#
Default root password for VM images created by Vagrant is “vagrant”.
List of Docker containers running on this VM can be seen as:
[root@kubernetes-minion-1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7fc1fca102bf arungupta/wildfly-mysql-javaee7:knetes "/opt/jboss/wildfly/ 28 minutes ago Up 28 minutes k8s_wildfly.6c5f240e_wildfly.default.api_1230e74a-b178-11e4-8464-0800279696e1_509268aa 4aa49c0ebb70 kubernetes/pause:go "/pause" 43 minutes ago Up 43 minutes 0.0.0.0:8080->8080/tcp, 0.0.0.0:9090->9090/tcp k8s_POD.bca60d1a_wildfly.default.api_1230e74a-b178-11e4-8464-0800279696e1_0bff6efa c36e99cd4557 mysql:latest "/entrypoint.sh mysq 47 minutes ago Up 47 minutes k8s_mysql.278e3c40_mysql.default.api_f3d07101-b175-11e4-8464-0800279696e1_ddbcaf62 ed4611b5c276 google/cadvisor:0.8.0 "/usr/bin/cadvisor" 56 minutes ago Up 56 minutes k8s_cadvisor.8d424740_cadvisor-agent.file-6bb810db-kubernetes-minion-1.file_80331227d28e618b4cef459507a31796_36d83f7d 50a3428612f0 kubernetes/pause:go "/pause" 58 minutes ago Up 58 minutes 0.0.0.0:3306->3306/tcp k8s_POD.c783ea16_mysql.default.api_f3d07101-b175-11e4-8464-0800279696e1_e46a8424 11a95eeda794 kubernetes/pause:go "/pause" 59 minutes ago Up 59 minutes 0.0.0.0:4194->8080/tcp k8s_POD.252debe0_cadvisor-agent.file-6bb810db-kubernetes-minion-1.file_80331227d28e618b4cef459507a31796_734d54eb
Last 10 lines of the WildFly log (after application has been accessed a few times) can be seen as:
23:12:25,004 INFO [stdout] (ServerService Thread Pool -- 50) Hibernate: INSERT INTO EMPLOYEE_SCHEMA(ID, NAME) VALUES (8, 'Priya') 23:12:27,928 INFO [org.jboss.resteasy.spi.ResteasyDeployment] (MSC service thread 1-5) Deploying javax.ws.rs.core.Application: class org.javaee7.samples.employees.MyApplication 23:12:27,987 INFO [org.wildfly.extension.undertow] (MSC service thread 1-5) JBAS017534: Registered web context: /employees 23:12:28,073 INFO [org.jboss.as.server] (ServerService Thread Pool -- 28) JBAS018559: Deployed "employees.war" (runtime-name : "employees.war") 23:12:28,203 INFO [org.jboss.as] (Controller Boot Thread) JBAS015961: Http management interface listening on http://127.0.0.1:9990/management 23:12:28,203 INFO [org.jboss.as] (Controller Boot Thread) JBAS015951: Admin console listening on http://127.0.0.1:9990 23:12:28,204 INFO [org.jboss.as] (Controller Boot Thread) JBAS015874: WildFly 8.2.0.Final "Tweek" started in 26772ms - Started 280 of 334 services (92 services are lazy, passive or on-demand) 23:23:16,091 INFO [stdout] (default task-16) Hibernate: select employee0_.id as id1_0_, employee0_.name as name2_0_ from EMPLOYEE_SCHEMA employee0_ 23:24:07,322 INFO [stdout] (default task-17) Hibernate: select employee0_.id as id1_0_, employee0_.name as name2_0_ from EMPLOYEE_SCHEMA employee0_ 23:35:07,030 INFO [stdout] (default task-18) Hibernate: select employee0_.id as id1_0_, employee0_.name as name2_0_ from EMPLOYEE_SCHEMA employee0_
Similarly, MySQL log is seen as:
2015-02-10 22:52:55 1 [Note] Server hostname (bind-address): '*'; port: 3306 2015-02-10 22:52:55 1 [Note] IPv6 is available. 2015-02-10 22:52:55 1 [Note] - '::' resolves to '::'; 2015-02-10 22:52:55 1 [Note] Server socket created on IP: '::'. 2015-02-10 22:52:56 1 [Note] Event Scheduler: Loaded 0 events 2015-02-10 22:52:56 1 [Note] Execution of init_file '/tmp/mysql-first-time.sql' started. 2015-02-10 22:52:56 1 [Note] Execution of init_file '/tmp/mysql-first-time.sql' ended. 2015-02-10 22:52:56 1 [Note] mysqld: ready for connections. Version: '5.6.23' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL) 2015-02-10 23:12:21 1 [Warning] IP address '10.246.1.1' could not be resolved: Name or service not known
Enjoy!
Reference: | MySQL as Kubernetes Service, Access from WildFly Pod from our JCG partner Arun Gupta at the Miles to go 2.0 … blog. |