Kubernetes-Pod詳解

Pod

為什么需要Pod

Pod印荔,是Kubernetes項目中的原子調(diào)度單位乙濒。容器就是未來云計算系統(tǒng)中的進程搏明;容器鏡像就是系統(tǒng)里的.exe安裝包肛响,Kubernetes就是操作系統(tǒng)。在一個真正的操作系統(tǒng)里麸拄,進程并不是“孤苦伶仃”地獨自運行派昧,而是以進程組的方式,“有原則”的組織在一起感帅。在kubernetes中斗锭,“進程組”所映射的概念就是Pod。Google的工程師發(fā)現(xiàn)失球,他們部署的應(yīng)用岖是,往往都存在著類似于“進程和進程組”的關(guān)系,也就是說這些應(yīng)用之間有著親密的協(xié)作關(guān)系实苞,使得他們必須部署在同一臺機器上豺撑。

Pod的實現(xiàn)原理

Pod只是一個邏輯概念。

Pod其實是一組共享了某些資源的容器黔牵,具體來說聪轿,Pod里的所有容器,共享的是同一個Network Namespace猾浦,并且可以聲明共享同一個Volume陆错。

在Kubernetes中,Pod的實現(xiàn)需要使用一個中間容器金赦,這個容器叫做Infra容器音瓷。在Pod中,Infra容器永遠是第一個被創(chuàng)建的容器夹抗,而其他用戶定義的容器绳慎,則通過Join Network Namespace的方式與Infra容器關(guān)聯(lián)在一起。

Infra容器使用的是一個非常特殊的鏡像漠烧,叫做:k8s.gcr.io/pause杏愤。這個鏡像是一個用匯編語言編寫的、永遠處于暫停狀態(tài)的容器已脓。在Infra容器“Hold住”NetworkNamespace之后珊楼,用戶容器就可以加入到Infra容器的NetworkNamespace中了。這也就意味著度液,對于Pod中的容器A和容器B:

  • 它們可以直接使用localhost進行通信
  • 它們看到的網(wǎng)絡(luò)設(shè)備和Infra容器看到的完全一樣
  • 一個Pod只有一個IP地址厕宗,也就是這個Pod的Network Namespace對應(yīng)的IP地址
  • 所有的網(wǎng)絡(luò)資源邓了,都是一個Pod一份,并且被該Pod內(nèi)的所有容器共享
  • Pod的生命周期只和Infra容器一致媳瞪,與容器A和容器B無關(guān)

對于Pod共享Volume來說,Kubernetes只要把所有Volume定義設(shè)計在Pod層即可照宝。例如:

apiVersion: v1
kind: Pod
metadata:
 name: two-containers
spec:
 restartPolicy: Never #Pod的重啟策略蛇受。1.Always:容器失效時,kubelet自動重啟該容器厕鹃。2.OnFailure:容器終止運行且退出碼不為0時重啟兢仰。3.Never:無論狀態(tài)如何,kubelet都不重啟該容器剂碴。
 volumes:
 - name: shared-data
   hostPath:
    path : /data
 containers:
 - name: nginx-container
   image: nginx
   volumeMounts:
   - name: shared-data
     mountPath: /usr/share/nginx/html
 - name: debian-container
   image: debian
   volumeMounts:
   - name: shared-data
     mountPath: /pod-data
   command: ["/bin/sh"]
   args: ["-c","echo Hello from the debian container > /pod/data/index.html"]

Pod對象的生命周期

Pod生命周期變化主要體現(xiàn)在Pod API對象的Status部分把将。

  • Pending,這個狀態(tài)意味著Pod的YAML文件已經(jīng)提交給了Kubernetes忆矛,API對象已經(jīng)被創(chuàng)建并被保存在etcd中察蹲。但是,這個Pod里有些容器因為某種原因不能被成功創(chuàng)建催训,比如洽议,調(diào)度不成功
  • Running,這個狀態(tài)下漫拭,Pod已經(jīng)調(diào)度成功亚兄,和一個具體的節(jié)點綁定。它包含的容器都已經(jīng)創(chuàng)建成功采驻,并且至少有一個正在運行中审胚。
  • Succeed,這個狀態(tài)意味著礼旅,Pod中所有容器都正常運行完畢膳叨,并且已經(jīng)退出了。
  • Failed各淀,這個狀態(tài)下懒鉴,Pod里至少有一個容器以不正常的狀態(tài)(非0狀態(tài)碼)退出。這個狀態(tài)的出現(xiàn)意味著你要想辦法Debug這個容器的應(yīng)用碎浇,比如查看Pod的Events和日志
  • Unknown临谱,這是一個異常狀態(tài),意味著Pod的狀態(tài)不能持續(xù)被kubelet匯報給kube-apiserver奴璃,這很可能是Master和kubelet間的通信出了問題悉默。

