一、kubernetes的前生今生
Kubernetes(簡稱k8s)是Google在2014年6月開源的一個容器集群管理系統,使用Go語言開發,用于管理云平臺中多個主機上的容器化的應用,Kubernetes的目標是讓部署容器化的應用簡單并且高效,Kubernetes提供了資源調度、部署管理、服務發現、擴容縮容、監控,維護等一整套功能,努力成為跨主機集群的自動部署、擴展以及運行應用程式容器的平臺, 它支持一系列容器工具, 包括Docker等,
從Borg到Kubernetes

在Docker 作為高級容器引擎快速發展的同時,Google也開始將自身在容器技術及集群方面的積累貢獻出來,在Google內部,容器技術已經應用了很多年,Borg系統運行管理著成千上萬的容器應用,在它的支持下,無論是谷歌搜索、Gmail還是谷歌地圖,可以輕而易舉地從龐大的資料中心中獲取技術資源來支撐服務運行,
Borg是集群的管理器,在它的系統中,運行著眾多集群,而每個集群可由成千上萬的服務器聯接組成,Borg每時每刻都在處理來自眾多應用程式所提交的成百上千的Job, 對這些Job進行接收、調度、啟動、停止、重啟和監控,
Borg提供了3大好處:
1)隱藏資源管理和錯誤處理,用戶僅需要關注應用的開發,
2) 服務高可用、高可靠,
3) 可將負載運行在由成千上萬的機器聯合而成的集群中,
作為Google的競爭技術優勢,Borg理所當然的被視為商業秘密隱藏起來,但當Tiwtter的工程師精心打造出屬于自己的Borg系統(Mesos)時, Google也審時度勢地推出了來源于自身技術理論的新的開源工具,
2014年6月,谷歌云計算專家埃里克·布魯爾(Eric Brewer)在舊金山的發布會為這款新的開源工具揭牌,它的名字Kubernetes在希臘語中意思是船長或領航員,這也恰好與它在容器集群管理中的作用吻合,即作為裝載了集裝箱(Container)的眾多貨船的指揮者,負擔著全域調度和運行監控的職責,
雖然Google推出Kubernetes的目的之一是推廣其周邊的計算引擎(Google Compute Engine)和谷歌應用引擎(Google App Engine),但Kubernetes的出現能讓更多的互聯網企業可以享受到連接眾多計算機成為集群資源池的好處,
Kubernetes對計算資源進行了更高層次的抽象,通過將容器進行細致的組合,將最終的應用服務交給用戶,Kubernetes在模型建立之初就考慮了容器跨機連接的要求,支持多種網路解決方案,同時在Service層次構建集群范圍的SDN網路,其目的是將服務發現和負載均衡放置到容器可達的范圍,這種透明的方式便利了各個服務間的通信,并為微服務架構的實踐提供了平臺基礎,而在Pod層次上,作為Kubernetes可操作的最小物件,其特征更是對微服務架構的原生支持,
Kubernetes專案來源于Borg,可以說是集結了Borg設計思想的精華,并且吸收了Borg系統中的經驗和教訓,
Kubernetes作為容器集群管理工具,于2015年7月22日迭代到 v 1.0并正式對外公布,這意味著這個開源容器編排系統可以正式在生產環境使用,與此同時,谷歌聯合Linux基金會及其他合作伙伴共同成立了CNCF基金會( Cloud Native Computing Foundation),并將Kuberentes 作為首個編入CNCF管理體系的開源專案,助力容器技術生態的發展進步,Kubernetes專案凝結了Google過去十年間在生產環境的經驗和教訓,從Borg的多任務Alloc資源塊到Kubernetes的多副本Pod,從Borg的Cell集群管理,到Kubernetes設計理念中的聯邦集群,在Docker等高級引擎帶動容器技術興起和大眾化的同時,為容器集群管理提供獨了到見解和新思路,
二、kubernetes的特點
-
可移植:支持公有云,私有云,混合云,多重云(multi-cloud)
-
可擴展::模塊化, 插件化, 可掛載, 可組合
-
自動化: 自動部署,自動重啟,自動復制,自動伸縮/擴展,自我修復
-
服務發現和負載均衡
Kubernetes一個核心的特點就是自動化,能夠自主的管理容器來保證云平臺中的容器按照用戶的期望狀態運行著(比如用戶想讓apache一直運行,用戶不需要關心怎么去做,Kubernetes會自動去監控,然后去重啟,新建,總之,讓apache一直提供服務),管理員可以加載一個微型服務,讓規劃器來找到合適的位置,同時,Kubernetes也系統提升工具以及人性化方面,讓用戶能夠方便的部署自己的應用(就像canary deployments),
現在Kubernetes著重于不間斷的服務狀態(比如web服務器或者快取服務器)和原生云平臺應用(Nosql),在不久的將來會支持各種生產云平臺中的各種服務,例如,分批,作業流,以及傳統資料庫,
所有Kubernetes中的資源,比如Pod,都通過一個叫URI的東西來區分,這個URI有一個UID,URI的重要組成部分是:物件的型別(比如pod),物件的名字,物件的命名空間,對于特殊的物件型別,在同一個命名空間內,所有的名字都是不同的,在物件只提供名稱,不提供命名空間的情況下,這種情況是假定是默認的命名空間,UID是時間和空間上的唯一,
三、kubernetes的相關概念

