Pod - K8S最小管理单位
Pod模型可以理解为应用程序特定的“逻辑主机”,并且可以包含相对紧密耦合的不同应用程序容器。例如,Pod 可能包含带有 Node.js 应用程序的容器以及另一个要吸收 Node.js Web 服务器提供的数据的不同容器。Pod 中的容器有如下特点:
- 共享 IP 地址和端口空间(共用一个Network Namespace)
 - 始终位于同一位置并且统一调度
 - 在相同的Node上运行
 - 共享上下文环境
 
如图所示是一些大小不同的Pod:

Pod是Kubernetes平台管理的最小单位,每个Pod在Kubernetes中都有一个唯一的 IP 地址,且能从Pod外部进行访问的容器端口由用户明确指定。当我们在Kubernetes上创建一个部署(Deployment)时,该部署将在其中创建包含容器的 Pod(而不是直接创建容器)。
(其实就相当于一个docker-compose,用户指定expose端口)
# Pod定义
使用K8s时一般不建议直接创建Pod,而是通过控制器和模版配置来管理和调度。比如在Deployment中的template字段定义一个Pod模板:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment_a
spec:
  ...
  template: #Pod模板
    metadata:
      name: pod_a
    spec:
      ...
      containers:
        - image: XXX
          name: XXX
          ...
        - image: XXXX
          name: XXXX
        ...
 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
其中的template等效于一个Pod定义:
apiVersion: apps/v1
kind: Deployment
metadata:
    name: pod_a
spec:
    ...
    containers:
    - image: XXX
        name: XXX
        ...
    - image: XXXX
        name: XXXX
    ...
 2
3
4
5
6
7
8
9
10
11
12
13
# Pod重启策略
Pod的重启策略由restartPolicy字段指定,策略有三种:
Always:只要退出就会重启OnFailure:只有在失败退出(exit code不等于0)时,才会重启。Never:只要退出,就不再重启
apiVersion: apps/v1
kind: Deployment
metadata:
  ...
spec:
  ...
  template: #Pod模板
    metadata:
      ...
    spec:
      ...
      restartPolicy: Always #重启策略
      containers:
        ...
 2
3
4
5
6
7
8
9
10
11
12
13
14
默认地,Pod重启策略为Always
(相当于docker-compose中的restart: always)。
# 资源请求和资源限制
资源请求和资源限制由resources字段指定,其中:
requests:资源请求,调度器会保证这个Pod调度到资源充足的Node上limits:资源限制,资源使用上限
apiVersion: apps/v1
kind: Deployment
metadata:
  ...
spec:
  ...
  template: #Pod模板
    metadata:
      ...
    spec:
      containers:
        - image: XXX
          name: XXX
          resources:
            requests: #资源请求
              cpu: "300m"
              memory: "64Mi"
            limits: #资源限制
              cpu: "500m"
              memory: "128Mi"
          ...
        - image: XXXX
          name: XXXX
          ...
        ...
 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 健康检查
对于每个Pod,k8s会定期进行健康检查,若检查未通过,则Kill这个Pod的进程,是否重启取决于restartPolicy。
# 重要概念:Probe(探针)
探针是一类用于检测容器状态的程序的统称。
探针可以是一个指令。比如一个容器中的主程序会在完全启动后创建一个文件,那么健康检查探针就可以是cat [文件]指令,当程序正常启动后,文件被创建,执行此探针(指令)会正常返回文件内容(exit 0),否则会报错(exit 1)。由指令返回值即可知道程序是否正常启动。
探针可以是一个TCP连接程序或Http请求程序。这种探针多用于服务端应用,其目的很明显:像一个用户一样向服务端发起请求,通过是否正常返回以及其返回内容可以很容易地判断服务卡死或出错。
# 健康检查类型
livenessProbe:存活性检查。检查容器是否处于运行状态- 如果检测失败,kubelet将会杀掉掉容器,并根据重启策略进行下一步的操作
 
readnessProbe:可读性检查。检查容器是否已经处于可接受服务请求的状态。- 如果Readiness Probe失败,端点控制器将会从服务端点(与Pod匹配的)中移除容器的IP地址
 
apiVersion: apps/v1
kind: Deployment
metadata:
  ...
spec:
  ...
  template: #Pod模板
    metadata:
      ...
    spec:
      containers:
        - image: XXX
          name: XXX
          livenessProbe: #存活性检查
            ...
          readnessProbe: #可读性检查
            ...
          ...
        - image: XXXX
          name: XXXX
          livenessProbe:
            ...
          ...
        ...
 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 健康检查参数
initialDelaySeconds:检查开始执行的时间,以容器启动完成为起点计算periodSeconds:检查执行的周期,默认为10秒,最小为1秒timeoutSeconds:每次检查的时间限制,默认为1秒,最小为1秒successThreshold:从上次检查失败后重新认定检查成功的检查次数阈值(必须是连续成功),默认为1failureThreshold:从上次检查成功后认定检查失败的检查次数阈值(必须是连续失败),默认为1
# 健康检查方法(探针)
exec:在容器中执行特定的命令,命令退出返回0表示成功- 使用
command字段指定指令 
- 使用
 tcpSocket:根据容器IP地址及特定的端口进行TCP检查,端口开放表示成功host:主机名或IPport:请求端口
