kubernetes 必備知識介紹

Kubernetes是什麼?

K8s是什麼
Kubernetes項目是2014年由Google公司啓動的,是Google公司在15年生產環境經驗基礎上 ,結合了社區的一些優秀點子和實踐而構建的。

Kubernetes是一個以容器爲中心的基礎架構,可以實現在物理集羣或虛擬機集羣上調度和運行容器,提供容器自動部署、擴展和管理的開源平臺。滿足了應用程序在生產環境中的一些通用需求:應用實例副本、水平自動擴展、命名與發現、負載均衡、滾動升級、資源監控等。

使用Kubernetes可以:

  1. 自動化容器的部署和複製

  2. 隨時擴展或收縮容器規模

  3. 將容器組織成組,並且提供容器間的負載均衡

  4. 很容易地升級應用程序容器的新版本

  5. 提供容器彈性,如果容器失效就替換它,等等

Kubernetes不提供:

  1. 中間件(例如消息總線)、數據處理框架(如Spark)、數據庫(如MySQL),也不提供集羣存儲系統(如Ceph)。

  2. 源代碼到鏡像的處理,即不部署源代碼也不會構建的應用,持續集成(Continuous Integration: CI)的工作也需要由用戶按自己項目決定。

  3. 不提供應用配置系統。

  4. 不提供機器配置、維護、管理。

Kubernetes架構

K8s架構
Kubernetes集羣由2類節點組成:Master和Node。

在Master上運行etcd、kube-apiserver、kube-scheduler、kube-controller-magager四個組件,其中後3個組件構成了Kubernetes的總控中心,負責對集羣中所有資源進行管控和調度。

在Node上運行kubelet、kube-proxy、dockerdaemon三個組件,其中前2個組件負責對本節點上的Pod的生命週期進行管理,以及實現服務代理的功能。 
另外在所有結點上都可以運行kubectl命令行工具,它提供了Kubernetes的集羣管理工具集。

etcd:是一個高可用的key/value存儲系統,用於持久化K8s集羣內中的所有資源對象,例如集羣中的Node、Service、Pod、RC、Namespace等。

kube-apiserver:封裝了操作etcd的接口,以REST的方式對外提供服務,這些接口基本上都是集羣資源對象的增刪改查以及監聽資源變化的接口,如創建Pod、創建RC,監聽Pod變化的接口。kube-apiserver是連接其它服務組件的樞紐。

kube-scheduler:集羣中的調度器,負責Pod在集羣節點中的調度分配。

kube-controller-manager:集羣內部的管理控制中心,主要實現Kubernetes集羣的故障檢查和恢復自動化的工作。比如endpoints控制器負責Endpoints對象的創建,更新。node控制器負責節點的發現,管理和監控。複製控制器負責pod的數量符合預期定義。

kubelet:負責本Node上的Pod創建、修改、監控、刪除等全生命週期管理,以及Pod對應的容器、鏡像、卷的管理,同時定時上報本Node的狀態信息給kube-apiserver。

kube-proxy:實現了Service的代理以及軟件模式的負載均衡器。

Kubernetes基本概念

Pod

Pod基本概念

Pod是Kubernetes的裏可部署的和管理的最小單元,一個或多個容器構成一個Pod,通常Pod裏的容器運行相同的應用。Pod包含的容器都運行在同一個宿主機上,看作一個統一管理單元。

每個Pod中都有一個pause容器,pause容器做爲Pod的網絡接入點,Pod中其他的容器會使用容器映射模式啓動並接入到這個pause容器。屬於同一個Pod的所有容器共享網絡的namespace。

一個Pod可以被一個容器化的環境看做是應用層的邏輯宿主機(Logical Host),每個Pod中有多個容器,同一個Pod中的多個容器通常是緊密耦合的。同一個pod中的容器共享如下資源:

PID 名字空間:Pod中不同應用程序可以看到其它應用程序的進程ID。 
網絡名字空間:Pod中的多個容器訪問同一個IP和端口空間。 
IPC名字空間:Pod中的應用能夠使用SystemV IPC和POSIX消息隊列進行通信。

UTS名字空間:Pod中的應用共享一個主機名。

Volumes:Pod中的各個容器應用還可以訪問Pod級別定義的共享卷。

Pod的生命週期,通過模板定義Pod,然後分配到一個Node上運行,在Pod所包含的容器運行結束後Pod也結束。

在整個過程中,Pod的狀態:

掛起 ︰ Pod已被提交到Master,但一個或多個容器鏡像尚未創建。包括調度和下載鏡像,可能需要一段時間。

