文章目錄
- 1. Kubernetes簡介
- 2. Kubernetes組件結構與基本概念
- 2.1 結構
- 2.2 核心組件
- 2.2.1 K8s API server
- 2.2.2 Controller Manager
- 2.2.3 Scheduler調度器
- 2.2.4 kubelet
- 2.2.5 kubernetes Service Proxy
- 2.3 基本概念
- 3. 資源對象定義基本與常用命令
- 4. Pod詳細
- 4.1 pod基本
- 4.2 Pod配置與卷掛載
- 4.3 Pod生命週期、重啓策略、可用性檢查、優雅退出
- 4.4 Pod調度
- 4.5 Pod複雜調度
- 4.6 pod升級、回滾、擴縮容
- 4.7 有狀態的副本集合StatefulSet
- 5. 服務詳細
- 6. 共享存儲
- 7. 參考
- 8. 歡迎關注公衆號
1. Kubernetes簡介
1.1 是什麼
-
基於容器技術的分佈式架構方案,源自谷歌內部的大規模集羣管理系統Borg
-
希臘語,領航員;抽象數據a中心的硬件基礎設施,對外暴露的是巨大的資源池
1.2 用途
- 單體應用=>微服務:單機=>集羣管理,應用內耦合=>不便維護=>拆解服務=>微服務架構;
- 微服務部署難點:環境需求的差異、持續交付的需求=>容器(單容器單進程模型)=>集羣資源的自動化管理和大量容器應用的自動化部署
- 核心功能:集中一切資源、提高資源利用率、幫助開發聚焦核心應用(遠離服務發現、擴容、基礎設施)、健康檢查和自我修復、自動擴容、簡化部署
2. Kubernetes組件結構與基本概念
2.1 結構
- Master(主節點、控制平面、1-3臺物理主機):整個集羣的控制節點,以單進程的形式運行多個組件:
- kubernetes API server:提供HTTP Rest接口,集羣內增刪改查的唯一入口,集羣控制的唯一入口
- Kubernetes Controller Manager:所有資源的自動化控制中心
- kubernetes Scheduler:資源調度器,自動化分配pod
- etcd持久化存儲服務:存儲所有資源對象的數據
- Node(工作節點,一臺物理主機):運行一定的工作負載(pod),
- kubelet: 負責pod對應的容器的創建、啓停任務;與master協作,實現集羣整體的基本管理
- kube-proxy:實現k8s service的通信與負載均衡機制的重要組件
- 容器引擎:docker,負責容器創建和管理
- 除了上述組件的附加組件:
- k8s dns
- dashboard
- Ingress控制器
- Heapster
- CNI插件
- 關於組件
- 單組件多實例:工作節點的組件運行在一臺機器上,master節點上的組件除了調度器和controller manager同一時間只能有一個實例起作用外,其餘組件可以以單組件多實例並行運行的模式運行在多臺機器上
- 組件如何運行:除了kubelet是系統組件,其他組件作爲pod運行;可以在kube-system namespace下查看
2.2 核心組件
2.2.1 K8s API server
-
集羣數據唯一訪問入口
-
安全:HTTPS安全傳輸與CA簽名數字證書強制雙向認證
-
RBAC訪問控制策略
-
api層(Restful api 接口:get list watch)->訪問控制(鑑權、覈准訪問權)->註冊表層(保存所有資源對象,如何創建對象、轉換資源不同版本)->etcd數據庫(存儲kv數據,提供watch接口以實現List Watch機制)
-
此外還有kube proxy api 接口,通過FQDN(全限定域名)轉發請求到特定pod、服務,例如:
curl http://master-ip:8080/api/v1/proxy/namespaces/default/pods/my-pod-name/
訪問對應的pod
2.2.2 Controller Manager
-
各種資源的Controller通過設置資源的期望狀態、watch資源對象事件自動化管理資源對象;controller manager則負責管理這些controller
-
常見的有:replication controller\node controller\resourceQuota controller\namespace controller\service controller\endpoints controller\pv controller
2.2.3 Scheduler調度器
-
負責pod的調度:接收controller要求創建pod的信號,在node list中選取合適的node分配pod,最後由node上的kubelet實際創建管理pod
-
調度流程:
- 預選調度(xxx predicates預選策略選出候選節點):內置多個預選算法,以插件形式註冊在系統中;包含資源要求的相互匹配、標籤選擇是否滿足、端口是否被佔用、使用卷要求、是否容忍節點污點、是否符合親緣性非親緣性要求
- 確定最優節點 (xxx Priority優選策略計算節點積分,選取積分最高的節點)
2.2.4 kubelet
- 註冊節點到master
- 管理pod:創建、停止、健康檢查(探針)
2.2.5 kubernetes Service Proxy
- 確保對服務ip和端口的某個連接最終會到達某個pod,同時負責負載均衡
- 功能:
- 起初,kube proxy是真實的tcp/udp代理:pod用cluster IP訪問某個服務->流量被本機的iptables轉發到本機的kube-proxy->kube-proxy建立到後端pod的tcp/udp連接
- 1.2版本後,kube-proxy只負責監聽service\endpoints的變更信息,更新iptables,流量則通過iptables的nat機制直接路由到目標pod;相比前一個方式,iptables的轉發操作不需要經過kube-proxy,效率更高
- 進一步,iptables規則膨脹後效率降低,目前使用第三種方式,使用IPVS(IP virtual Server)+ipset,IPVS同樣基於內核的netfilter(提供網絡協議棧上的操作掛載點,在各個階段放置hook函數,處理、轉發、丟棄流量數據)實現,但是ipVS專門用於高性能負載均衡,並且使用hash表,易於擴張。ipset是iptables的擴展(iptables是線性結構,ipset具有索引)
2.3 基本概念
- Master:集羣控制節點
- Node:工作節點
- Pod:工作負載的基本單元
- pod內有一個或者多個業務相關的容器
- 結構上,有一個根容器pause容器;業務容器共享pause容器的ip\掛接的卷資源,pause容器的狀態與業務容器無關,代表了整個pod的狀態(某個具體業務容器的死亡,不能影響整個pod的狀態判斷,因而採用此結構;所有資源基於pause容器,簡化了共享資源時發生的容器通信過程)。
- pod分爲靜態和動態,靜態pod數據不存放在master上,而是放在node上的具體文件中,只存在此node上,無法被調度
- pod中一個容器死亡會重啓整個pod;所在的node死亡則重新調度到別的node
- Label:標籤,一組鍵值對,可以標記版本、環境、架構、分區、質量管控、開發階段;資源對象之間可以通過標籤選擇器進行相互匹配
- Replication Controller: rc,定義了一個期望場景:
- pod期待的副本數量
- 篩選pod的標籤
- 創建、恢復pod的pod template
- 可以通過命令進行pod的滾動升級。
- 已廢棄,繼任者:replicaSet\depeloyment,rc的命令基本使用於rs,rs標籤選擇功能更豐富,而deplyment則是更高一級的資源,隱藏管理rs的細節,提供自動化的pod創建、刪除、更新的機制
- deplyment
- horizontal pod autoscaler:hpa,pod橫向自動擴容,追蹤分析rc控制的pod的負載情況,確定是否調整副本數量。
- 指標:cpu平均利用率(已使用/request)、自定義的度量指標(tps,qps)
- StatefulSet:rc,rs,deployment,daemonset、job都是面向無狀態的,statefulset是有狀態的
- 每個pod都有穩定、唯一的網絡標識,例如ss-0,ss-1
- pod的啓停順序受控,操作第n個pod時,前n-1個必然已經是運行且ready的狀態
- pod採用持久化存儲,刪除pod不會刪除相關的存儲卷(爲了數據安全)
- 需要與headless service配合使用,訪問其中的pod需要使用唯一的dns域名
- service:服務入口,
- 通過endpoint訪問後端的pod
- 服務發現:
- 內部:唯一的cluster IP和service name,通過dns服務訪問
- 外部:NodePort、LB
- job:批處理任務,處理work item
- job控制的容器短暫運行,僅運行一次,失敗後不重啓====>cronJob,定時啓動
- 可以多實例並行處理
- namespace:資源隔離,資源可見行
- annotation:註解,kv對,通常可以記輔助信息
- 存儲\數據、配置相關:
- Volume:卷,emtpyDir gitrepo hostpath…
- Persistent Volume:pv 持久卷
- 網絡存儲
- 定義在pod之外
- 可以定義訪問模式,通過pvc引用
- configmap:配置集中化,配置存儲在etcd中,聲明configmap對象定義配置,pod可以掛載configmap將配置映射到容器中;如果需要加密,可以使用Secret
3. 資源對象定義基本與常用命令
3.1 YAML文件
-
K8s內所有的資源對象都是使用YAML文件定義的;Yaml Ain’t Markup Language(發音
/ˈjæməl/
) -
基本語法:
- 大小寫敏感
- 縮進表示層級關係
- 縮進時不允許使用tab鍵,縮進的空格數沒有約束,同一層級的空格數一樣
- #表示註釋
-
支持的數據結構
-
對象:鍵值對的集合
- eg:
name: jeff
,或者同一個對象所有的鍵值對寫在一行:postions: {home: 0, company: 1}
- eg:
-
數組:一組按次序排列的值
-
一組連詞線開頭的行,構成一個數組:
- cat - dog - goldfish # 子成員也可以是一個數組 - - pig1 - pig2 - pig3 # 也可以行內 animal: [cat, dog]
-
-
純標量 scalars:單個不可分割的值
- 字符串、布爾、整數、浮點、Null、時間、日期
- 兩個感嘆號可以用來進行強制類型轉換
- 字符串默認不需要使用引號,雙引號會對特殊字符轉義,單引號不會;字符串可以多行,但是第二行開始,每一行之前要有一個空格,換行符會被轉義稱空格,
|
、>
可以用來保留換行、摺疊換行;+ -
可以用來表述是否保留換行符
-
錨點&和別名*,可以用來引用
-
3.2 K8s資源對象普遍格式
- 指定api版本,
- 資源對象的類型:kind
- metadata:包含名稱、命名空間、標籤和關於容器的其他信息
- spec包含pod內容的實際說明,例如pod的容器、卷和其他數據
- status包含運行中的資源的當前信息,例如pod所處的條件、每個容器的描述和狀態以及內部IP和其他基本信息
可以通過kubectl explain
命令發現資源對象定義所需要的字段信息eg:kubectl explain pod.spec
4. Pod詳細
4.1 pod基本
- 單容器單進程模型=>需要一種更高級別的結構將容器組合在一起作爲一個單位=>pod:爲一些密切相關的進程提供幾乎相同的環境,使得它們環境一致的同時又保持相對隔離
- pod中如何設置容器:
- 將多層應用分散在多個容器中:例如前後端
- 基於擴縮容考慮而分割到多個pod中:具有相近擴縮容需求的容器放一起
- 一個pod多個容器的模式通常爲一個主進程+多個輔助進程
- 靜態Pod:僅存在於特定Node的pod,無法被高一級的資源對象管理
- 配置文件方式:設置kubelet的啓動參數
--config
,kubelet會定期讀取該目錄,如果有配置文件,則啓動對應的pod.如果需要刪除pod,刪除配置文件即可。api server是無法刪除這個pod的,但是能查看這個pod的狀態 - Http方式,設置kubelet的啓動參數
--manifest-url
,則會定期從接口上拉取配置文件
- 配置文件方式:設置kubelet的啓動參數
**注意事項:**Docker會根據pid=1的進程的狀態來判斷容器的狀態,因此如果bash運行腳本時,bash進程是第一個進程,pid=1;運行完腳本,bash就會退出;如果pod此時被高一級的資源託管,可能會出現反覆啓動、停止的死循環。解決辦法是讓應用運行在前臺,如果不能運行在前臺,可以使用類似supervisor這樣的工具輔助進行前臺運行的功能。
4.2 Pod配置與卷掛載
-
pod容器共享Volume:同一個Pod中的多個容器能共享Pod級別的存儲卷Volume,Volume可以有多種類型,各個容器各自進行掛載:
- volumes
- pod模板中定義volumeMounts字段
-
ConfigMap:集中式的配置管理使得應用和配置分離。應用方便服用,配置也更靈活;Configmap存儲kv對,也可以表示一個完整配置文件的內容的內容
-
ConfigMap典型用法:
- 生成容器內的環境變量
- 設置容器啓動命令的啓動參數(需要設置爲環境變量)
- 以Volume的形式掛載爲容器內部的文件或者目錄
-
使用:創建COnfigMap對象=>在pod定義中引用configMap
- 作爲環境變量引入env.valueFrom.configMapKeyRef.{name key};envFrom.configMap引用所有鍵值對
- 掛載卷的形式:volumes.configMap.{name items}
-
注意:
- configMap必須在pod創建之前創建
- ConfigMap不能跨namespace
- 靜態pod無法引用configmap
- 掛載時,pod只能掛載其爲目錄,目錄下包含item內容,並且會覆蓋原有目錄下的內容,
-
Download API: pod自身信息的獲取,例如自己的名字、ip、所處的namespace、pod資源使用量、註解和標籤
- 環境變量 resourceFieldRef.xxx
- 卷掛載
-
敏感數據使用Secret,不過Secret只是多了一層base64編碼
4.3 Pod生命週期、重啓策略、可用性檢查、優雅退出
- 生命週期,pod啓動、容器開始運行、退出不完全成功、未知狀態
- Pending
- Running
- Successed
- Failed
- Unknown
- 重啓策略,重啓延遲時間以2N遞增,直到5min,並且在成功後10min重置此時間
- Always: 容器一旦失效,kubelet立馬重啓
- OnFailure: 容器終止運行且退出碼不爲0,kubelet自動重啓
- Never:不重啓
- 容器可用性檢查
- LivenessProbe 存活探針,通過exec http tcp socket三種方式進行存活檢查
- ReadinessProbe 就緒探針,類似,判斷pod是否可用
- 兩者配置類似:initialDelaySeconds,timeoutSeconds
- 複雜場景:Pod Readiness Gates機制
- 容器生命期hook: exec http
- PostStart
- preStop
- Pod的終止過程:一個pod被刪除時,爲了應用能夠優雅的退出,同時pod又被有效的刪除,通常會經歷如下的過程:
- 用戶發送命令刪除pod,默認設置 grace period爲30s
- API服務器中的Pod對象被更新使用寬限時間,超過grace period的時間後,pod將被視爲死亡
- 客戶端查看時,pod狀態變更爲
Teminating
- 與步驟3同時發生:當kubelet發現Pod被標記爲terminating,並且graceful period爲30s時,kubelet開啓pod關閉過程
- 如果pod中的容器定義了
preStop hook
,將被觸發,如果preStop運行超過graceful period,將觸發下一步並延長2s的graceful period - 容器被髮送SigTerm信號
- 如果pod中的容器定義了
- 與步驟3同時發生:pod從各種上級資源對象的列表中移除,正在關閉中的pod也不會接受來自load balancers的流量
- 最終如果還是超過graceful period的時限,pod會被SigKill信號殺死
- Kubelet完成pod刪除過程,grace period被設置爲0,pod對象在api服務器上消失,並且客戶端也無法查看到該對象
- 默認,
graceful period
是30s,如果不想pod優雅的退出,可以--grace-period=0 --force
進行強制刪除,強制刪除不保證應用優雅的結束,需要謹慎使用
4.4 Pod調度
4.4.1 標籤、註解
- 標籤用於組織組員,
metadata.labels
- 展示標籤:
--show-labels
,-l xx_label=xxx
- 利用多個標籤條件,進行篩選
spec.nodeSelector
通過標籤選擇被調度到的節點- 註解:也是一種鍵值對,但是不會用來篩選pod,通常API對象引入新的字段時,會首先放在註解字段
4.4.2 停止和移除Pod
kubectl delete po xx-pod
,kubectl delete po -l xx-label=xx
通過標籤刪除一組pod- 通過刪除命名空間,刪除所有pod,
kubectl delete po --all
- 被rc\rs託管的pod,刪除一個pod立馬會新建另一個,要徹底刪除,需要調整上層資源(刪除所有資源,
kubectl delete all --all
)
4.5 Pod複雜調度
-
副本管理:RC、RS、Deployment:自動部署一個容器應用的多份副本;其中RC目前不推薦用,推薦用Deployment、RS
-
NodeSelector:通過標籤來篩選node,如果指定了pod的nodeselector,但是集羣中不存在包含相應標籤的node,那麼pod無法被成功調度
-
NodeAffinity: Node親和性調度,是用於替換NodeSelector的全新調度策略,有兩種
- RequiredDuringSchedulingIgnoredDuringExecution: 類似nodeSelector的硬性限制,必須被滿足的條件
- PreferredDuringSchedulingIgnoredDuringExecution: 強調優先滿足指定規則,相當於軟限制,多個優先級規則還可以設置權重,以定義執行的先後順序;IgnoredDuringExecution的意思是: 如果一個Pod所在的節點在Pod運行期間標籤發生了變更, 不再符合該Pod的節點親和性需求, 則系統將
忽略Node上Label的變化, 該Pod能繼續在該節點運行 - 如果同時定義了nodeSelector和nodeAffinity,必須兩個條件都滿足才能調度
- 如果nodeAffinity指定了多個nodeSelectorTerms,匹配其中一個即可
- 一個nodeSelectorTerm中有多個matchExpressions,則都滿足才行調度
-
PodAffinity:pod親和與互斥調度(antiAffinity)策略,另一種pod調度方式,通過node上運行的pod的標籤,而不是node的標籤,來進行調度,基本與nodeAffinity類似,其中可以使用topologykey字段來篩選node的範圍。
-
Taints和Tolerations(污點和容忍):之前的是pod如何選擇node,污點則是node是否拒絕pod。Taint需要和Toleration配合使用, 讓Pod避開那些不合適的Node。 在Node上設置一個或多個Taint之後, 除非Pod明確聲明能夠容忍這些污
點, 否則無法在這些Node上運行。 Toleration是Pod的屬性, 讓Pod能夠
(注意, 只是能夠, 而非必須) 運行在標註了Taint的Node上。- node設置污點屬性,pod設置是否能容忍
-
可以自定義驅逐行爲,應對節點故障
-
Pod Priority Preemption: pod優先級調度,某些情況下,系統可以選擇釋放優先級不高的資源,保障最重要的負載能夠獲取足夠的資源穩定運行。定義負載重要性的指標:
- Priority: 優先級
- QoS: 服務質量等裏
- 系統定義的其他度量指標
優先級搶佔調度策略的核心行爲是驅逐(eviction)和搶佔(Preemption);驅逐由節點上的kubelet完成,搶佔由api server上的scheduler完成
- 節點資源不足時,kubelet會eviction優先級低的,同樣優先級時驅逐資源量超過申請量最大倍數的
- 當一個pod因爲資源無法滿足而不能被導讀時,調度器有可能選擇驅逐部分低優先級的pod實例來滿足此pod的調度目標
用戶可以自定義kind爲PriorityClass的對象,表徵優先級,並在pod中引用此優先級
-
DaemonSet: 在每個Node上僅運行一份Pod的副本實例;支持滾動升級
-
Job 批處理調度:批處理任務分爲幾種模式:
- Job Template Expansion模式:一個job對象對應一個待處理的work item,適合work item少,單次處理耗時長數據大的場景
- Queue with pod Per Work Item模式:採用一個隊列存放Work item,一個Job對象作爲消費者去完成這些work item,此模式下,job會創建多個pod,每個pod對應一個work item
- Queue with Variable Pod Count模式,也是任務隊列的模式,與上一個類似,但是pod數量是可變的
- Single Job with Static Work Assignment模式,一個job產生多個pod,採用靜態方式分配任務,而不是用隊列動態分配
考慮並行運行的i情況,kubernetes的job還可以分爲以下三種
- Non-paralel jobs: 一個job啓動一個pod,除非pod異常,才重啓,一旦正常結束,job結束
- Parallel jobs with a fixed completion count: 並行job啓動多個pod,此時需要設定job
spec.completions
參數爲一個證書,正常結束的pod數量達到此值後,job結束,job.spec.parallelism
參數可以控制並行度 - Parallel jobs with a work queue: 任務隊列方式的並行Job需要一個獨立的Queue, Work item都在一個Queue中存放, 不能設置
job.spec.completions
參數
-
Cronjob:定時任務
4.6 pod升級、回滾、擴縮容
-
升級的方式
- 升級的過程中刪除舊版本pod,使用新版本pod
- 先創建新版本,等待成功運行後再刪除舊版本
- 滾動升級
-
可以通過
kubectl rolling-update
命令手動升級RC:通過伸縮兩個RC將舊pod替換爲新pod;但是已經過時了。 -
使用Deployment聲明式地升級應用:實際過程同樣是伸縮兩個RS來實現,升級方式:
- 默認是滾動rollingUpdate,滾動升級時,還可以設置
maxUnavailable
、maxSurge
來控制滾動更新的過程,分別制定更新過程中不可用狀態的Pod數量上線,pod總數超過期望副本數的最大值;roll-over時,也就是一次跟新還沒結束就開始下一個更新,進行幾次更新就會創建幾個RS,之前的RS都會被認爲是舊版本 - recreate
通常不建議更新Deployment的標籤選擇器,會導致pod列表發生變化,可能與其他控制器產生衝突
- 默認是滾動rollingUpdate,滾動升級時,還可以設置
-
使用Deployment回滾:
kubectl rollout history
可以查看Deployment的歷史記錄,如果創建Deployment時使用了--record
參數,CHANGE-Cause列就能看到每個版本使用的命令了,可以通過--revision=3
選擇特定版本來查看- 回滾到上一個版本
rollout undo
- 回滾到指定版本
--to-revision
- 回滾到上一個版本
-
DaemonSet的更新策略:
- OnDelete: 默認升級策略,只有手動刪除舊版本的pod,纔會觸發新建操作
- RollingUpdate:整個過程與Deployment類似,但是不支持查看和管理DaemonSet的歷史記錄,不能自動回滾舊版本,需要重新提交舊版本的配置才行
-
StatefulSet的更新策略:和Deployment\StatefulSet看齊
-
擴縮容:
kubectl scale
對Deployment進行擴縮容- 自動擴縮容:Horizontal Pod Autoscaler HPA控制器,基於COU使用率進行自動Pod擴縮容的功能
- 指標類型:Pod資源使用率,pod自定義性能指標、對象自定義指標或者外部自定義指標(依賴自定義metrics Server:eg. Prometheus、Microsoft Azure…)
- 擴縮容算法:需求數量=當前數量*(當前指標值/期望指標值),向上取整
4.7 有狀態的副本集合StatefulSet
- 什麼是有狀態的副本集?
- 應用中每一個實例都是不可替代的個體,擁有穩定的名字和狀態
- 有狀態的pod在失敗後重新調度或者啓動後,需要保持原有的狀態、網絡、名稱,每個StatefulSet裏的pod擁有一組獨立的數據卷而有所區別,名字上也不是隨機生成,而是有一定的規律(SS名稱+index值)
- 基於上述定義,有狀態的pod通常可以用他們的名稱唯一的定位;
- SS通常對應headless Service
- 擴縮容
- 縮容時,過程可預測,通常刪除index最大的pod
- 爲了留有時間方便集羣轉移數據,縮容通常是線性的
- statefulSet中夥伴節點發現:可以通過一個headless service創建SRV記錄指向pod的主機名
SRV記錄:DNS服務器會把域名解析到一個IP地址,然後此IP地址的主機上將一個子目錄與域名綁定。域名解析時會添加解析記錄,這些記錄包括:A記錄、AAAA記錄、CNAME記錄、MX記錄、NS記錄等,其中,SRV記錄記錄了哪臺計算機提供了哪個服務的信息。
SRV常見格式:
_Service._Proto.Name TTL Class SRV Priority Weight Port Target Service: 服務名稱,前綴“_”是爲防止與DNS Label(普通域名)衝突。 Proto: 服務使用的通信協議,_TCP、_UDP、其它標準協議或者自定義的協議。 Name: 提供服務的域名。 TTL: 緩存有效時間。 CLASS: 類別 Priority: 該記錄的優先級,數值越小表示優先級越高,範圍0-65535。 Weight: 該記錄的權重,數值越高權重越高,範圍0-65535。 Port: 服務端口號,0-65535。 Target: host地址。
當一個pod需要獲取一個StatefulSet裏其他pod列表時,需要做的就是觸發一次headless service的FDQN的SRV DNS查詢.例如Node.js中查詢命令爲:dns.resolveSrv("kubia.default.svc.cluster.local", callBackFunction)
,返回的記錄順序爲隨機,不存在優先級順序。
5. 服務詳細
5.1 集羣內部訪問服務
下述爲服務暴露方式的演進過程
-
對於容器應用最簡便的方式就是通過TCP/IP+端口號來實現;例如定義一個Web服務的RC,指定容器的ContainerPort爲8080,獲取pod的ip地址後,既可以通過IP+端口的方式訪問應用服務
-
但是Pod是無狀態且動態的,因此Pod的Ip是不可靠的,且存在多個應用實例時,需要對服務進行負載均衡,Service資源對象就是做這樣的事情的;在RC的基礎上,可以通過命令
kubectl expose rc webapp
爲webapp這個rc暴露一個服務;k8s會爲該服務分配一個虛擬的ClusterIP,集羣內可以通過該ip與端口訪問該服務;負載均衡的方式,有兩種- RoundRobin 默認爲輪詢
- SessionAffinity: 基於客戶端IP進行會話保持,同一個客戶端ip,分配同樣的後端pod ip
-
多端口服務,複雜的應用在會暴露多個端口,或者不同的端口使用不同的協議,可以在Service的YAML文件中進行指定
Service提供服務的過程中,Service爲服務的最前端,之後是EndPoint對象,將服務與Pod IP+port進行關聯,流量最後纔會到達Pod。通常,Endpoint對象根據服務的標籤選擇器生成。也可以通過YAML文件創建並綁定服務。
-
外部服務service,如果創建Service時不指定標籤選擇器,那麼將無法創建endpoint對象,這個時候,手動創建endpoint對象綁定服務,並將服務路由到特定的外部ip,即可實現對集羣外部服務的訪問。相應的,如果之後外部服務添加到集羣內,更新服務的標籤選擇器即可改回來,反之,如果把內部服務遷到外部,刪除標籤選擇器並修改endpoint即可。
服務的
spec.type
默認是ClusterIP,即集羣會默認分配給服務一個唯一的虛擬ClusterIP以供服務發現和定位。如果設置其爲ExternalName,就可以使服務指向另一個外部服務,在DNS級別創建一條CNAME記錄,當解析該服務域名時,DNS服務器將得到另一個域名,從而訪問實際的外部服務。 -
headless service:通常service通過一個ClusterIP暴露服務並且隱藏了後端pod ip,但是某些情況下,客戶端想連接所有的pod,或者用戶想要摒棄service提供的默認負載均衡策略;那麼用戶可以指定clusterIp爲None。這類服務即爲headless service。這時候,通過dns解析服務時,將會獲取多個A記錄。可以臨時新建一個pod使用nsloop命令查詢。
A記錄:將域名指向一個IPv4地址(例如:100.100.100.100)
5.2 外部訪問
上面有關服務的內容僅限集羣內部的服務暴露,但是我們還需要對集羣外部提供服務。
-
type=nodeport;通過每個 Node 上的 IP 和靜態端口(
NodePort
)暴露服務。NodePort
服務會路由到ClusterIP
服務,這個ClusterIP
服務會自動創建 -
type=loadbalancer;使用雲提供商的負載局衡器,可以向外部暴露服務。外部的負載均衡器可以路由到
NodePort
服務和ClusterIP
服務。例如apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 9376 clusterIP: 10.0.171.239 loadBalancerIP: 78.11.24.19 type: LoadBalancer status: loadBalancer: ingress: - ip: 146.148.47.155
在這些情況下,將根據用戶設置的 loadBalancerIP
來創建負載均衡器。 某些雲提供商允許設置 loadBalancerIP
。如果沒有設置 loadBalancerIP
,將會給負載均衡器指派一個臨時 IP。 如果設置了 loadBalancerIP
,但云提供商並不支持這種特性,那麼設置的 loadBalancerIP
值將會被忽略掉。設置的146.148.47.155爲雲服務商提供的負載均衡器的IP地址。 對該Service的訪問請求將會通過LoadBalancer轉發到後端Pod上, 負載分發的實現方式則依賴於雲服務商提供的LoadBalancer的實現機制。
除了上述service的兩種方式;還可以通過Ingress來暴露服務, Ingress 不是服務類型,但它充當集羣的入口點。 它可以將路由規則整合到一個資源中,因爲它可以在同一IP地址下公開多個服務。
-
Ingress是一個 API 對象,用於管理對集羣中服務的外部訪問,通常是 HTTP。Ingress 可以提供負載平衡,SSL 終端和基於名稱的虛擬主機。Ingress定義了集羣外部到服務的HTTP或者HTTPS路由,流量路由由Ingress的路由規則控制,實現http層的代理,Ingress控制器則負責通過負載平衡實現入口。將 HTTP 和 HTTPS 以外的服務公開給 Internet 時,通常使用以下類型的服務 Service.Type=NodePort或者Service.Type=LoadBalancer
-
Ingress可以爲同一個域名下的不同路徑,分配不同服務,將負載均衡器的數量保持在最低水平,並實現7層代理上的策略控制
-
或者將不同的域名路由到同一個IP地址上的多個主機名
-
Ingressde的TLS安全設置,爲了Ingress提供https的安全訪問,可以爲Ingress中的域名進行TLS安全證書的設置,步驟如下:
- 創建自簽名的密鑰和SSL證書文件
- 保存證書到k8s的一個Secret資源對象
- 將該Secret對象設置到Ingress.spec.tls字段
-
6. 共享存儲
持久存儲PersistentVolume(PV)與持久存儲聲明PersistentVolumeClaim(PVC)的作用在於屏蔽底層存儲實現,將存儲抽象爲一種字眼,可供pod進行消費,方便用戶使用。PVC則是對資源的一種申請。申請時,不同的應用對存儲的大小、讀寫速度、併發性能有一定的要求,這個時候,又引入了StorageClass對象,用於標記存儲資源的特性和性能。基於上述資源對象,應用可以實現根據自己需求,申請特定存儲資源了。
Kubernetes從1.9版本開始引入容器存儲接口Container Storage Interface(CSI) 機制, 目標是在Kubernetes和外部存儲系統之間建立一套標準的存儲管理接口, 通過該接口爲容器提供存儲服務, 類似於
CRI(容器運行時接口) 和CNI(容器網絡接口) 。
6.1 PV
關鍵參數
- 存儲能力 capacity 未來可能加入IOPS 吞吐率等指標
- 存儲卷模式 Volume Mode,包括文件系統,塊設備等
- 訪問模式 Access Modes ,PV可以支持多種,但是PVC只支持一種
- RWO
- ROX
- RWX
- 存儲類別 Class,storage class ,不設置類別的PV,只能被不要求類別的PVC神情
- 回收策略 Reclaim Policy
- 保留
- 回收空間
- 刪除
- 掛載參數 mount opions
- 節點親和性 node affinity
生命階段
- available 可用狀態,未與某個pvc綁定
- Bound 已綁定
- released 綁定的PVC已刪除,資源已釋放,但是集羣還沒回收
- Failed 自動資源回收失敗
6.2 PVC
關鍵配置
- 資源請求 request.storage 目前僅支持存儲大小
- 訪問模式 access mode
- 存儲卷模式 文件|塊
- PV選擇條件 selector 對於PV的篩選
- 存儲類別 class 可以不設置
6.4 PV與PVC的生命週期
一次PV的使用可以按照如下流程
- 資源供應:
- 靜態模式:管理員手動創建很多PV,定義PVC時根據後端存儲特定進行設置
- 動態模式:集羣管理員無須手工創建PV, 而是通過StorageClass的設置對後端存儲進行描述, 標記爲某種類型。 此時要求PVC對存儲的類型進行聲明, 系統將自動完成PV的創建及與PVC的綁定。 PVC可以聲明Class爲"", 說明該PVC禁止使用動態模式。
- 資源綁定:PV與PVC匹配後,進行綁定,用戶即可使用該存儲;如果在系統中沒有滿足PVC要求的PV, PVC則會無限期處於Pending狀態, 直到等到系統管理員創建了一個符合其要求的PV 。
- 資源使用:在容器應用掛載了一個PVC後, 就能被持續獨佔使用。 不過,多個Pod可以掛載同一個PVC, 應用程序需要考慮多個實例共同訪問一塊存儲空間的問題。
- 資源釋放:使用完畢後, 用戶可以刪除PVC, 與該PVC綁定的PV將會被標記爲“已釋放”, 但還不能立刻與其他PVC進行綁定。 通過之前PVC寫入的數據可能還被留在存儲設備上, 只有在清除之後該PV才能再次使用。
- 資源回收:PV的存儲空間完成回收,才能供新的PVC綁定和使用 。
6.4 StorageClass
SC抽象了存儲資源的定義,一旦創建,無法更改,如需更改,只能刪除原有定義重建。
關鍵參數如下:
- 提供者 provisioner
- 參數,paramenters 資源提供者的參數設置,這個根據不同的資源有所不同
7. 參考
- k8s官網文檔
- 《Kubernetes In Action》
- 《Kubernetes權威指南》第四版