使用Kubernetes,需要對pods、services、replication controller等概念了然于心,
1、Pod
Pod是最小部署單元,一個Pod由一個或多個容器組成,Pod中容器共享存盤和網路,在同一臺Docker主機上運行,每個Pod都會包含一個 “根容器”,還會包含一個或者多個緊密相連的業務容器,
-
Pod運行在節點Node中;
-
Pod是對容器的封裝,是k8s最小的調度單元,也是Kubernetes最重要的基本概念;
-
Pause容器簡述:每個Pod都有一個特殊的被稱為“根容器”的Pause容器,Pause容器對應的鏡像屬于Kubernetes平臺的一部分,Kubernetes設計出全新Pod概念的原因如下,原因一、在一組容器作為一個單位的情況下,我們難以簡單地對整組容器的狀態進行判斷,如果其中一個容器死亡,此時該去定義整組容器都死亡呢?還是定義N/M的死亡率呢?通過引入與業務無關并且不容易死亡的Pause容器作為Pod的根容器,以它的狀態代表整組容器的狀態,可以簡單的解決整個問題,原因二、Pod里的多個業務容器共享Pause容器IP,共享Pause容器掛接的Volume,這樣既簡化了密切關聯的業務容器之間的通信問題,也很好地解決了它們之間的檔案共享問題,
-
Kubernetes為每個Pod都分配了唯一的IP地址,稱之為Pod IP,一個Pod里的多個容器共享Pod IP,Kubernetes要求底層網路支持集群內任意兩個Pod之間的TCP/IP直接通信,因此一個Pod容器與另外主機上的Pod容器能夠直接通信,
pod 清單:
apiVersion: v1 # Pod版本號為v1
kind: Pod # 使用的資源型別為Pod
metadata:
name: string # 當前Pod的名稱,名字唯一
namespace: string # Pod所屬的命名空間,默認值為default
labels: # 自定義標簽串列
- name: string # 當前pod標簽為“name=string”
annotations: # 自定義注解串列
- name: string
spec: # Pod中的詳細定義
containers: # Pod的容器串列
- name: string # 容器名字
image: string # 容器鏡像
imagePullPolicy: # 容器的鏡像拉取策略
command: [string] # 容器的啟動命令串列
args: [string] # 容器的啟動命令引數串列
workingDir: String 容器的作業目錄
volumeMounts: # 掛載到容器內部的存盤卷配置
- name: String # 參考Pod定義的共享存盤卷的名,需用Pod.spec.volumes[]部分定義的卷名
mountPath: String # 存盤卷在容器內的絕對路徑
readOnly: boolean # 設定為只讀模式,默認為false
volumes: # 在該Pod上定義共享存盤卷串列
- name: String # 共享存盤卷名稱,必須字母小寫
emptyDir: { } # 型別為emptyDir的存盤卷,與Pod同生命周期的一個臨時目錄,為空值
hostPath: String # 型別為hostPath的存盤卷,表示掛載Pod所在宿主機的目錄
path: String # Pod所在宿主機的目錄,將被用于同期中Mount的目錄
ports: 容器需要暴露的埠庫號串列
- name: String 埠號名稱
containerPort: Int 容器需要監聽的埠號
hostPort: Int 可選,容器所在主機需要監聽的埠號,默認與Container相同
env: # 容器運行前需設定的環境變數串列
- name: String # 環境變數名稱
value: String # 環境變數的值
resources: # 資源限制和請求的設定
limits: # 資源限制的設定
cpu: String # Cpu的限制,單位為Core數,將用于docker run --cpu-shares引數,如果整數后跟m,表示占用權重,1Core=1000m
memory: String # 記憶體限制,單位可以為Mib/Gib,將用于docker run --memory引數
requests: # 資源請求的設定
cpu: string # CPU請求,容器啟動的初始可用數量
memory: string # 記憶體請求,容器啟動的初始可用數量
livenessProbe: # 對Pod內容器健康檢查設定,當探測無回應幾次后將自動重啟該容器,檢查方法有exec、httpGet和tcpSocket,對一個容器只需設定其中一種方法即可,
exec: # 對Pod容器內檢查方式設定為exec方式
command: [String] # exec方式需要制定的命令或腳本
httpGet: # 對Pod容器內檢查方式設定為HttpGet方式,需要指定path、port
path: String # 網址URL路徑(去除對應的域名或IP地址的部分)
port: Int # 對應埠
host: String # 域名或IP地址
schema: String # 對應的檢測協議,如http
HttpHeaders: # 指定報文頭部資訊
- name: String
value: String
tcpSocket: # 對Pod容器內檢查方式設定為tcpSocket方式
port: Int
initialDelaySeconds: Int # 容器啟動完成后首次探測的時間,單位為秒
timeoutSeconds: Int # 對容器健康檢查探測等待回應的超時時間,單位為秒,默認為1秒
periodSeconds: Int # 對容器監控檢查的定期探測時間設定,單位為秒,默認10秒一次
successThreshold: Int # 探測幾次成功后認為成功
failureThreshold: Int # 探測幾次失敗后認為失敗
securityContext:
privileged: false
restartPolicy: # Pod的重啟策
nodeSelector: 設定NodeSelector表示將該Pod調度到包含這個label的node上,以Key:Value的格式指定
Key: Value 調度到指定的標簽Node上
imagePullSecrets: Pull鏡像時使用的secret名稱,以Key:SecretKey格式指定
- name: String
hostNetwork: false 是否使用主機網路模式,默認為false,如果設定為true,表示使用宿主機網路
secret: 型別為Secret的存盤卷,掛載集群與定義的Secret物件到容器內部
secretname: String
items: 當僅需掛載一個Secret物件中的指定Key時使用
- key: String
path: String
configMap: # 型別為ConfigMap的存盤卷,掛載預定義的ConfigMap物件到容器內部
name: String
items: # 當僅需掛載一個ConfigMap物件中的指定Key時使用
- key: String
path: String
2、Service
Service一個應用服務抽象,定義了Pod邏輯集合和訪問這個Pod集合的策略,Service代理Pod集合對外表現是為一個訪問入口,分配一個集群IP地址,來自這個IP的請求將負載均衡轉發后端Pod中的容器,Service通過LableSelector選擇一組Pod提供服務,
在K8s集群中,客戶端需要訪問的服務就是Service物件,每個Service會對應一個集群內部有效的虛擬IP,集群內部通過虛擬IP訪問一個服務,在K8s集群中微服務的負載均衡是由Kube-proxy實作的,Kube-proxy是K8s集群內部的負載均衡器,它是一個分布式代理服務器,在K8s的每個節點上都有一個;這一設計體現了它的伸縮性優勢,需要訪問服務的節點越多,提供負載均衡能力的Kube-proxy就越多,高可用節點也隨之增多,與之相比,我們平時在服務器端做個反向代理做負載均衡,還要進一步解決反向代理的負載均衡和高可用問題,
“Service微服務”,kubernetes中的核心,通過分析、識別并建模系統中的所有服務為微服務,最終系統有多個提供不同業務能力而又彼此獨立的微服務單元所組成,服務之間通過TCP/IP進行通信,每個Pod都會被分配一個單獨的IP地址,而且每個Pod都提供了一個獨立的Endpoint以被客戶端訪問,
客戶端想要訪問到Pod中的服務需要 部署負載均衡器,為Pod開啟對外服務埠,將Pod的Endpoint串列加入轉發串列中,客戶端通過負載均衡器的對外IP+Port來訪問此服務,每個Service都有一個全域唯一的虛擬ClusterIP,這樣每個服務就變成了具備唯一IP地址的“通信節點”,服務呼叫就變成了最基礎的TCP網路通信問題,
-
在K8S的世界里,雖然每個Pod都會被分配一個單獨的IP地址,但這個IP地址會隨著Pod的銷毀而消失
-
Service (服務)就是用來解決這個問題的核心概念
-
一個Service可以看作- -組提供相同服務的Pod的對外訪問介面
-
Service作用于哪些Pod是通過標簽選擇器來定義的
3、訪問方式
A、ClusterIP模式
用于為集群內Pod訪問時,提供的固定訪問地址,默認是自動分配地址,可使用ClusterIP關鍵字指定固定IP.
B、NodePort模式
用于為集群外部訪問Service后面Pod提供訪問接入埠.,這種型別的service作業流程為:Client----->NodeIP:NodePort----->ClusterIP:ServicePort----->PodIP:ContainerPort
C、LoadBalancer模式
用于當K8s運行在一個云環境內時,若該云環境支持LBaaS,則此型別可自動觸發創建一個軟體負載均衡器用于對Service做負載均衡調度.
因為外部所有Client都訪問一個NodeIP,該節點的壓力將會很大, 而LoadBalancer則可解決這個問題,
而且它還直接動態監測后端Node是否被移除或新增了,然后動態更新調度的節點數,
D、ExternalName模式
用于將集群外部的服務引入到集群內部,在集群內部可直接訪問來獲取服務,它的值必須是 FQDN, 此FQDN為集群內部的FQDN, 即: ServiceName.Namespace.Domain.LTD.4
4、Kubernetes Ingress
Ingress 是 Kubernetes 中非常重要的外網流量入口,在Kubernetes中所推薦的默認值為Nginx Ingress,為了與后面Nginx 提供的商業版 Ingress 區分開來,我就稱它為Kubernetes Ingress,

