日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【云原生|实战研发】2:Pod的深入实践与理解

發布時間:2023/12/20 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【云原生|实战研发】2:Pod的深入实践与理解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本期文章是介紹Pod的簡單實踐和容器設計模式深入學習,上次的文章中我們已經學習過了Docker、K8s的核心概念理解與簡單的代碼實戰相關知識,也學習了DevOps與微服務的概念,感興趣的同學可以去我的云原生專欄中學習,任意門:云原生學習專欄

Pod的深入實踐理解

  • Pod深入實踐學習
    • 1、創建一個簡單的Pod
    • 2、通過label組成一個Pod
      • pause的label信息
      • nginx的label信息
    • 3、到底為什么需要Pod?
      • 真實的操作系統案例:進程組
      • Pod的真正作用
    • 4、Pod的具體業務案例
    • 5、Pod的深入理解:超親密關系
    • 總結
  • Pod的實現機制
    • 1、刨根究底:Pod到底怎么實現的?
      • 解法1:通過共享網絡
      • 解法2:通過共享存儲
  • 附錄:Pod的詳細定義
  • 附錄:Pod的常用命令

Pod深入實踐學習

我們已經了解到,K8s的所有功能都是通過Pod進行展開實現的,大致如下圖所示:

Pod是一組container的集合,container之間可以通過localhost:port的方式直接訪問。

1、創建一個簡單的Pod

apiVersion: v1 kind: Pod metadata:name: nginxlabels:app: hello-world spec:containers:- name: nginximage: nginxports:- containerPort: 80

創建一個Pod

kubectl create -f pod1.yaml

查看Pod信息:

$ kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx 1/1 Running 0 69s 10.244.1.3 node01 <none> <none>

對該node01節點進行docker ps命令操作得到:


通過上圖我們可以看到,該pod的組成是:一個pause的容器和n個自定義的容器。

大致如下圖所示:

2、通過label組成一個Pod

Pod使用label把上述的container組成一個的,接下來查看看container的label信息:

pause的label信息

nginx的label信息

通過上面的對比分析,會發現: pod.name:“nginx”, namespace: “default”,"pod.uid"都是一樣的。

而K8s就是通過這些label來組織Pod的。

3、到底為什么需要Pod?

首先需要回顧一下容器的概念,容器的本質是一個視圖被隔離、資源受限的進程。

而容器里PID=1的進程就是應用本身(如下圖與下文所示),所以,管理虛擬機 = 管理基礎設施;管理容器=直接管理應用本身。

而這一點也正是不可變基礎設施的最佳表現,這個時候應用就是基礎設施,一定是不可變的。

Docker中,進程管理的基礎就是Linux的PID名空間技術。在不同PID名空間中,進程ID是獨立的:即在兩個不同名空間下的進程可以有相同的PID。

當創建一個Docker容器的時候,就會新建一個PID名空間。容器啟動進程在該名空間內PID為1。當PID1進程結束之后,Docker會銷毀對應的PID名空間,并向容器內所有其它的子進程發送SIGKILL。

需要注意的是:PID=1的進程對于操作系統而言具有特殊意義。操作系統的PID1進程是init進程,以守護進程方式運行,是所有其他進程的祖先,具有完整的進程生命周期管理能力。在Docker容器中,PID1進程是啟動進程,它也會負責容器內部進程管理的工作。而這也將導致進程管理在Docker容器內部和完整操作系統上的不同。

而介于上面的場景之下,K8s的作用又是什么呢?這里需要引用一個特殊的經典話語,那就是容器本身沒有價值,有價值的是“容器編排”。而K8s就是用來容器編排的,也有很多人說K8s是云原生時代的操作系統。那么如果按照這個比較關系下去,那么容器鏡像就是操作系統里的軟件安裝包,容器、容器鏡像、K8s就是這樣一個相互之間的關系。

可以大致的認為:K8s=操作系統linux、容器=進程(linux線程),Pod=進程組(線程組)

真實的操作系統案例:進程組

引入一個Helloworld程序,而該程序由4個進程組構成,這些進程之間共享某些系統的資源文件。

如下圖所示,程序中有4個進程。(這里的進程就是linux系統中的線程),分別是api、main、log、compute,這四個線程共同協作helloworld程序的系統資源,進行運行程序的工作。這就是進程組的概念。