運行 ︰ Pod已綁定到的節點,和所有容器鏡像已創建完成。至少一個容器是仍在運行,或正在啓動或重新啓動。

成功 ︰ Pod的所有容器已經成功的終止,並不會重新啓動。

失敗 ︰ Pod的所有容器已經都終止,至少一個容器已都終止失敗 (以非零退出狀態退出)。

未知 ︰ 出於某種原因的Pod狀態無法獲得,通常由於在與主機的Pod通信錯誤。

容器探測的診斷方式:

ExecAction :在container中執行指定的命令。當其執行成功時,將其退出碼設置爲0;

TCPSocketAction :執行一個TCP檢查使用container的IP地址和指定的端口作爲socket。如果端口處於打開狀態視爲成功;

HTTPGetAcction :執行一個HTTP默認請求使用container的IP地址和指定的端口以及請求的路徑作爲url,用戶可以通過host參數設置請求的地址,通過scheme參數設置協議類型(HTTP、HTTPS)如果其響應代碼在200~400之間,設爲成功。

探測的結果有:

Success :表示通過檢測 
Failure :表示沒有通過檢測 
Unknown :表示檢測沒有正常進行

探測的種類:

LivenessProbe :表示container是否處於live狀態。如果LivenessProbe失敗,LivenessProbe將會通知kubelet對應的container不健康了。隨後kubelet將kill掉container,並根據RestarPolicy進行進一步的操作。默認情況下LivenessProbe在第一次檢測之前初始化值爲Success,如果container沒有提供LivenessProbe,則也認爲是Success;

ReadinessProbe :表示container是否以及處於可接受service請求的狀態了。如果ReadinessProbe失敗,endpointscontroller將會從service所匹配到的endpoint列表中移除關於這個container的IP地址。因此對於Service匹配到的endpoint的維護其核心是ReadinessProbe。默認Readiness的初始值是Failure,如果一個container沒有提供Readiness則被認爲是Success。

對容器實施配額,只要在Pod的定義文件中設定resources的屬性就可以爲容器指定配額,目前容器支持的CPU和Memory兩種資源的配額。requests指定必須保證的最小資源,limits限制最大資源。

LabelandSelector

LabelandSelector
Label以key/value鍵值對的形式附加到各種對象上,如Pod、Node等。Label定義了這些對象的可識別屬性,用來對它們進行管理和選擇。Label可以在創建對象時指定也可以在對象創建後通過api進行添加。

在爲對象定義好了Label後,其它對象就可以使用Label Selector來選擇還有指定Label的對象。

有效的Label key有兩個部分︰可選前綴和名稱,以一個正斜槓(/)分隔。名稱部分是必須的並且長度爲 63 個字符或更少,開始和結束以字母數字字符 ([a-z0-9A-Z]) 中間可以有破折號(-),下劃線 (_),圓點(.)和字母數字。前綴是可選的。如果指定,前綴必須是 DNS 子域︰一系列的 DNS 標籤分隔用點(.),不長於 253 個字符總數,其次是斜槓(/)。如果省略前綴,則標籤鍵是須推定爲私人用戶。kubernetes.io/ 前綴爲 Kubernetes 核心組件保留。

有效的Label value必須是 63 個字符或更少,必須爲空或開始和結束以字母數字字符 ([a-z0-9A-Z])中間可以有破折號(-),下劃線 (_),圓點(.)和字母數字。 
有2種Label Selector:基於等式的(Equality-based requirement)和基於集合的(Set-based requirement),在使用時可以將多個Label進行組合來選擇。

基於等式的Label Selector使用等式的表達式來進行選擇。

· name=redis:選擇所有包含Label中key=“name”且value=“redis”的對象。

· tier!=frontend:選擇所有包含Label中key=“tier”且value!=“frontend”的對象。

基於集合的Label Selector使用集合操作的表達式來進行選擇。

· name in(redis-master, redis-slave):選擇所有包含Label中key=“name”且value=“redis-master”或”redis-slave”的對象。

· tier notin(frontend):選擇所有包含Label中key=“tier”且value不等於”frontend”的對象。

可以將多個Label Selector進行組合,使用”,”進行分割。基於等於的Label Selector和基於集合的Label Selector可以任意組合。例如:

name=redis,tier!=frontend 
name in(redis-master, redis-slave), tier=backend

使用Label可以給對象創建多組標籤,Service,RC組件通過Label Selector來選擇對象範圍,Label 和 Label Selector共同構成了Kubernetes系統中最核心的應用模型,使得對象能夠被精細的分組管理,同時實現了高可用性。

