注:本文基于CentOS 7.2编写
背景
最近在阅读《Kubernetes权威指南》这本书,该书最开始的例子是搭建单机版k8s集群,然后部署一个Java应用。跟着操作的过程中,遇到不少的坑,记录一下,也算是给后面的人提个醒吧。
项目介绍
该例子就是一个简单的Java Web应用,结构简单,是一个运行在Tomcat里的Web App,JSP页面通过JDBC直接访问MySQL数据库并展示数据。因此就两个主体,一个tomcat,一个MySQL。
环境准备
1、关闭防火墙,包括设置开启不启动。
systemctl disable firewalld
systemctl stop firewalld
2、k8s及etcd安装
yum install -y etcd kubernetes
以上操作会自动安装docker。
3、关闭docker的selinux
将/etc/sysconfig/docker配置文件中OPTIONS做如下修改,
OPTIONS='--selinux-enabled=false --log-driver=journald'
4、关闭kube-apiserver服务的ServiceAccount
/etc/kubernetes/apiserver文件中,KUBE_ADMISSION_CONTROL选项去掉ServiceAccount,
KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ResourceQuota"
5、设置k8s相关服务开机启动,并启动服务
systemctl enable etcd docker kube-apiserver kube-controller-manager kube-scheduler kubelet kube-proxy
systemctl start etcd docker kube-apiserver kube-controller-manager kube-scheduler kubelet kube-proxy
至此,单机版k8s集群搭建完毕,我们可以查看下结点情况,
[root@CentOS-7-2 /home/k8s]# kubectl get node
NAME STATUS AGE
127.0.0.1 Ready 3m
部署应用
1、拉取镜像
上面说过我们有两个依赖,一个tomcat,一个MySQL,可以通过以下命令拉取这两个镜像,
docker pull mysql:5.5
docker pull kubeguide/tomcat-app
书上MySQL镜像并没有交代版本号,因此这就是天坑之一。不指定版本号,docker默认拉取的是最新的版本,目前,MySQL的最新版本是8.0.13,而作者对应tomcat使用的MySQL连接lib库是5.1.37,明显不匹配啊。。。。。这也就导致部署到最后面一直无法出现正常的表格页面。文章最后我们会详细看看这些坑最后呈现的报错。
2、创建rc及service
首先是MySQL的RC定义文件,
apiVersion: v1
kind: ReplicationController
metadata:
name: mysql
spec:
replicas: 1
selector:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.5
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
除了images改成mysql:5.5外,其他和书本一致。对应的服务文件如下,
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
selector:
app: mysql
然后使用kubectl create命令创建资源,
[root@CentOS-7-2 /home/k8s]# ls
. .. mysql-rc.yaml mysql-service.yaml
[root@CentOS-7-2 /home/k8s]# kubectl create -f mysql-rc.yaml
replicationcontroller "mysql" created
[root@CentOS-7-2 /home/k8s]# kubectl create -f mysql-service.yaml
service "mysql" created
[root@CentOS-7-2 /home/k8s]# kubectl get rc
NAME DESIRED CURRENT READY AGE
mysql 1 1 0 33s
[root@CentOS-7-2 /home/k8s]# kubectl get pod
NAME READY STATUS RESTARTS AGE
mysql-dmmht 1/1 Running 0 39s
[root@CentOS-7-2 /home/k8s]# kubectl get service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.254.0.1 <none> 443/TCP 3d
mysql 10.254.34.195 <none> 3306/TCP 33s
如果出现创建rc成功,但是get pod却返回无该资源或者状态一直为ContainerCreating的,可以参考以下链接,尝试解决。
kubernetes新建rc成功却没创建pod
kubectl get pods一直显示ContainerCreating
MySQL相关资源创建完毕,接下来就是tomcat了,其RC定义文件如下,
apiVersion: v1
kind: ReplicationController
metadata:
name: myweb
spec:
replicas: 1
selector:
app: myweb
template:
metadata:
labels:
app: myweb
spec:
containers:
- name: myweb
image: kubeguide/tomcat-app:v1
ports:
- containerPort: 8080
env:
- name: MYSQL_SERVICE_PORT
value: '3306'
这里是天坑之二,原书作者在env里指定了MYSQL_SERVICE_HOST属性为mysql,但是最后就是因为这里出错一直连接不上数据库,报的是无法解析mysql这个hostname。文章最后也会详细讲述一下这个错误。接着是对应的service文件,
apiVersion: v1
kind: Service
metadata:
name: myweb
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30002
selector:
app: myweb
同样,使用kubectl create命令创建资源,
[root@CentOS-7-2 /home/k8s]# ls
. .. mysql-rc.yaml mysql-service.yaml myweb-rc.yaml myweb-service.yaml
[root@CentOS-7-2 /home/k8s]# kubectl create -f myweb-rc.yaml
replicationcontroller "myweb" created
[root@CentOS-7-2 /home/k8s]# kubectl create -f myweb-service.yaml
service "myweb" created
[root@CentOS-7-2 /home/k8s]# kubectl get rc
NAME DESIRED CURRENT READY AGE
mysql 1 1 1 15m
myweb 1 1 1 11s
[root@CentOS-7-2 /home/k8s]# kubectl get pod
NAME READY STATUS RESTARTS AGE
mysql-dmmht 1/1 Running 0 15m
myweb-z99xn 1/1 Running 0 16s
[root@CentOS-7-2 /home/k8s]# kubectl get service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.254.0.1 <none> 443/TCP 3d
mysql 10.254.34.195 <none> 3306/TCP 15m
myweb 10.254.115.49 <nodes> 8080:30002/TCP 15s
一切正常的情况下,我们就能如书上所说通过浏览器查看到demo的表格网页了。需要注意的是我们通过浏览器访问,用的是虚拟机的ip,和上面kubectl get service没关系,
往数据库里添加信息也是正常的,
各种报错
上面我们说到有两处坑,下面我们来看下这些坑呈现的错误是怎样的。
1、完全按照书本配置进行操作
这种情况,也就是使用最新的MySQL镜像,同时也配置了MYSQL_SERVICE_HOST属性。
此时在你使用浏览器访问的时候呈现的是Error:com.mysql.jdbc.exceptions.jdbc4.CommunicationsException错误。
通过kubectl logs命令查看对应tomcat pod的日志,
[root@CentOS-7-2 /home/k8s]# kubectl logs -f myweb-xr12x
......
Connecting to database...
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
......
Caused by: java.net.UnknownHostException: mysql: Name or service not known
at java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method)
at java.net.InetAddress$1.lookupAllHostAddr(InetAddress.java:922)
at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1316)
at java.net.InetAddress.getAllByName0(InetAddress.java:1269)
at java.net.InetAddress.getAllByName(InetAddress.java:1185)
at java.net.InetAddress.getAllByName(InetAddress.java:1119)
at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:191)
at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:298)
... 41 more
Goodbye!
可见,这里tomcat的java应用无法解析mysql这个hostname,因此我们删除MYSQL_SERVICE_HOST属性再来看下。
(注:我不知道怎么通过正确的配置来使得tomcat pod能正常解析mysql这个主机名,同样,删除这个配置后java应用又是怎么连接到数据库的,也不知道。这需要查看具体的java代码,目前暂无这个能力。希望有知道的读者能告知其中逻辑,感激不尽。)
2、使用最新MySQL镜像,不配置MYSQL_SERVICE_HOST属性
此时浏览器报错Error:com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException,如下,
通过kubectl logs命令查看报错如下,
[root@CentOS-7-2 /home/k8s]# kubectl logs -f myweb-d70jq
......
Connecting to database...
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server.
......
Caused by: java.lang.NullPointerException
at com.mysql.jdbc.ConnectionImpl.getServerCharset(ConnectionImpl.java:3004)
at com.mysql.jdbc.MysqlIO.sendConnectionAttributes(MysqlIO.java:1908)
at com.mysql.jdbc.MysqlIO.proceedHandshakeWithPluggableAuthentication(MysqlIO.java:1837)
at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1207)
at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2254)
Goodbye!
at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2285)
... 39 more
可见,此时出现空指针异常了,这就是由于JDBC的驱动不匹配导致的,也就是MySQL的版本不匹配。我们可以查看tomcat镜像里Java应用使用的MySQL库版本,
[root@CentOS-7-2 /home/k8s]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d92cf45e4498 kubeguide/tomcat-app:v1 "catalina.sh run" 6 minutes ago Up 6 minutes k8s_myweb.35b7208f_myweb-d70jq_default_9a50c71f-1df4-11e9-a6f1-000c292e7489_c9b5b331
426cc40053e8 registry.access.redhat.com/rhel7/pod-infrastructure:latest "/usr/bin/pod" 6 minutes ago Up 6 minutes k8s_POD.24f70ba9_myweb-d70jq_default_9a50c71f-1df4-11e9-a6f1-000c292e7489_882ce6ef
59b9133cab18 mysql "docker-entrypoint.sh" 26 minutes ago Up 26 minutes k8s_mysql.f6601b53_mysql-wgpg6_default_75573acd-1df1-11e9-a6f1-000c292e7489_bd53f046
bf54851bded5 registry.access.redhat.com/rhel7/pod-infrastructure:latest "/usr/bin/pod" 28 minutes ago Up 28 minutes k8s_POD.1d520ba5_mysql-wgpg6_default_75573acd-1df1-11e9-a6f1-000c292e7489_17a0bb95
[root@CentOS-7-2 /home/k8s]# docker exec -ti d92cf45e4498 /bin/bash
root@myweb-d70jq:/usr/local/tomcat# ls
LICENSE NOTICE RELEASE-NOTES RUNNING.txt bin conf include lib logs temp webapps work
root@myweb-d70jq:/usr/local/tomcat# cd webapps/demo/WEB-INF/lib/
root@myweb-d70jq:/usr/local/tomcat/webapps/demo/WEB-INF/lib# ls
mysql-connector-java-5.1.37.jar
可见,mysql-connector-java-5.1.37.jar版本和最新版本MySQL(8.0.13)不匹配。将MySQL换成5.5版本后,一切正常。