第4課 在k8s集群運(yùn)行一個(gè)極簡(jiǎn)的web APP

k8s4.png

摘要

本文是《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ù)冻辩。

JAVA WEB APP
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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末洒扎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子衰絮,更是在濱河造成了極大的恐慌袍冷,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岂傲,死亡現(xiàn)場(chǎng)離奇詭異难裆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)镊掖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門乃戈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人亩进,你說我怎么就攤上這事症虑。” “怎么了归薛?”我有些...
    開封第一講書人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵谍憔,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我主籍,道長(zhǎng)习贫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮金麸,結(jié)果婚禮上惕耕,老公的妹妹穿的比我還像新娘。我一直安慰自己祟身,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開白布物独。 她就那樣靜靜地躺著袜硫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪挡篓。 梳的紋絲不亂的頭發(fā)上婉陷,一...
    開封第一講書人閱讀 52,696評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼憨攒。 笑死世杀,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的肝集。 我是一名探鬼主播瞻坝,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼杏瞻!你這毒婦竟也來了所刀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤捞挥,失蹤者是張志新(化名)和其女友劉穎浮创,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體砌函,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡斩披,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了讹俊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垦沉。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖仍劈,靈堂內(nèi)的尸體忽然破棺而出厕倍,到底是詐尸還是另有隱情,我是刑警寧澤贩疙,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布讹弯,位于F島的核電站,受9級(jí)特大地震影響这溅,放射性物質(zhì)發(fā)生泄漏组民。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一悲靴、第九天 我趴在偏房一處隱蔽的房頂上張望臭胜。 院中可真熱鬧,春花似錦对竣、人聲如沸庇楞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蛋褥,卻和暖如春临燃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工膜廊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乏沸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓爪瓜,卻偏偏與公主長(zhǎng)得像蹬跃,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子铆铆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容