ReplicationController

Replication Controller
Replication Controller核心作用是確保在任何時候集羣中一個RC所關聯的Pod都保持一定數量的副本處於正常運行狀態。如果該Pod的副本數量太多,則Replication Controller會銷燬一些Pod副本;反之Replication Controller會添加副本,直到Pod的副本數量達到預設的副本數量。

最好不要越過RC直接創建Pod,因爲Replication Controller會通過RC管理Pod副本,實現自動創建、補足、替換、刪除Pod副本,這樣就能提高應用的容災能力,減少由於節點崩潰等意外狀況造成的損失。即使應用程序只有一個Pod副本,也強烈建議使用RC來定義Pod。

當Pod通過RC創建後,即使修改RC的模板定義,也不會影響到已經創建的Pod。此外Pod可以通過修改標籤來實現脫離RC的管控,該方法可以用於將Pod從集羣中遷移、數據修復等調試。對於被遷移的Pod副本,RC會自動創建一個新副本替換被遷移的副本。需要注意的是,通過kubectl刪除RC時會一起刪掉RC所創建的Pod副本,但是通過REST API刪除時,需要將replicas設置爲0,等到Pod刪除後再刪除RC。

重新調度:如前面所說,不論是想運行1個副本還是1000個副本,Replication Controller都能確保指定數量的副本存在於集羣中,即使發生節點故障或Pod副本被終止運行等意外情況。

伸縮:修改Replication Controller的replicas的屬性值,可以非常容易的實現擴大或縮小副本的數量。例如,通過下列命令可以實現手工修改名爲foo的RC副本數量爲3:kubectl scale –replicas=3 rc/foo