Pod核心字段

可以把Pod堪稱傳統(tǒng)環(huán)境中的“機器”,把容器看作運行在這個“機器”里的“用戶程序”苟穆。

凡是調(diào)度抄课、網(wǎng)絡(luò)唱星、存儲以及安全相關(guān)的屬性,都是Pod級別的跟磨。

NodeSelector

這是一個供用戶將Pod與Node進行綁定的字段间聊,用法如下:

apiVersion: v1
kind: Pod
...
sepc:
 nodeSelector:
 disktype: ssd

這樣一個配置后,這個Pod只能被調(diào)度到攜帶了“disktype:ssd”標(biāo)簽的節(jié)點上抵拘。

NodeName

一旦Pod這個字段被輔助哎榴,Kubernetes就會認為這個Pod已經(jīng)經(jīng)過了調(diào)度,調(diào)度的結(jié)果就是賦值的節(jié)點名字僵蛛。這個字段一般由調(diào)度器負責(zé)設(shè)置尚蝌,用戶也可以設(shè)置這個字段“騙過”調(diào)度器

HostAliases

定義了Pod的hosts文件(/etc/hosts)里的內(nèi)容。

apiVersion: v1
kind: Pod
...
spec:
 hostAliases:
 - ip: "10.1.2.3"
   hostnames:
   - "foo.remote"
   - "bar.remote"

這個Pod啟動后充尉,/etc/hosts文件內(nèi)容將如下所示:

127.0.0.1 localhost
...
10.244.135.10 hostaliases-pod
10.1.2.3 foo.remote
10.1.2.3 bar.remote

在Kubernetes中如何過要設(shè)置hosts文件的內(nèi)容飘言,一定要通過這種方式,否則驼侠,如果直接修改hosts文件的話姿鸿,在Pod刪除重建之后,kubelet會自動覆蓋掉被修改的內(nèi)容倒源。

Containers

Image般妙、Command、workingDir相速、Ports以及VolumeMounts都是構(gòu)成kubernetes項目中container的主要字段碟渺。還有其他幾個屬性值需要你關(guān)注

ImagePullPolicy

定義了鏡像拉取的策略。

  • Always:默認值突诬,即每次創(chuàng)建Pod都重新拉取一次鏡像苫拍。另外當(dāng)容器的鏡像類似于nginx,nginx:latest這樣的名字時旺隙,ImagePullPolicy也會被認為是Always绒极。
  • Never:永遠不主動拉取這個鏡像
  • IfNotPresent:只有在宿主機上不存在這個鏡像時才拉取

Lifecycle

定義的是Container Lifecycle Hooks。它的作用是在容器狀態(tài)發(fā)生變化的時候觸發(fā)一系列“鉤子”蔬捷。比如

apiVersion: v1
kind: Pod
metadata:
 name: lifecycle-demo
spec:
 containers:
 - name: lifecycle-demo-container
   image: nginx
   lifecycle:
    postStart:
     exec:
      command: ["/bin/sh","-c","echo Hello fomr the postStart handler > /usr/share/message"]
    preStop:
     exec:
      command: ["/usr/sbin/nginx","-s","quit"]

postStart垄提,指的是在容器啟動后,立刻執(zhí)行一個指定的操作周拐。postStart定義的操作铡俐,雖然是在Docker容器ENTRYPOINT執(zhí)行之后,但不嚴格保證順序妥粟,也就是說在postStart啟動時审丘,ENTRYPOINT有可能還沒結(jié)束。

preStop勾给,發(fā)生的時機滩报,是容器被殺死之前锅知。它會阻塞當(dāng)前的容器殺死流程,直到這個Hook定義的操作完成脓钾。

Projected Volume

