# Pod解析
Pod是kubernetes中可以創建的最小部署單元。
V1 core版本的Pod的配置模板見[Pod template](../manifests/template/pod-v1-template.yaml)。
## 什么是Pod?
Pod就像是豌豆莢一樣,它由一個或者多個容器組成(例如Docker容器),它們共享容器存儲、網絡和容器運行配置項。Pod中的容器總是被同時調度,有共同的運行環境。你可以把單個Pod想象成是運行獨立應用的“邏輯主機”——其中運行著一個或者多個緊密耦合的應用容器——在有容器之前,這些應用都是運行在幾個相同的物理機或者虛擬機上。
盡管kubernetes支持多種容器運行時,但是Docker依然是最常用的運行時環境,我們可以使用Docker的術語和規則來定義Pod。
Pod中共享的環境包括Linux的namespace、cgroup和其他可能的隔絕環境,這一點跟Docker容器一致。在Pod的環境中,每個容器中可能還有更小的子隔離環境。
Pod中的容器共享IP地址和端口號,它們之間可以通過`localhost`互相發現。它們之間可以通過進程間通信,例如[SystemV](https://en.wikipedia.org/wiki/UNIX_System_V)信號或者POSIX共享內存。不同Pod之間的容器具有不同的IP地址,不能直接通過IPC通信。
Pod中的容器也有訪問共享volume的權限,這些volume會被定義成pod的一部分并掛載到應用容器的文件系統中。
根據Docker的結構,Pod中的容器共享namespace和volume,不支持共享PID的namespace。
就像每個應用容器,pod被認為是臨時(非持久的)實體。在Pod的生命周期中討論過,pod被創建后,被分配一個唯一的ID(UID),調度到節點上,并一致維持期望的狀態直到被終結(根據重啟策略)或者被刪除。如果node死掉了,分配到了這個node上的pod,在經過一個超時時間后會被重新調度到其他node節點上。一個給定的pod(如UID定義的)不會被“重新調度”到新的節點上,而是被一個同樣的pod取代,如果期望的話甚至可以是相同的名字,但是會有一個新的UID。
Volume跟pod有相同的生命周期(當其UID存在的時候)。當Pod因為某種原因被刪除或者被新創建的相同的Pod取代,它相關的東西(例如volume)也會被銷毀和再創建一個新的volume。

*一個多容器Pod,包含文件提取程序和Web服務器,該服務器使用持久卷在容器之間共享存儲。*
## Pod的動機
### 管理
Pod是一個服務的多個進程的聚合單位,pod提供這種模型能夠簡化應用部署管理,通過提供一個更高級別的抽象的方式。Pod作為一個獨立的部署單位,支持橫向擴展和復制。共生(協同調度),命運共同體(例如被終結),協同復制,資源共享,依賴管理,Pod都會自動的為容器處理這些問題。
### 資源共享和通信
Pod中的應用可以共享網絡空間(IP地址和端口),因此可以通過`localhost`互相發現。因此,pod中的應用必須協調端口占用。每個pod都有一個唯一的IP地址,跟物理機和其他pod都處于一個扁平的網絡空間中,它們之間可以直接連通。
Pod中應用容器的hostname被設置成Pod的名字。
Pod中的應用容器可以共享volume。Volume能夠保證pod重啟時使用的數據不丟失。
## Pod的使用
Pod也可以用于垂直應用棧(例如LAMP),這樣使用的主要動機是為了支持共同調度和協調管理應用程序,例如:
- 內容管理系統、文件和數據加載器、本地換群管理器等。
- 日志和檢查點備份、壓縮、旋轉、快照等。
- 數據變更觀察者、日志和監控適配器、活動發布者等。
- 代理、橋接和適配器等。
- 控制器、管理器、配置器、更新器等。
通常單個pod中不會同時運行一個應用的多個實例。
詳細說明請看: [The Distributed System ToolKit: Patterns for Composite Containers](https://kubernetes.io/blog/2015/06/the-distributed-system-toolkit-patterns/).
## 其他替代選擇
**為什么不直接在一個容器中運行多個應用程序呢?**
1. 透明。讓Pod中的容器對基礎設施可見,以便基礎設施能夠為這些容器提供服務,例如進程管理和資源監控。這可以為用戶帶來極大的便利。
2. 解耦軟件依賴。每個容器都可以進行版本管理,獨立的編譯和發布。未來kubernetes甚至可能支持單個容器的在線升級。
3. 使用方便。用戶不必運行自己的進程管理器,還要擔心錯誤信號傳播等。
4. 效率。因為由基礎架構提供更多的職責,所以容器可以變得更加輕量級。
**為什么不支持容器的親和性的協同調度?**
這種方法可以提供容器的協同定位,能夠根據容器的親和性進行調度,但是無法實現使用pod帶來的大部分好處,例如資源共享,IPC,保持狀態一致性和簡化管理等。
## Pod的持久性(或者說缺乏持久性)
Pod在設計支持就不是作為持久化實體的。在調度失敗、節點故障、缺少資源或者節點維護的狀態下都會死掉會被驅逐。
通常,用戶不需要手動直接創建Pod,而是應該使用controller(例如[Deployments](./deployment.md)),即使是在創建單個Pod的情況下。Controller可以提供集群級別的自愈功能、復制和升級管理。
使用集合API作為主要的面向用戶的原語在集群調度系統中相對常見,包括[Borg](https://research.google.com/pubs/pub43438.html)、[Marathon](https://mesosphere.github.io/marathon/docs/rest-api.html)、[Aurora](http://aurora.apache.org/documentation/latest/reference/configuration/#job-schema)和[Tupperware](https://www.slideshare.net/Docker/aravindnarayanan-facebook140613153626phpapp02-37588997)。
Pod 原語有利于:
- 調度程序和控制器可插拔性
- 支持pod級操作,無需通過控制器API“代理”它們
- 將pod生命周期與控制器生命周期分離,例如用于自舉(bootstrap)
- 控制器和服務的分離——端點控制器只是監視pod
- 將集群級功能與Kubelet級功能的清晰組合——Kubelet實際上是“pod控制器”
- 高可用性應用程序,它們可以在終止之前及在刪除之前更換pod,例如在計劃驅逐、鏡像預拉取或實時pod遷移的情況下[#3949](https://github.com/kubernetes/kubernetes/issues/3949)
[StatefulSet](statefulset.md) 控制器支持有狀態的Pod。在1.4版本中被稱為PetSet。在kubernetes之前的版本中創建有狀態pod的最佳方式是創建一個replica為1的replication controller。
## Pod的終止
因為Pod作為在集群的節點上運行的進程,所以在不再需要的時候能夠優雅的終止掉是十分必要的(比起使用發送KILL信號這種暴力的方式)。用戶需要能夠發起一個刪除 Pod 的請求,并且知道它們何時會被終止,是否被正確的刪除。用戶想終止程序時發送刪除pod的請求,在pod可以被強制刪除前會有一個寬限期,會發送一個TERM請求到每個容器的主進程。一旦超時,將向主進程發送KILL信號并從API server中刪除。如果kubelet或者container manager在等待進程終止的過程中重啟,在重啟后仍然會重試完整的寬限期。
示例流程如下:
1. 用戶發送刪除pod的命令,默認寬限期是30秒;
2. 在Pod超過該寬限期后API server就會更新Pod的狀態為“dead”;
3. 在客戶端命令行上顯示的Pod狀態為“terminating”;
4. 跟第三步同時,當kubelet發現pod被標記為“terminating”狀態時,開始停止pod進程:
1. 如果在pod中定義了preStop hook,在停止pod前會被調用。如果在寬限期過后,preStop hook依然在運行,第二步會再增加2秒的寬限期;
2. 向Pod中的進程發送TERM信號;
5. 跟第三步同時,該Pod將從該service的端點列表中刪除,不再是replication controller的一部分。關閉的慢的pod將繼續處理load balancer轉發的流量;
6. 過了寬限期后,將向Pod中依然運行的進程發送SIGKILL信號而殺掉進程。
7. Kubelet會在API server中完成Pod的的刪除,通過將優雅周期設置為0(立即刪除)。Pod在API中消失,并且在客戶端也不可見。
刪除寬限期默認是30秒。 `kubectl delete`命令支持 `—grace-period=<seconds>` 選項,允許用戶設置自己的寬限期。如果設置為0將強制刪除pod。在kubectl>=1.5版本的命令中,你必須同時使用 `--force` 和 `--grace-period=0` 來強制刪除pod。
在 yaml 文件中可以通過 `{{ .spec.spec.terminationGracePeriodSeconds }}` 來修改此值。
### 強制刪除Pod
Pod的強制刪除是通過在集群和etcd中將其定義為刪除狀態。當執行強制刪除命令時,API server不會等待該pod所運行在節點上的kubelet確認,就會立即將該pod從API server中移除,這時就可以創建跟原pod同名的pod了。這時,在節點上的pod會被立即設置為terminating狀態,不過在被強制刪除之前依然有一小段優雅刪除周期。
強制刪除對于某些pod具有潛在危險性,請謹慎使用。使用StatefulSet pod的情況下,請參考刪除StatefulSet中的pod文章。
## Pod中容器的特權模式
從Kubernetes1.1版本開始,pod中的容器就可以開啟privileged模式,在容器定義文件的 `SecurityContext` 下使用 `privileged` flag。 這在使用Linux的網絡操作和訪問設備的能力時是很有用的。容器內進程可獲得近乎等同于容器外進程的權限。在不需要修改和重新編譯kubelet的情況下就可以使用pod來開發節點的網絡和存儲插件。
如果master節點運行的是kuberentes1.1或更高版本,而node節點的版本低于1.1版本,則API server將也可以接受新的特權模式的pod,但是無法啟動,pod將處于pending狀態。
執行 `kubectl describe pod FooPodName`,可以看到為什么pod處于pending狀態。輸出的event列表中將顯示:
`Error validating pod "FooPodName"."FooPodNamespace" from api, ignoring: spec.containers[0].securityContext.privileged: forbidden '<*>(0xc2089d3248)true'`
如果master節點的版本低于1.1,無法創建特權模式的pod。如果你仍然試圖去創建的話,你得到如下錯誤:
`The Pod "FooPodName" is invalid. spec.containers[0].securityContext.privileged: forbidden '<*>(0xc20b222db0)true'`
## API Object
Pod是kubernetes REST API中的頂級資源類型。
在kuberentes1.6的V1 core API版本中的Pod的數據結構如下圖所示:

- 序言
- 云原生
- 云原生(Cloud Native)的定義
- CNCF - 云原生計算基金會簡介
- CNCF章程
- 云原生的設計哲學
- Play with Kubernetes
- 快速部署一個云原生本地實驗環境
- Kubernetes與云原生應用概覽
- 云原生應用之路——從Kubernetes到Cloud Native
- 云原生編程語言
- 云原生編程語言Ballerina
- 云原生編程語言Pulumi
- 云原生的未來
- Kubernetes架構
- 設計理念
- Etcd解析
- 開放接口
- CRI - Container Runtime Interface(容器運行時接口)
- CNI - Container Network Interface(容器網絡接口)
- CSI - Container Storage Interface(容器存儲接口)
- Kubernetes中的網絡
- Kubernetes中的網絡解析——以flannel為例
- Kubernetes中的網絡解析——以calico為例
- 具備API感知的網絡和安全性管理開源軟件Cilium
- Cilium架構設計與概念解析
- 資源對象與基本概念解析
- Pod狀態與生命周期管理
- Pod概覽
- Pod解析
- Init容器
- Pause容器
- Pod安全策略
- Pod的生命周期
- Pod Hook
- Pod Preset
- Pod中斷與PDB(Pod中斷預算)
- 集群資源管理
- Node
- Namespace
- Label
- Annotation
- Taint和Toleration(污點和容忍)
- 垃圾收集
- 控制器
- Deployment
- StatefulSet
- DaemonSet
- ReplicationController和ReplicaSet
- Job
- CronJob
- Horizontal Pod Autoscaling
- 自定義指標HPA
- 準入控制器(Admission Controller)
- 服務發現
- Service
- Ingress
- Traefik Ingress Controller
- 身份與權限控制
- ServiceAccount
- RBAC——基于角色的訪問控制
- NetworkPolicy
- 存儲
- Secret
- ConfigMap
- ConfigMap的熱更新
- Volume
- Persistent Volume(持久化卷)
- Storage Class
- 本地持久化存儲
- 集群擴展
- 使用自定義資源擴展API
- 使用CRD擴展Kubernetes API
- Aggregated API Server
- APIService
- Service Catalog
- 資源調度
- QoS(服務質量等級)
- 用戶指南
- 資源對象配置
- 配置Pod的liveness和readiness探針
- 配置Pod的Service Account
- Secret配置
- 管理namespace中的資源配額
- 命令使用
- Docker用戶過度到kubectl命令行指南
- kubectl命令概覽
- kubectl命令技巧大全
- 使用etcdctl訪問kubernetes數據
- 集群安全性管理
- 管理集群中的TLS
- kubelet的認證授權
- TLS bootstrap
- 創建用戶認證授權的kubeconfig文件
- IP偽裝代理
- 使用kubeconfig或token進行用戶身份認證
- Kubernetes中的用戶與身份認證授權
- Kubernetes集群安全性配置最佳實踐
- 訪問Kubernetes集群
- 訪問集群
- 使用kubeconfig文件配置跨集群認證
- 通過端口轉發訪問集群中的應用程序
- 使用service訪問群集中的應用程序
- 從外部訪問Kubernetes中的Pod
- Cabin - Kubernetes手機客戶端
- Kubernetic - Kubernetes桌面客戶端
- Kubernator - 更底層的Kubernetes UI
- 在Kubernetes中開發部署應用
- 適用于kubernetes的應用開發部署流程
- 遷移傳統應用到Kubernetes中——以Hadoop YARN為例
- 最佳實踐概覽
- 在CentOS上部署Kubernetes集群
- 創建TLS證書和秘鑰
- 創建kubeconfig文件
- 創建高可用etcd集群
- 安裝kubectl命令行工具
- 部署master節點
- 安裝flannel網絡插件
- 部署node節點
- 安裝kubedns插件
- 安裝dashboard插件
- 安裝heapster插件
- 安裝EFK插件
- 生產級的Kubernetes簡化管理工具kubeadm
- 使用kubeadm在Ubuntu Server 16.04上快速構建測試集群
- 服務發現與負載均衡
- 安裝Traefik ingress
- 分布式負載測試
- 網絡和集群性能測試
- 邊緣節點配置
- 安裝Nginx ingress
- 安裝配置DNS
- 安裝配置Kube-dns
- 安裝配置CoreDNS
- 運維管理
- Master節點高可用
- 服務滾動升級
- 應用日志收集
- 配置最佳實踐
- 集群及應用監控
- 數據持久化問題
- 管理容器的計算資源
- 集群聯邦
- 存儲管理
- GlusterFS
- 使用GlusterFS做持久化存儲
- 使用Heketi作為Kubernetes的持久存儲GlusterFS的external provisioner
- 在OpenShift中使用GlusterFS做持久化存儲
- GlusterD-2.0
- Ceph
- 用Helm托管安裝Ceph集群并提供后端存儲
- 使用Ceph做持久化存儲
- 使用rbd-provisioner提供rbd持久化存儲
- OpenEBS
- 使用OpenEBS做持久化存儲
- Rook
- NFS
- 利用NFS動態提供Kubernetes后端存儲卷
- 集群與應用監控
- Heapster
- 使用Heapster獲取集群和對象的metric數據
- Prometheus
- 使用Prometheus監控kubernetes集群
- Prometheus查詢語言PromQL使用說明
- 使用Vistio監控Istio服務網格中的流量
- 分布式跟蹤
- OpenTracing
- 服務編排管理
- 使用Helm管理Kubernetes應用
- 構建私有Chart倉庫
- 持續集成與發布
- 使用Jenkins進行持續集成與發布
- 使用Drone進行持續集成與發布
- 更新與升級
- 手動升級Kubernetes集群
- 升級dashboard
- 領域應用概覽
- 微服務架構
- 微服務中的服務發現
- 使用Java構建微服務并發布到Kubernetes平臺
- Spring Boot快速開始指南
- Service Mesh 服務網格
- 企業級服務網格架構
- Service Mesh基礎
- Service Mesh技術對比
- 采納和演進
- 定制和集成
- 總結
- Istio
- 安裝并試用Istio service mesh
- 配置請求的路由規則
- 安裝和拓展Istio service mesh
- 集成虛擬機
- Istio中sidecar的注入規范及示例
- 如何參與Istio社區及注意事項
- Istio教程
- Istio免費學習資源匯總
- 深入理解Istio Service Mesh中的Envoy Sidecar注入與流量劫持
- 深入理解Istio Service Mesh中的Envoy Sidecar代理的路由轉發
- Linkerd
- Linkerd 使用指南
- Conduit
- Condiut概覽
- 安裝Conduit
- Envoy
- Envoy的架構與基本術語
- Envoy作為前端代理
- Envoy mesh教程
- SOFAMesh
- SOFAMesh中的Dubbo on x-protocol
- SOFAMosn
- 使用 SOFAMosn 構建 SOFAMesh
- 大數據
- Spark standalone on Kubernetes
- 運行支持Kubernetes原生調度的Spark程序
- Serverless架構
- 理解Serverless
- FaaS-函數即服務
- OpenFaaS快速入門指南
- 邊緣計算
- 人工智能