介紹Kubernetes架構
Kubernetes 架構
從高層看,kubernetes 是由如下東西組成的:
一個或多個 master node
一個或多個 worker node
一個分布式的 key-value 存儲,比如etcd
Master Node
Master node 是集群管理者,我們發出的所有請求都是到 master node 的 api server 上。
一個集群可以有多個 master node 做 HA,當有多個 master node 的時候,只有一個會提供服務,剩下的都是 follower。
集群的狀態一般存儲在etcd里面,所有的 master node 都會連接到 etcd。etcd 是一個分布式 k-v 存儲。etcd 可以是 master 內部的,也可以是外部的。
Master node 的組件
master node 一般都有如下組件:
API Server
所有的操作都是通過 API Server 去完成的。每個用戶 / 操作者通過發送 REST 請求到 api server,然后 api server 先驗證然后執行這些操作。在執行完之后把集群的狀態存到 etcd 里面。
Scheduler
顧名思義,Scheduler 的作用是調度,Scheduler 擁有所有 worker node 的資源使用情況,同時也知道用戶設置的資源需求,比如說一個 disk=ssd的 label。在調度之前,scheduler 還會考慮到 service requirements,data locality,affinity,anti-affinity 等。scheduler 負責的是 service 和 pod 的調度。
Controller Manager
簡單來說,Controller Manager 是負責啟動和關閉 pod 的。Controller Manager 的任務是讓集群維持在期望的狀態上。Controller Manager 知道每個 Pod 的狀態應該是什么樣,然后會不斷檢測是否有不達標的 pod。
Worker Node
Worker Node 就是一個被 master node 控制的機器,Pod 一般都是調度到 worker node 里面的。Worker node 會有一些可以運行以及連接容器的工具。Pod 是 kubernetes 里面的調度單元,是一個或多個容器組成的通常一起調度的邏輯上的集合。
Worker Node 組件
一個 worker node 一般會有以下組件:
Contrainer Runtime
不用多說了,運行容器必備的,默認用的是 Docker
kubelet
kubelet 是在每個 worker node 上都會運行的,用來和 master node 通信的。kubelet 從 master 接收 pod 的定義,然后啟動里面的容器,並監控容器是否一直正常運行。
kube-proxy
kube-proxy 簡單來說,就是對外提供代理服務的。換句話說,沒有 kube-proxy,我們要訪問其中的 application,就得直接訪問到 worker node 上,這顯然是不合理的。我們可以通過 kube-proxy 來做 load balancer 等。以前版本的 Service 也借助了 kube-proxy。
用 etcd 來管理狀態
在 kubernetes 里面,都是用的 etcd 來管理所有的狀態。除了集群的狀態之外,還會用來存放一些信息,比如 configmap,secret。
網絡需求
為了啟動一個全功能的 kubernetes 集群,我們需要先確認以下信息:
- 每個 Pod 有唯一一個獨立的 IP
- 每個 Pod 里面的容器可以互相溝通
- Pod 之間可以互相溝通
- 通過設置,在 Pod 里面的 application 可以被外部訪問到
- 這些問題都是需要在部署之前被解決的。
我們一個個看:
給每個 Pod 分配一個獨立的 IP
在 kubernetes 里面,每個 Pod 都要有一個獨立的 IP。一般容器網絡有兩種規格:
- Container Network Model (CNM)
- Container Network Interface (CNI)
Kubernetes 用 CNI 來給 Pod 分配 IP
簡單來說,容器運行時向 CNI 申請 IP,然后 CNI 通過其下面指定的 plugin 來獲取到 IP,並且返回給容器運行時。
容器之間交流
一般基於底層操作系統的幫助,所有的容器運行時都會給每個容器創建一個獨立的隔離的網絡整體。在 Linux 上,這個整體被稱為 Network Namespace,這些 Network Namespace 可以在容器之間共享。
在一個 Pod 里面,容器共享 Network Namespace,所以所有在同一個 Pod 里面的容器可以通過 localhost 來互相訪問。
跨 Node 的 Pod 之間訪問
在一個集群的環境下,每個 Pod 可以被調度到任何一個 Node 上,我們需要讓在不同機器上的 Pod 也可以相互通信,並且任何 Node 都可以訪問到任何 Pod。Kubernetes 設定了一個條件:不能有任何的 NAT 轉換,我們可以通過以下方式來達成:
- 可路由(Routable)的 Pod 和 Node,通過底層的服務,比如 GCE。
- 通過一些軟件定義的網絡(Software Defined Networking),比如 flannel,weave,calico 等
更多的信息可以看看 kubernetes 的官方文檔。
外網和集群之間的訪問
我們可以通過kube-proxy來暴露我們的 service,然后就能從外面訪問到我們集群里面的應用了。
如何實現節點的擴縮容
在node節點上安裝docker、kubelet和kube-proxy服務,然后將kubelet和kube-proxy的啟動參數中的master url指定為當前kubernetes集群master的地址,然后啟動服務即可。基於kubelet的自動注冊機制,新的node會自動加入現有的kubernetes集群中
刪除node節點kubectl delete node k8s-node1
如何實現pod的擴縮容
手動:kubectl scale rc redis-slave --replicas=3
自動:HPA控制器,可以實現基本CPU使用率進行自動Pod擴容和縮容的功能。
(原理:HAP控制器基於Master的Kube-controller-manager服務啟動參數--horizontal-pod-autoscaler-sync-period定義的時長(默認值為30s),周期性地檢測目標Pod的CPU使用率,並在滿足條件時對ReplicationController或Deployment中的Pod副本數量進行調整,以符合用戶定義的平均Pod CPU使用率。Pod CPU使用率來源於Heapster組件,所有需要預先安裝好Heapster.)
kubernetes相關組件原理
kubernetes API Server原理分析
- 核心功能:
提供了Kubernetes各類資源對象(Pod、RC、Service等)的增刪改查及Watch等HTTP Rest接口;
是集群內各個功能模塊之間交互和通信的中心樞紐,整個系統的數據總線和數據中心。
- 功能特性:
1、集群管理的API入口
2、資源配額控制的入口
3、提供了完備的集群安全機制
- 連接:
默認: --insecure-port=8080
啟動HTTPS安全端口:--secure-port=6443
- 交互方式:
命令行工具kubectl(實際上就是REST調用)
curl驗證接口:curl localhost:8080/api/v1/pods
暴露部分REST,啟動內部代理:kubectl proxy --reject-paths="^/api/v1/replicationcontrollers" --port=8001 --v=2
編程的方式:Pod內用戶進程調用Kubernetes API,通常用來實現分布式集群搭建的目標。Kubernetes API Server本身也是一個Service,名字是Kubernetes。
開發基於Kubernetes的管理平台。使用Client-go。
- 擴展接口:kubernetes Prox API
kubernetes API Server會把收到的REST轉發到某個Node上的kubelet的REST端口上,由該kubelete負責響應,不通過etcd獲取。
/api/v1/proxy/nodes/{name}/pods/
/api/v1/proxy/nodes/{name}/run(需要kubelet啟動時運行--enable-debugging-handlers=true)
通常用於kubernetes集群之外訪問某個Pod容器的服務,多用於管理目的,比如檢查Pod副本異常。
- 集群功能模塊之間的通信
各個組件通過API Server將信息存入etcd,
通過API Server的REST接口(GET、LIST、WATCH)獲取和操作數據。
例:
kubelet每隔一個時間周期,調用API Server的REST接口報告自身狀態,api server將節點狀態信息更新到etcd。
kubelet通過API Server的Watch接口監聽Pod信息。
kube-controller-manage中的Node Controller通過API Sever提供的Watch接口實時監控Node信息,並作出相應處理。
Scheduler通過API server的watch接口監聽到新建Pod副本的信息后,執行調度邏輯,將Pod綁定到目標節點。
為了緩解訪問壓力,各個組件采用緩存機制緩存數據。定時(LIST WATCH)指定資源對象,保存到本地。
Controller Manager原理分析
- 功能:集群內部的管理控制中心,負責將Node、Pod副本、服務端點(Endpoint),命名空間(namespace)、服務賬號(ServiceAccount)、資源定額(ResourceQuota)等的管理,當某個Node意外宕機時,Controller Manage會發現故障並執行自動化修復流程,確保集群始終處於預期的工作狀態。
- Replication Controller
- Node Controller
- ResourceQuota Controller
- Namespace Controller
- Service Controller & Endpoint Controller
Scheduler原理分析
- 功能:承上,接口COntroller Manager創建的新Pod,調度到合適節點。啟下,調度之后交給kubelet執行
- 詳細:將待調度的Pod(API新建Pod、Controller Manage維護調度的Pod)按照特定的算法綁定到Node,並寫入到etcd。涉及對象:待調度Pod列表、可用Node列表、調度算法和策略。隨后,目標節點Kubelet通過API Server將聽到Kubernetes Scheduler產生的額Pod綁定事件,然后獲取響應Pod清單,下載Image鏡像,並啟動容器。
- 調度流程:1)預選調度(xxx Predicates
):篩選可用Node節點。
2)優選策略(xxx Priority):確定最優節點。
插件方式:“算法提供者”(AlgorithmProvider),包含一組預選策略與一組優選策略的結構體。
注冊AlorithmProvider函數:func RegisterAlgorithmProvider(name string, predicateKeys, priorityKeys util.StringSet)
name string為算法名,predicateKeys為預選策略集合,PriorityKeys為優選策略集合。- 預選策略:
1 NoDiskConflict 是否存在磁盤沖突
2 PodFitsResouces 是否滿足在資源需求
3 PodSelectorMatches pod的label selector是否滿足
4 PodFitsHost pod指定spec.nodeName
5 PodFitsPorts Pod端口是否可用
*6 CheckNodeLabelPresence 標簽集
*7 CheckServiceAffinity service和Namespace下Pod標簽是否存在- 優選策略:
1 LeastRequestedPriority:
資源消耗最小節點
score = int(((nodeCpuCapacity - totalMilliCPU)*10)/ nodeCpuCapacity+((nodeMemoryCapacity-totalMemory)*10)/nodeCpuMemory)/2)
totalMilliCPU為所有備選節點上運行的Pod和備選Pod的CPU占用量
totalMemory為所有備選節點上運行的Pod和備選Pod的內存占用量
nodeCpuCapacity為節點cpu計算能力
nodeMemoryCapacity為節點內存大小
2 CalculateNodeLabelPriority:
判斷標簽是否需要判斷同時是否存在
3 BalancedResoruceAllocation
選出各項資源使用率最均衡的節點
Score = int(10-math.Abs(totalMilliCPU/nodeCpuCapacity-totalMemory/nodeMemoryCapacity)*10)
kubelet運行機制分析
描述:每個Node節點都會啟動一個kubelet服務。
功能:
1 向API Server注冊節點
2 定期向Master匯報節點資源使用情況
3 通過cAdvisor監控容器和節點資源
節點管理:
Pod管理:
容器健康檢查:
cAdvisor資源監控:是一個開源的Fenix容器資源使用率和性能特性的代理工具。自動查找所有在其節點上的容器,自動采集CPU、內存、文件系統和網絡使用的統計信息。
同時kubelet通過REST API暴露這些聚合后的Pod資源使用的統計信息。Heapster提供集群級別的監控和事件數據集成器(Aggregator)。
kube-proxy運行機制分析
描述:Service的透明代理兼負載均衡器。
對每個service都會在本地Node上建立已給SocketServer負責接收請求,Round Robin發送到后端Pod上。
Service的Cluster IP、NodePort等概念也是kube-proxy服務通過Iptables的NAT轉換實現。
Kube-proxy通過查詢和監聽API Server中的Service與Endpoints的變化,為每個Service都建立了一個“服務代理對象”包括SocketServer。此外還建立了一個負載均衡器。具體路由選擇取決於Round Robin算法及Service的Session會話保持(SessionAffinity)特性。
網絡原理
Kubernetes網絡模型
IP-per-Pod:
Docker0以Pod為單位分配IP,一個Pod內部的所有容器共享一個網絡命名空間(ip、網絡設備、配置)。Pod內外IP一致。
好處:Pod內共享端口,通信簡單高效。
壞處:共享端口降低了容器的隔離性。
Docker網絡基礎
NetworkNamespace
獨立的路由表、獨立的Iptables/Netfilter、NAT及IP包過濾等功能
Veth設備對
NETIF_F_ETNS_LOCAL=on,屬於可以轉移到其他網絡命名空間的網絡設備
docker創建veth對通信步驟:
1 創建veth對
2 轉移到另一個ns
3 改名eth0
4 分配IP
5 重啟
Iptables/Netfilter
網橋
二層虛擬網絡設備,連接若干網絡接口,使網口之間的報文能夠互相轉發。
內核Netfilter,用戶Iptables。
路由
Docker網絡實現
- host模式
- container模式
- none模式
- bridge模式
默認橋接網絡模型
1 創建Docker0網橋(docker deamon啟動時)
2 給網橋分配子網
3 創建veth對(任一Docker容器啟動)
4 轉移並給Veth對分配IP
kubernetes網絡實現
1 容器到容器通信
2 Pod到Pod之間的通信
3 Pod到Service之間的通信
4 集群外部與內部組件之間的通信。
容器到容器的通信
同一個Pod內容器共享同一個網絡命名空間。直接通過localhost:port端口可以直接通信
Pod之間的網絡通信
同一個Node之間的Pod通信
直接訪問Pod的全局ip因為,同一個Docker0網橋分配的ip、進行路由。
1 創建Docker網橋、分配子網ip
2 創建veth對
3 轉移並分配IP
不同Node之間的Pod通信
Kubernetes會記錄所有正在運行的Pod的IP分配信息,並將這些信息保存在etcd中(作為Service的Endpoint)
通信的條件
1:k8s集群上的IP不沖突
2:PodIP與NodeIP關聯使Pod可以相互訪問
需要使用開源網絡組件,如Flannel能管理資源池的分配。
開源網絡組件
Flannel
作用:實現Node間pod通信
1 給每個Node上的Docker容器分配互相不沖突的IP地址
2 能在這些IP地址之間建立一個覆蓋網絡(Overlay Network)
流程:
首先創建flannel0網橋,
網橋的一端連接docker0網橋,
另一端連接一個flanneld服務進程。
flanneld進程:
1 利用etcd管理可分配IP池
2 監控etcd中Pod地址
3 內存中建立Pod節點路由表
4 包裝docker0發送的數據
5 投遞至目標flanneld上,完成Node間Pod通信
缺點:
引入了多個網絡組件,導致網絡的時延損耗。
Calico
簡介:基於BGP的三層網絡。
1 在每個計算節點利用Linux Kernel實現了高效的vRouter來負責數據轉發。
2 每個vRouter通過BGP1協議廣播本節點上運行容器的路由信息。
3 容器間數據流量通過IP路由方式互聯。
組件:
Felix:設置容器網絡資源
etcd:后端存儲
BIGP Client(BIRD):BGP廣播Felix路由信息
BIRD(BGP Route Reflector):大規模集群分析路由分發
calicoctl:calico命令行管理工具
共享存儲原理
- 目的:
容器重建后,仍可使用之前的數據- 目標:
有狀態容器應用、數據持久化應用- 類別:
宿主機目錄
emptyDir臨時存儲卷
共享存儲
PersistentVolume(PV)
是對底層網絡共享存儲的抽象,將共享存儲定義為一種“資源”
PersistentVolumeClaim(PVC)
是對用戶對於存儲資源的一個“申請”。StorageClass,標記存儲資源的特性和性能
PV詳解
包括:
存儲能力(5Gi)、
訪問模式(RWO\ROX\RWX)、
存儲類型(快\慢\有冗余\無冗余\slow)、
回收策略(Retain保留\Recycle回收空間\Delete刪除)、
后端存儲類型(HostPath\AWS\GCE)
生命周期:
Available:可用,還未與pvc綁定
Bound:已經和pvc綁定
Released:綁定的pvc已經刪除,資源釋放但未回收
Failed:自動資源回收失敗
pvc詳解
包括:
存儲空間請求、
訪問模式、
PV選擇條件、
存儲類別
KUbernetes集群高可用部署
原生應用層高可用:
Kubernetes作為容器應用的管理平台,通過對Pod的運行狀態進行監控,並且根據主機或容器是小的狀態將新的Pod調度到其他Node上,實現了應用層的高可用。
etcd數據存儲的高可用
防止單點故障
1 集群方式部署etcd
2 etcd本身的數據本身考慮使用可靠的存儲設備(RAID磁盤陣列、高性能存儲設備、共享存儲文件系統,雲服務商提供的存儲系統。)
訪問集群參數設置:
--etcd-servers=http://10.0.0.1:2379,http://10.0.0.2:2379,http://10.0.0.3:2379
kubernetes Master組件的高可用
Master節點工作:
總控中心,主要的三個服務kube-apiserver、kube-controller0mansger和kube-scheduler通過不斷與工作節點上的kubelet和kube-proxy進行通信來維護整個集群的健康工作狀態。
高可用概述:
1 至少三台Master實現高可用。
2 容器啟動。
3 kubelet以StaticPod形式啟動並由kubelet進行監控和自動重啟。kubelet本身的高可用通過系統的systemd管理。
kube-apiserver的高可用部署
- 首先創建CA證書、鑒權文件、每台服務器創建其日志文件
- 其次kubelet啟動參數指定--config=/etc/kubernetes/manifests(Static Pod定義文件所在的目錄)
- 創建kube-apiserver.yaml用於啟動kube-apiserver
1 hostNetwork網絡模式
2 k8s發布包的鏡像tag
3 --etcd-servers指定etcd服務的URL地址
4 CA證書等
5 hostPort端口號
6 kube-apiserver.yaml文件復制到kubelet監控的/etc/kubernetes/manifests,kubelet將自動創建yaml文件中定義的kube-apiserver的Pod。
- 配置kube-apiserver的負載均衡器
GCE,阿里雲都是現成的
本地使用haproxy和keepalived實現:
haproxy負責負載均衡,keepalived負責對haproxy監控和進行高可用。
- 注意:1、Master開啟安全認證機制要確保證書中包含負載均衡服務的節點。
2、對於外部的訪問,比如通過kubectl訪問,需要配置為訪問API Server對應的負載均衡器的IP地址。
kube-controller-manager和kube-scheduler的高可用配置
這兩個組件會修改集群狀態信息,因此不僅需要啟動多個實例,還要有選舉機制選舉出leader,保證同一時間只有一個實例對集群狀態信息進行讀寫,避免出現同步和一致性問題。
選舉機制通過租賃鎖(lease-locak)實現,在每個實例的啟動參數中設置--leader-elect=true。
步驟:
1 每個Master節點上創建相應的日志文件。
2 創建kube-controller-manager和kube-scheduler的Pod定義文件。
- 最后的關鍵:確認集群中所有訪問API Server的地方都已經將訪問地址修改為負載均衡的地址。
Master高可用架構的演進
支持多個Master配置,實現不需要負載均衡器的Master高可用架構。
集群監控
cAdvisor
cAdvisor已被默認集成到kubelet組件內,會實時采集所在節點的性能指標及在節點上運行的容器的性能指標。kubelet啟動采納數--cadvisor-port可自定義cAvisor對外提供服務的端口號,默認為4194。
REST API返回JSON數據格式,采用如下URL訪問:http://: /api/ /
缺點:只能采集本機的性能指標數據。
Heapster+Influxdb+Grafana集群性能監控平台搭建
大規模集群需要對所有Node和全部容器進行性能監控,使用一套工具來實現集群性能數據化肚餓采集、存儲和展示:Heapster、InfuluxDB和Grafana。
Heapster:對集群中各Node上cAdvisor的 數據采集匯聚的系統。
通過kubelet的API,再通過kubelet調用cAdvisor的API來采集該節點上所有容器的性能數據。Heapster對性能進行聚合,結果保存到后端存儲系統中。可以是memory(內存)、InfluxDB等
InfluxDB:分布式時序數據庫(每條記錄都帶有時間戳屬性),用於實施數據次啊及、時間跟蹤記錄、存儲時間圖表、原始數據等。
Grafana:通過Dashboard將InfluxDB中的時序數據展現成圖表或曲線等形式。
Helm:kubernetes應用包管理工具
用於對Kubernetes上部署的復雜因公應進行定義、安裝和更新。Helm以Chart的方式對應用軟件進行描述,可以方便的創建、版本化、共享和發布復雜的應用軟件。
主要概念:
Chart:一個Helm包,包含了運行一個應用所需要的工具和資源定義,還可能包含service定義。
Release:在Kubernetes集群上運行一個Chart實例。在同一個集群上,一個Chart可以安裝多次。
Repository:用於存放Chart的倉庫。
主要任務:
在Repository中查找需要的Chart然后將Chart以Release的形式安裝到Kubernetes集群。
組件:
- HelmClient:對Repository、Chart、Release等對象的管理能力
- TillerServer:負責客戶端指令和Kubernetes集群之間的交互,根據Chart定義,生成和管理各種Kubernetes的資源對象。
文件夾:
wordpress/
Chart.yaml #應用定義yaml文件
values.yaml #默認配置信息
charts/ #包含依賴chart,推薦使用requirement.yaml僅需要注明以來的Chart倉庫信息,不需要定義整個Chart文件
templates/ #結合values.yaml能生成Kubernetes的manifest文件
問題定位
- 查看kubernetes對象當前運行時信息
- 深入容器內部進行故障診斷,查看容器運行日志
- Kubernetes服務日志。如kube-apiserver等的。
kubectl get pods
kubectl describe pod
Pod失敗原因:無可用Node、目標節點無可用資源、正在下載鏡像
kubectl logs
kubectl logs-c <container_name>
存儲卷保存日志
systemd系統管理Kubernetes服務,systemd的journal系統會接管服務程序的輸出日志。
systemctl status kube-controller-manager -l
journalctl -u kube-controller-manager