假設現在需要用容器跑起來上面的程序,那么該怎么進行處理?

最直接的方法,就是通過啟動一個docker容器,里面運行四個進程,那么就會存在一個問題,即該容器中PID=1的進程是應用本身的話,如mian進程,那么誰來負責管理剩余的3個進程成了需要解決的難題。

那么對于這個方法,最需要注意的問題是,容器本身是“單進程”模型。(這并不是意味著容器只能跑一個進程。)
而是說因為容器=應用=進程,所以只能管理PID=1的進程,而其他再跑起來的進程,只能認為是托管狀態。所以說除非應用進程具備“進程管理”能力,即helloworld程序需要具備systemd的能力。或者將容器的Pid=1的進程改成systemd,而這樣會導致管理容器=管理systemd!=直接管理應用本身。

而如果不具備systemd的能力,那么一旦PID=1的進程kill或者死掉了,那么剩下3個進程的資源沒有進行回收,那么這是一個很嚴重的問題。

總結的來說,一旦容器啟動了多個進程,那么只能有一個PID=1的進程,而如果PID=1的進程掛了,那么就會沒人回收剩下3個應用的回收,而如果run一個systemd進程來管理其他進程,那么這個時候沒有辦法直接管理其他的應用,這個時候應用狀態的生命周期就不等于容器的生命周期,這樣的情況就十分復雜了。

引申:Linux 容器的“單進程”模型,指的是容器的生命周期等同于 PID=1 的進程(容器應用進程)的生命周期,而不是說容器里不能創建多進程。當然,一般情況下,容器應用進程并不具備進程管理能力,所以你通過 exec 或者 ssh 在容器里創建的其他進程,一旦異常退出(比如 ssh 終止)是很容易變成孤兒進程的。

Pod的真正作用

而Pod就是用來K8s抽象出來的類比為進程組的概念,而上面提到的情況,就可以認為是一個擁有4個容器的pod,即現在不會塞進一個容器中,而是用4個分別獨立的容器啟動起來,包含在一個pod里面,而4個容器共享了一部分資源,所以說,Pod在K8s里面是一個邏輯單位(沒有真實的去對應某些東西)。

總的來說,Pod 是 Kubernetes 分配資源的一個單位,因為里面的容器要共享某些資源,所以 Pod 也是 Kubernetes 的原子調度單位。

而Pod的設計問題早在 Google 研發 Borg 的時候,就已經發現了這樣一個情況:這些應用之前往往有著密切的協作關系,使得它們必須部署在同一臺機器上并共享某些資源。

4、Pod的具體業務案例

現在通過一個例子來幫助我們更好的理解為什么Pod是原子調度單位。

假設現在兩個容器,是需要協作完成業務的,所以應該在一個Pod里面。第一個容器為業務容器A,完成寫日志文件的功能,第二個容器為轉發容器B,顧名思義,即將日志文件轉發到后端進行對應處理。

A和B的資源需求如下:A 需要 1G 內存,B需要 0.5G 內存。
而當前集群環境的可用內存情況如下:Node01:1.25G 內存,Node02:2G 內存。

如果沒有Pod,那么A和B需要運行在一臺機子上,調度器先把A調到了Node01上,那么這就會使得B不能調度到01上了,因為資源不夠,也就是內存不夠B用了,這個時候調度失敗,需要重新調度。

這類問題在以前沒有K8s的Pod的幫助下,很多企業解決這類問題都比較復雜,并且需要額外的開銷。

而現在只需要一個Pod就解決了。這樣的一個 A 容器和 B 容器一定是屬于一個 Pod 的,在調度時是以一個 Pod 為單位進行調度,問題是不存在的。

5、Pod的深入理解:超親密關系

通過上述講解,已經有了一定的了解。那么繼續深入研究一下Pod的“超親密關系”。

對于普通的親密關系,就是通過調度來解決的。例如兩個應用需要在同一臺主機上運行。

而對于Pod的超親密關系則會存在這樣幾類關系:

1、兩個進程之間會發生文件交換,一個寫日志,一個讀日志
2、兩個進程之間需要通過 localhost 或者說是本地的 Socket 去進行通信,這種本地通信也屬于超親密關系
3、兩個容器是微服務,需要發生非常頻繁的 RPC 調用,考慮性能方面將之認為是超親密關系
4、兩個容器是應用,需要共享某些 Linux Namespace。舉個簡單例子:有一個容器需要加入另一個容器的 Network Namespace。這樣就能看到另一個容器的網絡設備,和它的網絡信息。

總結

所以通過上述的講解,理解了Pod的概念設計來由,以及為什么需要Pod。

通過Pod,可以知道怎么去描述超親密關系,怎么去進行統一的業務調度。

這就是Pod最主要的來由與作用。

Pod的實現機制

1、刨根究底:Pod到底怎么實現的?

在機器上,Pod是怎么實現的,對于這個問題,核心就在于如何讓一個 Pod 里的多個容器之間最高效的共享某些資源和數據。

容器之間原本是被 Linux Namespace 和 cgroups 隔開的,現在要解決的是怎么去打破這個隔離,然后共享某些資源等。這就是 Pod 的設計要解決的核心問題所在。

解法1:通過共享網絡

假設現在有一個 Pod,其中包含了兩個容器A 和 B,它們要共享 Network Namespace。
在 Kubernetes 里的解法是這樣的:它會在每個 Pod 里,額外起一個 Infra container 小容器來共享整個 Pod 的 Network Namespace。

Infra container 是一個十分小的鏡像,大概 100-200KB ,是一個匯編語言寫的、永遠處于“暫停”狀態的容器。

這就可以使得其他所有容器都會通過 Join Namespace 的方式加入到 Infra container 的 Network Namespace 中。

所以 Pod 里面的所有容器,它們看到的網絡視圖是一致的,如它們看到的網絡設備、IP地址、Mac地址等等,跟網絡相關的信息等。上述這些信息都來自于Pod 第一次創建的這個 Infra container。這就是 Pod 解決網絡共享的一個方法。

在 Pod 里面,有一個 IP 地址,是這個 Pod 的 Network Namespace 對應的地址,也是這個 Infra container 的 IP 地址。所以Pod里面的容器看到的都是這個。而對于宿主機上的其他網絡資源,都是一個 Pod為 一組來分的,并且被該 Pod 中的所有容器共享網絡視圖。

該Infra容器相當于總dialing,所以整個 Pod 中是 Infra container 第一個啟動。并且整個 Pod 的生命周期是等同于 Infra container 的生命周期的,與容器 A 和 B 是無關的。這也是為什么 K8s中,允許去單獨更新 Pod 里的某一個鏡像的,即做這個操作,整個 Pod 并不會進行重建或者重啟。

解法2:通過共享存儲

有兩個容器,一個是 A,一個是B,在A放一些文件,使之能通過 Nginx 訪問到。所以A需要去 share 這個目錄。 share 文件或者是 share 目錄在 Pod 里面是容易實現的,就是把 volume 變成了 Pod level。對于同一個Pod下的容器來說共享所有的 volume即可。

在下圖的案例中,這個 volume 叫做 shared-data,是屬于 Pod level 的,在每一個容器里可以直接聲明:掛載 shared-data 這個 volume。只要聲明掛載這個 volume,在容器里去看這個目錄,實際上每個容器看到的就是同一份。

在之前的例子中,A寫了日志,只要這個日志是寫在一個 volume 中,只要聲明掛載了同樣的 volume,這個 volume 就可以立刻被另外一個 B容器給看到。以上就是 Pod 實現存儲的方式。

附錄:Pod的詳細定義