ProjectVolume可以翻譯為投射數(shù)據(jù)卷售睹,Kubernetes中,有幾種特殊的Volume可训,它們存在的意義并不是為了存放容器中的數(shù)據(jù)侣姆,也不是用來進行容器和宿主機之間的數(shù)據(jù)交換,它們的作用是為容器提供預(yù)先定義好的數(shù)據(jù)沉噩。這些Volume中的信息好像是被Kubernetes“投射”進容器中的。

目前為止柱蟀,Kubernetedes支持的Projected Volume一共有四種:

  • Secret
  • ConfigMap
  • Downward API
  • ServiceAccountToken

Secret

secret可以幫你把Pod想要訪問的加密數(shù)據(jù)存放到Etcd中川蒙,然后,你就可以通過在Pod的容器里掛載Volume的方式长已,訪問到這些Secret保存的信息

Secret使用實例:

apiVersion: v1
kind: Pod
metadata: 
 name: test-projected-volume
spec:
 containers:
 - name: test-secret-volume
   image: busybox
   args: 
   - sleep
   - "86400"
   volumeMounts:
   - name: mysql-cred
     mountPath: "/projected-volume"
     readOnly: true
 volumes:
 - name: mysql-cred
   projected:
    sources:
    - secret:
       name: user
    - secret:
       name: pass

上述Pod中畜眨,聲明掛載的Volume,是projected類型的术瓮。這個volume的數(shù)據(jù)來源則是名為user和pass的secret對象

secret創(chuàng)建命令:

kubectl create secret generic [NAME] [DATA] [TYPE] #TYPE默認為Opaque
kubectl create secret generic [NAME] --from-file=[KEY]=[VALUE的文件路徑]
kubectl create secret generic [NAME] --from-literal=[KEY]=[VALUE] --from-literal=[KEY]=[VALUE] ....

然后康聂,我們創(chuàng)建這兩個secret對象

kubectl create secret generic user --from=literal=username=admin
kubectl create secret generic pass --from=literal=password=hanjiaxv123

也可以使用文件創(chuàng)建

$ cat ./username.txt
admin
$ cat ./password.txt
hanjiaxv123
$ kubectl create secret generic user --from-file=./username.txt
$ kubectl create secret generic pass --from-file=./password.txt

接下來,我們創(chuàng)建這個pod胞四,然后進入pod恬汁。

[root@host1 ~]# kubectl create -f geektime/pod/test-projected-volume.yaml 
pod/test-projected-volume created
[root@host1 ~]# kubectl exec -it test-projected-volume -- /bin/sh
/ # ls /projected-volume
pass      username
/ # cd /projected-volume
/projected-volume # cat pass
hanjiaxv123/projected-volume # cat username

ConfigMap

ConfigMap與secret的區(qū)別在于,ConfigMap保存的是不需要加密的辜伟、應(yīng)用所需的配置信息氓侧。

ConfigMap用法幾乎和secret相同。

ConfigMap創(chuàng)建語法:

kubectl create configmap [NAME] [DATA]

指定文件:

kubectl create configmap kube-flannel-cfg --from-file=configure-pod-container/configmap/cni-conf.json -n kube-system

指定鍵值對:

kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm

ConfigMap使用

apiVersion: v1
kind: ConfigMap
metadta:
 name: special-config
data:
 special.how: very
 special.type: charm

第一種导狡,用ConfigMap配置環(huán)境變量

apiVersion: v1
kind: Pod
metadata:
 name: cm-env-test
spec:
 containers:
  - name: test-container
    image: k8s.gcr.io/busybox
    command: ["/bin/sh","-c","env"]
    env:
     #使用special-config中的special.how定義環(huán)境變量
     - name: SPECIAL_LEVEL_KEY
       valueFrom:
        configMapKeyRef:
         name: special-config
         key: special.how

第二種约巷,使用ConfigMap管控命令行參數(shù)

apiVersion: v1
kind: Pod
metadata:
 name: cm-cmd-test
spec:
 containers:
 - name: test-container
   image: k8s.io.gcr/busybox
   command: ["/bin/sh","-c","echo $(SPECIAL_LEVEL_KEY)"]
   env:
   - name: SPECIAL_LEVEL_KEY
     valueFrom:
      configMapKeyRef:
       name: special-config
       key: special.how

