elasticsearch入門系列">elasticsearch入門系列
790
2025-04-02
目錄
文章目錄
目錄
Object
容器與鏡像
什么是容器?
什么是鏡像?
如何運行容器?
容器運行時的生命周期
Pod
Pod 的本質是什么?
Pod 的實現機制
共享網絡
共享存儲
Pod 的生命周期
Volume
PV、PVC
PV、PVC 的生命周期
Controller
ReplicaSet(副本控制器)
Deployment(部署控制器)
StatefuleSet(有狀態部署控制器)
DaemonSet(守護進程控制器)
Job(任務控制器)
Service
Label
Ingress
Namespace
ConfigMap
容器設計模式
InitContainer
Sidecar
Object
Object 是 Kubernetes 系統中的持久化實體(存儲在 etcd cluster 中),Kubernetes 使用這些 objects 來表示集群中的狀態。
這些 Object 描述了哪些應用應該運行在集群中,它們請求的資源下限和上限以及重啟、升級和容錯的策略。每一個創建的對象其實都是我們對集群狀態的改變,這些對象描述的其實就是集群的期望狀態,Kubernetes 會根據我們指定的期望狀態不斷檢查對當前的集群狀態進行遷移。
type Deployment struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` Spec DeploymentSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"` Status DeploymentStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` }
每一個 Object 都包含兩個嵌套對象來描述規格(Spec)和狀態(Status),對象的規格其實就是我們期望的目標狀態,而狀態描述了對象的當前狀態,這部分一般由 Kubernetes 系統本身提供和管理,是我們觀察集群本身的一個接口。
容器與鏡像
什么是容器?
在介紹容器的具體概念之前,先簡單回顧一下操作系統是如何管理進程的。
首先,當我們登錄到操作系統之后,可以通過 ps 等操作看到各式各樣的進程,這些進程包括系統自帶的服務和用戶的應用進程。那么,這些進程都有什么樣的特點?
第一,這些進程可以相互看到、相互通信;
第二,它們使用的是同一個文件系統,可以對同一個文件進行讀寫操作;
第三,這些進程會使用相同的系統資源。
這樣的三個特點會帶來什么問題呢?
因為這些進程能夠相互看到并且進行通信,高級權限的進程可以攻擊其他進程;
因為它們使用的是同一個文件系統,因此會帶來兩個問題:這些進程可以對于已有的數據進行增刪改查,具有高級權限的進程可能會將其他進程的數據刪除掉,破壞掉其他進程的正常運行;此外,進程與進程之間的依賴可能會存在沖突,如此一來就會給運維帶來很大的壓力;
因為這些進程使用的是同一個宿主機的資源,應用之間可能會存在資源搶占的問題,當一個應用需要消耗大量 CPU 和內存資源的時候,就可能會破壞其他應用的運行,導致其他應用無法正常地提供服務。
針對上述的三個問題,如何為進程提供一個獨立的運行環境呢?
針對不同進程使用同一個文件系統所造成的問題而言,Linux 和 Unix 操作系統可以通過 chroot 系統調用將子目錄變成根目錄,達到視圖級別的隔離;進程在 chroot 的幫助下可以具有獨立的文件系統,對于這樣的文件系統進行增刪改查不會影響到其他進程;
因為進程之間相互可見并且可以相互通信,使用 Namespace 技術來實現進程在資源的視圖上進行隔離。在 chroot 和 Namespace 的幫助下,進程就能夠運行在一個獨立的環境下了;
但在獨立的環境下,進程所使用的還是同一個操作系統的資源,一些進程可能會侵蝕掉整個系統的資源。為了減少進程彼此之間的影響,可以通過 Cgroup 來限制其資源使用率,設置其能夠使用的 CPU 以及內存量。
綜上可以得到答案:容器就是一個視圖隔離、資源可限制、獨立文件系統的進程集合。
所謂 “視圖隔離” 就是能夠看到部分進程以及具有獨立的主機名等;
控制資源使用率則是可以對于內存大小以及 CPU 使用個數等進行限制;
容器具有一個獨立的文件系統,因為使用的是系統的資源,所以在獨立的文件系統內不需要具備內核相關的代碼或者工具,我們只需要提供容器所需的二進制文件、配置文件以及依賴即可。只要容器運行時所需的文件集合都能夠具備,那么這個容器就能夠運行起來。
什么是鏡像?
綜上所述,我們將這些:容器運行時所需要的所有的文件集合稱之為容器鏡像。
通常情況下,我們會采用 Dockerfile 來構建鏡像,這是因為 Dockerfile 提供了非常便利的語法糖,能夠幫助我們很好地描述構建的每個步驟。當然,每個構建步驟都會對已有的文件系統進行操作,這樣就會帶來文件系統內容的變化,我們將這些變化稱之為 changeset。當我們把構建步驟所產生的變化依次作用到一個空文件夾上,就能夠得到一個完整的鏡像。
changeset 的分層以及復用特點能夠帶來幾點優勢:
第一,能夠提高分發效率,簡單試想一下,對于大的鏡像而言,如果將其拆分成各個小塊就能夠提高鏡像的分發效率,這是因為鏡像拆分之后就可以并行下載這些數據;
第二,因為這些數據是相互共享的,也就意味著當本地存儲上包含了一些數據的時候,只需要下載本地沒有的數據即可,舉個簡單的例子就是 golang 鏡像是基于 alpine 鏡像進行構建的,當本地已經具有了 alpine 鏡像之后,在下載 golang 鏡像的時候只需要下載本地 alpine 鏡像中沒有的部分即可;
第三,因為鏡像數據是共享的,因此可以節約大量的磁盤空間,簡單設想一下,當本地存儲具有了 alpine 鏡像和 golang 鏡像,在沒有復用的能力之前,alpine 鏡像具有 5M 大小,golang 鏡像有 300M 大小,因此就會占用 305M 空間;而當具有了復用能力之后,只需要 300M 空間即可。
如何運行容器?
運行一個容器一般情況下分為三步:
第一步:從鏡像倉庫中將相應的鏡像下載下來;
第二步:當鏡像下載完成之后就可以通過 docker images 來查看本地鏡像,這里會給出一個完整的列表,我們可以在列表中選中想要的鏡像;
第三步:當選中鏡像之后,就可以通過 docker run 來運行這個鏡像得到想要的容器,當然可以通過多次運行得到多個容器。一個鏡像就相當于是一個模板,一個容器就像是一個具體的運行實例,因此鏡像就具有了一次構建、到處運行的特點。
容器運行時的生命周期
容器是一組具有隔離特性的進程集合,在使用 docker run 的時候會選擇一個鏡像來提供獨立的文件系統并指定相應的運行程序。這里指定的運行程序稱之為 initial 進程,這個 initial 進程啟動的時候,容器也會隨之啟動,當 initial 進程退出的時候,容器也會隨之退出。
因此,可以認為容器的生命周期和 initial 進程的生命周期是一致的。當然,因為容器內不只有這樣的一個 initial 進程,initial 進程本身也可以產生其他的子進程或者通過 docker exec 產生出來的運維操作,也屬于 initial 進程管理的范圍內。當 initial 進程退出的時候,所有的子進程也會隨之退出,這樣也是為了防止資源的泄漏。
但是這樣的做法也會存在一些問題,首先應用里面的程序往往是有狀態的,其可能會產生一些重要的數據,當一個容器退出被刪除之后,數據也就會丟失了,這對于應用方而言是不能接受的,所以需要將容器所產生出來的重要數據持久化下來。容器能夠直接將數據持久化到指定的目錄上,這個目錄就稱之為數據卷。
數據卷有一些特點,其中非常明顯的就是數據卷的生命周期是獨立于容器的生命周期的,也就是說容器的創建、運行、停止、刪除等操作都和數據卷沒有任何關系,因為它是一個特殊的目錄,是用于幫助容器進行持久化的。簡單而言,我們會將數據卷掛載到容器內,這樣一來容器就能夠將數據寫入到相應的目錄里面了,而且容器的退出并不會導致數據的丟失。
通常情況下,數據卷管理主要有兩種方式:
第一種是通過 bind 的方式,直接將宿主機的目錄直接掛載到容器內;這種方式比較簡單,但是會帶來運維成本,因為其依賴于宿主機的目錄,需要對于所有的宿主機進行統一管理。
第二種是將目錄管理交給運行引擎。
Pod
Kubernetes 以 Pod 為最小單位進行調度、擴展、資源分配、管理生命周期。Pod 的運行模式通常設置為單個主容器,也可選擇添加對日志支持等輔助功能的挎斗模式(sidecar)容器。Pod 通常由 Deployment 管理。
為什么要引入 Pod 這一邏輯對象?
可管理性:有些容器天生就是需要緊密聯系,一起工作的。例如:微服務中的 Side Car(邊車)模式,Pod 中的一個 ContainerA 提供業務,另一個 ContainerB 專門負責對 ContainerA 進行收集、監控日志和流量信息;又例如:ContainerA 作為 File Puller 定期從外部拉取最新的文件,將其存放到共享 Volume 中,ContainerB 作為 Web Server 直接從 Volume 讀取文件,兩個 Containers 緊密合作;Pod 將 Containers 封裝到一個部署單元中。
通信和資源共享:Pod 中的所有 Containers 使用同一個 network namespace,即 Containers 具有相同的 IP 地址和 Port 空間,它們互相之間可以直接用 localhost 進行通信。同樣的,這些容器也會共享存儲,當 Kubernetes 掛載 Volume 到 Pod,本質上是將 Volume 掛載到 Pod 中的每一個 Container。
由此,Pod 是 Containers 的集合,共享存儲和網絡。Pod 具有獨立的 IP 地址、主機名(Hostname),Pod 中的 Containers 共享這個 IP 地址、端口空間,并且可以通過 localhost 彼此查找。Pod 利用 Namespace 進行資源隔離,相當于一個獨立的沙箱環境。不同的 Pod 之間的通信屬于遠程訪問。
Pod 是虛擬的資源對象(進程),如果沒有實體(物理機,物理網卡)與之對應,就無法直接對外提供服務訪問。所以,Pod 如果想要對外提供服務,必須綁定物理主機的端口,讓這個端口和 Pod 的端口進行映射,這樣就可以通過物理主機的 IP + Port 進行數據包的轉發。
kind: Pod apiVersion: v1 metadata: labels: app: nginx-app spec: containers: - name: nginx-container image: nginx:latest restartPolicy: Never
Pod 的本質是什么?
容器的本質是一個進程,是一個視圖被隔離,資源被受限的進程。
容器鏡像的本質是一個包含了容器運行時全部所需文件的集合。
Kubernetes 的本質是是云時代的操作系統,它管理著這些進程(容器)。
實際上,一個生產應用往往需要多個進程之間(進程組)的協同才能完成工作,所以同一個進程組中的進程應該統一被原子性的進行調度、運行和銷毀。
可見,Pod 的本質對應的就是一個進程組,是一個最終生產應用的邏輯集合。
Pod 的實現機制
像 Pod 這樣一個東西,本身是一個邏輯概念。那在機器上,它究竟是怎么實現的呢?
核心就在于如何讓一個 Pod 里的多個容器之間最高效的共享某些資源和數據。因為,容器之間原本是被 Linux Namespace 和 cgroups 隔開的,所以現在實際要解決的是怎么去打破這個隔離,然后共享某些事情和某些信息。這就是 Pod 的設計要解決的核心問題所在。
共享網絡
比如說現在有一個 Pod,其中包含了一個容器 A 和一個容器 B,它們兩個就要共享 Network Namespace。在 Kubernetes 里的解法是這樣的:它會在每個 Pod 里,額外起一個 Infra container 小容器來共享整個 Pod 的 Network Namespace。
Infra container 是一個非常小的鏡像,大概 100~200KB 左右,是一個匯編語言寫的、永遠處于 “暫停” 狀態的容器。由于有了這樣一個 Infra container 之后,其他所有容器都會通過 Join Namespace 的方式加入到 Infra container 的 Network Namespace 中。
所以說一個 Pod 里面的所有容器,它們看到的網絡視圖是完全一樣的。即:它們看到的網絡設備、IP地址、Mac地址等等,跟網絡相關的信息,其實全是一份,這一份都來自于 Pod 第一次創建的這個 Infra container。這就是 Pod 解決網絡共享的一個解法。
在 Pod 里面,一定有一個 IP 地址,是這個 Pod 的 Network Namespace 對應的地址,也是這個 Infra container 的 IP 地址。所以大家看到的都是一份,而其他所有網絡資源,都是一個 Pod 一份,并且被 Pod 中的所有容器共享。這就是 Pod 的網絡實現方式。
由于需要有一個相當于說中間的容器存在,所以整個 Pod 里面,必然是 Infra container 第一個啟動。并且整個 Pod 的生命周期是等同于 Infra container 的生命周期的,與容器 A 和 B 是無關的。這也是為什么在 Kubernetes 里面,它是允許去單獨更新 Pod 里的某一個鏡像的,即:做這個操作,整個 Pod 不會重建,也不會重啟,這是非常重要的一個設計。
共享存儲
Pod 共享存儲就相對比較簡單。
比如說現在有兩個容器,一個是 Nginx,另外一個是非常普通的容器,在 Nginx 里放一些文件,讓我能通過 Nginx 訪問到。所以它需要去 share 這個目錄。我 share 文件或者是 share 目錄在 Pod 里面是非常簡單的,實際上就是把 volume 變成了 Pod level。然后所有容器,就是所有同屬于一個 Pod 的容器,他們共享所有的 volume。
例如有一個 volume 叫做 shared-data,它是屬于 Pod level 的,所以在每一個容器里可以直接聲明:要掛載 shared-data 這個 volume,只要你聲明了你掛載這個 volume,你在容器里去看這個目錄,實際上大家看到的就是同一份。這個就是 Kubernetes 通過 Pod 來給容器共享存儲的一個做法。
所以,如果一個應用容器 App 寫了日志,只要這個日志是寫在一個 volume 中,只要聲明掛載了同樣的 volume,這個 volume 就可以立刻被另外一個 LogCollector 容器給看到。以上就是 Pod 實現存儲的方式。
Pod 的生命周期
在 kubernetes 的官方文檔中,對 Pod 的生命周期做出了解釋。
和容器類似的,Pod 也是一個具有臨時性(而不是長期存在)的實體。Pod 本身不具備自愈能力,在創建時,Pod 會被賦予一個 UUID,然后被調度到某個 Node,在終止(根據重啟策略)或刪除該 Pod 之前就一直運行在該 Node 上。注意,如果一個 Node 宕機了,那么調度到該 Node 的 Pods 也會在計劃給定的超時期限后被刪除。
Kubernetes 通過 Controller 來管理這些 “臨時性” 的 Pod,當一個 Pod(由 UUID 定義)被刪除后,Controller 會啟動一個新的、幾乎完全相同的 Pod 來進行替代。如果需要的話,新 Pod 的名字保持不變,但是其 UID 也會不同,表示并非是同一個 Pod。
對于 “普通” 的 Volume 而言,其生命周期與 Pod 一樣,即:Volume 會伴隨 Pod 的整個生命周期,Pod 刪除或重建后,那么 Pod 運行期間產生的數據就會隨之被刪除。
Volume
Filesystem:在 Kubernetes 中,每個 Container 都可以在其自身的文件系統中執行讀寫操作。但是,Container 重啟或刪除后,寫入該文件系統的數據將被破壞。
Volume:是 Pod 可訪問的文件系統目錄,被同一個 Pod 中的 Containers 間共享。Volume 的生命周期與包含它的 Pod 一致。
Persistent Volume(持久化卷):持久卷,則提供長期存儲,只要 Kubernetes 集群存在,持久卷就存在。Pod 可聲明使用持久卷讀取、寫入和讀寫。
Kubernetes Volume 支持多種存儲插件,它可以支持本地的存儲,可以支持分布式的存儲,比如:Ceph、GlusterFS;也可以支持云存儲,比如:阿里云的云盤等。
PV、PVC
PV、PVC Object 面向持久化存儲。
PV(PersistentVolume):是 Kubernetes Cluster 中的一塊存儲空間,由管理員創建和維護,或者使用 Storage Class 動態擴展。與 Node 一樣,屬于集群資源。與 Volume 相似,但生命周期獨立于 Pod。
PVC(PersistentVolumeClaim):是用戶對存儲的請求。需要為 Pod 分配存儲資源時,用戶可以創建一個 PVC,指明存儲資源的容量大小和訪問模式(e.g. 只讀、讀寫)等信息,Kubernetes 會查找并提供滿足條件的 PV。
有了 PersistentVolumeClaim,用戶只需要告訴 Kubernetes 需要什么樣的存儲資源,而不必關心真正的空間從哪里分配、以及如何訪問等底層細節信息。這些 Storage Provider 的底層信息交給管理員來處理,只有管理員才應該關心創建 PersistentVolume 的細節信息。
PV、PVC 的生命周期
PV 是群集中的資源,PVC 是對這些資源的請求,并且還充當對資源的檢查。PV 和 PVC 之間的相互作用遵循以下生命周期:
Provisioning(供應準備):通過集群外的存儲系統(e.g. CEPH)或者云平臺(e.g. OpenStack Cinder)來提供存儲持久化支持。
Static(靜態提供):集群管理員創建多個 PV,它們攜帶可供集群用戶使用的真實存儲的詳細信息,然后再綁定到 PVC。
Dynamic(動態提供):當管理員創建的 Static PV 都不匹配用戶的 PVC 時,集群可能會嘗試為 PVC 動態創建一個 PV,該操作需要基于 Storage Classes。即:PVC 必須請求一個 Classes(類別),并且集群管理員必須已經創建并配置好了該 Classes,才能動態提供 PV。
Binding(綁定):用戶創建 PVC 并指定需要的資源和訪問模式。在找到可用 PV 之前,PVC 會保持未綁定狀態。
Using(使用):Pod 資源基于 PVC 的定義將選定的 PV 關聯為 PVC,而后即可被容器所使用。對于支持多種訪問模式的 PV 而言,用戶需要額外指定訪問模式。
Storage Object in Use Protection(保護):有用戶希望刪除仍處于某個 Pod 使用中的 PVC 或 PV 時,Kubernetes 不會立即予以移除、而是推遲到 PV 不再被任何 Pod 使用后方才執行刪除操作。
Reclaiming(回收):PV 可以設置 2 種回收策略:
Retain(保留)策略:刪除 PVC 之后,kubernetes 不會自動刪除 PV,而僅僅是將它置于 “Releases(釋放)” 狀態。此種狀態的 PV 尚且不能被其他 PVC 申請所綁定,因為此前的申請生成的數據仍然存在,需要由管理員手動決定其后續處理方案。
Delete(刪除)策略:對于支持 Delete 策略的 CSI 來說、在 PVC 被刪除后會直接移除 PV,同時移除 PV 相關的外部存儲系統上的存儲資產。Dynamic PV 的回收策略取決于相關 Storage Classes 的定義,默認為 Delete 策略。
Controller
Kubernetes 提供了多種 Controllers 來對 Pods 進行管理,包括:Deployment、ReplicaSet、DaemonSet、StatefuleSet、Job 等,以滿足不同的業務需求。這些控制器都運行在 Master 上。
在 Kuberentes 的 kubernetes/pkg/controller/ 目錄中包含了官方提供的一些常見控制器,可以通過下面這個函數看到所有需要運行的控制器。這些 Controller 會隨著 Controller Manager 的啟動而運行,它們會監聽集群狀態的變更來調整集群中的 Kuberentes 對象的狀態。
func NewControllerInitializers(loopMode ControllerLoopMode) map[string]InitFunc { controllers := map[string]InitFunc{} controllers["endpoint"] = startEndpointController controllers["replicationcontroller"] = startReplicationController controllers["podgc"] = startPodGCController controllers["resourcequota"] = startResourceQuotaController controllers["namespace"] = startNamespaceController controllers["serviceaccount"] = startServiceAccountController controllers["garbagecollector"] = startGarbageCollectorController controllers["daemonset"] = startDaemonSetController controllers["job"] = startJobController controllers["deployment"] = startDeploymentController controllers["replicaset"] = startReplicaSetController controllers["horizontalpodautoscaling"] = startHPAController controllers["disruption"] = startDisruptionController controllers["statefulset"] = startStatefulSetController controllers["cronjob"] = startCronJobController // ... return controllers }
ReplicaSet(副本控制器)
負責 Pod 的多副本管理,保證 Pod 的副本數量永遠與設定的數量一致,以此達到:“Pod 是脆弱的,但應用是健壯的” 的效果。在版本較新(1.18)的 ContrKubernetesller 中,建議使用 ReplicaSet 代替 ReplicationController 作為副本控制器。
注意:ReplicaSet 控制器是不支持滾動更新的,應用的需求在不斷更新迭代,版本也在不斷的升級,此時就需要應用 Deployment 控制器來支持滾動升級。所以 Deployment 和 ReplicaSet 通常會一起使用。使用 Deployment 的同時會自動創建 ReplicaSet,也就是說 Deployment 實際是通過 ReplicaSet 來管理 Pod 多副本的,通常不需要直接使用 ReplicaSet。
Deployment(部署控制器)
負責 Pod 的部署,并維護部署拓撲(e.g. 創建、監控、自修復 Pod),保證 Pod 按照期望的狀態運行。
注意:不能使用 Deployment 部署有狀態的服務。對于有狀態的服務,使用 StatefulSet 控制器來進行部署。有狀態服務,即:有實時的數據需要存儲;無狀態服務,即:沒有實時的數據需要存儲。
下面是一個 Deployment 的配置文件(nginx-deployment.yaml)。在正方形灰框內(從 template 開始)的是嵌入在 Deployment 里的 Pod 的設置,灰框上面的是部署(Deployment)的設置。當你運行這個配置文件時,它會創建一個 Deployment,同時也會創建嵌入在里面的 Pod。這就是為什么我們一般不需要單獨的 Pod 的配置文件,因為已經把它嵌入在了 Deployment 里了。
StatefuleSet(有狀態部署控制器)
一般的,當 Pod 因為故障需要刪除并重新啟動時,它的名稱會發生變化。為了解決有狀態服務使用容器化部署的問題,StatefulSet 保證 Pod 重新建立后,Hostname 不會發生變化,Pod 就可以通過 Hostname 來關聯持久化的數據。即:StatefuleSet 控制器可以保證 Pod 的所有副本的名稱在其整個生命周期中是不變的。StatefuleSet 還可以保證 Pod 的副本按照固定的順序啟動、更新或者刪除。
DaemonSet(守護進程控制器)
用于每個 Node 都運行且只運行一個 Pod 副本的場景,通常用于運行 daemon 守護服務進程。這對于在所有 Node 上運行諸如 Fluentd 之類的日志代理非常有用。當然,也可以通過使用污點(Taint)略過某些節點。
Job(任務控制器)
特殊的任務控制器,用于 App 運行結束就可以立即刪除 Pod 的場景。
Service
Pod 是一個進程,具有生命周期,宕機、版本更新時都會創建新的 Pod。這時候 Pod 的 IP 地址、Hostname 就會發生變化,無法直接使用 Nginx 等反向代理來進行負載均衡。
為此,Kubernetes 設計了 Service 這一抽血的概念,表示可以被 “他人” 所使用的服務。Service 用于定義外界訪問一組特定 Pod 的方式:北向定義訪問方式(ClusterIP、NodePort、LoadBalancer),南向通過 Label 和 Selectors 來匹配特定的 Pods,還可以為 Pods 提供了負載均衡。
客戶端只需要訪問 Service 的 IP,Kubernetess 則負責建立和維護 Service 與 Pod 的映射關系。無論后端 Pod 的 IP 地址如何變化,對客戶端不會有任何影響,因為 Service 的 IP 沒有變。
Service 和 Pod 之間可以直接進行通信,它們的通信屬于局域網通信。Pod 把請求交給 Service 后,Service 使用 iptable、ipvs 等技術做數據包的分發(NAT、LB)。
Service 資源對象包括如下三部分:
Pod IP:每個 Pod 特有的 IP 地址,Pod IP 無法通過外網訪問,只能在 Service 下屬的 Pods 進行訪問。
Node IP:每臺物理主機的 IP 地址,如果有一個 Service 申請的 IP 類型為 Node IP,并且 Service 的 Port 為 30222,那么外部就可以通過 Node IP: 30222 來訪問這個 Service 了。
Cluster IP:虛擬 IP(VIP),如果 Service 申請的 IP 類型為 Cluster IP,那么該 Service 對象就是一個 VIP 的資源對象,而且這個 IP 是不變的。每個 Node 中都有 Kube-Proxy,監聽所有 Pods。如果發現 Pod 的 IP 地址發生變化時,就動態更新(Etcd 中存儲的)對應的 IP 地址映射關系。
selector: app=x 選擇一組訂單的服務 pod ,創建一個 service; 通過 endpoints 存放一組 pod ip;
下面就是 Service 的配置文件 nginx-service.yaml。一般來說調用 Service 需要知道三個東西:IP、Port、Protocol,例如:http://10.0.2.1:80。但如果我們希望使用域名來尋址,就需要 DNS 服務了。下面 Service 通過 selector 來與 Pod 進行綁定,這里它把請求轉發給 label app 為 nginx-app 的 Pod。而 NodePort 則表示給 Service 創建了一個外部可以訪問的端口,這樣在虛擬機上就可以直接訪問服務了。
Label
Label 是一個非常核心的 kubernetes API 的概念,本質是一組鍵值對。這些 Label 可以被 Selector,也就是被選擇器所查詢到。與 SQL 中的 select 語句是非常相似的。通過 Label,kubernetes 的 API 層就可以對這些資源進行一個篩選。
每個 Kubernetes Object 都可以貼上多個 Label,下述的 app 就是一個用來標識 Pod 對象的 label。圖里有兩個 Pod,它們的 Label app 值分別為 A 和 B,其中 Pod B 是一個服務集群,而 Pod A 不是。Service 和 Deployment 都通過 Label Selector(標簽選擇器)來綁定與之匹配的 Pods。
Ingress
在大多數組網場景中,Pods 和 Service 的 IP 地址只能在 Kubernetes Cluster 內部被訪問,外網都是無法直接訪問的。
Ingress 就可以通過一個 VIP 與 Kubernetes Cluster 內部進行通訊,一般會和 Service 進行配合使用,以提供外網訪問入口。
它可以用于負載平衡、終止 TLS、提供外部可路由 URL 等等。Ingress 的本質也是 Kubernetes 的一個資源對象,然而,在大多數情況下 Ingress 對象需要有一個入口控制器(Ingress Controller),像 Nginx 等。
Namespace
Namespace 提供了一種集群資源的劃分方法,包括鑒權、資源管理等,用于 Kubernetes 實現多租戶的效果。將一個物理的 Kubernetes Cluster 從邏輯上劃分成多個虛擬的 Kubernetes Cluster,每個虛擬 Cluster 就是一個 Namespace,不同 Namespace 間的資源完全隔離。
default Namespace:默認的 Namespace,如果創建任意資源時若不特別指定,就會將資源放到這個 namespace 下。
kube-system Namespace:Kubernetes 自己創建的系統資源將放到這個 namespace 下。
custom Namespace:租戶自定義的 namespace。
ConfigMap
設計良好的應用程序應該遵循 12 因素的應用程序聲明,對于應用程序的配置,應該將配置存儲在 “環境” 中。盡管現在常見的安全實踐指出,在環境中存儲配置可能會導致機密的意外泄漏,因為一些應用程序在失敗時拋出了它們的環境,但是配置應該與構建的應用程序分開存儲,因為每個環境都有配置更改。(開發、臨時、生產)。
ConfigMap 允許將配置文件作為環境變量或文件系統掛載到 Pod 中,從而解決了這個問題。
容器設計模式
InitContainer
有了 InitContainer 之后就可以這樣去描述:Pod 是一個自包含的,可以把這一個 Pod 在全世界任何一個 Kubernetes 上面都順利啟用起來。不用擔心有沒有分布式存儲、Volume 是不是持久化的。
通過組合兩個不同角色的容器,并且按照這樣一些像 Init Container 這樣一種編排方式,統一的去打包這樣一個應用,把它用 Pod 來去做的非常典型的一個例子。像這樣的一個概念,在 Kubernetes 里面就是一個非常經典的容器設計模式,叫做:“Sidecar”。
Sidecar
什么是 Sidecar?就是說其實在 Pod 里面,可以定義一些專門的容器,來執行主業務容器所需要的一些輔助工作,比如我們前面舉的例子,其實就干了一個事兒,這個 Init Container,它就是一個 Sidecar,它只負責把鏡像里的 WAR 包拷貝到共享目錄里面,以便被 Tomcat 能夠用起來。
其它有哪些操作呢?比如說:
原本需要在容器里面執行 SSH 需要干的一些事情,可以寫腳本、一些前置的條件,其實都可以通過像 Init Container 或者另外像 Sidecar 的方式去解決;
還有一個典型例子就是日志收集,日志收集本身是一個進程,是一個小容器,那么就可以把它打包進 Pod 里面去做這個收集工作;
還有一個非常重要的東西就是 Debug 應用,實際上現在 Debug 整個應用都可以在應用 Pod 里面再次定義一個額外的小的 Container,它可以去 exec 應用 pod 的 namespace;
查看其他容器的工作狀態,這也是它可以做的事情。不再需要去 SSH 登陸到容器里去看,只要把監控組件裝到額外的小容器里面就可以了,然后把它作為一個 Sidecar 啟動起來,跟主業務容器進行協作,所以同樣業務監控也都可以通過 Sidecar 方式來去做。
這種做法一個非常明顯的優勢就是在于其實將輔助功能從我的業務容器解耦了,所以我就能夠獨立發布 Sidecar 容器,并且更重要的是這個能力是可以重用的,即同樣的一個監控 Sidecar 或者日志 Sidecar,可以被全公司的人共用的。這就是設計模式的一個威力。
Kubernetes 任務調度 容器
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。