5、Volume
資料卷,是Pod中能夠被多個容器訪問的共享目錄,定義在Pod之上,被一個Pod里的多個容器掛載到具體的檔案目錄之下;與Pod生命周期相同,可以讓一個Pod里的多個容器共享檔案、讓容器的資料寫到宿主機的磁盤上或者寫檔案到 共享存盤中
Kubernetes提供了眾多的volume型別,現在列出一部分
emptyDir hostPath gcePersistentDisk awsElasticBlockStore nfs iscsi flocker glusterfs rbd cephfs gitRepo secret persistentVolumeClaim downwardAPI azureFileVolume azureDisk vsphereVolume Quobyte
下面是比較常用的兩個
emptyDir
emptyDir的生命周期與所屬的pod相同,pod洗掉時,其emptyDir中的資料也會被洗掉,
emptyDir型別的volume在pod分配到node上時被創建,kubernetes會在node上自動分配 一個目錄,因此無需指定宿主機node上對應的目錄檔案,
emptyDir Volume主要用于某些應用程式無需永久保存的臨時目錄,多個容器的共享目錄等
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- image: test-webserver
name: test-container
volumeMounts:
- name: cache-volume
mountPath: /cache
volumes:
- name: cache-volume
emptyDir: {}
hostPath
pod洗掉或者是調度到另外一個Node,原先Node上的存盤卷還在,
hostPath Volume為pod掛載宿主機上的目錄或檔案,使得容器可以使用宿主機的檔案系統進行存盤,缺點是,在k8s中,pod都是動態在各node節點上調度,當一個pod在當前node節點上啟動并通過hostPath存盤了檔案到本地以后,下次調度到另一個節點上啟動時,就無法使用在之前節點上存盤的檔案,
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- image: test-webserver
name: test-container
volumeMounts:
- name: test-volume
mountPath: /www
volumes:
- name: test-volume
hostPath:
path: /data
6、持久存盤卷(Persistent Volume,PV)和持久存盤卷宣告(Persistent Volume Claim,PVC)
PV和PVC使得K8s集群具備了存盤的邏輯抽象能力,使得在配置Pod的邏輯里可以忽略對實際后臺存盤技術的配置,而把這項配置的作業交給PV的配置者,即集群的管理者,存盤的PV和PVC的這種關系,跟計算的Node和Pod的關系是非常類似的;PV和Node是資源的提供者,根據集群的基礎設施變化而變化,由K8s集群管理員配置;而PVC和Pod是資源的使用者,根據業務服務的需求變化而變化,有K8s集群的使用者即服務的管理員來配置,
7、Namespace
命名空間將物件邏輯上分配到不同Namespace,可以是不同的專案、用戶等區分管理,并設定控制策略,從而實作多租戶,命名空間也稱為虛擬集群,
8、Label
標簽用于區分物件(比如Pod、Service);每個物件可以有多個標簽,通過標簽關聯物件,是一個key=value的鍵值對,其中key與value由用戶自己指定,可以附加到各種資源物件上,一個資源物件可以定義任意數量的Label,可以通過LabelSelector(標簽選擇器)查詢和篩選資源物件,
-
給資源打上標簽后,可以使用標簽選擇器過濾指定的標簽
-
標簽選擇器目前有兩個:基于等值關系(等于、不等于)和基于集合關系(屬于、不屬于、存在)
-
許多資源支持內嵌標簽選擇器欄位
9、ReplicationController
Replication Controller宣告某個Pod的副本數在任意時刻都符合某個預期值,定義包含如下:
(1)Pod期待的副本數(replicas)
(2)用于篩選目標Pod的Label Selector
(3)當Pod副本數小于期望時,用于新的創建Pod的模板template
(4)通過改變RC里的Pod副本數量,可以實作Pod的擴容或縮容功能
(5)通過改變RC里Pod模板中的鏡像版本,可以實作Pod的滾動升級功能
10、ReplicaSet
下一代ReplicationController,確保任何給定時間指定的Pod副本數量,并提供宣告式更新等功能,
RC與RS唯一區別就是lableselector支持不同,RS支持新的基于集合的標簽,RC僅支持基于等式的標簽,
在kubernetes1.2的時候,RC就由Replication Controller升級成Replica Set,“下一代RC”,命令兼容適用,Replica Set主要被Deployment這個更高層的資源物件所使用,從而形成一套Pod創建、洗掉、更新的編排機制,當我們使用Deployment時,無需關心它是如何創建和維護ReplicaSet的,這一切是自動發生的,
11、Deployment
Deployment是一個更高層次的API物件,它管理ReplicaSets和Pod,并提供宣告式更新等功能,
官方建議使用Deployment管理ReplicaSets,而不是直接使用ReplicaSets,這就意味著可能永遠不需要直接操作ReplicaSet物件,
12、StatefulSet
StatefulSet適合持久性的應用程式,有唯一的網路識別符號(IP),持久存盤,有序的部署、擴展、洗掉和滾動更新,
13、DaemonSet
DaemonSet確保所有(或一些)節點運行同一個Pod,當節點加入Kubernetes集群中,Pod會被調度到該節點上運行,當節點從集群中移除時,DaemonSet的Pod會被洗掉,洗掉DaemonSet會清理它所有創建的Pod,
14、Job
一次性任務,運行完成后Pod銷毀,不再重新啟動新容器,還可以任務定時運行,
15、有狀態服務集(PetSet)
K8s在1.3版本里發布了Alpha版的PetSet功能,在云原生應用的體系里,有下面兩組近義詞;
第一組是無狀態(stateless)、牲畜(cattle)、無名(nameless)、可丟棄(disposable);
第二組是有狀態(stateful)、寵物(pet)、有名(having name)、不可丟棄(non-disposable),
RC和RS主要是控制提供無狀態服務的,其所控制的Pod的名字是隨機設定的,一個Pod出故障了就被丟棄掉,在另一個地方重啟一個新的Pod,名字變了、名字和啟動在哪兒都不重要,重要的只是Pod總數;而PetSet是用來控制有狀態服務,PetSet中的每個Pod的名字都是事先確定的,不能更改,PetSet中Pod的名字的作用,是關聯與該Pod對應的狀態,
對于RC和RS中的Pod,一般不掛載存盤或者掛載共享存盤,保存的是所有Pod共享的狀態,Pod像牲畜一樣沒有分別(這似乎也確實意味著失去了人性特征);對于PetSet中的Pod,每個Pod掛載自己獨立的存盤,如果一個Pod出現故障,從其他節點啟動一個同樣名字的Pod,要掛載上原來Pod的存盤繼續以它的狀態提供服務,
適合于PetSet的業務包括資料庫服務MySQL和PostgreSQL,集群化管理服務Zookeeper、etcd等有狀態服務,PetSet的另一種典型應用場景是作為一種比普通容器更穩定可靠的模擬虛擬機的機制,傳統的虛擬機正是一種有狀態的寵物,運維人員需要不斷地維護它,容器剛開始流行時,我們用容器來模擬虛擬機使用,所有狀態都保存在容器里,而這已被證明是非常不安全、不可靠的,使用PetSet,Pod仍然可以通過漂移到不同節點提供高可用,而存盤也可以通過外掛的存盤來提供高可靠性,PetSet做的只是將確定的Pod與確定的存盤關聯起來保證狀態的連續性,PetSet還只在Alpha階段,后面的設計如何演變,我們還要繼續觀察,
16、集群聯邦(Federation)
K8s在1.3版本里發布了beta版的Federation功能,在云計算環境中,服務的作用距離范圍從近到遠一般可以有:同主機(Host,Node)、跨主機同可用區(Available Zone)、跨可用區同地區(Region)、跨地區同服務商(Cloud Service Provider)、跨云平臺,K8s的設計定位是單一集群在同一個地域內,因為同一個地區的網路性能才能滿足K8s的調度和計算存盤連接要求,而聯合集群服務就是為提供跨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之間的負載均衡是通過域名服務的負載均衡來實作的,
所有的設計都盡量不影響K8s Cluster現有的作業機制,這樣對于每個子K8s集群來說,并不需要更外層的有一個K8s Federation,也就是意味著所有現有的K8s代碼和機制不需要因為Federation功能有任何變化,
17、密鑰物件(Secret)
Secret是用來保存和傳遞密碼、密鑰、認證憑證這些敏感資訊的物件,使用Secret的好處是可以避免把敏感資訊明文寫在組態檔里,在K8s集群中配置和使用服務不可避免的要用到各種敏感資訊實作登錄、認證等功能,例如訪問AWS存盤的用戶名密碼,為了避免將類似的敏感資訊明文寫在所有需要使用的組態檔中,可以將這些資訊存入一個Secret物件,而在組態檔中通過Secret物件參考這些敏感資訊,這種方式的好處包括:意圖明確,避免重復,減少暴漏機會,
18、用戶帳戶(User Account)和服務帳戶(Service Account)
顧名思義,用戶帳戶為人提供賬戶標識,而服務賬戶為計算機行程和K8s集群中運行的Pod提供賬戶標識,用戶帳戶和服務帳戶的一個區別是作用范圍;用戶帳戶對應的是人的身份,人的身份與服務的namespace無關,所以用戶賬戶是跨namespace的;而服務帳戶對應的是一個運行中程式的身份,與特定namespace是相關的,
19、RBAC訪問授權
K8s在1.3版本中發布了alpha版的基于角色的訪問控制(Role-based Access Control,RBAC)的授權模式,相對于基于屬性的訪問控制(Attribute-based Access Control,ABAC),RBAC主要是引入了角色(Role)和角色系結(RoleBinding)的抽象概念,在ABAC中,K8s集群中的訪問策略只能跟用戶直接關聯;而在RBAC中,訪問策略可以跟某個角色關聯,具體的用戶在跟一個或多個角色相關聯,顯然,RBAC像其他新功能一樣,每次引入新功能,都會引入新的API物件,從而引入新的概念抽象,而這一新的概念抽象一定會使集群服務管理和使用更容易擴展和重用,
四、Kubernetes架構
1. etcd保存整個集群的狀態 2. apiserver提供了資源的唯一入口,并提供認證、授權、訪問控制、API注冊和發現等 3. controller manager負責維護集群的狀態,比如故障檢測、自動擴展、滾動更新等 4. scheduler負責資源的調度,按照預定的調度策略將Pod調度到相應的機器上 5. kubelet負責維護容器的生命周期,同時也負責Volume(CVI)和網路(CNI)的管理 6. Container runtime負責鏡像的管理以及Pod和容器的真正運行(CRI) 7. kube-poxy負責為Service提供cluster內部的服務發現和負載均衡 除了核心組件,還有一些推薦的組件: 8. kube-dns負責為整個集群提供DNS服務 9. Ingress Controller 為服務提供外網入口 10. Heapster提供資源監控 11. Dashboard提供GUIFederation提供跨可用區的集群 12. Fluentd-elasticsearch提供集群日志采集,存盤與查詢