第三種,使用ConfigMap掛載配置文件

apiVersion: v1
kind: Pod
metadata:
 name: cm-volume-test
spec:
 containers:
  - name: test-container
    image: k8s.io.gcr/busybox
    command: ["/bin/sh","-c","ls /etc/config/"]
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
 volumes:
  - name: config-volume
    configMap:
     name: special-config

Service Account

如果現(xiàn)在有一個Pod旱捧,我能否在這個Pod里安裝一個Kubernetes的Client独郎,這樣就可以從容器里直接訪問并操作這個Kubernetes的API了呢?

答案是可以枚赡。

首先氓癌,要解決API Server的授權(quán)問題

Service Account對象的作用,就是Kubernetes系統(tǒng)內(nèi)置的一種“服務(wù)賬號”贫橙,它是Kubernetes進行權(quán)限分配的對象顽铸。比如,Service Account A料皇,可以只被允許對Kubernetes API進行GET操作谓松,而Service Account B星压,則可以有Kubernetes API的所有操作權(quán)限。

這種Service Account的授權(quán)信息和文件鬼譬,實際上保存在它所綁定的一個特殊的Secret對象中娜膘,這種特殊的Service Account對象,就叫做ServiceAccountToken优质。任何運行在Kubernetes集群上的應(yīng)用竣贪,都必須使用這個ServiceAccountToken中保存的授權(quán)信息,才可以合法地訪問API Server巩螃。ServiceAccountToken只是一種特殊地Secret演怎。

Kubernetes已經(jīng)為你提供了一個默認“服務(wù)賬戶”,并且避乏,任何一個運行在Kubernetes里的Pod爷耀,都可以直接使用這個默認的Service Account,無需顯示地聲明掛載它拍皮。

查看一下集群中運行的Pod歹叮,就會發(fā)現(xiàn),每一個Pod铆帽,都已經(jīng)聲明了一個類型是Secret咆耿、名為default-token-xxxx的Volume,然后自動掛載在每一個容器的固定目錄上爹橱。

[root@host1 ~]# kubectl describe pods test-projected-volume
...
Volumes:
  mysql-cred:
    Type:                Projected (a volume that contains injected data from multiple sources)
    SecretName:          user
    SecretOptionalName:  <nil>
    SecretName:          pass
    SecretOptionalName:  <nil>
  default-token-j5k7m:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-j5k7m
    Optional:    false
....

Kubernetes在每個Pod創(chuàng)建的時候萨螺,自動在它的spec.volumes部分添加上了默認ServiceAccountToken的定義,然后自動給每個容器加上了對應(yīng)的volumeMounts字段愧驱。這個容器內(nèi)的路徑在Kubernetes里是固定的屑迂,即:/var/run/secrets/kubernetes.io/serviceaccount,這個Secret類型的Volume內(nèi)容如下所示:

/ # ls /var/run/secrets/kubernetes.io/serviceaccount/
ca.crt     namespace  token

你的應(yīng)用程序只要加載這些授權(quán)文件冯键,就可以訪問并操作Kubernetes API了惹盼。如果使用的是Kubernetes官方的Client包,還可以自動加載這個目錄下的文件惫确。

Pod的健康檢查機制

Liveness Probe是存活探針手报、Readiness是就緒探針。

一個程序在長時間運行后或者有bug的情況下改化,會進入不正常狀態(tài)掩蛤,Liveness會將容器內(nèi)的進程殺死,重啟整個容器/Pod陈肛,使得Pod恢復(fù)最初始的狀態(tài)揍鸟。readiness探測失敗后,Pod和容器并不會被刪除句旱,而是被標(biāo)記為特殊狀態(tài)阳藻,進入這個狀態(tài)后晰奖,會切斷上層流量到達該Pod。

探測方式

  • httpGet 通過發(fā)送http Get請求返回200-399狀態(tài)碼則表示容器健康
  • Exec 通過執(zhí)行命令檢查服務(wù)是否正常腥泥,命令返回值為0表示容器健康
  • tcpSocket 通過容器的IP和PORT執(zhí)行TCP檢查匾南,如果可以建立TCP連接表示容器健康

探測結(jié)果

  • Success Container通過了檢查
  • Failure Container未能通過檢查
  • Unknown 未能執(zhí)行檢查,不采取任何動作

