從單機(jī)容器化技術(shù) Docker 到分布式容器化架構(gòu)方案 Kubernetes,,當(dāng)今容器化技術(shù)發(fā)展盛行。本文面向小白讀者,,旨在快速帶領(lǐng)讀者了解 Docker,、Kubernetes 的架構(gòu)、原理,、組件及相關(guān)使用場景,。Docker1.什么是 DockerDocker 是一個開源的應(yīng)用容器引擎,是一種資源虛擬化技術(shù),,讓開發(fā)者可以打包他們的應(yīng)用以及依賴包到一個可移植的容器中,,然后發(fā)布到任何流行的 Linux 機(jī)器上。虛擬化技術(shù)演歷路徑可分為三個時代:
在沒有 Docker 的時代,我們會使用硬件虛擬化(虛擬機(jī))以提供隔離,。這里,,虛擬機(jī)通過在操作系統(tǒng)上建立了一個中間虛擬軟件層 Hypervisor ,并利用物理機(jī)器的資源虛擬出多個虛擬硬件環(huán)境來共享宿主機(jī)的資源,,其中的應(yīng)用運(yùn)行在虛擬機(jī)內(nèi)核上,。但是,虛擬機(jī)對硬件的利用率存在瓶頸,,因為虛擬機(jī)很難根據(jù)當(dāng)前業(yè)務(wù)量動態(tài)調(diào)整其占用的硬件資源,,加之容器化技術(shù)蓬勃發(fā)展使其得以流行。 Docker,、虛擬機(jī)對比:
另外開發(fā)人員在實(shí)際的工作中,,經(jīng)常會遇到測試環(huán)境或生產(chǎn)環(huán)境與本地開發(fā)環(huán)境不一致的問題,,輕則修復(fù)保持環(huán)境一致,重則可能需要返工,。但 Docker 恰好解決了這一問題,,它將軟件程序和運(yùn)行的基礎(chǔ)環(huán)境分開。開發(fā)人員編碼完成后將程序整合環(huán)境通過 DockerFile 打包到一個容器鏡像中,,從根本上解決了環(huán)境不一致的問題,。 2.Docker 的構(gòu)成Docker 由鏡像、鏡像倉庫,、容器三個部分組成
3.Docker 的實(shí)現(xiàn)原理到此讀者們肯定很好奇 Docker 是如何進(jìn)行資源虛擬化的,,并且如何實(shí)現(xiàn)資源隔離的,其核心技術(shù)原理主要有(內(nèi)容部分參考自 Docker 核心技術(shù)與實(shí)現(xiàn)原理): (1).Namespace在日常使用 Linux 或者 macOS 時,,我們并沒有運(yùn)行多個完全分離的服務(wù)器的需要,,但是如果我們在服務(wù)器上啟動了多個服務(wù),這些服務(wù)其實(shí)會相互影響的,,每一個服務(wù)都能看到其他服務(wù)的進(jìn)程,,也可以訪問宿主機(jī)器上的任意文件,這是很多時候我們都不愿意看到的,,我們更希望運(yùn)行在同一臺機(jī)器上的不同服務(wù)能做到完全隔離,,就像運(yùn)行在多臺不同的機(jī)器上一樣。 命名空間 (Namespaces) 是 Linux 為我們提供的用于分離進(jìn)程樹,、網(wǎng)絡(luò)接口,、掛載點(diǎn)以及進(jìn)程間通信等資源的方法。Linux 的命名空間機(jī)制提供了以下七種不同的命名空間,,通過這七個選項我們能在創(chuàng)建新的進(jìn)程時設(shè)置新進(jìn)程應(yīng)該在哪些資源上與宿主機(jī)器進(jìn)行隔離,。
在 Linux 系統(tǒng)中,有兩個特殊的進(jìn)程,,一個是 pid 為 1 的 /sbin/init 進(jìn)程,,另一個是 pid 為 2 的 kthreadd 進(jìn)程,這兩個進(jìn)程都是被 Linux 中的上帝進(jìn)程 idle 創(chuàng)建出來的,,其中前者負(fù)責(zé)執(zhí)行內(nèi)核的一部分初始化工作和系統(tǒng)配置,,也會創(chuàng)建一些類似 getty 的注冊進(jìn)程,而后者負(fù)責(zé)管理和調(diào)度其他的內(nèi)核進(jìn)程,。 當(dāng)在宿主機(jī)運(yùn)行 Docker,,通過 接著,,在方法 func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) { s := oci.DefaultSpec() // ... if err := setNamespaces(daemon, &s, c); err != nil { return nil, fmt.Errorf("linux spec namespaces: %v", err) } return &s, nil } func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error { // user // network // ipc // uts // pid if c.HostConfig.PidMode.IsContainer() { ns := specs.LinuxNamespace{Type: "pid"} pc, err := daemon.getPidContainer(c) if err != nil { return err } ns.Path = fmt.Sprintf("/proc/%d/ns/pid", pc.State.GetPID()) setNamespace(s, ns) } else if c.HostConfig.PidMode.IsHost() { oci.RemoveNamespace(s, specs.LinuxNamespaceType("pid")) } else { ns := specs.LinuxNamespace{Type: "pid"} setNamespace(s, ns) } return nil } 網(wǎng)絡(luò)當(dāng) Docker 容器完成命名空間的設(shè)置,其網(wǎng)絡(luò)也變成了獨(dú)立的命名空間,,與宿主機(jī)的網(wǎng)絡(luò)互聯(lián)便產(chǎn)生了限制,這就導(dǎo)致外部很難訪問到容器內(nèi)的應(yīng)用程序服務(wù),。Docker 提供了 4 種網(wǎng)絡(luò)模式,,通過
由于后續(xù)介紹 Kubernetes 利用了 Docker 的 bridge 網(wǎng)絡(luò)模式,,所以僅介紹該模式,。Linux 中為了方便各網(wǎng)絡(luò)命名空間的網(wǎng)絡(luò)互相訪問,設(shè)置了 Veth Pair 和網(wǎng)橋來實(shí)現(xiàn),,Docker 也是基于此方式實(shí)現(xiàn)了網(wǎng)絡(luò)通信,。 下圖中 掛載點(diǎn) 解決了進(jìn)程和網(wǎng)絡(luò)隔離的問題,,但是 Docker 容器中的進(jìn)程仍然能夠訪問或者修改宿主機(jī)器上的其他目錄,,這是我們不希望看到的。 在新的進(jìn)程中創(chuàng)建隔離的掛載點(diǎn)命名空間需要在 clone 函數(shù)中傳入 CLONE_NEWNS,,這樣子進(jìn)程就能得到父進(jìn)程掛載點(diǎn)的拷貝,,如果不傳入這個參數(shù)子進(jìn)程對文件系統(tǒng)的讀寫都會同步回父進(jìn)程以及整個主機(jī)的文件系統(tǒng)。當(dāng)一個容器需要啟動時,,它一定需要提供一個根文件系統(tǒng)(rootfs),,容器需要使用這個文件系統(tǒng)來創(chuàng)建一個新的進(jìn)程,所有二進(jìn)制的執(zhí)行都必須在這個根文件系統(tǒng)中,,并建立一些符號鏈接來保證 IO 不會出現(xiàn)問題,。 另外,通過 Linux 的 (2).Control Groups(CGroups)Control Groups(CGroups) 提供了宿主機(jī)上物理資源的隔離,,例如 CPU、內(nèi)存,、磁盤 I/O 和網(wǎng)絡(luò)帶寬,。主要由這幾個組件構(gòu)成:
在 Linux 的 Docker 安裝目錄下有一個 docker 目錄,當(dāng)啟動一個容器時,,就會創(chuàng)建一個與容器標(biāo)識符相同的 CGroup,,舉例來說當(dāng)前的主機(jī)就會有以下層級關(guān)系: 每一個 CGroup 下面都有一個 tasks 文件,其中存儲著屬于當(dāng)前控制組的所有進(jìn)程的 pid,,作為負(fù)責(zé) cpu 的子系統(tǒng),,cpu.cfs_quota_us 文件中的內(nèi)容能夠?qū)?CPU 的使用作出限制,如果當(dāng)前文件的內(nèi)容為 50000,,那么當(dāng)前控制組中的全部進(jìn)程的 CPU 占用率不能超過 50%,。 當(dāng)我們使用 Docker 關(guān)閉掉正在運(yùn)行的容器時,Docker 的子控制組對應(yīng)的文件夾也會被 Docker 進(jìn)程移除,。 (3).UnionFS聯(lián)合文件系統(tǒng)(Union File System),,它可以把多個目錄內(nèi)容聯(lián)合掛載到同一個目錄下,而目錄的物理位置是分開的,。UnionFS 可以把只讀和可讀寫文件系統(tǒng)合并在一起,,具有寫時復(fù)制功能,允許只讀文件系統(tǒng)的修改可以保存到可寫文件系統(tǒng)當(dāng)中,。Docker 之前使用的為 AUFS(Advanced UnionFS),,現(xiàn)為 Overlay2。 Docker 中的每一個鏡像都是由一系列只讀的層組成的,,Dockerfile 中的每一個命令都會在已有的只讀層上創(chuàng)建一個新的層: FROM ubuntu:15.04 COPY . /app RUN make /app CMD python /app/app.py 容器中的每一層都只對當(dāng)前容器進(jìn)行了非常小的修改,,上述的 Dockerfile 文件會構(gòu)建一個擁有四層 layer 的鏡像: 當(dāng)鏡像被 命令創(chuàng)建時就會在鏡像的最上層添加一個可寫的層,,也就是容器層,所有對于運(yùn)行時容器的修改其實(shí)都是對這個容器讀寫層的修改,。容器和鏡像的區(qū)別就在于,,所有的鏡像都是只讀的,而每一個容器其實(shí)等于鏡像加上一個可讀寫的層,,也就是同一個鏡像可以對應(yīng)多個容器,。 KubernetesKubernetes,簡稱 K8s,,其中 8 代指中間的 8 個字符,。Kubernetes 項目龐大復(fù)雜,文章不能面面俱到,,因此這個部分將向讀者提供一種主線學(xué)習(xí)思路:
有更多未交代或淺嘗輒止的地方讀者可以查閱文章或書籍深入研究,。 1.為什么要 Kubernetes盡管 Docker 為容器化的應(yīng)用程序提供了開放標(biāo)準(zhǔn),,但隨著容器越來越多出現(xiàn)了一系列新問題:
Kubernetes 應(yīng)運(yùn)而生,。 2.什么是 KubernetesKubernetes 是一個全新的基于容器技術(shù)的分布式架構(gòu)方案,這個方案雖然還很新,,但卻是 Google 十幾年來大規(guī)模應(yīng)用容器技術(shù)的經(jīng)驗積累和升華的重要成果,,確切的說是 Google 一個久負(fù)盛名的內(nèi)部使用的大規(guī)模集群管理系統(tǒng)——Borg 的開源版本,其目的是實(shí)現(xiàn)資源管理的自動化以及跨數(shù)據(jù)中心的資源利用率最大化,。 Kubernetes 具有完備的集群管理能力,,包括多層次的安全防護(hù)和準(zhǔn)入機(jī)制、多租戶應(yīng)用支撐能力,、透明的服務(wù)注冊和服務(wù)發(fā)現(xiàn)機(jī)制,、內(nèi)建的智能負(fù)載均衡器、強(qiáng)大的故障發(fā)現(xiàn)和自我修復(fù)能力,、服務(wù)滾動升級和在線擴(kuò)容能力,、可擴(kuò)展的資源自動調(diào)度機(jī)制,以及多力度的資源配額管理能力,。同時,,Kubernetes 提供了完善的管理工具,這些工具涵蓋了包括開發(fā),、部署測試,、運(yùn)維監(jiān)控在內(nèi)的各個環(huán)節(jié),,不僅是一個全新的基于容器技術(shù)的分布式架構(gòu)解決方案,還是一個一站式的完備分布式系統(tǒng)開發(fā)和支撐平臺,。 3.Kubernetes 術(shù)語(1).PodPod 是 Kubernetes 最重要的基本概念,,可由多個容器(一般而言一個容器一個進(jìn)程,不建議一個容器多個進(jìn)程)組成,,它是系統(tǒng)中資源分配和調(diào)度的最小單位,。下圖是 Pod 的組成示意圖,其中有一個特殊的 Pause 容器: Pause 容器的狀態(tài)標(biāo)識了一個 Pod 的狀態(tài),,也就是代表了 Pod 的生命周期,。另外 Pod 中其余容器共享 Pause 容器的命名空間,使得 Pod 內(nèi)的容器能夠共享 Pause 容器的 IP,,以及實(shí)現(xiàn)文件共享,。以下是一個 Pod 的定義: apiVersion: v1 # 分組和版本 kind: Pod # 資源類型 metadata: name: myWeb # Pod名 labels: app: myWeb # Pod的標(biāo)簽 spec: containers: - name: myWeb # 容器名 image: kubeguide/tomcat-app:v1 # 容器使用的鏡像 ports: - containerPort: 8080 # 容器監(jiān)聽的端口 env: # 容器內(nèi)環(huán)境變量 - name: MYSQL_SERVICE_HOST value: 'mysql' - name: MYSQL_SERVICE_PORT value: '3306' resources: # 容器資源配置 requests: # 資源下限,m表示cpu配額的最小單位,,為1/1000核 memory: "64Mi" cpu: "250m" limits: # 資源上限 memory: "128Mi" cpu: "500m" EndPoint : PodIP + containerPort,,代表一個服務(wù)進(jìn)程的對外通信地址。一個 Pod 也存在具有多個 Endpoint 的情 況,,比如當(dāng)我們把 Tomcat 定義為一個 Pod 時,,可以對外暴露管理端口與服務(wù)端口這兩個 Endpoint。 (2).LabelLabel 是 Kubernetes 系統(tǒng)中的一個核心概念,,一個 Label 表示一個 key=value 的鍵值對,,key、value 的值由用戶指定,。Label 可以被附加到各種資源對象上,,例如 Node、Pod,、Service,、RC 等,一個資源對 象可以定義任意數(shù)量的 Label,,同一個 Label 也可以被添加到任意數(shù)量的資源對象上,。Label 通常在資源對象定義時確定,也可以在對象創(chuàng)建后動態(tài)添加或者刪除,。給一個資源對象定義了 Label 后,,我們隨后可以通過 Label Selector 查詢和篩選擁有這個 Label 的資源對象,來實(shí)現(xiàn)多維度的資源分組管理功能,,以便靈活,、方便地進(jìn)行資源分配、調(diào) 度、配置,、部署等管理工作,。 Label Selector 當(dāng)前有兩種表達(dá)式,基于等式的和基于集合的:
以 myWeb Pod 為例: apiVersion: v1 # 分組和版本 kind: Pod # 資源類型 metadata: name: myWeb # Pod名 labels: app: myWeb # Pod的標(biāo)簽 當(dāng)一個 Service 的 selector 中指明了這個 Pod 時,,該 Pod 就會與該 Service 綁定 apiVersion: v1 kind: Service metadata: name: myWeb spec: selector: app: myWeb ports: - port: 8080 (3).Replication ControllerReplication Controller,簡稱 RC,,簡單來說,,它其實(shí)定義了一個期望的場景,即聲明某種 Pod 的副本數(shù)量在任意時刻都符合某個預(yù)期值,。 RC 的定義包括如下幾個部分:
apiVersion: v1 kind: ReplicationController metadata: name: frontend spec: replicas: 3 # Pod 副本數(shù)量 selector: app: frontend template: # Pod 模版 metadata: labels: app: frontend spec: containers: - name: tomcat_demp image: tomcat ports: - containerPort: 8080 當(dāng)提交這個 RC 在集群中后,Controller Manager 會定期巡檢,,確保目標(biāo) Pod 實(shí)例的數(shù)量等于 RC 的預(yù)期值,,過多的數(shù)量會被停掉,少了則會創(chuàng)建補(bǔ)充,。通過 目前,,RC 已升級為新概念——Replica Set(RS),,兩者當(dāng)前唯一區(qū)別是,RS 支持了基于集合的 Label Selector,,而 RC 只支持基于等式的 Label Selector,。RS 很少單獨(dú)使用,更多是被 Deployment 這個更高層的資源對象所使用,,所以可以視作 RS+Deployment 將逐漸取代 RC 的作用,。 (4).DeploymentDeployment 和 RC 相似度超過 90%,無論是作用,、目的,、Yaml 定義還是具體命令行操作,所以可以將其看作是 RC 的升級,。而 Deployment 相對于 RC 的一個最大區(qū)別是我們可以隨時知道當(dāng)前 Pod“部署”的進(jìn)度,。實(shí)際上由于一個 Pod 的創(chuàng)建、調(diào)度,、綁定節(jié)點(diǎn)及在目 標(biāo) Node 上啟動對應(yīng)的容器這一完整過程需要一定的時間,,所以我們期待系統(tǒng)啟動 N 個 Pod 副本的目標(biāo)狀態(tài),實(shí)際上是一個連續(xù)變化的“部署過程”導(dǎo)致的最終狀態(tài),。 apiVersion: v1 kind: Deployment metadata: name: frontend spec: replicas: 3 selector: matchLabels: app: frontend matchExpressions: - {key: app, operator: In, values [frontend]} template: metadata: labels: app: frontend spec: containers: - name: tomcat_demp image: tomcat ports: - containerPort: 8080 (5).Horizontal Pod Autoscaler除了手動執(zhí)行
apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: php-apache namespace: default spec: maxReplicas: 3 minReplicas: 1 scaletargetRef: kind: Deployment name: php-apache targetCPUUtilizationPercentage: 90 根據(jù)上邊定義,當(dāng) Pod 副本的 CPUUtilizationPercentage 超過 90%時就會出發(fā)自動擴(kuò)容行為,,數(shù)量約束為 1 ~ 3 個,。 (6).StatefulSet在 Kubernetes 系統(tǒng)中,Pod 的管理對象 RC,、Deployment,、DaemonSet 和 Job 都面向無狀態(tài)的服務(wù)。但現(xiàn)實(shí)中有很多服務(wù)是有狀態(tài)的,,特別是 一些復(fù)雜的中間件集群,,例如 MySQL 集群、MongoDB 集群,、Akka 集 群,、ZooKeeper 集群等,這些應(yīng)用集群有 4 個共同點(diǎn),。
因此,StatefulSet 具有以下特點(diǎn):
(7).ServiceService 在 Kubernetes 中定義了一個服務(wù)的訪問入口地址,,前段的應(yīng)用(Pod)通過這個入口地址訪問其背后的一組由 Pod 副本組成的集群實(shí)例,,Service 與其后端 Pod 副本集群之間則是通過 Label Selector 來實(shí)現(xiàn)無縫對接的。 apiVersion: v1 kind: service metadata: name: tomcat_service spec: ports: - port: 8080 name: service_port - port: 8005 name: shutdown_port selector: app: backend Service 的負(fù)載均衡在 Kubernetes 集群中,,每個 Node 上會運(yùn)行著 kube-proxy 組件,,這其實(shí)就是一個負(fù)載均衡器,負(fù)責(zé)把對 Service 的請求轉(zhuǎn)發(fā)到后端的某個 Pod 實(shí)例上,,并在內(nèi)部實(shí)現(xiàn)服務(wù)的負(fù)載均衡和繪畫保持機(jī)制,。其主要的實(shí)現(xiàn)就是每個 Service 在集群中都被分配了一個全局唯一的 Cluster IP,因此我們對 Service 的網(wǎng)絡(luò)通信根據(jù)內(nèi)部的負(fù)載均衡算法和會話機(jī)制,,便能與 Pod 副本集群通信,。 Service 的服務(wù)發(fā)現(xiàn)因為 Cluster IP 在 Service 的整個聲明周期內(nèi)是固定的,所以在 Kubernetes 中,,只需將 Service 的 Name 和 其 Cluster IP 做一個 DNS 域名映射即可解決,。 (8).VolumeVolume 是 Pod 中能夠被多個容器訪問的共享目錄,,Kubernetes 中的 Volume 概念,、用途、目的與 Docker 中的 Volumn 比較類似,,但不等價,。首先,其可被定義在 Pod 上,,然后被 一個 Pod 里的多個容器掛載到具體的文件目錄下,;其次,Kubernetes 中的 Volume 與 Pod 的生命周期相同,,但與容器的生命周期不相關(guān),,當(dāng)容器終止或者重啟時,Volume 中的數(shù)據(jù)也不會丟失。 template: metadata: labels: app: frontend spec: volumes: # 聲明可掛載的volume - name: dataVol emptyDir: {} containers: - name: tomcat_demo image: tomcat ports: - containerPort: 8080 volumeMounts: # 將volume通過name掛載到容器內(nèi)的/mydata-data目錄 - mountPath: /mydata-data name: dataVol Kubernetes 提供了非常豐富的 Volume 類型:
(9).Persistent Volume在使用虛擬機(jī)的情況下,,我們通常會先定義一個網(wǎng)絡(luò)存儲,,然后從中 劃出一個“網(wǎng)盤”并掛接到虛擬機(jī)上。Persistent Volume(PV) 和與之相關(guān)聯(lián)的 Persistent Volume Claim(PVC) 也起到了類似的作用,。PV 可以被理解成 Kubernetes 集群中的某個網(wǎng)絡(luò)存儲對應(yīng)的一塊存儲,,它與 Volume 類似,但有以下區(qū)別:
apiVersion: v1 kind: PersistentVolume metadata: name: pv001 spec: capacity: storage: 5Gi accessMods: - ReadWriteOnce nfs: path: /somePath server: xxx.xx.xx.x accessModes,有幾種類型,,1.ReadWriteOnce:讀寫權(quán)限,,并且只能被單個 Node 掛載。 2. ReadOnlyMany:只讀權(quán)限,,允許被多個 Node 掛載,。 3.ReadWriteMany:讀寫權(quán)限,允許被多個 Node 掛載,。 如果 Pod 想申請某種類型的 PV,,首先需要定義一個 PersistentVolumeClaim 對象, apiVersion: v1 kind: PersistentVolumeClaim # 聲明pvc metadata: name: pvc001 spec: resources: requests: storage: 5Gi accessMods: - ReadWriteOnce 然后在 Pod 的 Volume 中引用 PVC 即可,。 volumes: - name: mypd persistentVolumeClaim: claimName: pvc001 PV 有以下幾種狀態(tài):
(10).NamespaceNamespace 在很多情況下用于實(shí)現(xiàn)多租戶的資源隔離。分組的不同項目,、小組或用戶組,,便于不同的分組在共享使用整個集群的資源的同時還能被分別管理,。Kubernetes 集群在啟動后會創(chuàng)建一個名為 default 的 Namespace,通過 kubectl 可以查看: (11).ConfigMap我們知道,,Docker 通過將程序,、依賴庫、數(shù)據(jù)及 配置文件“打包固化”到一個不變的鏡像文件中的做法,,解決了應(yīng)用的部署的難題,,但這同時帶來了棘手的問題,即配置文件中的參數(shù)在運(yùn)行期如何修改的問題,。我們不可能在啟動 Docker 容器后再修改容器里的配置 文件,,然后用新的配置文件重啟容器里的用戶主進(jìn)程。為了解決這個問題,,Docker 提供了兩種方式:
在大多數(shù)情況下,后一種方式更合 適我們的系統(tǒng),,因為大多數(shù)應(yīng)用通常從一個或多個配置文件中讀取參數(shù),。但這種方式也有明顯的缺陷:我們必須在目標(biāo)主機(jī)上先創(chuàng)建好對應(yīng) 配置文件,然后才能映射到容器里,。上述缺陷在分布式情況下變得更為嚴(yán)重,,因為無論采用哪種方式, 寫入(修改)多臺服務(wù)器上的某個指定文件,,并確保這些文件保持一致,,都是一個很難完成的目標(biāo)。針對上述問題,, Kubernetes 給出了一個很巧妙的設(shè)計實(shí)現(xiàn),。 首先,把所有的配置項都當(dāng)作 key-value 字符串,,這些配置項可以 作為 Map 表中的一個項,,整個 Map 的數(shù)據(jù)可以被持久化存儲在 Kubernetes 的 Etcd 數(shù)據(jù)庫中,然后提供 API 以方便 Kubernetes 相關(guān)組件或 客戶應(yīng)用 CRUD 操作這些數(shù)據(jù),,上述專門用來保存配置參數(shù)的 Map 就是 Kubernetes ConfigMap 資源對象,。Kubernetes 提供了一種內(nèi)建機(jī)制,將存儲在 etcd 中的 ConfigMap 通過 Volume 映射的方式變成目標(biāo) Pod 內(nèi)的配置文件,,不管目標(biāo) Pod 被調(diào)度到哪臺服務(wù)器上,,都會完成自動映射。進(jìn)一步地,,如果 ConfigMap 中的 key-value 數(shù)據(jù)被修改,則映射到 Pod 中的“配置文件”也會隨之自動更新,。 4.Kubernetes 的架構(gòu)Kubernetes 由 Master 節(jié)點(diǎn),、 Node 節(jié)點(diǎn)以及外部的 ETCD 集群組成,,集群的狀態(tài)、資源對象,、網(wǎng)絡(luò)等信息存儲在 ETCD 中,,Mater 節(jié)點(diǎn)管控整個集群,包括通信,、調(diào)度等,,Node 節(jié)點(diǎn)為工作真正執(zhí)行的節(jié)點(diǎn),并向主節(jié)點(diǎn)報告,。Master 節(jié)點(diǎn)由以下組件構(gòu)成: (1).Master 組件:
(2).Node 組件:
5.Kubernetes 架構(gòu)模塊實(shí)現(xiàn)原理(1).API ServerKubernetes API Server 通過一個名為 kube-apiserver 的進(jìn)程提供服務(wù),,該進(jìn)程運(yùn)行在 Master 上。在默認(rèn)情況下,,kube-apiserver 進(jìn)程在本機(jī)的 8080 端口(對應(yīng)參數(shù)--insecure-port)提供 REST 服務(wù),。我們可以同時啟動 HTTPS 安全端口(--secure-port=6443)來啟動安全機(jī)制,加強(qiáng) REST API 訪問的安全性,。 由于 API Server 是 Kubernetes 集群數(shù)據(jù)的唯一訪問入口,,因此安全性與高性能就成為 API Server 設(shè)計和實(shí)現(xiàn)的兩大核心目標(biāo)。通過采用 HTTPS 安全傳輸通道與 CA 簽名數(shù)字證書強(qiáng)制雙向認(rèn)證的方式,,API Server 的安全性得以保障,。此外,,為了更細(xì)粒度地控制用戶或應(yīng)用對 Kubernetes 資源對象的訪問權(quán)限,Kubernetes 啟用了 RBAC 訪問控制策略,。Kubernetes 的設(shè)計者綜合運(yùn)用以下方式來最大程度地保證 API Server 的性 能,。
(2).安全認(rèn)證RBACRole-Based Access Control(RBAC),,基于角色的訪問控制,。 4 種資源對象
Role 與 ClusterRole一個角色就是一組權(quán)限的集合,都是以許可形式,,不存在拒絕的規(guī)則,。Role 作用于一個命名空間中,ClusterRole 作用于整個集群,。 apiVersion:rbac.authorization.k8s.io/v1beta1 kind:Role metadata: namespace: default #ClusterRole可以省略,,畢竟是作用于整個集群 name: pod-reader rules: - apiGroups: [""] resources: ["pod"] verbs: ["get","watch","list"] RoleBinding 和 ClusterRoleBinding 是把 Role 和 ClusterRole 的權(quán)限綁定到 ServiceAccount 上。 kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: default name: app-admin subjects: - kind: ServiceAccount name: app apiGroup: "" namespace: default roleRef: kind: ClusterRole name: cluster-admin apiGroup: rbac.authorization.k8s.io ServiceAccountService Account 也是一種賬號,,但它并不是給 Kubernetes 集群的用戶 (系統(tǒng)管理員,、運(yùn)維人員、租戶用戶等)用的,,而是給運(yùn)行在 Pod 里的進(jìn)程用的,,它為 Pod 里的進(jìn)程提供了必要的身份證明。在每個 Namespace 下都有一個名為 default 的默認(rèn) Service Account 對象,,在這個 Service Account 里面有一個名為 Tokens 的可以當(dāng)作 Volume 被掛載到 Pod 里的 Secret,,當(dāng) Pod 啟動時,這個 Secret 會自動被掛載到 Pod 的指定目錄下,,用來協(xié)助完成 Pod 中的進(jìn)程訪問 API Server 時的身份鑒權(quán),。 (3).Controller Manager下邊介紹幾種 Controller Manager 的實(shí)現(xiàn)組件 ResourceQuota Controllerkubernetes 的配額管理使用過 Admission Control 來控制的,提供了兩種約束,,LimitRanger 和 ResourceQuota,。LimitRanger 作用于 Pod 和 Container 之上(limit ,request),,ResourceQuota 則作用于 Namespace,。 資源配額,,分三個層次:
+ pod數(shù)量 + RC數(shù)量 + Service數(shù)量 + ResourceQuota數(shù)量 + Secrete數(shù)量 + PV數(shù)量 Namespace Controller管理 Namesoace 創(chuàng)建刪除. Endpoints ControllerEndpoints 表示一個 service 對應(yīng)的所有 Pod 副本的訪問地址,,而 Endpoints Controller 就是負(fù)責(zé)生成和維護(hù)所有 Endpoints 對象的控制器。
(4).SchedulerKubernetes Scheduler 的作用是將待調(diào)度的 Pod(API 新創(chuàng) 建的 Pod、Controller Manager 為補(bǔ)足副本而創(chuàng)建的 Pod 等)按照特定的調(diào) 度算法和調(diào)度策略綁定(Binding)到集群中某個合適的 Node 上,,并將綁定信息寫入 etcd 中,。Kubernetes Scheduler 當(dāng)前提供的默認(rèn)調(diào)度流程分為以下兩步。
(5).網(wǎng)絡(luò)Kubernetes 的網(wǎng)絡(luò)利用了 Docker 的網(wǎng)絡(luò)原理,,并在此基礎(chǔ)上實(shí)現(xiàn)了跨 Node 容器間的網(wǎng)絡(luò)通信,。
CNI 提供了一種應(yīng)用容器的插件化網(wǎng)絡(luò)解決方案,定義對容器網(wǎng)絡(luò) 進(jìn)行操作和配置的規(guī)范,,通過插件的形式對 CNI 接口進(jìn)行實(shí)現(xiàn),,以 Flannel 舉例,完成了 Node 間容器的通信模型,。 可以看到,,F(xiàn)lannel 首先創(chuàng)建了一個名為 flannel0 的網(wǎng)橋,,而且這個 網(wǎng)橋的一端連接 docker0 網(wǎng)橋,另一端連接一個叫作 flanneld 的服務(wù)進(jìn)程,。flanneld 進(jìn)程并不簡單,,它上連 etcd,利用 etcd 來管理可分配的 IP 地 址段資源,,同時監(jiān)控 etcd 中每個 Pod 的實(shí)際地址,,并在內(nèi)存中建立了一 個 Pod 節(jié)點(diǎn)路由表;它下連 docker0 和物理網(wǎng)絡(luò),使用內(nèi)存中的 Pod 節(jié)點(diǎn) 路由表,,將 docker0 發(fā)給它的數(shù)據(jù)包包裝起來,,利用物理網(wǎng)絡(luò)的連接將 數(shù)據(jù)包投遞到目標(biāo) flanneld 上,從而完成 Pod 到 Pod 之間的直接地址通信,。 (6).服務(wù)發(fā)現(xiàn)從 Kubernetes 1.11 版本開始,,Kubernetes 集群的 DNS 服務(wù)由 CoreDNS 提供。CoreDNS 是 CNCF 基金會的一個項目,,是用 Go 語言實(shí)現(xiàn)的高性能,、插件式、易擴(kuò)展的 DNS 服務(wù)端,。 結(jié)語文章包含的內(nèi)容說多不多,,說少不少,但對于 Docker,、Kubernetes 知識原理的小白來說是足夠的,,筆者按照自己的學(xué)習(xí)經(jīng)驗,以介紹為出發(fā)點(diǎn),,讓大家更能了解相關(guān)技術(shù)原理,,所以實(shí)操的部分較少。Kubernetes 技術(shù)組件還是十分豐富的,,文章有選擇性地進(jìn)行了介紹,,感興趣的讀者可以再自行從官方或者書籍中學(xué)習(xí)了解。(附《Kubernetes 權(quán)威指南——從 Docker 到 Kubernetes 實(shí)踐全接觸》第四版) |
|