1、Master節點
Master:集群控制管理節點,所有的命令都經由master處理
2、master:kube-apiserver
Kubernetes API,集群的統一入口,各組件協調者,以HTTP API提供介面服務,所有物件資源的增刪改查和監聽操作都交給APIServer處理后再提交給Etcd存盤,
負責處理來自用戶的請求,其主要作用就是對外提供RESTful的介面 包括用于查看集群狀態的讀請求以及改變集群狀態的寫請求,也是唯一一個于etcd集群通信的組件,
3、master:kube-controller-manager
處理集群中常規后臺任務,一個資源對應一個控制器,而ControllerManager就是負責管理這些控制器的,
管理器運行了一系列的控制器行程,這些行程會按照用戶的期望狀態在后臺不斷地調節整個集群中的物件,需要有高可用機制 當服務的狀態發生改變,控制器就會發現這個改變并且開始向目標狀態遷移, 由一系列控制器組成,通過apiserver監控整個集群的狀態,并確保集群處于預期的作業狀態 Node Controller #節點控制器 Deployment Controller #pod控制器 Service Controller #服務控制器 Volume Controller #存盤卷控制器 Endpoint Controller #接入點控制器 Garbage Controller #垃圾回收控制器 Namespace Controller #名稱空間控制器 Job Controller #任務控制器 Resource quta Controller #資源配額控制器
4、master:kube-scheduler
根據調度演算法為新創建的Pod選擇一個Node節點,
調度器其實為kubernetes中運行的Pod選擇部署的Worker節點 它會根據用戶的需要選擇最能滿足請求的節點來運行Pod,它會在每次需要調度Pod時執行, 主要功能是接收調度pod到適合的運算節點上 預選策略( predict ) 優選策略( priorities )
5、master:kubelet
kubelet是Master在Node節點上的Agent,管理本機運行容器的生命周期,比如創建容器、Pod掛載資料卷、下載secret、獲取容器和節點狀態等作業,kubelet將每個Pod轉換成一組容器,
6、master:kube-proxy
在Node節點上實作Pod網路代理,維護網路規則和四層負載均衡作業,
7、Node節點
Node:是kubernetes集群的作業負載節點,Master為其分配作業,當某個Node宕機時,Master會將其作業負載自動轉移到其他節點,
#1.kube-kubelet(部署容器,監控容器) kubelet是一個節點上的主要服務,他周期性的從APIServer接受新的或者修改的pod規范并且保證節點上的pod和其容器的正常運行 還會保證節點會向目標狀態遷移,該節點仍然會向Master節點發送宿主機的健康狀態, 簡單地說, kubelet的主要功能就是定時從某個地方獲取節點上pod的期望狀態(運行什么容器、運行的副本數量、網路或者存盤如何配置等等) ,并呼叫對應的容器平臺介面達到這個狀態 定時匯報當前節點的狀態給apiserver,以供調度的時候使用 鏡像和容器的清理作業,保證節點上鏡像不會占滿磁盤空間,退出的容器不會占用太多資源 #2.kube-proxy(提供容器間的網路) 負責宿主機的子網管理,同時也能將服務暴露給外部 其原理就是在多個隔離的網路中把請求轉發給正確的Pod或者容器, 是K8S在每個節點 上運行網路代理, service資源的載體 建立了pod網路和集群網路的關系( clusterip >podip ) 常用三種流量調度模式 Userspace (廢棄) Iptables (瀕臨廢棄)(絕大部分公司在用) Ipvs(推薦) 負責建立和洗掉包括更新調度規則、通知apiserver自己的更新,或者從apiserver哪里獲取其他kube- proxy的調度規則變化來更新自己的
8、docker或rocket(rkt)
9、etcd