重啟策略

  • Always 總是重啟
  • OnFailure 失敗才重啟
  • Never 永遠不重啟

實例參考

exec方式:

apiVersion: v1
kind: Pod
metadata:
 labels:
  test: liveness
 name: liveness-exec
spec:
 containers:
 - name: liveness
   image: k8s.gcr.io/busybox
   args:
   - /bin/sh
   - -c
   - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
   livenessProbe:
    exec:
     command:
     - cat
     - /tmp/healthy
    initialDelaySeconds: 5
    periodSeconds: 5

httpGet

apiVersion: v1
kind: Pod
metadata:
 labels:
  test: liveness
 name: liveness-http
spec:
 containers:
 - name: liveness
   image: k8s.gcr.io/liveness
   args:
   - /server
   livenessProbe:
    httpGet:
     path: /healthz
     port: 8080
     httpHeaders:
     - name: Custom-Header
       value: Awesome
    initialDelaySeconds: 3
    periodSeconds: 3

tcpSocket

apiVersion: v1
kind: Pod
metadata:
 name: goproxy
 labels:
  app: goproxy
spec:
 containers:
 - name: goproxy
   image: k8s.gcr.io/goproxy:0.1
   ports:
   - containerPort: 8080
     readinessProbe:
      tcpSocket:
       port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5
     livenessProbe:
      tcpSocket:
       port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20

參數(shù):

  • initialDelaySeconds:Pod啟動后延遲多久進行檢查
  • periodSeconds:檢查間隔事件蛔外,默認10S
  • timeoutSeconds:探測的超時時間蛆楞,默認1S
  • successThreshold:探測失敗后再次判斷成功的閾值,默認為1次
  • failureThreshold:探測失敗的重試次數(shù)夹厌,默認3次

總結(jié)

Liveness(存活探針) Readiness(就緒探針)
介紹 用于判斷容器是否存活豹爹,即容器的狀態(tài)是否是Running,如果Liveness探針判斷容器不健康矛纹,則會觸發(fā)kubelet殺掉容器臂聋,并根據(jù)配置的策略判斷是否重啟容器,如果默認不配置Liveness探針崖技,則認為返回值默認為成功 用于判斷容器是否啟動完成,即Pod得Condition是否為Ready钟哥,如果探測結(jié)果不成功迎献,則會將Pod從Endpoint中移除,直至下次判斷成功腻贰,再將Pod掛回到Endpoint上
檢測失敗 殺掉Pod 切斷上層流量到Pod
使用場景 支持重新拉起的應(yīng)用 啟動后無法立即對外服務(wù)的應(yīng)用

參考: 阿里云大學(xué)云原生技術(shù)公開課 極客時間深入剖析Kubernetes

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吁恍,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子播演,更是在濱河造成了極大的恐慌冀瓦,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件写烤,死亡現(xiàn)場離奇詭異翼闽,居然都是意外死亡,警方通過查閱死者的電腦和手機洲炊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門感局,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人暂衡,你說我怎么就攤上這事询微。” “怎么了狂巢?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵撑毛,是天一觀的道長。 經(jīng)常有香客問我唧领,道長藻雌,這世上最難降的妖魔是什么雌续? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮蹦疑,結(jié)果婚禮上西雀,老公的妹妹穿的比我還像新娘。我一直安慰自己歉摧,他們只是感情好艇肴,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著叁温,像睡著了一般再悼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上膝但,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天冲九,我揣著相機與錄音,去河邊找鬼跟束。 笑死莺奸,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的冀宴。 我是一名探鬼主播灭贷,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼略贮!你這毒婦竟也來了甚疟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤逃延,失蹤者是張志新(化名)和其女友劉穎览妖,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體揽祥,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡讽膏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了拄丰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桅打。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖愈案,靈堂內(nèi)的尸體忽然破棺而出挺尾,到底是詐尸還是另有隱情,我是刑警寧澤站绪,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布遭铺,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏魂挂。R本人自食惡果不足惜甫题,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望涂召。 院中可真熱鬧坠非,春花似錦、人聲如沸果正。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秋泳。三九已至潦闲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間迫皱,已是汗流浹背歉闰。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留卓起,地道東北人和敬。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像戏阅,于是被迫代替她去往敵國和親昼弟。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容