您好,登錄后才能下訂單哦!
Kubernetes是Google開源的一個容器編排引擎,它支持自動化部署、大規模可伸縮、應用容器化管理。在生產環境中部署一個應用程序時,通常要部署該應用的多個實例以便對應用請求進行負載均衡。
在Kubernetes中,我們可以創建多個容器,每個容器里面運行一個應用實例,然后通過內置的負載均衡策略,實現對這一組應用實例的管理、發現、訪問,而這些細節都不需要運維人員去進行復雜的手工配置和處理。
可移植: 支持公有云,私有云,混合云,多重云(multi-cloud)
可擴展: 模塊化,插件化,可掛載,可組合
自動化: 自動部署,自動重啟,自動復制,自動伸縮/擴展
在K8s中創建資源的方式有兩種:命令行和YAML文件,本次博文主要介紹使用YAML文件的方式,如需使用命令行創建資源請參考K8s資源對象的基本管理
Kubernetes中的YAML文件與配置清單是一樣的,根據個人習慣。本次博文統稱為YAML文件!
YAML是專門用來配置文件的語言,非常簡潔和強大。與了解的properties、XML、json等數據格式,習慣之后就會發現越來越好用。其實YAML就是結合了大部分的標記語言的特性,整合新開發的。
YAML文件的特點:
- 層次分明、結構清晰;
- 使用簡單、上手容易;
- 功能強大、語義豐富;
需要特別注意的是:- 大小寫敏感;
- 嚴格要求縮進;
Kubernetes中的YAML文件主要由五個一級字段組成,分別是:
- apiVersion:api版本信息;
- kind:指定創建資源對象的類型;
- metadata:元數據內部的嵌套字段,定義了資源對象的名稱、名稱空間等;
- spec:規范定義資源應該擁有什么樣的特性,依靠控制器確保性能可以滿足,滿足用戶期望的狀態。
- status:顯示資源的當前狀態,K8s就是確保當前狀態向目標狀態無限靠近從而滿足用戶期望。代表資源當前的狀態;
雖然知道了YAML文件中的一級字段都是什么,但是還是不知道應該怎么寫。可以借助以下命令來獲取一些幫助信息。
[root@master ~]# kubectl api-versions
//獲取當前集群支持的 apiserver版本
[root@master ~]# kubectl api-resources
//獲取全部的api資源對象
[root@master ~]# kubectl explain deployment
//查看k8s某個對象的配置清單格式,應該包含哪些字段及使用方法
[root@master ~]# kubectl explain deployment.spec
//這個命令是非常重要的,它可以一級一級來獲取幫助
[root@master ~]# cat web.yaml
kind: Deployment //指定要創建的資源對象
apiVersion: extensions/v1beta1 //指定deployment所對應的API版本信息
metadata:
name: web //定義deployment的名稱
spec:
replicas: 2 //指定副本數量
template:
metadata:
labels: //指定pod的標簽
app: web_server
spec:
containers:
- name: nginx //指定pod運行的容器的名稱
image: nginx //指定運行容器所需的鏡像
[root@master ~]# kubectl apply -f web.yaml
//使用“-f”來指定yaml文件,根據yaml文件中定義的內容生成所需的資源
apply可以指定多次,如果發現文件不同,則更新
[root@master ~]# kubectl delete -f web.yaml
//刪除yaml文件中定義的資源
[root@master ~]# kubectl get deployments. web
//查看web控制器所產生的pod
NAME READY UP-TO-DATE AVAILABLE AGE
web 2/2 2 2 5m50s
[root@master ~]# kubectl describe deployments. web
//查看web控制器的詳細信息
返回的結果如下:
這樣一來,Kubernetes已經根據YAML文件生成了我們所需的pod資源!
[root@master ~]# kubectl get pod -o wide //查看pod的詳細信息
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-d6ff6c799-7jtvd 1/1 Running 0 17m 10.244.2.2 node02 <none> <none>
web-d6ff6c799-7tpdc 1/1 Running 0 17m 10.244.1.2 node01 <none> <none>
K8s集群內部測試訪問:
[root@master ~]# cat web-svc.yaml
kind: Service
apiVersion: v1
metadata:
name: web-svc
spec:
type: NodePort //指定類型為NodePort,可以讓外部訪問,否則默認情況下是cluster IP,僅限集群內部訪問
selector:
app: web_server //必須與deployment資源對象的標簽進行關聯
ports:
- protocol: TCP
port: 80 //指定要映射到的Cluster IP的端口
targetPort: 80 //指定的是要映射pod中的端口
nodePort: 31000 //指定映射到宿主機的端口,范圍是30000~32767
[root@master ~]# kubectl apply -f web-svc.yaml
//生成service的控制文件(yaml中已經定義其名稱為web-svc)
[root@master ~]# kubectl get svc web-svc //查看service控制器
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web-svc NodePort 10.99.32.22 <none> 80:31000/TCP 12m
//TYPE:為NodePort,可以使外部訪問;
//PORT:映射出的端口與我們定義的一樣
測試訪問:
注意:是訪問群集中任意節點都可以訪問k8s集群中pod所提供的服務!
[root@master ~]# kubectl describe svc web-svc
//查看service的詳細信息
返回的信息如下:
既然說到,Endpoints指定的是后端pod的IP地址,那么下面進行驗證:
[root@master ~]# kubectl get pod -o wide | awk '{print $6}'
//提取后端pod的IP地址
IP
10.244.2.2
10.244.1.2
//與上述查詢的結果一樣!
我們知道service是有負載均衡的能力,那么是怎么實現的?
其實,背后的原理并沒有那么高大上,kube-proxy通過iptables的轉發機制來實現負載均衡的效果的,先定義目標IP是service提供的群集IP,然后使用“-j”選項轉發到其他iptables規則,接下來驗證一下:
[root@master ~]# kubectl get svc web-svc | awk '{print $3}'
//首先查看service的群集IP地址
CLUSTER-IP
10.99.32.22
[root@master ~]# iptables-save | grep 10.99.32.22
//查看iptables規則中與群集IP地址相關的內容
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.99.32.22/32 -p tcp -m comment --comment "default/web-svc: cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.99.32.22/32 -p tcp -m comment --comment "default/web-svc: cluster IP" -m tcp --dport 80 -j KUBE-SVC-3RBUQ3B6P3MTQ3S7
從上述結果中可以看出,當目標地址是群集IP時,就會轉發到KUBE-SVC-3RBUQ3B6P3MTQ3S7規則中
[root@master ~]# iptables-save | grep KUBE-SVC-3RBUQ3B6P3MTQ3S7
:KUBE-SVC-3RBUQ3B6P3MTQ3S7 - [0:0]
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/web-svc:" -m tcp --dport 31000 -j KUBE-SVC-3RBUQ3B6P3MTQ3S7
-A KUBE-SERVICES -d 10.99.32.22/32 -p tcp -m comment --comment "default/web-svc: cluster IP" -m tcp --dport 80 -j KUBE-SVC-3RBUQ3B6P3MTQ3S7
-A KUBE-SVC-3RBUQ3B6P3MTQ3S7 -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-E3SP5QDRAUFB55IC
-A KUBE-SVC-3RBUQ3B6P3MTQ3S7 -j KUBE-SEP-3T3LUFAKMOTS5BKN
//從查詢結果中可以看出其負載均衡的效果,因為后端只創建了兩個pod,所以其概率為0.5
由此可以看出service實現負載均衡的效果:默認情況下使用iptables規則,當然還可以使用其他的方法,這里就不介紹了!
查看負載均衡的詳細信息需根據cluster ip為切入口!
實現負載均衡最根本的原理就是:iptables規則根據random(隨機數)實現的負載均衡!
通過K8s資源對象的基本管理之使用命令行的方式可以了解到kubernetes版本升級、回滾的操作與docker swarm幾乎是一樣的。回滾操作只能回滾到上一個版本。
搭建私有倉庫,使用鏡像制作自定義鏡像(三個版本),根據主頁內容進行區分,將自定義鏡像上傳到私有倉庫中,由于過于簡單,過程略……
kubernetes還可以回滾到指定的版本,方法如下:
[root@master yaml]# cat httpd01.deployment.yaml
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: httpd
spec:
revisionHistoryLimit: 10 //記錄歷史版本信息為10個
replicas: 3
template:
metadata:
labels:
app: httpd-server
spec:
containers:
- name: httpd
image: 192.168.1.1:5000/httpd:v1 //三個版本根據鏡像進行區分
ports: //這個只是一個聲名沒有任何作用
- containerPort: 80
[root@master yaml]# cat httpd02.deployment.yaml
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: httpd
spec:
revisionHistoryLimit: 10
replicas: 3
template:
metadata:
labels:
app: httpd-server
spec:
containers:
- name: httpd
image: 192.168.1.1:5000/httpd:v2 //三個版本根據鏡像進行區分
ports:
- containerPort: 80
[root@master yaml]# cat httpd03.deployment.yaml
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: httpd
spec:
revisionHistoryLimit: 10
replicas: 3
template:
metadata:
labels:
app: httpd-server
spec:
containers:
- name: httpd
image: 192.168.1.1:5000/httpd:v3 //三個版本根據鏡像進行區分
ports:
- containerPort: 80
[root@master yaml]# kubectl apply -f httpd01.deployment.yaml --record
//--record的作用就是記錄歷史版本信息
[root@master yaml]# kubectl rollout history deployment httpd
//查看歷史的版本信息
deployment.extensions/httpd
REVISION CHANGE-CAUSE
1 kubectl apply --filename=httpd01.deployment.yaml --record=true
//1,表示版本對應的編號,也可以看出其對應的yaml
[root@master yaml]# kubectl apply -f httpd02.deployment.yaml --record
[root@master yaml]# kubectl apply -f httpd03.deployment.yaml --record
//根據yaml文件進行兩次升級
[root@master yaml]# kubectl rollout history deployment httpd
deployment.extensions/httpd
REVISION CHANGE-CAUSE
1 kubectl apply --filename=httpd01.deployment.yaml --record=true
2 kubectl apply --filename=httpd02.deployment.yaml --record=true
3 kubectl apply --filename=httpd03.deployment.yaml --record=true
//確認升級的版本信息已經記錄
[root@master yaml]# vim httpd-svc.yaml
kind: Service
apiVersion: v1
metadata:
name: httpd-svc
spec:
type: NodePort
selector:
app: httpd-server
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 31000
[root@master yaml]# kubectl apply -f httpd-svc.yaml
//創建一個svc便于訪問測試
[root@master yaml]# curl 127.0.0.1:31000
<h2>hello lvzhenjiang:v3</h2>
//訪問測試頁面效果
[root@master yaml]# kubectl rollout undo deployment httpd --to-revision=1
//回滾到版本1,使用--to-revision=1表示,1表示查看歷史版本的第一列編號
[root@master yaml]# curl 127.0.0.1:31000 //測試訪問
<h2>hello lvzhenjiang:v1</h2>
如果不指定pod的位置的話,默認情況下,是由K8s中scheduler這個組件來完成的,不能人為的干預。如果是業務需要手動指定的話,那么就需要以下方法:
[root@master yaml]# kubectl label nodes node02 disk=ssd
//手動給node02打上一個 disk=ssd的標簽
[root@master yaml]# kubectl get nodes --show-labels | grep disk=ssd
//查看集群中各個節點的標簽(包含disk=ssd)
node02 Ready <none> 5d22h v1.15.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disk=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=node02,kubernetes.io/os=linux
//從結果中可以可看出只有node02包含這個標簽
[root@master yaml]# vim httpd.yaml
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: httpd
spec:
revisionHistoryLimit: 10
replicas: 3
template:
metadata:
labels:
app: httpd-server
spec:
containers:
- name: httpd
image: 192.168.1.1:5000/httpd:v1
ports:
- containerPort: 80
nodeSelector: //指定標簽選擇器
disk: ssd
[root@master yaml]# kubectl apply -f httpd.yaml
//根據yaml文件生成所需的pod資源
[root@master yaml]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
httpd-5895f5548b-6lb97 1/1 Running 0 12s 10.244.2.8 node02 <none> <none>
httpd-5895f5548b-gh8br 1/1 Running 0 10s 10.244.2.10 node02 <none> <none>
httpd-5895f5548b-llxh7 1/1 Running 0 12s 10.244.2.9 node02 <none> <none>
//從查詢結果中可以看出三個pod資源都運行在node02節點上
上述需求已經實現,但是只要有人為干預的地方就會錯誤的產生,不得不考慮以下這種情況!倘若將node02的標簽進行刪除的話,看一下會發生什么情況!
[root@master yaml]# kubectl label nodes node02 disk-
//將node02的disk=ssd的標簽進行刪除
[root@master yaml]# kubectl get nodes --show-labels | grep disk=ssd
//驗證,標簽已經被刪除
[root@master yaml]# kubectl delete -f httpd.yaml
//將原本的pod資源進行刪除
[root@master yaml]# kubectl apply -f httpd.yaml
//重新生成pod資源(yaml文件中依然指定了標簽)
[root@master yaml]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
httpd-5895f5548b-7w26q 0/1 Pending 0 65s <none> <none> <none> <none>
httpd-5895f5548b-c6p6s 0/1 Pending 0 65s <none> <none> <none> <none>
httpd-5895f5548b-v4s5c 0/1 Pending 0 65s <none> <none> <none> <none>
//但是查看pod的狀態為Pending,顯然這種狀態的pod是不正常的
即使標簽的不存在的,yaml文件中也指定了標簽,創建pod資源時,不會出現錯誤,但是pod的狀態為Pending(等待的狀態),解決方法如下:
[root@master yaml]# kubectl describe pod httpd-5895f5548b-7w26q
//查看pod的詳細信息
返回的結果如下:
從結果中就已經看出了是因為標簽選擇器與集群中node的標簽不匹配導致的!
如果以上沒有發現錯誤的信息,還需進行以下操作:
[root@master yaml]# kubectl logs -n kube-system kube-scheduler-master
//查看Scheduler組件所產生的日志信息
[root@master yaml]# less /var/log/messages | grep kubelet
//查看系統日志中包含kubelet組件的信息
//因為kubelet是負責管理pod的
有關K8s的詳細介紹還是建議參考K8s中文文檔
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。