本文的演練環境為基於Virtualbox搭建的Kubernetes集群,具體搭建步驟可以參考kubeadm安裝kubernetes V1.11.1 集群
1. 基本概念
1.1 Pod是什么
Pod是Kubernetes中能夠創建和部署的最小單元,是Kubernetes集群中的一個應用實例,總是部署在同一個節點Node上。Pod中包含了一個或多個容器,還包括了存儲、網絡等各個容器共享的資源。Pod支持多種容器環境,Docker則是最流行的容器環境。
- 單容器Pod,最常見的應用方式。
- 多容器Pod,對於多容器Pod,Kubernetes會保證所有的容器都在同一台物理主機或虛擬主機中運行。多容器Pod是相對高階的使用方式,除非應用耦合特別嚴重,一般不推薦使用這種方式。一個Pod內的容器共享IP地址和端口范圍,容器之間可以通過 localhost 互相訪問。
Pod並不提供保證正常運行的能力,因為可能遭受Node節點的物理故障、網絡分區等等的影響,整體的高可用是Kubernetes集群通過在集群內調度Node來實現的。通常情況下我們不要直接創建Pod,一般都是通過Controller來進行管理,但是了解Pod對於我們熟悉控制器非常有好處。
1.2 Pod帶來的好處
Pod帶來的好處
- Pod做為一個可以獨立運行的服務單元,簡化了應用部署的難度,以更高的抽象層次為應用部署管提供了極大的方便。
- Pod做為最小的應用實例可以獨立運行,因此可以方便的進行部署、水平擴展和收縮、方便進行調度管理與資源的分配。
- Pod中的容器共享相同的數據和網絡地址空間,Pod之間也進行了統一的資源管理與分配。
1.3 常用Pod管理命令
Pod的配置信息中有幾個重要部分,apiVersion、kind、metadata、spec以及status。其中apiVersion
和kind
是比較固定的,status
是運行時的狀態,所以最重要的就是metadata
和spec
兩個部分。
先來看一個典型的配置文件,命名為 first-pod.yml
apiVersion: v1
kind: Pod
metadata:
name: first-pod
labels:
app: bash
tir: backend
spec:
containers:
- name: bash-container
image: docker.io/busybox
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
在編寫配置文件時,可以通過API Reference來參考,也可以通過命令查看。
[root@devops-101 ~]# kubectl explain pod
KIND: Pod
VERSION: v1
DESCRIPTION:
Pod is a collection of containers that can run on a host. This resource is
created by clients and scheduled onto hosts.
FIELDS:
apiVersion <string>
APIVersion defines the versioned schema of this representation of an
object. Servers should convert recognized schemas to the latest internal
value, and may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#resources
kind <string>
Kind is a string value representing the REST resource this object
represents. Servers may infer this from the endpoint the client submits
requests to. Cannot be updated. In CamelCase. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
metadata <Object>
Standard object's metadata. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
spec <Object>
Specification of the desired behavior of the pod. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
status <Object>
Most recently observed status of the pod. This data may not be up to date.
Populated by the system. Read-only. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
[root@devops-101 ~]# kubectl explain pod.spec
KIND: Pod
VERSION: v1
RESOURCE: spec <Object>
DESCRIPTION:
Specification of the desired behavior of the pod. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
PodSpec is a description of a pod.
FIELDS:
activeDeadlineSeconds <integer>
Optional duration in seconds the pod may be active on the node relative to
StartTime before the system will actively try to mark it failed and kill
associated containers. Value must be a positive integer.
affinity <Object>
If specified, the pod's scheduling constraints
automountServiceAccountToken <boolean>
AutomountServiceAccountToken indicates whether a service account token
should be automatically mounted.
1.3.1 創建
利用kubectl命令行管理工具,我們可以直接在命令行通過配置文件創建。如果安裝了Dashboard圖形管理界面,還可以通過圖形界面創建Pod。因為最終Pod的創建都是落在命令上的,這里只介紹如何使用kubectl管理工具來創建。
使用配置文件的方式創建Pod。
$ kubectl create -f first-pod.yml
1.3.2 查看配置
如果想了解一個正在運行的Pod的配置,可以通過以下命令獲取。
[root@devops-101 ~]# kubectl get pod first-pod -o yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: 2018-08-08T01:45:16Z
labels:
app: bash
name: first-pod
namespace: default
resourceVersion: "184988"
selfLink: /api/v1/namespaces/default/pods/first-pod
uid: b2d3d2b7-9aac-11e8-84f4-080027b7c4e9
spec:
containers:
- command:
- sh
- -c
- echo Hello Kubernetes! && sleep 3600
image: docker.io/busybox
imagePullPolicy: Always
name: bash-container
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-trvqv
readOnly: true
dnsPolicy: ClusterFirst
nodeName: devops-102
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- name: default-token-trvqv
secret:
defaultMode: 420
secretName: default-token-trvqv
status:
conditions:
- lastProbeTime: null
lastTransitionTime: 2018-08-08T01:45:16Z
status: "True"
type: Initialized
- lastProbeTime: null
lastTransitionTime: 2018-08-08T01:45:16Z
message: 'containers with unready status: [bash-container]'
reason: ContainersNotReady
status: "False"
type: Ready
- lastProbeTime: null
lastTransitionTime: null
message: 'containers with unready status: [bash-container]'
reason: ContainersNotReady
status: "False"
type: ContainersReady
- lastProbeTime: null
lastTransitionTime: 2018-08-08T01:45:16Z
status: "True"
type: PodScheduled
containerStatuses:
- image: docker.io/busybox
imageID: ""
lastState: {}
name: bash-container
ready: false
restartCount: 0
state:
waiting:
reason: ContainerCreating
hostIP: 192.168.0.102
phase: Pending
qosClass: BestEffort
startTime: 2018-08-08T01:45:16Z
1.3.3 查看日志
可以查看命令行標准輸出的日志。
[root@devops-101 ~]# kubectl logs first-pod
Hello Kubernetes!
如果Pod中有多個容器,查看特定容器的日志需要指定容器名稱kubectl logs pod-name -c container-name
。
1.3.4 標簽管理
標簽是Kubernetes管理Pod的重要依據,我們可以在Pod yaml文件中 metadata 中指定,也可以通過命令行進行管理。
顯示Pod的標簽
[root@devops-101 ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
first-pod 1/1 Running 0 15m app=bash
使用 second-pod.yml 我們再創建一個包含兩個標簽的Pod。
[root@devops-101 ~]# kubectl create -f first-pod.yml
pod/second-pod created
[root@devops-101 ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
first-pod 1/1 Running 0 17m app=bash
second-pod 0/1 ContainerCreating 0 20s app=bash,tir=backend
根據標簽來查詢Pod。
[root@devops-101 ~]# kubectl get pods -l tir=backend --show-labels
NAME READY STATUS RESTARTS AGE LABELS
second-pod 1/1 Running 0 1m app=bash,tir=backend
增加標簽
[root@devops-101 ~]# kubectl label pod first-pod tir=frontend
pod/first-pod labeled
[root@devops-101 ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
first-pod 1/1 Running 0 24m app=bash,tir=frontend
second-pod 1/1 Running 0 7m app=bash,tir=backend
修改標簽
[root@devops-101 ~]# kubectl label pod first-pod tir=unkonwn --overwrite
pod/first-pod labeled
[root@devops-101 ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
first-pod 1/1 Running 0 25m app=bash,tir=unkonwn
second-pod 1/1 Running 0 8m app=bash,tir=backend
可以將標簽顯示為列
[root@devops-101 ~]# kubectl get pods -L app,tir
NAME READY STATUS RESTARTS AGE APP TIR
first-pod 1/1 Running 0 26m bash unkonwn
second-pod 1/1 Running 0 9m bash backend
標簽是Kubernetes中非常強大的一個功能,Node節點也可以增加標簽,再利用Pod的標簽選擇器,可以將Pod分配到不同類型的Node上。
1.3.5 刪除Pod
[root@devops-101 ~]# kubectl delete pods first-pod
pod "first-pod" deleted
也可以根據標簽選擇器刪除。
[root@devops-101 ~]# kubectl delete pods -l tir=backend
pod "second-pod" deleted
1.4 Pod的生命周期
像單獨的容器應用一樣,Pod並不是持久運行的。Pod創建后,Kubernetes為其分配一個UID,並且通過Controller調度到Node中運行,然后Pod一直保持運行狀態直到運行正常結束或者被刪除。在Node發生故障時,Controller負責將其調度到其他的Node中。Kubernetes為Pod定義了幾種狀態,分別如下:
- Pending,Pod已創建,正在等待容器創建。經常是正在下載鏡像,因為這一步驟最耗費時間。
- Running,Pod已經綁定到某個Node並且正在運行。或者可能正在進行意外中斷后的重啟。
- Succeeded,表示Pod中的容器已經正常結束並且不需要重啟。
- Failed,表示Pod中的容器遇到了錯誤而終止。
- Unknown,因為網絡或其他原因,無法獲取Pod的狀態。
2. 如何對Pod進行健康檢查
Kubernetes利用Handler功能,可以對容器的狀況進行探測,有以下三種形式。
- ExecAction:在容器中執行特定的命令。
- TCPSocketAction:檢查容器端口是否可以連接。
- HTTPGetAction:檢查HTTP請求狀態是否正常。
這部分內容展開來也比較多,這部分的內容參考Kubernetes中Pod的健康檢查。
3. Init Containers
Pod中可以包含一到多個Init Container,在其他容器之前開始運行。Init Container 只能是運行到完成狀態,即不能夠一直存在。Init Container必須依次執行。在App Container運行前,所有的Init Container必須全部正常結束。
在Pod啟動過程中,Init Container在網絡和存儲初始化完成后開始按順序啟動。Pod重啟的時候,所有的Init Container都會重新執行。
However, if the Pod restartPolicy is set to Always, the Init Containers use RestartPolicy OnFailure.
3.1 好處
- 運行一些不希望在 App Container 中運行的命令或工具
- 包含一些App Image中沒有的工具或特定代碼
- 應用鏡像構建人員和部署人員可以獨立工作而不需要依賴對方
- 擁有與App Container不同的命名空間
- 因為在App Container運行前必須運行結束,適合做一些前置條件的檢查和配置
3.2 語法
先看一下解釋
[root@devops-101 ~]# kubectl explain pod.spec.initContainers
KIND: Pod
VERSION: v1
RESOURCE: initContainers <[]Object>
DESCRIPTION:
List of initialization containers belonging to the pod. Init containers are
executed in order prior to containers being started. If any init container
fails, the pod is considered to have failed and is handled according to its
restartPolicy. The name for an init container or normal container must be
unique among all containers. Init containers may not have Lifecycle
actions, Readiness probes, or Liveness probes. The resourceRequirements of
an init container are taken into account during scheduling by finding the
highest request/limit for each resource type, and then using the max of of
that value or the sum of the normal containers. Limits are applied to init
containers in a similar fashion. Init containers cannot currently be added
or removed. Cannot be updated. More info:
https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
A single application container that you want to run within a pod.
具體語法。
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: docker.io/busybox
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: docker.io/busybox
command: ['sh', '-c', 'echo init-service && sleep 2']
- name: init-mydb
image: docker.io/busybox
command: ['sh', '-c', 'echo init-mydb && sleep 2']
兼容性問題
1.5之前的語法都寫在 annotation 中,1.6 以上的版本使用.spec.initContainers
字段。建議還是使用 1.6 版本的語法。1.6、1.7的版本還兼容1.5以下的版本,1.8之后就不再兼容老版本了。
4. Pod Preset
利用這個特性,可以在Pod啟動過程中向Pod中注入密碼 Secrets、存儲 Volumes、掛載點 Volume Mounts和環境變量。通過標簽選擇器來指定Pod。利用這個特性,Pod Template的維護人員就不需要為每個Pod顯示的提供相關的屬性。
具體的工作步驟
- 檢查所有可用的ProdPresets
- 檢查是否有ProdPreset的標簽與即將創建的Pod相匹配
- 將PodPreset中定義的參數與Pod定義合並
- 如果參數合並出錯,則丟棄ProPreset參數,繼續創建Pod
- 為Pod增加注解,表示層被ProdPreset修改過,形式為
podpreset.admission.kubernetes.io/podpreset-<pod-preset name>: "<resource version>"
對於 Env
、EnvFrom
、VolumeMounts
Kubernetes修改Container Spec,對於Volume
修改Pod Spec。
4.1 對個別Pod停用
在Spec中增加注解:
podpreset.admission.kubernetes.io/exclude: "true"
5. 中斷
Pod會因為各種各樣的原因發生中斷。
5.1 計划內中斷
- 刪除部署 Deployment或者其他控制器
- 更新部署模版導致的Pod重啟
- 直接刪除Pod
- 集群的縮容
- 手工移除
5.2 計划外中斷
- 硬件故障、物理節點宕機
- 集群管理員誤刪VM
- 雲供應商故障導致的主機不可用
- Kernel panic
- 集群網絡分區導致節點消失
- 資源耗盡導致的節點剔除
5.3 PDB Disruption Budgets
Kubernetes offers features to help run highly available applications at the same time as frequent voluntary disruptions. We call this set of features Disruption Budgets.
Kubernetes允許我們創建一個PDB對象,來確保一個RS中運行的Pod不會在一個預算(個數)之下。
Eviction API。
PDB是用來解決集群管理和應用管理職責分離的情況,如果你的單位不存在這種情況,就可以不使用PDB。