簡介
Kubernetes(簡稱K8S)是開源的容器集群管理系統,可以實現容器集群的自動化部署、自動擴縮容、維護等功能。它既是一款容器編排工具,也是全新的基於容器技術的分布式架構領先方案。在Docker技術的基礎上,為容器化的應用提供部署運行、資源調度、服務發現和動態伸縮等功能,提高了大規模容器集群管理的便捷性。Kubernetes是容器集群管理工具
架構
Kubernetes集群包含有節點代理kubelet和Master組件(APIs, scheduler, etc),一切都基於分布式的存儲系統。下面這張圖是Kubernetes的架構圖。
kubernetes 集群主要由 master 和 node 節點組成。
分層架構
- 核心層:Kubernetes最核心的功能,對外提供API構建高層的應用,對內提供插件式應用執行環境
- 應用層:部署(無狀態應用、有狀態應用、批處理任務、集群應用等)和路由(服務發現、DNS解析等)
- 管理層:系統度量(如基礎設施、容器和網絡的度量),自動化(如自動擴展、動態Provision等)以及策略管理(RBAC、Quota、PSP、NetworkPolicy等)
- 接口層:kubectl命令行工具、客戶端SDK以及集群聯邦
- 生態系統:在接口層之上的龐大容器集群管理調度的生態系統,可以划分為兩個范疇
- Kubernetes外部:日志、監控、配置管理、CI、CD、Workflow、FaaS、OTS應用、ChatOps等
- Kubernetes內部:CRI、CNI、CVI、鏡像倉庫、Cloud Provider、集群自身的配置和管理等
Kubernetes 集群組件
核心組件
- etcd保存了整個集群的狀態;
- apiserver提供了資源操作的唯一入口,並提供認證、授權、訪問控制、API注冊和發現等機制;
- controller manager負責維護集群的狀態,比如故障檢測、自動擴展、滾動更新等;
- scheduler負責資源的調度,按照預定的調度策略將Pod調度到相應的機器上;
- kubelet負責維護容器的生命周期,同時也負責Volume(CVI)和網絡(CNI)的管理;
- Container runtime負責鏡像管理以及Pod和容器的真正運行(CRI);
- kube-proxy負責為Service提供cluster內部的服務發現和負載均衡;
Addons(插件)
- kube-dns負責為整個集群提供DNS服務
- Ingress Controller為服務提供外網入口
- Heapster提供資源監控
- Dashboard提供GUI
- Federation提供跨可用區的集群
- Fluentd-elasticsearch提供集群日志采集、存儲與查詢
開放接口
- CRI(Container Runtime Interface):容器運行時接口,提供計算資源
- CNI(Container Network Interface):容器網絡接口,提供網絡資源
- CSI(Container Storage Interface):容器存儲接口,提供存儲資源
組件
Master 組件
Master組件提供集群的管理控制中心。
Master組件可以在集群中任何節點上運行。但是為了簡單起見,通常在一台VM/機器上啟動所有Master組件,並且不會在此VM/機器上運行用戶容器。請參考 構建高可用群集以來構建multi-master-VM。
kube-apiserver
kube-apiserver用於暴露Kubernetes API。任何的資源請求/調用操作都是通過kube-apiserver提供的接口進行。請參閱構建高可用群集。
ETCD
etcd是Kubernetes提供默認的存儲系統,保存所有集群數據,使用時需要為etcd數據提供備份計划。
kube-controller-manager
kube-controller-manager運行管理控制器,它們是集群中處理常規任務的后台線程。邏輯上,每個控制器是一個單獨的進程,但為了降低復雜性,它們都被編譯成單個二進制文件,並在單個進程中運行。
控制器類型
- 節點控制器(NodeController):kubelet進程在啟動時通過API Server注冊自身的節點信息,並定時向API Server匯報狀態信息,API Server在接收到這些信息后,會將這些信息更新到etcd中。在etcd中存儲的節點信息包括節點健康狀況、節點資源、節點名稱、節點地址信息、操作系統版本、Docker版本、kubelet版本等。節點健康狀況包含“就緒”(True)“未就緒”(False)和“未知”(Unknown)三種。
- 工作流程圖:Node Controller通過API Server實時獲取Node的相關信息,實現管理和監控集群中的各個Node的相關控制功能
- 工作流程圖:Node Controller通過API Server實時獲取Node的相關信息,實現管理和監控集群中的各個Node的相關控制功能
- 副本控制器(Replication Controller):核心作用是確保在任何時候集群中某個RC關聯的Pod副本數量都保持預設值。資源對象Replication Controller簡寫為RC
- 職責
- 確保在當前集群中有且僅有N個Pod實例,N是在RC中定義的Pod副本數量。
- 通過調整RC的spec.replicas屬性值來實現系統擴容或者縮容。
- 通過改變RC中的Pod模板(主要是鏡像版本)來實現系統的滾動升級。
- 使用場景
- 重新調度(Rescheduling):即使發生節點故障或Pod副本被終止運行等意外狀況,副本控制器時刻都能確保集群中指定數量的pod副本
- 彈性伸縮(Scaling):手動或者通過自動擴容代理修改副本控制器的spec.replicas屬性值的方式來實現增加或減少副本的數量
- 滾動更新(Rolling Updates):本控制器被設計成通過逐個替換Pod的方式來輔助服務的滾動更新。
- 職責
- 端點控制器(Endpoints Controller):填充Endpoints對象(即連接Services&Pods)
- ServiceAccount Controller和Token Controller:為新的Namespace 創建默認帳戶訪問API Token
- 資源配額管理(ResourceQuota Controller):資源配額管理確保了指定的資源對象在任何時候都不會超量占用系統物理資源,避免了由於某些業務進程的設計或實現的缺陷導致整個系統運行紊亂甚至意外宕機,對整個集群的平穩運行和穩定性有非常重要的作用。
- 資源管理級別
- 容器級別:可以對CPU和Memory進行限制
- Pod級別:可以對一個Pod內所有容器的可用資源進行限制
- Namespace級別:為Namespace(多租戶)級別的資源限制
- Pod數量
- Replication Controller數量
- Service數量
- ResourceQuota數量
- Secret數量
- 可持有的PV數量
- 資源管理級別
-
Namespace Controller:
- Service Controller:
cloud-controller-manager
雲控制器管理器負責與底層雲提供商的平台交互。雲控制器管理器是Kubernetes版本1.6中引入的,目前還是Alpha的功能。
雲控制器管理器僅運行雲提供商特定的(controller loops)控制器循環。可以通過將--cloud-provider
flag設置為external啟動kube-controller-manager ,來禁用控制器循環。
cloud-controller-manager 具體功能:
-
節點(Node)控制器
-
路由(Route)控制器
-
Service控制器
-
卷(Volume)控制器
kube-scheduler
kube-scheduler 監視新創建沒有分配到Node的Pod,為Pod選擇一個Node。
插件 addons
插件(addon)是實現集群pod和Services功能的 。Pod由Deployments,ReplicationController等進行管理。Namespace 插件對象是在kube-system Namespace中創建。
DNS
雖然不嚴格要求使用插件,但Kubernetes集群都應該具有集群 DNS。
群集 DNS是一個DNS服務器,能夠為 Kubernetes services提供 DNS記錄。
由Kubernetes啟動的容器自動將這個DNS服務器包含在他們的DNS searches中。
了解更多詳情
用戶界面
kube-ui提供集群狀態基礎信息查看。更多詳細信息,請參閱使用HTTP代理訪問Kubernetes API
容器資源監測
容器資源監控提供一個UI瀏覽監控數據。
Cluster-level Logging
Cluster-level logging,負責保存容器日志,搜索/查看日志。
Node 組件
節點組件運行在Node,提供Kubernetes運行時環境,以及維護Pod。
kubelet
kubelet是主要的節點代理,它會監視已分配給節點的pod,具體功能:
- 安裝Pod所需的volume。
- 下載Pod的Secrets。
- Pod中運行的 docker(或experimentally,rkt)容器。
- 定期執行容器健康檢查。
- Reports the status of the pod back to the rest of the system, by creating a mirror pod if necessary.
- Reports the status of the node back to the rest of the system.
kube-proxy
kube-proxy通過在主機上維護網絡規則並執行連接轉發來實現Kubernetes服務抽象。
docker
docker用於運行容器。
RKT
rkt運行容器,作為docker工具的替代方案。
supervisord
supervisord是一個輕量級的監控系統,用於保障kubelet和docker運行。
fluentd
fluentd是一個守護進程,可提供cluster-level logging.。
名詞解釋
API 對象
API對象是K8s集群中的管理操作單元。
API 的屬性
每個API對象都有3大類屬性:元數據(metadata)、規范(spec)和狀態(status)。
- metadata: 元數據是用來標識API對象的,每個對象都至少有3個元數據
- namespace
- name
- uid
- 各種各樣的標簽labels用來標識和匹配不同的對象
- spec: 規范描述了用戶期望K8s集群中的分布式系統達到的理想狀態(Desired State)
- 如:通過復制控制器Replication Controller設置期望的Pod副本數為3
- status: 描述了系統實際當前達到的狀態(Status)
Pod
Pod是在K8s集群中運行部署應用或服務的最小單元。Pod的設計理念是支持多個容器在一個Pod中共享網絡地址和文件系統,可以通過進程間通信和文件共享這種簡單高效的方式組合完成服務。
Pods提供兩種共享資源:網絡和存儲
-
網絡
- 每個Pod被分配一個獨立的IP地址,Pod中的每個容器共享網絡命名空間,包括IP地址和網絡端口。Pod內的容器可以使用localhost相互通信。當Pod中的容器與Pod 外部通信時,他們必須協調如何使用共享網絡資源(如端口)
-
存儲
- Pod可以指定一組共享存儲volumes。Pod中的所有容器都可以訪問共享volumes,允許這些容器共享數據。volumes 還用於Pod中的數據持久化,以防其中一個容器需要重新啟動而丟失數據。
K8S中主要任務類型及其對應的控制器
Controller可以創建和管理多個Pod,提供副本管理、滾動升級和集群級別的自愈能力。
任務類型 | 控制器 |
---|---|
長期伺服型(long-running) | 部署(Deployment) |
批處理型(batch) | 任務(Job) |
節點后台支撐型(node-daemon) | 后台支撐服務集(DaemonSet) |
有狀態應用型(stateful application) | 有狀態服務集(PetSet) |
Namespace
Namespace是對一組資源和對象的抽象集合,通常用於隔離不同的用戶。
namespace 的狀態
- Active
- Terminating : 在namespace刪除過程中,其狀態被置為 Terminating
namespace 的管理
# 1. 查詢
kubectl get namespaces
# 2. 創建
## 注意:命名空間名稱滿足正則表達式[a-z0-9]([-a-z0-9]*[a-z0-9])?, 最大長度為63位
## 2.1 命令行直接創建
kubectl create namespace new-namespace
## 2.2 通過文件創建
cat > my-namespace.yaml <<-'EOF'
apiVersion: v1
kind: Namespace
metadata:
name: new-namespace
EOF
kubectl create -f ./my-namespace.yaml
# 3. 刪除
## default和kube-system 默認命名空間不可刪除
## 刪除一個namespace會自動刪除所有屬於該namespace的資源
kubectl delete namespaces new-namespace
復制控制器(Replication Controller,RC)
通過監控運行中的Pod來保證集群中運行指定數目的Pod副本。RC 只支持基於等式的selector(env=dev或environment!=qa)
副本集(Replica Set,RS)
RS是新一代RC,提供同樣的高可用能力,區別主要在於 RS 能支持更多種類的匹配模式,如基於集合的selector(version in (v1.0, v2.0)或env notin (dev, qa))。副本集對象一般不單獨使用,而是作為Deployment的理想狀態參數使用。
Deployments是一個更高層次的概念,它管理ReplicaSets,並提供對pod的聲明性更新以及許多其他的功能。因此,建議您使用Deployments而不是直接使用ReplicaSets。
部署(Deployment)
部署表示對K8s集群的一次更新操作。Deployment為Pod和ReplicaSet提供了一個聲明式定義(declarative)方法。
應用場景
- 定義Deployment來創建Pod和ReplicaSet
- 滾動升級和回滾應用
- 擴容和縮容
- 暫停和繼續Deployment
服務(Service)
一個Pod只是一個運行服務的實例,它不能以確定的IP和端口號提供服務。Kubernete Service 是一個定義了一組 Pod 的策略的抽象,前端通過 Service 訪問 對應的后端 Pod。
要穩定地提供服務需要服務發現和負載均衡能力。服務發現完成的工作,是針對客戶端訪問的服務,找到對應的的后端服務實例。在K8s集群中,客戶端需要訪問的服務就是Service對象。每個Service會對應一個集群內部有效的虛擬IP,集群內部通過虛擬IP訪問一個服務。在K8s集群中微服務的負載均衡是由Kube-proxy實現的。Kube-proxy是K8s集群內部的負載均衡器。它是一個分布式代理服務器。
Virtual IPs and service proxies(虛擬IP和服務代理)
每一個節點上都運行了一個kube-proxy,這個應用監控着Kubermaster增加和刪除服務,對於每一個服務,kube-proxy會隨機開啟一個本機端口,任何發向這個端口的請求都會被轉發到一個后台的Pod當中,而如何選擇是哪一個后台的pod的是基於SessionAffinity進行的分配。kube-proxy會增加iptables rules來實現捕捉這個服務的Ip和端口來並重定向到前面提到的端口。這樣,用戶感覺不到請求被轉發到后端的Pod上。
Discovering services (服務發現)
Kubernetes 支持兩種方式的來發現服務 ,環境變量和 DNS
環境變量
當一個Pod在一個node上運行時,kubelet 會針對運行的服務增加一系列的環境變量,它支持Docker links compatible 和普通環境變量。必須在POD創建之前聲明環境變量
DNS
DNS 服務器監控着API SERVER ,當有服務被創建的時候,DNS 服務器會為之創建相應的記錄,如果DNS這個服務被添加了,那么Pod應該是可以自動解析服務的。
External services(外部服務)
對於應用程序來說,可能有部分應用是放在Kubernete外部的(如:有單獨的物理機來承擔數據庫的角色)的情況。Kubernetes支持兩種調用方式:NodePorts,LoadBalancers
每一個服務都會有一個字段定義了該服務如何被調用(發現),該字段的枚舉值:
- ClusterIP:使用一個集群固定IP,這個是默認選項
- NodePort:使用一個集群固定IP,但是額外在每個POD上均暴露這個服務,端口
- LoadBalancer:使用集群固定IP和NODEPord ,額外還會申請申請一個負載均衡器來轉發到服務(load balancer )
任務(Job)
Job是K8s用來控制批處理型任務的API對象。批處理業務與長期伺服業務的主要區別是批處理業務的運行有頭有尾,而長期伺服業務在用戶不停止的情況下永遠運行。
Job負責批量處理短暫的一次性任務 (short lived one-off tasks),即僅執行一次的任務,它保證批處理任務的一個或多個Pod成功結束。
支持的 job 類型
- 非並行Job:通常創建一個Pod直至其成功結束
- 固定結束次數的Job:設置.spec.completions,創建多個Pod,直到.spec.completions個Pod成功結束
- 帶有工作隊列的並行Job:設置.spec.Parallelism但不設置.spec.completions,當所有Pod結束並且至少一個成功時,Job就認為是成功
根據.spec.completions和.spec.Parallelism的設置,可以將Job划分為以下幾種pattern:
Job類型 | 使用示例 | 行為 | completions | Parallelism |
---|---|---|---|---|
一次性Job | 數據庫遷移 | 創建一個Pod直至其成功結束 | 1 | 1 |
固定結束次數的Job | 處理工作隊列的Pod | 依次創建一個Pod運行直至completions個成功結束 | 2+ | 1 |
固定結束次數的並行Job | 多個Pod同時處理工作隊列 | 依次創建多個Pod運行直至completions個成功結束 | 2+ | 2+ |
並行Job | 多個Pod同時處理工作隊列 | 創建一個或多個Pod直至有一個成功結束 | 1 | 2+ |
Job Controller
Job Controller負責根據Job Spec創建Pod,並持續監控Pod的狀態,直至其成功結束。如果失敗,則根據restartPolicy(只支持OnFailure和Never,不支持Always)決定是否創建新的Pod再次重試任務。
Job Spec 格式
- spec.template格式同 Pod
- RestartPolicy僅支持Never或OnFailure
- 單個Pod時,默認Pod成功運行后Job即結束
- .spec.completions標志Job結束需要成功運行的Pod個數,默認為1
- .spec.parallelism標志並行運行的Pod的個數,默認為1
- spec.activeDeadlineSeconds標志失敗Pod的重試最大時間,超過這個時間不會繼續重試
守護進程服務集(DaemonSet)
DaemonSet保證在每個Node上都運行一個容器副本,典型的后台支撐型服務包括 存儲,日志和監控等在每個節點上支持K8s集群運行的服務。
有狀態服務集(PetSet|StatefulSet)
有狀態(stateful)<-> 無狀態(stateless)
- RC和RS主要是控制提供無狀態服務的,其所控制的Pod的名字是隨機設置的,一個Pod出故障了就被丟棄掉,在另一個地方重啟一個新的Pod
- PetSet是用來控制有狀態服務,PetSet中的每個Pod的名字都是事先確定的,不能更改。
- 適合於PetSet的業務包括數據庫服務MySQL和PostgreSQL,集群化管理服務Zookeeper、etcd等有狀態服務
- PetSet做的只是將確定的Pod與確定的存儲關聯起來保證狀態的連續性
應用場景
- 穩定的持久化存儲,即Pod重新調度后還是能訪問到相同的持久化數據,基於PVC來實現
- 穩定的網絡標志,即Pod重新調度后其PodName和HostName不變,基於Headless Service(即沒有Cluster IP的Service)來實現
- 有序部署,有序擴展,即Pod是有順序的,在部署或者擴展的時候要依據定義的順序依次依次進行(即從0到N-1,在下一個Pod運行之前所有之前的Pod必須都是Running和Ready狀態),基於init containers來實現
- 有序收縮,有序刪除(即從N-1到0)
StatefulSet 組成
- 用於定義網絡標志(DNS domain)的Headless Service
- 用於創建PersistentVolumes的volumeClaimTemplates
- 定義具體應用的StatefulSet
StatefulSet中每個Pod的DNS格式為statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local
,其中
serviceName
為Headless Service的名字0..N-1
為Pod所在的序號,從0開始到N-1statefulSetName
為StatefulSet的名字namespace
為服務所在的namespace,Headless Servic和StatefulSet必須在相同的namespace.cluster.local
為Cluster Domain
集群聯邦(Federation)
服務的作用距離范圍從近到遠划分:
- 同主機(Host,Node)
- 跨主機 同可用區(Available Zone)
- 跨可用區 同地區(Region)
- 跨地區 同服務商(Cloud Service Provider)
- 跨雲平台
K8s的設計定位是單一集群在同一個地域(Region)內,因為同一個地區的網絡性能才能滿足K8s的調度和計算存儲連接要求。
聯合集群(Federation)服務就是為提供跨Region跨服務商K8s集群服務而設計的。
每個K8s Federation有自己的分布式存儲、API Server和Controller Manager。用戶可以通過Federation的API Server注冊該Federation的成員K8s Cluster。當用戶通過Federation的API Server創建、更改API對象時,Federation API Server會在自己所有注冊的子K8s Cluster都創建一份對應的API對象。在提供業務請求服務時,K8s Federation會先在自己的各個子Cluster之間做負載均衡,而對於發送到某個具體K8s Cluster的業務請求,會依照這個K8s Cluster獨立提供服務時一樣的調度模式去做K8s Cluster內部的負載均衡。而Cluster之間的負載均衡是通過域名服務的負載均衡來實現的。
存儲卷(Volume)
K8s的存儲卷的生命周期和作用范圍是一個Pod。每個Pod中聲明的存儲卷由Pod中的所有容器共享。
支持的存儲卷類型
- 公有雲平台的存儲
- AWS
- Azure雲
- 分布式存儲
- GlusterFS
- Ceph
- 主機本地目錄|文件系統
- hostPath
- NFS
- Persistent Volume Claim (PVC) 邏輯存儲
持久存儲卷(Persistent Volume,PV)和持久存儲卷聲明(Persistent Volume Claim,PVC)
- PV和Node是資源的提供者,根據集群的基礎設施變化而變化,由K8s集群管理員配置
- PVC和Pod是資源的使用者,根據業務服務的需求變化而變化,有K8s集群的使用者即服務的管理員來配置
節點(Node)
K8s集群中的計算能力由Node提供,最初Node稱為服務節點Minion,后來改名為Node。K8s集群中的Node也就等同於 Apache Mesos(分布式資源管理框架) 集群中的Slave節點,是所有Pod運行所在的工作主機(物理機|虛擬機)。工作主機的統一特征是上面要運行kubelet管理節點上運行的容器。
為了管理Pod,每個Node節點上至少要運行container runtime(比如docker或者rkt)、kubelet和kube-proxy服務。
Node 管理
Kubernetes只使用 Node Controller 去檢查 Node 是否真的存在這個 Node 。
Node Controller 的職責
- 維護Node狀態
- 與Cloud Provider同步Node
- 給Node分配容器CIDR
- 刪除帶有NoExecute taint的Node上的Pods
默認情況下,kubelet在啟動時會向master注冊自己,並創建Node資源。
Node 的狀態
- 地址:包括hostname、外網IP和內網IP
- 條件(Condition):包括OutOfDisk、Ready、MemoryPressure和DiskPressure
- 容量(Capacity):Node上的可用資源,包括CPU、內存和Pod總數
- 基本信息(Info):包括內核版本、容器引擎版本、OS類型等
Node 維護模式
此種模式標志Node不可調度但不影響其上正在運行的Pod
kubectl cordon $NODENAME
Node 調度
Taints和tolerations用於保證Pod不被調度到不合適的Node上。
- Taint 應用於Node上
- toleration 則應用於Pod上(Toleration是可選的)
密鑰對象(Secret)
Secret是用來保存和傳遞密碼、密鑰、認證憑證這些敏感信息的對象。使用Secret的好處是可以避免把敏感信息明文寫在配置文件里。在K8s集群中配置和使用服務不可避免的要用到各種敏感信息實現登錄、認證等功能,例如訪問AWS存儲的用戶名密碼。為了避免將類似的敏感信息明文寫在所有需要使用的配置文件中,可以將這些信息存入一個Secret對象,而在配置文件中通過Secret對象引用這些敏感信息。這種方式的好處包括:意圖明確,避免重復,減少暴漏機會。
用戶帳戶(User Account)和服務帳戶(Service Account)
顧名思義,用戶帳戶為人提供賬戶標識,而服務賬戶為計算機進程和K8s集群中運行的Pod提供賬戶標識。用戶帳戶和服務帳戶的一個區別是作用范圍;用戶帳戶對應的是人的身份,人的身份與服務的namespace無關,所以用戶賬戶是跨namespace的;而服務帳戶對應的是一個運行中程序的身份,與特定namespace是相關的。
Service Account
Service account是為了方便Pod里面的進程調用Kubernetes API或其他外部服務而設計的。
- User account是為人設計的,而service account則是為Pod中的進程調用Kubernetes API而設計;
- User account是跨namespace的,而service account則是僅局限它所在的namespace;
- 每個namespace都會自動創建一個default service account
- Token controller檢測service account的創建,並為它們創建 secret
- 開啟ServiceAccount Admission Controller后
- 每個Pod在創建后都會自動設置spec.serviceAccount為default(除非指定了其他ServiceAccout)
- 驗證Pod引用的service account已經存在,否則拒絕創建
- 如果Pod沒有指定ImagePullSecrets,則把service account的ImagePullSecrets加到Pod中
- 每個container啟動后都會掛載該service account的token和ca.crt到/var/run/secrets/kubernetes.io/serviceaccount/
名字空間(Namespace)
名字空間為K8s集群提供虛擬的隔離作用,K8s集群初始有兩個名字空間,分別是默認名字空間default和系統名字空間kube-system,除此以外,管理員可以可以創建新的名字空間滿足需要。
RBAC訪問授權
K8s在1.3版本中發布了alpha版的基於角色的訪問控制(Role-based Access Control,RBAC)的授權模式。相對於基於屬性的訪問控制(Attribute-based Access Control,ABAC),RBAC主要是引入了角色(Role)和角色綁定(RoleBinding)的抽象概念。在ABAC中,K8s集群中的訪問策略只能跟用戶直接關聯;而在RBAC中,訪問策略可以跟某個角色關聯,具體的用戶在跟一個或多個角色相關聯。顯然,RBAC像其他新功能一樣,每次引入新功能,都會引入新的API對象,從而引入新的概念抽象,而這一新的概念抽象一定會使集群服務管理和使用更容易擴展和重用。