簡介:分布式鍵值存盤系統,用于保持集群狀態,比如Pod、Service等物件資訊,etcd是受Zookeeper與doozer啟發而催生的專案,
存盤:etcd的存盤分為內部存盤和持久化(硬碟)存盤兩部分,記憶體中的存盤除了順序化地記錄所有用戶對節點資料變更的記錄外,還會對用戶資料進行索引、建堆等方便查詢的操作,而持久化則使用WAL進行記錄存盤,在k8s中,所有資料的存盤以及操作記錄都在etcd中進行存盤,所以對于k8s集群來說,etcd是相當重要的,一旦故障,可能導致整個集群的癱瘓或者資料丟失,
在WAL體系中,所有的資料在提交之前都會進行日志記錄,持久化存盤的目錄分為兩個:snap和wal,snapshot相當于資料壓縮,默認會將10000條wal操作記錄merge成snapshot,節省存盤,又保證資料不會丟失,
WAL:存盤所有事務的變化記錄
Snapshot:用于存放某一時刻etcd所有目錄的資料
核心演算法:etcd的核心演算法是raft演算法,強一致性演算法,

注意:由于etcd是負責存盤,所以不建議搭建單點集群,如zookeeper一樣,由于存在選舉策略,所以一般推薦奇數個集群,如3,5,7,只要集群半數以上的結點存活,那么集群就可以正常運行,否則集群可能無法正常使用,
10、Flanne 網路相關
Kubernetes為每個Pod都分配了唯一的IP地址,稱之為PodIP,一個Pod里的多個容器共享PodIP地址,要求底層網路支持集群內任意兩個Pod之間的直接通信,通常采用虛擬二層網路技術來實作(Flannel),
Kubernetes支持一種特殊的網路模型,Kubernetes創建了一個地址空間,并且不動態的分配埠,它可以允許用戶選擇任何想使用的埠,為了實作這個功能,它為每個Pod分配IP地址,
現代互聯網應用一般都會包含多層服務構成,比如web前臺空間與用來存盤鍵值對的記憶體服務器以及對應的存盤服務,為了更好的服務于這樣的架構,Kubernetes提供了服務的抽象,并提供了固定的IP地址和DNS名稱,而這些與一系列Pod進行動態關聯,這些都通過之前提到的標簽進行關聯,所以我們可以關聯任何我們想關聯的Pod,當一個Pod中的容器訪問這個地址的時候,這個請求會被轉發到本地代理(kube proxy),每臺機器上均有一個本地代理,然后被轉發到相應的后端容器,Kubernetes通過一種輪訓機制選擇相應的后端容器,這些動態的Pod被替換的時候,Kube proxy時刻追蹤著,所以,服務的IP地址(dns名稱),從來不變,
五、Kubernetes主要功能
1、資料卷 : Pod中容器之間共享資料,可以使用資料卷,
2、應用程式健康檢查:容器內服務可能行程堵塞無法處理請求,可以設定監控檢查策略保證應用健壯性,
3、復制應用程式實體:控制器維護著Pod副本數量,保證一個Pod或一組同類的Pod數量始終可用,
4、彈性伸縮:根據設定的指標(CPU利用率)自動縮放Pod副本數,
5、服務發現:使用環境變數或DNS服務插件保證容器中程式發現Pod入口訪問地址,
6、負載均衡:一組Pod副本分配一個私有的集群IP地址,負載均衡轉發請求到后端容器,在集群內部其他Pod可通過這個ClusterIP訪問應用,
7、滾動更新:更新服務不中斷,一次更新一個Pod,而不是同時洗掉整個服務,
8、服務編排:通過檔案描述部署服務,使得應用程式部署變得更高效,
9、資源監控:Node節點組件集成cAdvisor資源收集工具,可通過Heapster匯總整個集群節點資源資料,然后存盤到InfluxDB時序資料庫,再由Grafana展示,
10、提供認證和授權:支持屬性訪問控制(ABAC)、角色訪問控制(RBAC)認證授權策略,
六、Kubernetes命令列管理工具
一般使用kubectl來管理Kubernetes集群,
Kubernetes UI/dashboard
Kubernetes有一個基于web的用戶界面,它可以圖表化顯示當前集群狀態,
Kubernetes界面默認是作為集群插件部署的,要訪問它需要進入 https:///ui 這個地址,之后會重定向到 https:///api/v1/proxy/namespaces/kube-system/services/kube-ui/#/dashboard/ ,
如果你發現你無法訪問UI,那有可能是Kubernetes UI服務在你的集群上還沒有啟動,如果是這樣,你可以手動開啟UI服務:
kubectl create -f cluster/addons/kube-ui/kube-ui-rc.yaml –namespace=kube-system kubectl create -f cluster/addons/kube-ui/kube-ui-svc.yaml –namespace=kube-system
通常,這些應該通過 kube-addons.sh 腳本自動地被運行在主節點上,
七、Kubernetes相關經驗
1、Pod的管理
在Kubernetes中,所有的容器均在Pod中運行,一個Pod可以承載一個或者多個相關的容器,在后邊的案例中,同一個Pod中的容器會部署在同一個物理機器上并且能夠共享資源,一個Pod也可以包含O個或者多個磁盤卷組(volumes),這些卷組將會以目錄的形式提供給一個容器,或者被所有Pod中的容器共享,對于用戶創建的每個Pod,系統會自動選擇那個健康并且有足夠容量的機器,然后創建類似容器的容器,當容器創建失敗的時候,容器會被node agent自動的重啟,這個node agent叫kubelet,但是,如果是Pod失敗或者機器,它不會自動的轉移并且啟動,除非用戶定義了 replication controller,
用戶可以自己創建并管理Pod,Kubernetes將這些操作簡化為兩個操作:基于相同的Pod組態檔部署多個Pod復制品;創建可替代的Pod當一個Pod掛了或者機器掛了的時候,而Kubernetes API中負責來重新啟動,遷移等行為的部分叫做“replication controller”,它根據一個模板生成了一個Pod,然后系統就根據用戶的需求創建了許多冗余,這些冗余的Pod組成了一個整個應用,或者服務,或者服務中的一層,一旦一個Pod被創建,系統就會不停的監控Pod的健康情況以及Pod所在主機的健康情況,如果這個Pod因為軟體原因掛掉了或者所在的機器掛掉了,replication controller 會自動在一個健康的機器上創建一個一摸一樣的Pod,來維持原來的Pod冗余狀態不變,一個應用的多個Pod可以共享一個機器,
我們經常需要選中一組Pod,例如,我們要限制一組Pod的某些操作,或者查詢某組Pod的狀態,作為Kubernetes的基本機制,用戶可以給Kubernetes Api中的任何物件貼上一組 key:value 的標簽,然后,我們就可以通過標簽來選擇一組相關的Kubernetes Api 物件,然后去執行一些特定的操作,每個資源額外擁有一組(很多) keys 和 values,然后外部的工具可以使用這些keys和vlues值進行物件的檢索,這些Map叫做annotations(注釋),
2、網路配置
如何從Internet訪問部署的應用?
部署前的服務有一個IP地址,但這個地址僅在Kubernetes集群中可用,這意味著無法通過網路訪問該服務!在Google Cloud Engine上運行時,Kubernetes會自動配置一個負載均衡用以訪問應用;如果不在Google Cloud Engine上運行(比如我們),那就需要做一些額外的作業來獲得負載均衡了,
直接在主機埠上開放服務是一個可行的解決方案(很多人一開始的確是這么做的),但我們發現,這樣的做法等于放棄了Kubernetes所提供的許多好處,如果我們依賴主機上的埠,部署多個應用時會遇到埠沖突,另外這樣的做法會加大擴展集群和更換主機的難度,
我們發現,解決以上問題的更好辦法,是在Kubernetes集群前配置負載均衡器,例如HAProxy或者NGINX,于是我們開始在AWS上的VPN中運行Kubernetes集群,并使用AWS ELB將外部web流量路由到內部HAProxy集群,HAProxy為每個Kubernetes服務配置了“后端”,以便將流量交換到各個pods,
在任何情況下,創建新的Kubernetes服務,我們都需要一種機制動態重新配置負載均衡器(在我們的例子中是HAProxy),
Kubernetes社區目前正在開發一個名為ingress的功能,用來直接從Kubernetes配置外部負載均衡器,
3、配置負載均衡
首先,我們需要一個地方存盤負載均衡器配置,負載均衡器配置可以存盤在任何地方,不過因為我們已經有etcd可用,就把這些配置放在了etcd里,我們使用一個名為“confd”的工具觀察etcd中的配置變動,并用模板生成了一個新的HAProxy組態檔,當一個新的服務添加到Kubernetes,我們向etcd中添加一個新的配置,一個新的HAProxy組態檔也就此產生,
4、資源限制
使用Kubernetes時,搞清楚資源限制很重要,你可以在每個pod上配置資源請求和CPU/記憶體限制,也可以控制資源保證和bursting limits,
這些設定對于高效運行多個容器極為重要,防止容器因分配記憶體不足而意外停止,
建議盡早設定和測驗資源限制,沒有限制時,看起來運行良好,不代表把重要負載放到容器中不會出現問題,
5、Kubernetes監控
當我們快要搭建好Kubernetes時,我們意識到監控和日志在這個新的動態環境中非常重要,當我們面對大規模服務和節點時,進入服務器查看日志檔案是不現實的,建一個中心化的日志和監控系統需要盡快提上議程,
6、日志
有很多用于日志記錄的開源工具,我們使用的是Graylog和Apache Kafka(從容器收集摘錄日志的訊息傳遞系統),容器將日志發送給Kafka,Kafka交給Graylog進行索引,我們讓應用組件將日志打給Kafka,方便將日志流式化,成為易于索引的格式,也有一些工具可以從容器外收集日志,然后發送給日志系統,
7、監控
Kubernetes具備超強的故障恢復機制,Kubernetes會重啟意外停止的pod,我們曾遇到過因記憶體泄露,導致容器在一天內宕機多次的情況,然而令人驚訝的是,甚至我們自己都沒有察覺到,
Kubernetes在這一點上做得非常好,不過一旦問題出現,即使被及時處理了,我們還是想要知道,因此我們使用了一個自定義的運行狀況檢查儀表盤來監控Kubernetes節點和pod,以及包括資料存盤在內的一些服務,可以說在監控方面,Kubernetes API再次證明了其價值所在,
檢測負載、吞吐量、應用錯誤等狀態也是同樣重要的,有很多開源軟體可以滿足這一需求,我們的應用組件將指標發布到InfluxDB,并用Heapster去收集Kubernetes的指標,我們還通過Grafana(一款開源儀表盤工具)使存盤在InfluxDB中的指標可視化,有很多InfluxDB/Grafana堆疊的替代方案,無論你才用哪一種,對于運行情況的跟蹤和監控都是非常有價值的,
8、資料存盤和Kubernetes
很多Kubernetes新用戶都有一個問題:我該如何使用Kubernetes處理資料?
運行資料存盤時(如MangoDB或MySQL),我們很可能會有持久化資料儲存的需求,不過容器一但重啟,所有資料都會丟失,這對于無狀態組件沒什么影響,但對持久化資料儲存顯然行不通,好在,Kubernetes具有Volume機制,
Volume可以通過多種方式備份,包括主機檔案系統、EBS(AWS的Elastic Block Store)和nfs等,當我們研究持久資料問題是,這是一個很好的方案,但不是我們運行資料存盤的答案,
9、副本問題
在大多數部署中,資料存盤也是有副本的,Mongo通常在副本集中運行,而MySQL可以在主/副模式下運行,我們都知道資料儲存集群中的每個節點應該備份在不同的volume中,寫入相同volume會導致資料損壞,另外,大多數資料存盤需要明確配置才能使集群啟動并運行,自動發現和配置節點并不常見,同時,運行著資料存盤的機器通常會針對某項作業負載進行調整,例如更高的IOPS,擴展(添加/洗掉節點)對于資料存盤來說,也是一個昂貴的操作,這些都和Kubernetes部署的動態本質不相符,
決定不在生產環境資料存盤上使用Kubernetes,以我們的情況,在Kubernetes內運行資料存盤沒有想象中那么完美,設定起來也比其他Kubernetes部署復雜得多,
于是我們決定不在生產環境資料存盤上使用Kubernetes,而是選擇在不同的機器上手動啟動這些集群,我們在Kubernetes內部運行的應用正常連接到資料存盤集群,
所以說,沒必要運行Kubernetes的一切,按自身情況與其他工具配合使用,會有意想不到的效果,比如我們的資料存盤和HAProxy服務器,
10、未來
看看我們現在的部署,可以負責任的說,Kubernetes的表現絕對是夢幻級的,而Kubernetes API更是自動化部署流程的利器,由于不需要處理VM,我們現在的部署相比之前更快、更可靠,更簡單的容器測驗和交付,也讓我們在構建和部署可靠性上得到了巨大提升,
這種新的部署方式迅速高效,讓我們得以跟上其他團隊的節奏,這絕對是必要的,
11、成本計算
任何事情都有兩面性,運行Kubernetes,需要一個etcd集群以及一個Master節點,對于較小的部署來說,這一開銷還是比較大的,適合通過一些云服務達成,
對于大規模部署,Kubernetes可以幫助節省大量服務器成本,etcd集群和Master節點這點開銷就顯得微不足道了,Kubernetes讓很多容器在一個主機上運行變得非常容易,最大程度上利用了現有資源,減少了服務器數量,成本自然下降了,不過這樣的集群也給運維作業提出了更高的要求,必須要的時候,我們可以選擇一些云計算平臺提供的云服務來輕松達成,
- 作者:踏雪無痕
- 出處:http://www.cnblogs.com/chenpingzhao/
- 本文著作權歸作者和博客園共有,如需轉載,請聯系 pingzhao1990#163.com
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/468764.html
標籤:其他
下一篇:linux基本使用
