摘要
本文是《Kubernetes權(quán)威指南:從Docker到Kubernetes實(shí)踐全接觸》的實(shí)踐篇,把該書的第一個(gè)案例在環(huán)境上完整跑起來,補(bǔ)充一些比較的信息,便于學(xué)習(xí)者參考浪讳。
實(shí)踐內(nèi)容
本示例是一個(gè)運(yùn)行在Tomcat里的Web App,如圖1.1所示涌萤,JSP頁(yè)面通過JDBC直接訪問MySQL數(shù)據(jù)庫(kù)并展示數(shù)據(jù)淹遵。出于演示和簡(jiǎn)化的目的口猜,只要程序正確連接到了數(shù)據(jù)庫(kù),就會(huì)自動(dòng)完成對(duì)應(yīng)的Table的創(chuàng)建與初始化數(shù)據(jù)的準(zhǔn)備工作透揣。所以济炎,當(dāng)我們通過瀏覽器訪問此應(yīng)用時(shí),就會(huì)顯示一個(gè)表格的頁(yè)面淌实,數(shù)據(jù)則來自數(shù)據(jù)庫(kù)冻辩。
2.1.2.1.1 MySQL容器
(1)下載docker鏡像
# 本案例有一個(gè)大坑,kubeguide/mysql-master:latest對(duì)應(yīng)的是mysql8.0的版本拆祈,跟java無法匹配恨闪。
# 需要采用5.7的版本。
#docker pull kubeguide/mysql-master:latest
$ docker pull mysql:5.7
(2)創(chuàng)建編輯RC資源文件
mysql-rc.yaml:
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.7
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
以上YAML定義文件中的kind屬性用來表明此資源對(duì)象的類型放坏,比如這里的值為ReplicationController咙咽,表示這是一個(gè)RC;
在spec一節(jié)中是RC的相關(guān)屬性定義淤年,比如spec.selector是RC的Pod標(biāo)簽選擇器钧敞,即監(jiān)控和管理?yè)碛羞@些標(biāo)簽的Pod實(shí)例,確保在當(dāng)前集群中始終有且僅有replicas個(gè)Pod實(shí)例在運(yùn)行麸粮,這里設(shè)置replicas=1溉苛,表示只能運(yùn)行一個(gè)MySQL Pod實(shí)例。
當(dāng)在集群中運(yùn)行的Pod數(shù)量少于replicas時(shí)弄诲,RC會(huì)根據(jù)在spec.template一節(jié)中定義的Pod模板來生成一個(gè)新的Pod實(shí)例愚战,spec.template.metadata. labels指定了該P(yáng)od的標(biāo)簽,需要特別注意的是:這里的labels必須匹配之前的spec.selector齐遵,否則此RC每創(chuàng)建一個(gè)無法匹配Label的Pod寂玲,就會(huì)不停地嘗試創(chuàng)建新的Pod,陷入惡性循環(huán)中梗摇。
(3)發(fā)布到kubernetes集群中:
$ kubectl create -f mysql-rc.yaml
(4)查看資源創(chuàng)建情況
用kubectl命令查看剛剛創(chuàng)建的RC
$ kubectl get rc
NAME DESIRED CURRENT READY AGE
mysql 1 1 0 9s
查看Pod的創(chuàng)建情況時(shí)拓哟,可以運(yùn)行下面的命令:
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysql-dcr5z 1/1 Running 0 114s 10.244.2.2 k8s-node1 <none> <none>
可以看到其在k8s-node1節(jié)點(diǎn)運(yùn)行。在k8s-node1節(jié)點(diǎn)伶授,我們通過docker ps指令查看正在運(yùn)行的容器:
$ docker ps |grep mysql
167e968bd621 mysql "docker-entrypoint.s…" 2 minutes ago Up 2 minutes k8s_mysql_mysql-dcr5z_default_55c116e6-aa2c-402e-87dd-2fcbc4877010_0
51ae0f275c3c k8s.gcr.io/pause:3.2 "/pause" 3 minutes ago Up 3 minutes k8s_POD_mysql-dcr5z_default_55c116e6-aa2c-402e-87dd-2fcbc4877010_0
(4)創(chuàng)建ubernetes Service
創(chuàng)建一個(gè)與之關(guān)聯(lián)的Kubernetes Service——MySQL的定義文件断序,完整的內(nèi)容和解釋如下:
mysql-svc.yaml :
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
selector:
app: mysql
(5)運(yùn)行kubectl命令,創(chuàng)建Service:
$ kubectl create -f mysql-svc.yaml
(6)查看創(chuàng)建的Service情況
運(yùn)行kubectl命令查看剛剛創(chuàng)建的Service:
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 22h
mysql ClusterIP 10.107.219.146 <none> 3306/TCP 14s
可以發(fā)現(xiàn)糜烹,MySQL服務(wù)被分配了一個(gè)值為10.107.219.146的Cluster IP地址逢倍。隨后,Kubernetes集群中其他新創(chuàng)建的Pod就可以通過Service的Cluster IP+端口號(hào)3306來連接和訪問它了景图。通常较雕,Cluster IP是在Service創(chuàng)建后由Kubernetes系統(tǒng)自動(dòng)分配的,其他Pod無法預(yù)先知道某個(gè)Service的Cluster IP地址,因此需要一個(gè)服務(wù)發(fā)現(xiàn)機(jī)制來找到這個(gè)服務(wù)亮蒋。為此扣典,最初時(shí),Kubernetes巧妙地使用了Linux環(huán)境變量(Environment Variable)來解決這個(gè)問題慎玖,后面會(huì)詳細(xì)說明其機(jī)制≈猓現(xiàn)在只需知道,根據(jù)Service的唯一名稱趁怔,容器可以從環(huán)境變量中獲取Service對(duì)應(yīng)的Cluster IP地址和端口湿硝,從而發(fā)起TCP/IP連接請(qǐng)求。
(7)其他Kubectl命令測(cè)試
我們可以執(zhí)行下述命令查看在集群中有多少個(gè)Node:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane,master 22h v1.20.5
k8s-node1 Ready worker 14h v1.20.5
k8s-node2 Ready worker 22h v1.20
通過kubectl describe node <node_name>查看某個(gè)Node的詳細(xì)信息:
$ kubectl describe node k8s-master
可以用kubectl describepod xxxx來查看它的描述信息润努,以定位問題的成因:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
mysql-dcr5z 1/1 Running 0 7m3s
$ kubectl describe pod mysql-dcr5z
Name: mysql-dcr5z
Namespace: default
Priority: 0
Node: k8s-node1/192.168.0.3
Start Time: Tue, 17 Aug 2021 11:39:20 +0800
Labels: app=mysql
Annotations: <none>
Status: Running
...
可以通過執(zhí)行kubectl scale命令來一鍵完成:
$ kubectl scale rc mysql --replicas=3
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysql-4gnp5 1/1 Running 0 60s 10.244.2.4 k8s-node1 <none> <none>
mysql-7pv7f 1/1 Running 0 60s 10.244.2.3 k8s-node1 <none> <none>
mysql-dcr5z 1/1 Running 0 10m 10.244.2.2 k8s-node1 <none> <none>
可知关斜,這3個(gè)pods都被k8s自動(dòng)分配到k8s-node1節(jié)點(diǎn)了。
需要注意的是铺浇,刪除RC并不會(huì)影響通過該RC已創(chuàng)建好的Pod痢畜。為了刪除所有Pod,可以設(shè)置replicas的值為0鳍侣,然后更新該RC丁稀。另外,kubectl提供了stop和delete命令來一次性刪除RC和RC控制的全部Pod倚聚。
2.1.2.2.2 Tomcat應(yīng)用
(1)下載鏡像:
$ docker search kubeguide
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
kubeguide/redis-master redis-master with "Hello World!" 33
kubeguide/tomcat-app Tomcat image for Chapter 1 30 kubeguide/guestbook-php-frontend Guestbook PHP website 25
kubeguide/guestbook-redis-slave Guestbook redis slave 23
kubeguide/mysql-master mysql master 6 [OK]
kubeguide/hadoop 5
kubeguide/centos7-ansible ansible with sshpass tool installed and sshk… 4
$ docker pull kubeguide/tomcat-app:v2
(2)創(chuàng)建對(duì)應(yīng)的RC文件myweb-rc.yaml:
apiVersion: v1
kind: ReplicationController
metadata:
name: myweb
spec:
replicas: 3
selector:
app: myweb
template:
metadata:
labels:
app: myweb
spec:
containers:
- name: myweb
image: kubeguide/tomcat-app:v1
ports:
- containerPort: 8080
env:
- name: MYSQL_SERVICE_HOST
value: 'mysql'
- name: MYSQL_SERVICE_PORT
value: '3306'
注意:在Tomcat容器內(nèi)线衫,應(yīng)用將使用環(huán)境變量MYSQL_SERVICE_HOST的值連接MySQL服務(wù)。更安全可靠的用法是使用服務(wù)的名稱mysql惑折。
(3)發(fā)布到集群中:
$ kubectl create -f myweb-rc.yaml
(4)創(chuàng)建對(duì)應(yīng)的Service(myweb-svc.yaml):
apiVersion: v1
kind: Service
metadata:
name: myweb
spec:
type: NodePort
ports:
- port: 8080
nodePort: 31330
selector:
app: myweb
type=NodePort和nodePort=31330的兩個(gè)屬性表明此Service開啟了NodePort方式的外網(wǎng)訪問模式授账。在Kubernetes集群之外,比如在本機(jī)的瀏覽器里唬复,可以通過31330這個(gè)端口訪問myweb(對(duì)應(yīng)到8080的虛端口上)。
采用netstat -nltp|grep 31330 命令來確認(rèn)在service運(yùn)行前全肮,端口是否已被占用敞咧。
(5)運(yùn)行kubectl create命令進(jìn)行創(chuàng)建:
$ kubectl create -f myweb-svc.yaml
注意:記得防火墻打開31330端口。
(6)運(yùn)行kubectl命令辜腺,查看創(chuàng)建的Service:
$ kubectl get services -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23h <none>
mysql ClusterIP 10.107.219.146 <none> 3306/TCP 12m app=mysql
myweb NodePort 10.109.12.156 <none> 8080:31330/TCP 36s app=myweb
查看pods情況:
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysql-4gnp5 1/1 Running 0 8m5s 10.244.2.4 k8s-node1 <none> <none>
mysql-7pv7f 1/1 Running 0 8m5s 10.244.2.3 k8s-node1 <none> <none>
mysql-dcr5z 1/1 Running 0 17m 10.244.2.2 k8s-node1 <none> <none>
myweb-b2kfl 1/1 Running 0 3m46s 10.244.1.4 k8s-node2 <none> <none>
myweb-nblv5 1/1 Running 0 3m46s 10.244.1.3 k8s-node2 <none> <none>
myweb-rxws6 1/1 Running 0 3m46s 10.244.1.2 k8s-node2 <none> <none>
可知休建,有3個(gè)mysql分布在k8s-node1上,3個(gè)myweb分布在k8s-node2上评疗。
2.1.2.2.3 測(cè)試
請(qǐng)確認(rèn)對(duì)應(yīng)的網(wǎng)絡(luò)安全組已打開端口31330. 例如在windows下采用 psping 114.67.107.240:31330 確認(rèn)端口已打開测砂。
在瀏覽器輸入http://虛擬機(jī)IP(外網(wǎng)):31330/demo/。比如虛擬機(jī)IP為114.67.107.240 (可以通過#ip a命令進(jìn)行查詢)百匆,在瀏覽器里輸入地址http://114.67.107.240:31330/demo/后砌些,可以看到如圖1.2所示的網(wǎng)頁(yè)界面。
問題描述:
先測(cè)試下服務(wù)是否聯(lián)通。
# 測(cè)試獲取web服務(wù)是否已啟動(dòng)存璃。
curl http://192.168.0.3:31330/demo/
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
...
<h3> Error:com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server.</h3>
此時(shí)表示無法跟MySql服務(wù)器鏈接仑荐。查看pods的打印信息:
p# kubectl get pods
NAME READY STATUS RESTARTS AGE
mysql-ppzgm 1/1 Running 0 48m
myweb-87j84 1/1 Running 0 28m
myweb-drqg9 1/1 Running 0 28m
myweb-dtfdt 1/1 Running 0 28m
myweb-gcfh5 1/1 Running 0 28m
myweb-kzcxc 1/1 Running 0 28m
root@k8s-master:/data/k8s/JavaWebApp# kubectl logs myweb-87j84
30-Jul-2021 06:33:35.868 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version: Apache Tomcat/8.0.35
30-Jul-2021 06:33:35.869 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: May 11 2016 21:57:08 UTC
...
30-Jul-2021 06:33:45.065 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 746 ms
Connecting to database...
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
... 39 more
Goodbye!
說明:
從github issue:https://github.com/kubeguide/K8sDefinitiveGuide-V4-Sourcecode/issues/7 找到原因:
1.3.3 myweb-rc.yaml 鏡像用的mysql-connector-java-5.1.37.jar,不兼容1.3.2 mysql-rc.yaml默認(rèn)鏡像 mysql 8纵东,導(dǎo)致連接失敗粘招,需要將1.3.2 mysql-rc.yaml 指定mysql5.7版本。
# 需要采用5.7的版本偎球。
docker pull mysql:5.7
# 刪除已運(yùn)行的RC
kubectl delete -f mysql-rc.yaml
# 刪除已運(yùn)行的RC
kubectl delete -f myweb-svc.yaml
參考
(1)本書示例中的Docker鏡像下載地址為:
https://hub.docker.com/u/kubeguide/
(2)https://github.com/kubeguide/K8sDefinitiveGuide-V4-Sourcecode