httpGet:根据容器IP、端口及访问路径发起HTTP请求,如果返回码在200到400之间表示成功host:主机名或IPscheme:链接类型,HTTP或HTTPS,默认为HTTPpath:请求路径httpHeaders:自定义请求头port:请求端口
一个健康检查设置实例如下:
apiVersion: apps/v1
kind: Deployment
metadata:
  ...
spec:
  ...
  template: #Pod模板
    metadata:
      ...
    spec:
      containers:
        - image: XXX
          name: XXX
          livenessProbe: #存活性检查
            exec: #检查方式是在容器中执行指定命令
              command: #指定命令
                - cat
                - /tmp/healthy
              initialDelaySeconds: 5 #容器启动5s后检查开始
              periodSeconds: 5 #每5s检查一次
          readnessProbe: #可读性检查
            httpGet: #检查方式是在容器中发起HTTP请求
              path: /index.html #请求路径
              port: 80 #请求端口
              httpHeaders: #请求头
                - name: X-Custom-Header
                  value: Awesome
        - image: XXXX
          name: XXXX
          livenessProbe: #存活性检查
            tcpSocket: #检查方式是TCP检查
              port: 8080 #检查的端口是8080
          ...
        ...
 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 初始化容器initContainers
 顾名思义,初始化容器用于Pod的初始化操作,比如向某个文件夹(volumes)中写入重要的运行时文件。初始化容器的配置由initContainers字段指定,主要用处:
- 初始化容器可以包含不能随普通容器一起发布出去的敏感信息。
 - 初始化容器可以包含用户自定义的代码、工具,如sed、awk、python等方便完成初始化、设置工作。
 - 因为初始化逻辑与主体业务逻辑分布在不同的image中,因此image构建者与主体业务逻辑开发者可以各自独立的工作。
 - 初始化容器使用Linux namespace,不同于普通应用容器,具有不同的文件系统视图,并且对于低层的操作系统有更大的访问权限。
 - 当应用启动的前置条件不具备时,初始化容器可以阻止普通应用容器启动,避免在条件不具备时反复启动注定会失败的容器而浪费系统资源。
 
apiVersion: apps/v1
kind: Deployment
metadata:
  ...
spec:
  ...
  template: #Pod模板
    metadata:
      ...
    spec:
      ...
      containers:
        - image: XXX
          name: XXX
          ...
      initContainers:
        - image: XXX #初始化容器
          name: XXX
          command: #初始化容器中的指令
            - wget #把一个文件下载到Pod里面
            - "-O"
            - "/some/dir/some.file"
            - "http://some.site/some/url"
          volumeMounts: #文件下载到这个volume里
            - name: workdir
              mountPath: "/work-dir"
            ...
          ...
        - image: XXXX #另一个初始化容器
          name: XXXX
          ...
      volumes:
        - name: workdir #上面那个volume的定义
          ...
 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# Pod调度
# 简单的方式:选择节点 - nodeSelector
 nodeSelector是目前最为简单的一种pod运行时调度限制,Pod.spec.nodeSelector通过kubernetes的label-selector机制选择节点,由调度器调度策略匹配label,而后调度pod到目标节点,该匹配规则属于强制约束。
# 节点(Node)的标签(label)是什么
节点的label是节点的一个标签,以键值对的形式存在。一个节点可以有多个label,一种label也可以关联到多个节点。
# 查看节点标签
查看节点标签的指令是kubectl get nodes --show-labels。比如在一个minikube节点上:
$ kubectl get nodes --show-labels
NAME       STATUS    ROLES     AGE       VERSION   LABELS
minikube   Ready     <none>    1m        v1.10.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=minikube
 2
3
可以看到,minikube节点有三个标签beta.kubernetes.io/arch、beta.kubernetes.io/os和kubernetes.io/hostname,其值分别为amd64、linux和minikube。
# 添加节点标签
查看节点标签的指令是kubectl label node [节点名] [标签名]=[标签值]比如在上面那个minikube节点上加个标签disktype=ssd:
$ kubectl label node minikube disktype=ssd
node/minikube labeled
$ kubectl get nodes --show-labels
NAME       STATUS    ROLES     AGE       VERSION   LABELS
minikube   Ready     <none>    5m        v1.10.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/host
 2
3
4
5
# 删除节点标签
删除节点标签的指令是标签名加减号kubectl label node [节点名] [标签名]-。比如删除上面那个disktype=ssd标签:
$ kubectl label node minikube disktype-
node/minikube labeled
$ kubectl get node --show-labels
NAME       STATUS    ROLES     AGE       VERSION   LABELS
minikube   Ready     <none>    23m       v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=minikube
 2
3
4
5
# 用nodeSelector字段通过标签选择部署节点
 apiVersion: apps/v1
kind: Deployment
metadata:
  ...
spec:
  ...
  template: #Pod模板
    metadata:
      ...
    spec:
      nodeSelector:
        disktype: ssd #选择在disktype标签值为ssd的节点上部署
      containers:
          ...
        ...
 2
3
4
5
6
7
8
9
10
11
12
13
14
15