pod部署
- 編寫nginx-pod.yml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx #容器內部nginx的日志
- name: nginx-conf
mountPath: /usr/share/nginx/html #容器內部nginx的html位置
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx #將宿主機的日志目錄掛載到容器中的日志目錄
- name: nginx-conf
hostPath:
path: /data/nginx #將宿主機的html目錄掛載到容器中的日志目錄
- 執行kubectl apply -f nginx-pod.yml創建成功pod
- 通過kubectl get pod nginx -o wide查看pod啟動情況
[root@master k8s]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 5m17s 10.0.3.164 cdh2 <none> <none>
- 通過執行kubectl exec -it nginx sh可以進入到容器內部,然后執行curl http://127.0.0.1可以查看內容
- 由于此刻Pod的端口還未對外暴露,因此無法在外部訪問,可以采取以下方法:
- hostNetwork
- hostPort
- NodePort
- LoadBalancer
- Ingress
hostNetwork
這是一種直接定義Pod網絡的方式。
如果在Pod中使用hostNotwork:true配置的話,在這種pod中運行的應用程序可以直接看到pod啟動的主機的網絡接口。在主機的所有網絡接口上都可以訪問到該應用程序。以下是使用主機網絡的pod的示例定義:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
hostNetwork: true
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx
- name: nginx-conf
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx
- name: nginx-conf
hostPath:
path: /data/nginx
這樣就可以訪問宿主機的80端口就可以訪問nginx的頁面了,但是這種方式的弊端就是由于k8s集群中節點很多,無法知道這個nginx的pod部署到哪個節點。
因此一般情況下除非您知道需要某個特定應用占用特定宿主機上的特定端口時才使用hostNetwork: true的方式。
hostPort
hostPort是直接將容器的端口與所調度的節點上的端口路由,這樣用戶就可以通過宿主機的IP加上來訪問Pod了
apiVersion: v1
kind: Pod
metadata:
name: nginx-host-port
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
hostPort: 7878
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx
- name: nginx-conf
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx
- name: nginx-conf
hostPath:
path: /data/nginx
這樣就可以訪問宿主機的7878端口就可以訪問nginx的頁面了,這樣做有個缺點,因為Pod重新調度的時候該Pod被調度到的宿主機可能會變動,這樣就變化了。問題通hostNetwork一樣。
用戶必須自己維護一個Pod與所在宿主機的對應關系。
NodePort
NodePort在kubenretes里是一個廣泛應用的服務暴露方式。Kubernetes中的service默認情況下都是使用的ClusterIP這種類型,這樣的service會產生一個ClusterIP,這個IP只能在集群內部訪問,要想讓外部能夠直接訪問service,需要將service type修改為 nodePort。
#聲明一個pod,然后定義一個Service去訪問pod,通過 selector來選擇標簽,這里記住,選擇的是pod中定義的標簽名,這樣定義一個Service可以負載均衡到一個標簽下的多個pod。
------------------------
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort #Service聲明為NodePort這樣將Service的端口映射到宿主機的一個端口
ports:
- port: 80 #Service的端口
targetPort: 80 #Pod容器的端口
nodePort: 30000 #宿主機的端口
selector:
app: nginx-node-1 #選擇 標簽為nginx-node-1的POD作為后端服務
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-node
labels:
app: nginx-node-1
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx
- name: nginx-conf
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx
- name: nginx-conf
hostPath:
path: /data/nginx
集群外就可以使用kubernetes任意一個節點的IP加上30000端口訪問該服務了。kube-proxy會自動將流量以round-robin的方式轉發給該service的每一個pod。
這種服務暴露方式,無法讓你指定自己想要的應用常用端口,不過可以在集群上再部署一個反向代理作為流量入口。
LoadBalancer
LoadBalancer 只能在service上定義。這是公有云提供的負載均衡器,如AWS、Azure、CloudStack、GCE等。
kind: Service
apiVersion: v1
metadata:
name: influxdb
spec:
type: LoadBalancer
ports:
- port: 80
selector:
app: nginx-node-1
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-node
labels:
app: nginx-node-1
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx
- name: nginx-conf
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx
- name: nginx-conf
hostPath:
path: /data/nginx
查看服務
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 192.168.0.1 <none> 443/TCP 22d <none>
nginx-service LoadBalancer 192.168.180.49 <pending> 80:31981/TCP 2m23s app=nginx-node-1
使用EXTERNAL-IP來訪問,這是一個VIP,是云供應商提供的負載均衡器IP
由于只能在公有云上建立,因此此方法無法在本機進行測試演示
Ingress
Ingress是自kubernetes1.1版本后引入的資源類型。必須要部署 Ingress controller 才能創建Ingress資源,Ingress controller是以一種插件的形式提供。Ingress controller 是部署在Kubernetes之上的Docker容器。它的Docker鏡像包含一個像nginx或HAProxy的負載均衡器和一個控制器守護進程。控制器守護程序從Kubernetes接收所需的Ingress配置。它會生成一個nginx或HAProxy配置文件,并重新啟動負載平衡器進程以使更改生效。換句話說,Ingress controller是由Kubernetes管理的負載均衡器。
Kubernetes Ingress提供了負載平衡器的典型特性:HTTP路由,粘性會話,SSL終止,SSL直通,TCP和UDP負載平衡等。目前并不是所有的Ingress controller都實現了這些功能,需要查看具體的Ingress controller文檔。
ingress.yml
ingress一定要配合service使用,這樣可以使service無需使用NodeType模式,將端口部署到節點
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-test
spec:
rules:
#定義域名
- host: test.ingress.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
nginx-pod.yml
這里無需將type設置為nodeType,直接去掉,無需對外訪問
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
ports:
- port: 80
targetPort: 80
selector:
app: nginx-node-1
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-node
labels:
app: nginx-node-1
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx
- name: nginx-conf
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx
- name: nginx-conf
hostPath:
path: /data/nginx
總結
總的來說Ingress是一個非常靈活和越來越得到廠商支持的服務暴露方式,包括Nginx、HAProxy、Traefik,還有各種Service Mesh,而其它服務暴露方式可以更適用于服務調試、特殊應用的部署。
Deployment
采用pod部署,無法進行很好的擴容操作,主流的都是是用deployment來部署,然后再結合上面的Ingress來進行負載均衡接入service
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx-deployment-pod
template:
metadata:
labels:
app: nginx-deployment-pod
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx
- name: nginx-html
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx
- name: nginx-html
hostPath:
path: /data/nginx
---
apiVersion: v1
kind: Service
metadata:
name: nginx-deploy-service
spec:
ports:
- port: 81
targetPort: 80
selector:
app: nginx-deployment-pod
執行kubectl apply -f nginx-deploy-pod.yml,查看運行情況
[root@master k8s]# kubectl get deployments -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx-deployment 2/2 2 2 69m nginx nginx:1.7.9 app=nginx-deployment-pod
[root@master k8s]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-78dbd4c9f4-9kw84 1/1 Running 0 11m 10.10.1.31 cdh3 <none> <none>
nginx-deployment-78dbd4c9f4-pngnn 1/1 Running 0 11m 10.10.2.25 cdh2 <none> <none>
Deployment + LoadBalancer模式的Service
如果要把ingress部署在公有云,那用這種方式比較合適。用Deployment部署ingress-controller,創建一個type為LoadBalancer的service關聯這組pod。大部分公有云,都會為LoadBalancer的service自動創建一個負載均衡器,通常還綁定了公網地址。只要把域名解析指向該地址,就實現了集群服務的對外暴露。
Deployment+NodePort模式的Service
同樣用deployment模式部署ingress-controller,并創建對應的Service,但是Service的type為NodePort。這樣,ingress就會暴露在集群節點ip的特定端口上。由于nodeport暴露的端口是隨機端口,一般會在前面再搭建一套負載均衡器來轉發請求。該方式一般用于宿主機是相對固定的環境ip地址不變的場景。
NodePort方式暴露ingress雖然簡單方便,但是NodePort多了一層NAT,在請求量級很大時可能對性能會有一定影響。
DaemonSet+HostNetwork+nodeSelector
用DaemonSet結合nodeselector來部署ingress-controller到特定的node上,然后使用HostNetwork直接把該pod與宿主機node的網絡打通,直接使用宿主機的80/433端口就能訪問服務。這時,ingress-controller所在的node機器就很類似傳統架構的邊緣節點,比如機房入口的nginx服務器。該方式整個請求鏈路最簡單,性能相對NodePort模式更好。缺點是由于直接利用宿主機節點的網絡和端口,一個node只能部署一個ingress-controller pod。比較適合大并發的生產環境使用。
更新deployment
- 升級nginx版本號,將版本號升級到1.16.1
[root@master k8s]# kubectl --record deployment.apps/nginx-deployment set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
deployment.apps/nginx-deployment image updated
deployment.apps/nginx-deployment image updated
更新后會一個個pod替換重啟
- 執行完命令后,要查看更新狀況
kubectl rollout status deployment/nginx-deployment
[root@master k8s]# kubectl rollout status deployment/nginx-deployment
deployment "nginx-deployment" successfully rolled out(全部更新完畢)
又或者會提示,即還有1個未更新
Waiting for rollout to finish: 1 out of 2 new replicas have been updated...
回滾
有可能更新版本出錯,這個時候可能需要回滾
1.執行回滾語句
kubectl rollout undo deployment.v1.apps/nginx-deployment
2.查看回滾狀況,同上述查看更新狀況命令一致
自動伸縮
1.指定擴容個數
[root@master k8s]# kubectl scale deployment.v1.apps/nginx-deployment --replicas=3
deployment.apps/nginx-deployment scaled
查看pod已生效
[root@master k8s]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-7fd7589cf4-h4jlz 1/1 Running 0 19s 10.10.2.29 cdh2 <none> <none>
nginx-deployment-7fd7589cf4-hd967 1/1 Running 0 95s 10.10.2.28 cdh2 <none> <none>
nginx-deployment-7fd7589cf4-vnvlg 1/1 Running 0 93s 10.10.1.34 cdh3 <none> <none>
2.動態擴容個數
假設集群中啟用了水平Pod自動縮放,則可以為Deployment設置一個自動縮放器,并根據現有Pod的CPU利用率選擇要運行的最小和最大Pod數。
使用動態擴容需要為k8s創建metric-server,且為容器配置資源
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx-deployment-pod
template:
metadata:
labels:
app: nginx-deployment-pod
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
resources:
limits: #限制最高資源
cpu: "500m"
requests: #最低保障資源
cpu: "200m"
volumeMounts:
- name: nginx-storage
mountPath: /var/log/nginx
- name: nginx-html
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-storage
hostPath:
path: /data/logs/nginx
- name: nginx-html
hostPath:
path: /data/nginx
---
apiVersion: v1
kind: Service
metadata:
name: nginx-deploy-service
spec:
ports:
- port: 81
targetPort: 80
selector:
app: nginx-deployment-pod
kubectl autoscale deployment.v1.apps/nginx-deployment --min=1 --max=3 --cpu-percent=50
我們可以通過運行以下命令檢查自動定標器的當前狀態:
[root@master k8s]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-deployment Deployment/nginx-deployment <unknown>/50% 1 3 3 3m13s
K8S的資源描述:
在K8s的資源:
CPU:
我們知道2核2線程的CPU,可被系統識別為4個邏輯CPU,在K8s中對CPU的分配限制是對邏輯CPU做分片限制的。
也就是說分配給容器一個CPU,實際是分配一個邏輯CPU。
而且1個邏輯CPU還可被單獨劃分子單位,即 1個邏輯CPU,還可被劃分為1000個millicore(毫核), 簡單說就是1個邏輯CPU,繼續邏輯分割為1000個豪核心。
豪核:可簡單理解為將CPU的時間片做邏輯分割,每一段時間片就是一個豪核心。
所以:500m 就是500豪核心,即0.5個邏輯CPU.