滾動更新:副本控制器被設計成通過逐個替換Pod的方式來輔助服務的滾動更新。推薦的方法是創建一個新的只有一個副本的RC,若新的RC副本數量加1,則舊的RC副本數量減1,直到這個舊的RC副本數量爲0,然後刪除舊的RC。這樣即使在滾動更新的過程中發生了不可預測的錯誤,Pod集合的更新也都在可控範圍之內。在理想情況下,滾動更新控制器需要將準備就緒的應用考慮在內,保證在集羣中任何時刻都有足夠數量的可用的Pod(https://github.com/kubernetes/kubernetes/issues/1353

Service

Service
雖然每個Pod都會被分配一個單獨的IP地址,但這個IP地址會隨着Pod的銷燬而消失。引出的一個問題是:如果有一組Pod組成一個應用集羣來提供服務,那麼該如何訪問它們呢?

Service就是用來解決這個問題的,一個Service可以看作一組提供相同服務的Pod的對外接口,Service是通過LabelSelector選擇一組Pod作用後端服務提供者。

舉個例子:redis運行了2個副本,這兩個Pod對於前端程序來說沒有區別,所以前端程序並不關心是哪個後端副本在提供服務。並且後端Pod在發生變化時,前端也無須跟蹤這些變化。Service就是用來實現這種解耦的抽象概念。

Pod的IP地址是由Docker Daemon根據docker0網橋的IP地址段進行分配的,但Service的Cluster IP地址是Kubernetes系統中的虛擬IP地址,由系統動態分配。

Service的Cluster IP相對於Pod的IP地址來說相對穩定,Service被創建時即被分配一個IP地址,在銷燬該Service之前,這個IP地址都不會再變化了。而Pod在Kubernetes集羣中生命週期較短,可能被Replication Controller銷燬、再次創建,新創建的Pod就會被分配一個新的IP地址。

如何通過Service Cluster IP訪問到後端的Pod呢?Kubernetes羣集中的每個節點運行kube-proxy。該程序負責對Service實現虛擬IP的實現。在 Kubernetes v1.0,代理即是純粹在用戶空間。在Kubernetes v1.1添加了iptables代理,但是並不是默認的操作模式。在Kubernetes v1.2默認用iptables代理模式。在iptables代理模式下kube-proxy會觀察Kubernetes Master節點添加和刪除Service對象和Endpoint對象的行爲,對於每個服務,kube-proxy會在本機的iptables中安裝相應的規則,iptables通過這些規則將會捕獲到該Service的流量並將他們重定向到一個後端的Pod。默認情況下後, 後端的選擇是隨機的。

但是也可以選擇基於客戶端IP的sessionaffinity,可以通過設置service.spec.sessionAffinity=ClientIP(默認值爲“None”)來選擇該方式。與用戶空間的代理一樣,客戶端不知道Kubernetes或Service或Pod,任何對於Service的IP:Port的訪問都會被代理到後端。但是iptables的代理比用戶空間代理是更快、 更可靠。

Kubernetes支持兩種主要的模式來找到Service:一個是容器的Service環境變量,另一個是DNS。在創建一個Pod時,kubelet在該Pod的所有容器中爲當前所有Service添加一系列環境變量。

Kubernetes支持形如“{SVCNAME}SERVICE_HOST”和“{SVCNAME}_SERVICE_PORT”的變量。其中“{SVCNAME}”是大寫的ServiceName,同時Service Name包含的“-”符號會轉化爲“”符號。例如,已存在名稱爲“redis-master”的Service,它對外暴露6379的TCP端口,且集羣IP爲10.0.0.11。kubelet會爲新建的容器添加以下環境變量:

REDIS_MASTER_SERVICE_HOST=10.0.0.11 
REDIS_MASTER_SERVICE_PORT=6379 
REDIS_MASTER_PORT=tcp://10.0.0.11:6379 
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379 
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp 
REDIS_MASTER_PORT_6379_TCP_PORT=6379 
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11

通過環境變量來創建Service會帶來一個不好的結果,即任何被某個Pod所訪問的Service,必須先於該Pod創建,否則和這個後創建的Service相關的環境變量,將不會被加入該Pod的容器中。

另一個通過名字找到服務的方式是DNS。DNS服務器通過Kubernetes API Server監控與Service相關的活動。當監控到添加Service的時,DNS服務器爲每個Service創建一系列DNS記錄。例如:有個叫做”my-service“的service,他對應的kubernetesnamespace爲”my-ns“,那麼會有他對應的dns記錄,叫做”my-service.my-ns“。那麼在my-ns的namespace中的pod都可以對my-service做name解析來輕鬆找到這個service。在其他namespace中的pod解析”my-service.my-ns“來找到他。解析出來的結果是這個service對應的cluster ip。

Service的ClusterIP地址只能在集羣內部訪問,如果集羣外部的用戶希望Service能夠提供一個供集羣外用戶訪問的IP地址。Kubernetes通過兩種方式來實現上述需求,一個是“NodePort”,另一個是“LoadBalancer”。

每個service都有個type字段,值可以有以下幾種:

· ClusterIP:使用集羣內的私有ip —— 這是默認值。

· NodePort:除了使用cluster ip外,也將service的port映射到每個node的一個指定內部port上,映射的每個node的內部port都一樣。

· LoadBalancer:使用一個ClusterIP & NodePort,但是會向cloud provider申請映射到service本身的負載均衡。

如果將type字段設置爲NodePort,kubernetesmaster將會爲service的每個對外映射的port分配一個”本地port“,這個本地port作用在每個node上,且必須符合定義在配置文件中的port範圍(爲–service-node-port-range)。這個被分配的”本地port“定義在service配置中的spec.ports[*].nodePort字段,如果爲這個字段設定了一個值,系統將會使用這個值作爲分配的本地port 或者 提示你port不符合規範。

Namespace

Namespace

Kubernetes 支持在一個物理集羣上創建多個虛擬羣集。這些虛擬羣集被稱爲命名空間。大多數Kubernetes資源(例如: pods, services, replication controllers, and others) 在名稱空間中。但是namespace資源本身不在名稱空間中。還有一些底層資源如Node, PersistentVolumes不在名稱空間中。

Kubernetes集羣啓動後,會創建一個名爲“default”的Namespace,如果不特別指明Namespace,則創建的Pod、RC、Service都將被創建到“default”的Namespace中。

當你創建一個服務時,它將創建相應的 DNS 條目。此條目是窗體..svc.cluster.local,這意味着如果一個容器只是使用 它將解析爲命名空間的本地的服務。這是用於跨多個命名空間,比如開發、分期和生產使用相同的配置。如果你想要達到整個命名空間,您需要使用完全限定的域名稱(FQDN)。

使用Namespace來組織Kubernetes的各種對象,可以實現對用戶的分組,即“多租戶”的管理。對不同的租戶還可以進行單獨的資源配額設置和管理,使得整個集羣的資源配置非常靈活、方便。一個集羣中的資源總是有限的,當這個集羣被多個租戶的應用同時使用時,爲了更好地使用這種有限的共享資源,需要將資源配額的管理單元提升到租戶級別,通過在不同租戶對應的Namespace上設置對應的ResourceQuota即可達到目的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章