一、簡介
參考:Kubernetes 官方文件、Kubernetes中文社群 | 中文文件
Kubernetes 是一個可移植的、可擴充套件的開源平臺,用於管理容器化的工作負載和服務,可促進宣告式配置和自動化,擁有一個龐大且快速增長的生態系統。
為什麼Kubernetes如此有用?
傳統部署時代: 早期,組織在物理伺服器上執行應用程式。無法為物理伺服器中的應用程式定義資源邊界,這會導致資源分配問題。例如,如果在物理伺服器上執行多個應用程式,則可能會出現一個應用程式佔用大部分資源的情況,結果可能導致其他應用程式的效能下降。一種解決方案是在不同的物理伺服器上執行每個應用程式,但是由於資源利用不足而無法擴充套件,並且組織維護許多物理伺服器的成本很高。
虛擬化部署時代: 作為解決方案,引入了虛擬化功能,它允許您在單個物理伺服器的 CPU 上執行多個虛擬機器(VM)。虛擬化功能允許應用程式在 VM 之間隔離,並提供安全級別,因為一個應用程式的資訊不能被另一應用程式自由地訪問。
因為虛擬化可以輕鬆地新增或更新應用程式、降低硬體成本等等,所以虛擬化可以更好地利用物理伺服器中的資源,並可以實現更好的可伸縮性。
每個 VM 是一臺完整的計算機,在虛擬化硬體之上執行所有元件,包括其自己的作業系統。
容器部署時代: 容器類似於 VM,但是它們具有輕量級的隔離屬性,可以在應用程式之間共享作業系統(OS)。因此,容器被認為是輕量級的。容器與 VM 類似,具有自己的檔案系統、CPU、記憶體、程式空間等。由於它們與基礎架構分離,因此可以跨雲和 OS 分發進行移植。
容器因具有許多優勢而變得流行起來,下面列出了容器的一些好處:
-
敏捷應用程式的建立和部署:與使用 VM 映象相比,提高了容器映象建立的簡便性和效率。
-
持續開發、整合和部署:通過快速簡單的回滾(由於映象不可變性),提供可靠且頻繁的容器映象構建和部署。
-
關注開發與運維的分離:在構建/釋出時而不是在部署時建立應用程式容器映象,從而將應用程式與基礎架構分離。
-
可觀察性不僅可以顯示作業系統級別的資訊和指標,還可以顯示應用程式的執行狀況和其他指標訊號。
-
跨開發、測試和生產的環境一致性:在行動式計算機上與在雲中相同地執行。
-
雲和作業系統分發的可移植性:可在 Ubuntu、RHEL、CoreOS、本地、Google Kubernetes Engine 和其他任何地方執行。
-
以應用程式為中心的管理:提高抽象級別,從在虛擬硬體上執行 OS 到使用邏輯資源在 OS 上執行應用程式。
-
鬆散耦合、分散式、彈性、解放的微服務:應用程式被分解成較小的獨立部分,並且可以動態部署和管理 - 而不是在一臺大型單機上整體執行。
-
資源隔離:可預測的應用程式效能。
-
資源利用:高效率和高密度。
Kubernetes能做什麼?
容器是打包和執行應用程式的好方式。在生產環境中,您需要管理執行應用程式的容器,並確保不會停機。例如,如果一個容器發生故障,則需要啟動另一個容器。如果系統處理此行為,會不會更容易?
這就是 Kubernetes 的救援方法!Kubernetes 為您提供了一個可彈性執行分散式系統的框架。Kubernetes 會滿足您的擴充套件要求、故障轉移、部署模式等。例如,Kubernetes 可以輕鬆管理系統的 Canary 部署。
Kubernetes 為您提供:
-
服務發現和負載均衡
Kubernetes 可以使用 DNS 名稱或自己的 IP 地址公開容器,如果到容器的流量很大,Kubernetes 可以負載均衡並分配網路流量,從而使部署穩定。 -
儲存編排
Kubernetes 允許您自動掛載您選擇的儲存系統,例如本地儲存、公共雲提供商等。 -
自動部署和回滾
您可以使用 Kubernetes 描述已部署容器的所需狀態,它可以以受控的速率將實際狀態更改為所需狀態。例如,您可以自動化 Kubernetes 來為您的部署建立新容器,刪除現有容器並將它們的所有資源用於新容器。 -
自動二進位制打包
Kubernetes 允許您指定每個容器所需 CPU 和記憶體(RAM)。當容器指定了資源請求時,Kubernetes 可以做出更好的決策來管理容器的資源。 -
自我修復
Kubernetes 重新啟動失敗的容器、替換容器、殺死不響應使用者定義的執行狀況檢查的容器,並且在準備好服務之前不將其通告給客戶端。 -
金鑰與配置管理
Kubernetes 允許您儲存和管理敏感資訊,例如密碼、OAuth 令牌和 ssh 金鑰。您可以在不重建容器映象的情況下部署和更新金鑰和應用程式配置,也無需在堆疊配置中暴露金鑰。
二、搭建Kubernetes叢集
如何搭建?
參考:睿雲智合 圖形化Kubernetes叢集部署工具、和我一步步部署 kubernetes 叢集
我這裡是根據睿雲智合一步一步搭建的,它提供了圖形化介面,適合初學者搭建一個環境
搭建一個Kubernetes叢集(整個元件的基礎設施包含k8s叢集等各種監控運維元件)需要如下節點資訊:
序號 | 主機名 | 角色 | CPU | 記憶體 | OS | 部署元件 |
---|---|---|---|---|---|---|
1 | breeze-deploy | 部署節點 | 4核 | 8G | CentOS-7.6-x64 | docker/docker-compose/breeze |
2 | k8s-master01 | k8s主節點 | 4核 | 16G | CentOS-7.6-x64 | docker/master元件/etcd/haproxy/keepalive/prometheus |
3 | k8s-master02 | k8s主節點 | 4核 | 16G | CentOS-7.6-x64 | docker/master元件/etcd/haproxy/keepalive/prometheus |
4 | k8s-master03 | k8s主節點 | 4核 | 16G | CentOS-7.6-x64 | docker/master元件/etcd/haproxy/keepalive/prometheus |
5 | k8s-worker01 | k8s工作節點 | 8核 | 32G | CentOS-7.6-x64 | docker/worker元件/prometheus/grafana/altermanager |
6 | k8s-worker02 | k8s工作節點 | 8核 | 32G | CentOS-7.6-x64 | docker/worker元件/prometheus/grafana/altermanager |
7 | k8s-worker03 | k8s工作節點 | 8核 | 32G | CentOS-7.6-x64 | docker/worker元件/prometheus/grafana/altermanager |
8 | k8s-worker04 | k8s工作節點 | 8核 | 32G | CentOS-7.6-x64 | docker/worker元件/prometheus/grafana/altermanager |
9 | k8s-worker05 | k8s工作節點 | 8核 | 32G | CentOS-7.6-x64 | docker/worker元件/prometheus/grafana/altermanager |
10 | k8s-worker06 | k8s工作節點 | 8核 | 32G | CentOS-7.6-x64 | docker/worker元件/prometheus/grafana/altermanager |
11 | harbor | 映象倉庫節點 | 4核 | 16G | CentOS-7.6-x64 | harbor |
12 | VIP | 3臺k8s master節點的高可用虛擬浮動IP地址 |
master元件:kube-apiserver、kube-controller-manager、kube-scheduler
worker元件:kubelet、kube-proxy
備註:
- 適合的作業系統:RHEL/CentOS: 7.4/7.5/7.6/7.7/7.8、Ubuntu 16/18
- 部署節點請儘量保證其為裸機,配置最低為2核4G
- 磁碟每個節點都儘量大一點60G+
- 為了保證K8S的高可用性,需要為所有的master節點繫結一個VIP
本人在本地採用虛擬機器部署方式如下(不推薦):
主機名 | 角色 | IP | OS | CPU | 記憶體 | 磁碟 | 部署元件 |
---|---|---|---|---|---|---|---|
breeze-deploy | 部署節點 | 192.168.47.130 | CentOS-7.8-x64 | 2核 | 2G | 20G | docker/docker-compose/breeze |
k8s-master01 | k8s主節點 | 192.168.47.131 | CentOS-7.8-x64 | 2核 | 4G | 20G | k8s master元件/etcd |
k8s-worker01 | k8s工作節點 | 192.168.47.132 | CentOS-7.8-x64 | 2核 | 4G | 20G | k8s worker元件/prometheus |
harbor | 映象倉庫節點 | 192.168.47.133 | CentOS-7.8-x64 | 2核 | 2G | 20G | harbor |
遇到的問題
-
Kubernetes建立Pod時從Harbor倉庫拉取映象出現‘沒有許可權’
生成的登入的資訊
$ docker login --username=admin 192.168.47.133 # 登入映象倉庫 $ cat ~/.docker/config.json # 登入後生成的登入資訊存放於該檔案 $ cat ~/.docker/config.json | base64 -w 0 # 使用base64加密生成金鑰
建立harbor-secret.yaml檔案,內容如下:
apiVersion: v1 kind: Secret metadata: name: adminsecret # 金鑰名稱 data: .dockerconfigjson: *** # 輸入上面生產的金鑰 type: kubernetes.io/dockerconfigjson
生成Secret物件
$ kubectl create -f harbor-secret.yam # 建立Secret物件
然後在Pod的模板檔案中新增
spec: imagePullSecrets: - name: adminsecret # 拉取映象時使用 adminsecret Secret 物件
-
如果Harbor映象倉庫所在節點的磁碟滿了,會導致Harbor頁面無法登入
先對該節點進行擴容,參考centos虛擬機器擴充套件磁碟空間(經歷無數坑,血一樣總結,史上最全)並結合評論區對該節點進行擴容
因為上面需要先關閉虛擬機器,所以需要再重新啟動Harbor
$ find / -name docker-compose.yml # 找到 Harbor 的配置檔案後進入該目錄 $ docker-compose down # 關閉 Harbor $ ./prepare # 進行準備工作,建立相應的配置檔案 $ docker-compose up -d # 以後臺方式啟動 Harbor
三、Pod
Pod是Kubernetes建立或部署的最小/最簡單的基本單位,一個Pod代表叢集上正在執行的一個程式。
一個Pod封裝一個應用容器(也可以有多個容器),儲存資源、一個獨立的網路IP以及管理控制容器執行方式的策略選項。Pod代表部署的一個單位:Kubernetes中單個應用的例項,它可能由單個容器或多個容器共享組成的資源。
3.1 配置示例
apiVersion: v1 # 1.9.0 之前的版本使用 apps/v1beta2,可通過命令 kubectl api-versions 檢視
kind: Pod # 指定建立資源的角色/型別
metadata: # 資源的後設資料/屬性
name: nginx # 資源的名字,在同一個namespace中必須唯一
labels:
app: nginx1.19.1 # 標籤
spec: # 模板的規範
containers:
- name: nginx # 容器的名字
image: 192.168.47.133/dwzq-info/nginx:v1.19.1 # 容器的映象地址
imagePullPolicy: IfNotPresent
# IfNotPresent:預設值,本地有則使用本地映象,不拉取,如果不存在則拉取
# Always:總是拉取
# Never:只使用本地映象,從不拉取
ports:
- name: http
containerPort: 8085 # 對service暴露埠
resources: # 資源限制標籤
requests: # 建立pod時向k8s請求的資源大小
memory: "64Mi"
cpu: "250m"
limits: # 執行中pod的最大資源空間
memory: "64Mi"
cpu: "250m"
restartPolicy: OnFailure
# Always:當容器停止,總是重建容器(預設)
# OnFailure:當容器異常退出(退出狀態碼非0)時才重啟容器
# Never:從不重啟容器
imagePullSecrets: # 因為我需要從harbor私庫拉取映象,需要配置金鑰,'adminsecret'是我已經建立好的
- name: adminsecret
3.2 建立pod的流程
描述:- 客戶端通過kubectl命令,或者通過API Server的Restful API(支援json和yaml格式)發起建立一個Pod請求;
- API Server處理使用者請求,儲存Pod資訊資料到etcd叢集中;
- Scheduler排程器通過API Server檢視未繫結的Pod,嘗試為Pod進行分配主機,通過排程演算法選擇主機後,繫結到這臺機器上並且把排程資訊寫入etcd叢集;
- Kubelet根據排程結果執行Pod建立操作,成功後將資訊通過API Server更新到etcd叢集中;
- 整個Pod建立過程完成,每個元件都在於API Server進行互動,API Server就是k8s叢集的中間者,元件之間的協同者,是一個叢集訪問入口
3.3 控制器
-
ReplicaSet
代使用者建立指定數量的pod副本數量,確保pod副本數量符合預期狀態,並且支援滾動式自動擴容和縮容功能。
ReplicaSet主要三個元件組成:- 使用者期望的pod副本數量
- 標籤選擇器,判斷哪個pod歸自己管理
- 當現存的pod數量不足,會根據pod資源模板進行新建幫助使用者管理無狀態的pod資源,精確反應使用者定義的目標數量,但是RelicaSet不是直接使用的控制器,而是使用Deployment。
-
Deployment
工作在ReplicaSet之上,用於管理無狀態應用,目前來說最好的控制器。支援滾動更新和回滾功能,還提供宣告式配置。 -
DaemonSet
用於確保叢集中的每一個節點只執行特定的pod副本,通常用於實現系統級後臺任務,比如ingress,elk.服務是無狀態的,服務必須是守護程式。參考文章:https://www.cnblogs.com/xzkzzz/p/9553321.html -
Job
只要任務或程式執行完成就立即退出,不需要重啟或重建。 參考文章:https://blog.csdn.net/bbwangj/article/details/82011610 -
Cronjob
週期性任務控制,執行後就退出, 不需要持續後臺執行, 參考文章:https://blog.csdn.net/bbwangj/article/details/82867830 -
StatefulSet
管理有狀態應用,比如redis,mysql
3.4 常用命令
$ kubectl create -f pod.yaml # 建立Pod資源
$ kubectl get pods nginx-pod # 檢視pods
$ kubectl describe pod/nginx # 檢視pod描述
$ kubectl apply -f pod.yaml # 更新資源
$ kubectl delete -f pod.yaml # 刪除資源
$ kubectl delete pods nginx-pod # 刪除資源
$ kubectl logs -f pod/nginx # 檢視日誌
$ kubectl exec -it pod/nginx /bin/bash # 進入容器
四、Deployment
- 使用Deployment來建立ReplicaSet(升級版的ReplicationController),ReplicaSet在後臺建立pod。檢查啟動狀態,看它是成功還是失敗。
- 通過更新Deployment的PodTemplateSpec欄位來宣告Pod的新狀態。這會建立一個新的ReplicaSet,Deployment會按照控制的速率將pod從舊的ReplicaSet移動到新的ReplicaSet中。
- 如果當前狀態不穩定,回滾到之前的Deployment revision。每次回滾都會更新Deployment的revision。
- 擴容Deployment以滿足更高的負載。
- 暫停Deployment來應用PodTemplateSpec的多個修復,然後恢復上線。
- 根據Deployment 的狀態判斷上線是否hang住了。
- 清除舊的不必要的ReplicaSet
4.1 配置示例
apiVersion: apps/v1 # 1.9.0之前的版本使用 apps/v1beta2,可通過命令 kubectl api-versions 檢視
kind: Deployment # 指定建立資源的角色/型別
metadata: # 資源的後設資料/屬性
name: nginx-deployment # 資源的名字,在同一個namespace中必須唯一
namespace: default # 名稱空間,預設為default
labels:
app: nginx1.19.0 # 標籤
spec:
replicas: 3 # 副本數量3
strategy:
rollingUpdate: # 由於replicas為3,則整個升級,pod個數在2-4個之間
maxSurge: 1 # 滾動升級時會先啟動1個pod
maxUnavailable: 1 # 滾動升級時允許的最大Unavailable的pod個數
selector: # 定義標籤選擇器,部署需要管理的pod(帶有該標籤的的會被管理)需在pod 模板中定義
matchLabels:
app: nginx1.19.0
template: # 從這裡開始是Pod的定義
metadata:
labels: # Pod的label
app: nginx1.19.0
spec: # 模板的規範
containers:
- name: nginx # 容器的名字
image: 192.168.47.133/dwzq-info/nginx:v1.19.0 # 容器的映象地址
# command: [ "/bin/sh","-c","cat /etc/config/path/to/special-key" ] # 啟動命令
args: # 啟動引數
- '-storage.local.retention=$(STORAGE_RETENTION)'
- '-storage.local.memory-chunks=$(STORAGE_MEMORY_CHUNKS)'
- '-config.file=/etc/prometheus/prometheus.yml'
- '-alertmanager.url=http://alertmanager:9093/alertmanager'
- '-web.external-url=$(EXTERNAL_URL)'
# 如果command和args均沒有寫,那麼用Docker預設的配置。
# 如果command寫了,但args沒有寫,那麼Docker預設的配置會被忽略而且僅僅執行.yaml檔案的command(不帶任何引數的)。
# 如果command沒寫,但args寫了,那麼Docker預設配置的ENTRYPOINT的命令列會被執行,但是呼叫的引數是.yaml中的args。
# 如果如果command和args都寫了,那麼Docker預設的配置被忽略,使用.yaml的配置。
imagePullPolicy: IfNotPresent
# IfNotPresent:預設值,本地有則使用本地映象,不拉取,如果不存在則拉取
# Always:總是拉取
# Never:只使用本地映象,從不拉取
livenessProbe:
# 表示container是否處於live狀態。如果LivenessProbe失敗,將會通知kubelet對應的container不健康了,
# 隨後kubelet將kill掉container,並根據RestarPolicy進行進一步的操作。
# 預設情況下LivenessProbe在第一次檢測之前初始化值為Success,
# 如果container沒有提供LivenessProbe,則也認為是Success;
# readinessProbe:如果檢查失敗,Kubeneres會把Pod從service endpoints中剔除。
httpGet:
path: / # 如果沒有心跳檢測介面就為/
port: 8080
scheme: HTTP
initialDelaySeconds: 60 # 啟動後延時多久開始執行檢測
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
ports:
- name: http
containerPort: 8085 # 對service暴露埠
resources: # CPU記憶體限制
requests:
cpu: 2
memory: 2048Mi
limits:
cpu: 2
memory: 2048Mi
env: # 通過環境變數的方式,直接傳遞pod=自定義Linux OS環境變數
- name: LOCAL_KEY # 本地Key
value: value
- name: CONFIG_MAP_KEY # 局策略可使用configMap的配置Key,
valueFrom:
configMapKeyRef:
name: special-config # configmap中找到name為special-config
key: special.type # 找到name為special-config裡data下的key
volumeMounts: # 掛載volumes中定義的磁碟
- name: log-cache
mount: /tmp/log
- name: sdb # 普通用法,該卷跟隨容器銷燬,掛載一個目錄
mountPath: /data/media
- name: nfs-client-root # 直接掛載硬碟方法,如掛載下面的nfs目錄到/mnt/nfs
mountPath: /mnt/nfs
- name: rbd-pvc # 高階用法第2中,掛載PVC(PresistentVolumeClaim)
volumes: # 定義磁碟給上面volumeMounts掛載
- name: log-cache
emptyDir: {}
- name: sdb # 掛載宿主機上面的目錄
hostPath:
path: /any/path/it/will/be/replaced
- name: nfs-client-root # 供掛載NFS儲存型別
nfs:
server: hostaddr # NFS伺服器地址
path: /opt/public # showmount -e 看一下路徑
- name: rbd-pvc # 掛載PVC磁碟
persistentVolumeClaim:
claimName: rbd-pvc1 # 掛載已經申請的PVC磁碟
4.2 相關使用
建立
$ kubectl create -f deployment.yaml --record # --record 為True,在annotation中記錄當前命令建立或者升級了該資源,如檢視在每個Deployment revision中執行了哪些命令
$ kubectl get deployments -n default -o wide # 獲取Deployments資訊
$ kubectl get rs -n default -o wide # 獲取Replica Set資訊,名字總是<Deployment的名字>-<pod template的hash值>
$ kubectl get pods -n default -o wide --show-labels # 獲取Pod資訊
更新
注意: Deployment的rollout當且僅當Deployment的pod template(例如.spec.template)中的label更新或者映象更改時被觸發。其他更新,例如擴容Deployment不會觸發rollout。
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1 # 更新映象
$ kubectl edit deployment/nginx-deployment # 或使用edit命令來編輯Deployment模板,儲存後即更新
$ kubectl rollout status deployment/nginx-deployment # 檢視rollout狀態
回退
$ kubectl describe deployment # 檢視狀態
$ kubectl rollout history deployment/nginx-deployment # 檢查Deployment升級的歷史記錄
$ kubectl rollout history deployment/nginx-deployment --revision=1 # 檢視某個revision的詳細資訊
$ kubectl rollout undo deployment/nginx-deployment # 回退當前的rollout到之前的版本
$ kubectl rollout undo deployment/nginx-deployment --to-revision=1 # 回退當前的rollout到某個歷史版本
擴容
$ kubectl scale deployment nginx-deployment --replicas 3 # 擴容,指定執行的副本
# 基於當前Pod的CPU利用率選擇最少和最多的Pod數(需啟用horizontal pod autoscaling)
$ kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80
暫停和恢復
$ kubectl get deployment # 檢視deployment列表(default namespace)
$ kubectl rollout pause deployment/nginx-deployment # 暫停deployment
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.19.1 # 更新映象
# 恢復之前可以多次進行更新操作,在恢復之前更新過程不會產生任何影響(前提是已暫停)
$ kubectl rollout resume deployment/nginx-deployment # 恢復deployment
五、StatefulSet
StatefulSet 是Kubernetes中的一種控制器,在很多的分散式應用場景中,他們各個例項之間往往會有對應的關係,例如:主從、主備。還有資料儲存類應用,它的多個例項,往往會在本地磁碟存一份資料,而這些例項一旦被殺掉,即使重建起來,例項與資料之間關係也會丟失,而這些例項有不對等的關係,例項與外部儲存有依賴的關係的應用,被稱作“有狀態應用”。StatefulSet與Deployment相比,相同於他們管理相同容器規範的Pod,不同的是,StatefulSet為Pod建立一個持久的識別符號,他可以在任何編排的時候得到相同的識別符號。
說明:進行下述操作前請先準備好2個1G的PersistentVolumes儲存卷
5.1 配置示例
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
type: "ClusterIP" # 預設服務型別
ports:
- port: 80
name: web
selector:
app: nginx
clusterIP: "None" # 建立 Headless Service
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: k8s.gcr.io/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates: # 生成PVC
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
六、Service
Kubernetes Pod 是有生命週期的。 它們可以被建立,而且銷燬之後不會再啟動。 如果您使用 Deployment 來執行您的應用程式,則它可以動態建立和銷燬 Pod。
每個 Pod 都有自己的 IP 地址,但是在 Deployment 中,在同一時刻執行的 Pod 集合可能與稍後執行該應用程式的 Pod 集合不同。
這導致了一個問題: 如果一組 Pod(稱為“後端”)為群集內的其他 Pod(稱為“前端”)提供功能, 那麼前端如何找出並跟蹤要連線的 IP 地址,以便前端可以使用工作量的後端部分?
Kubernetes Service,一個 Pod 的邏輯分組(Endpoint),一種可以訪問它們的策略(負載均衡),通常稱為微服務,這一組 Pod 能夠被 Service 訪問(服務發現,支援環境變數和DNS模式),通常是通過 Label Selector。
6.1 配置示例
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: default
spec:
selector: # 指定標籤 app:nginx1.19.0 來進行對Pod進行關聯(也就是上面Deployment配置裡labels定義的標籤 )
app: nginx1.19.0
ports:
- protocol: TCP
port: 8085 # 需要暴露的叢集埠(service暴露的)
targetPort: 8085 # 容器的埠(後端容器提供服務的埠)
nodePort: 30000 # 對映到物理機的埠(30000-32767),不填則隨機對映
type: NodePort
對映到物理機的埠範圍為:30000-32767
暴露的埠在Node節點上由kube-proxy來啟動並監聽的,可通過
kube-proxy是如何代理訪問到容器的呢?
因為kube-proxy在啟動的時候通過--proxy-mode=ipvs可以指定底層核心代理模式,預設是iptables進行代理轉發,kube-proxy通過這兩種模式來進行代理轉發,kube-proxy通過這兩種模式來代理直接對外提供服務。
6.2 服務型別
Service型別:ClusterIP(預設)、NodePort、LoadBalancer、ExternalName
-
ClusterIP
通過叢集的內部 IP 暴露服務,選擇該值,服務只能夠在叢集內部(同namespace內的pod)可以訪問,不對外提供訪問服務,這也是預設的服務型別。 -
NodePort
通過每個 Node 上的 IP 和靜態埠(NodePort)暴露服務。 NodePort 服務會路由到 ClusterIP 服務,這個 ClusterIP 服務會自動建立。 通過請求: ,可以從叢集的外部訪問一個 NodePort 服務。 -
LoadBalancer
使用雲提供商的負載局衡器,可以向外部暴露服務。 外部的負載均衡器可以路由到 NodePort 服務和 ClusterIP 服務,適用於雲平臺,AWS預設支援。
6.3 常用命令
kubectl get service -o wide # service可以使用縮寫svc,-n指定名稱空間,預設default
kubectl describe service nginx-service
6.4 代理模式
userspace模式
這種模式,kube-proxy 會監視 Kubernetes master 對 Service 物件和 Endpoints 物件的新增和移除。 對每個 Service,它會在本地 Node 上開啟一個埠(隨機選擇)。 任何連線到“代理埠”的請求,都會被代理到 Service 的 Backend Pods 中的某個上面(如 Endpoints 所報告的一樣)。 使用哪個 Backend Pod,是基於 Service 的 SessionAffinity 來確定的。 最後,它安裝 iptables 規則,捕獲到達該 Service 的 ClusterIP(虛擬 IP)和 Port 的請求,並重定向到代理埠,代理埠再代理請求到 Backend Pod。
網路返回的結果是,任何到達 Service 的 IP:Port 的請求,都會被代理到一個合適的 backend,不需要客戶端知道關於 Kubernetes、Service、或 Pod 的任何資訊。
預設的策略是,通過 round-robin 演算法來選擇 backend Pod。 實現基於客戶端 IP 的會話親和性,可以通過設定 service.spec.sessionAffinity 的值為 "ClientIP" (預設值為 "None")。
iptables模式
這種模式,kube-proxy 會監視 Kubernetes master 對 Service 物件和 Endpoints 物件的新增和移除。 對每個 Service,它會安裝 iptables 規則,從而捕獲到達該 Service 的 ClusterIP(虛擬 IP)和埠的請求,進而將請求重定向到 Service 的一組 Backend Pod 中的某個上面。 對於每個 Endpoints 物件,它也會安裝 iptables 規則,這個規則會選擇一個 Backend Pod。
預設的策略是,隨機選擇一個 backend。 實現基於客戶端 IP 的會話親和性,可以將 service.spec.sessionAffinity 的值設定為 "ClientIP" (預設值為 "None")。
和 userspace 代理類似,網路返回的結果是,任何到達 Service 的 IP:Port 的請求,都會被代理到一個合適的 backend,不需要客戶端知道關於 Kubernetes、Service、或 Pod 的任何資訊。 這應該比 userspace 代理更快、更可靠。然而,不像 userspace 代理,如果初始選擇的 Pod 沒有響應,iptables 代理能夠自動地重試另一個 Pod,所以它需要依賴 readiness probes。
IPVS模式
在 ipvs 模式下,kube-proxy監視Kubernetes服務和端點,呼叫 netlink 介面相應地建立 IPVS 規則, 並定期將 IPVS 規則與 Kubernetes 服務和端點同步。 該控制迴圈可確保IPVS 狀態與所需狀態匹配。訪問服務時,IPVS 將流量定向到一組 Backend Pod 中的某個上面。
IPVS代理模式基於類似於 iptables 模式的 netfilter 掛鉤函式, 但是使用雜湊表作為基礎資料結構,並且在核心空間中工作。 這意味著,與 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通訊的延遲要短,並且在同步代理規則時具有更好的效能。 與其他代理模式相比,IPVS 模式還支援更高的網路流量吞吐量。
IPVS提供了更多選項來平衡後端Pod的流量。 提供如下排程演算法:
rr
: round-robinlc
: least connection (smallest number of open connections)dh
: destination hashingsh
: source hashingsed
: shortest expected delaynq
: never queue
說明:
要在 IPVS 模式下執行 kube-proxy,必須在啟動 kube-proxy 之前使 IPVS Linux 在節點上可用。
當 kube-proxy 以 IPVS 代理模式啟動時,它將驗證 IPVS 核心模組是否可用。 如果未檢測到 IPVS 核心模組,則 kube-proxy 將退回到以 iptables 代理模式執行。
在這些代理模型中,繫結到服務IP的流量: 在客戶端不瞭解Kubernetes或服務或Pod的任何資訊的情況下,將Port代理到適當的後端。 如果要確保每次都將來自特定客戶端的連線傳遞到同一 Pod, 則可以通過將 service.spec.sessionAffinity
設定為 "ClientIP" (預設值是 "None"),來基於客戶端的 IP 地址選擇會話關聯。
您還可以通過適當設定 service.spec.sessionAffinityConfig.clientIP.timeoutSeconds
來設定最大會話停留時間。 (預設值為 10800 秒,即 3 小時)。
七、Ingress
Ingress公開了從叢集外部到叢集內服務(Service)的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 資源上定義的規則控制。
internet
|
[ Ingress ]
--|-----|--
[ Services ]
可以將 Ingress 配置為服務提供外部可訪問的 URL、負載均衡流量、終止 SSL/TLS,以及提供基於名稱的虛擬主機等能力。 Ingress 控制器 通常負責通過負載均衡器來實現 Ingress,儘管它也可以配置邊緣路由器或其他前端來幫助處理流量。
你必須具有 Ingress 控制器才能滿足 Ingress 的要求。 僅建立 Ingress 資源本身沒有任何效果。
你可能需要部署 Ingress 控制器,例如 ingress-nginx。 你可以從許多 Ingress 控制器 中進行選擇。
理想情況下,所有 Ingress 控制器都應符合參考規範。但實際上,不同的 Ingress 控制器操作略有不同。
示例
foo.bar.com -> 192.168.47.131 -> / foo service1:4200
/ bar service2:8080
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-example
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
backend:
serviceName: service1
servicePort: 4200
- path: /bar
backend:
serviceName: service2
servicePort: 8080
八、日誌收集
進行中