apiVersion: v1 # 必選,API的版本號 kind: Pod # 必選,類型Pod metadata: # 必選,元數據name: nginx # 必選,符合RFC 1035規范的Pod名稱# namespace: default # 可選,Pod所在的命名空間,不指定默認為default,可以使用-n 指定namespace labels: # 可選,標簽選擇器,一般用于過濾和區分Podapp: nginxrole: frontend # 可以寫多個annotations: # 可選,注釋列表,可以寫多個app: nginx spec: # 必選,用于定義容器的詳細信息 # initContainers: # 初始化容器,在容器啟動之前執行的一些初始化操作 # - command: # - sh # - -c # - echo "I am InitContainer for init some configuration" # image: busybox # imagePullPolicy: IfNotPresent # name: init-containercontainers: # 必選,容器列表- name: nginx # 必選,符合RFC 1035規范的容器名稱image: nginx:1.15.2 # 必選,容器所用的鏡像的地址imagePullPolicy: IfNotPresent # 可選,鏡像拉取策略, IfNotPresent: 如果宿主機有這個鏡像,那就不需要拉取了. Always: 總是拉取, Never: 不管是否存儲都不拉去command: # 可選,容器啟動執行的命令 ENTRYPOINT, arg --> cmd- nginx - -g- "daemon off;"workingDir: /usr/share/nginx/html # 可選,容器的工作目錄 # volumeMounts: # 可選,存儲卷配置,可以配置多個 # - name: webroot # 存儲卷名稱 # mountPath: /usr/share/nginx/html # 掛載目錄 # readOnly: true # 只讀ports: # 可選,容器需要暴露的端口號列表- name: http # 端口名稱containerPort: 80 # 端口號protocol: TCP # 端口協議,默認TCPenv: # 可選,環境變量配置列表- name: TZ # 變量名value: Asia/Shanghai # 變量的值- name: LANGvalue: en_US.utf8 # resources: # 可選,資源限制和資源請求限制 # limits: # 最大限制設置 # cpu: 1000m # memory: 1024Mi # requests: # 啟動所需的資源 # cpu: 100m # memory: 512Mi # startupProbe: # 可選,檢測容器內進程是否完成啟動。注意三種檢查方式同時只能使用一種。 # httpGet: # httpGet檢測方式,生產環境建議使用httpGet實現接口級健康檢查,健康檢查由應用程序提供。 # path: /api/successStart # 檢查路徑 # port: 80 # readinessProbe: # 可選,健康檢查。注意三種檢查方式同時只能使用一種。 # httpGet: # httpGet檢測方式,生產環境建議使用httpGet實現接口級健康檢查,健康檢查由應用程序提供。 # path: / # 檢查路徑 # port: 80 # 監控端口 # livenessProbe: # 可選,健康檢查#exec: # 執行容器命令檢測方式#command: #- cat#- /health#httpGet: # httpGet檢測方式# path: /_health # 檢查路徑# port: 8080# httpHeaders: # 檢查的請求頭# - name: end-user# value: Jason # tcpSocket: # 端口檢測方式 # port: 80 # initialDelaySeconds: 60 # 初始化時間 # timeoutSeconds: 2 # 超時時間 # periodSeconds: 5 # 檢測間隔 # successThreshold: 1 # 檢查成功為2次表示就緒 # failureThreshold: 2 # 檢測失敗1次表示未就緒 # lifecycle: # postStart: # 容器創建完成后執行的指令, 可以是exec httpGet TCPSocket # exec: # command: # - sh # - -c # - 'mkdir /data/ ' # preStop: # httpGet: # path: / # port: 80# exec:# command:# - sh# - -c# - sleep 9restartPolicy: Always # 可選,默認為Always,容器故障或者沒有啟動成功,那就自動該容器,Onfailure: 容器以不為0的狀態終止,自動重啟該容器, Never:無論何種狀態,都不會重啟#nodeSelector: # 可選,指定Node節點# region: subnet7 # imagePullSecrets: # 可選,拉取鏡像使用的secret,可以配置多個 # - name: default-dockercfg-86258 # hostNetwork: false # 可選,是否為主機模式,如是,會占用主機端口 # volumes: # 共享存儲卷列表 # - name: webroot # 名稱,與上述對應 # emptyDir: {} # 掛載目錄 # #hostPath: # 掛載本機目錄 # # path: /etc/hosts #

附錄:Pod的常用命令

#創建一個pod kubectl create -f po.yml #查看創建的pod kubectl get po #創建一個指定命名空間的pod kubectl create -f po.yml -n kube-public #創建一個命名空間 kubectl create ns ns_name #刪除一個pod kubectl delete po nginx #刪除指定命名空間的pod kubectl delete po nginx -n kube-public #查看刪除鍵pod 所用的時間 time kubectl delete po nginx

總結

以上是生活随笔為你收集整理的【云原生|实战研发】2:Pod的深入实践与理解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。