Kubernetes — 深刻解析Pod对象:基本概念(二)

做为 Kubernetes 项目里最核心的编排对象,Pod 携带的信息很是丰富。其中,资源定义(好比 CPU、内存等),以及调度相关的字段、在本篇,咱们就先从一种特殊的 Volume 开始,来帮助你更加深刻地理解 Pod 对象各个重要字段的含义。node

这种特殊的 Volume,叫做 Projected Volume,你能够把它翻译为“投射数据卷”。 (备注:Projected Volume 是 Kubernetes v1.11 以后的新特性)mysql

这是什么意思呢?nginx

在 Kubernetes 中,有几种特殊的 Volume,它们存在的意义不是为了存放容器里的数据,也不是用来进行容器和宿主机之间的数据交换。这些特殊 Volume 的做用,是为容器提供预先定义好的数据。因此,从容器的角度来看,这些 Volume 里的信息就是仿佛是被 Kubernetes“投射”(Project)进入容器当中的。这正是 Projected Volume 的含义。web

到目前为止,Kubernetes 支持的 Projected Volume 一共有四种:sql

  • Secret;
  • ConfigMap;
  • Downward API;
  • ServiceAccountToken。

Secret

我首先和你分享的是 Secret。它的做用,是帮你把 Pod 想要访问的加密数据,存放到 Etcd 中。而后,你就能够经过在 Pod 的容器里挂载 Volume 的方式,访问到这些 Secret 里保存的信息了。 Secret 最典型的使用场景,莫过于存放数据库的 Credential 信息,好比下面这个例子:数据库

test-projected-volume.yaml编程

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,并非常见的 emptyDir 或者 hostPath 类型,而是 projected 类型。而这个 Volume 的数据来源(sources),则是名为 user 和 pass 的 Secret 对象,分别对应的是数据库的用户名和密码。api

这里用到的数据库的用户名、密码,正是以 Secret 对象的方式交给 Kubernetes 保存的。完成这个操做的指令,以下所示:安全

cat ./username.txt
admin
cat ./password.txt
c1oudc0w!

kubectl create secret generic user --from-file=./username.txt
kubectl create secret generic pass --from-file=./password.txt

其中,username.txt 和password.txt 文件里,存放的就是用户名和密码;而 user 和 pass,则是我为 Secret 对象指定的名字。而我想要查看这些 Secret 对象的话,只要执行一条 kubectl get 命令就能够了:  app

kubectl get secrets
NAME           TYPE                                DATA      AGE
user          Opaque                                1         51s
pass          Opaque                                1         51s

删除secret

kubectl delete secret user

  

固然,除了使用 kubectl create secret 指令外,我也能够直接经过编写 YAML 文件的

my-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  user: YWRtaW4=
  pass: MWYyZDFlMmU2N2Rm

  

能够看到,经过编写 YAML 文件建立出来的 Secret 对象只有一个。但它的 data 字段,却以 Key-Value 的格式保存了两份 Secret 数据。其中,“user”就是第一份数据的 Key,“pass”是第二份数据的 Key。

须要注意的是,Secret 对象要求这些数据必须是通过 Base64 转码的,以避免出现明文密码的安全隐患。这个转码操做也很简单,好比:

$ echo -n 'admin' | base64
YWRtaW4=
$ echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm

  

这里须要注意的是,像这样建立的 Secret 对象,它里面的内容仅仅是通过了转码,而并无被加密。在真正的生产环境中,你须要在 Kubernetes 中开启 Secret 的加密插件,加强数据的安全性。关于开启 Secret 加密插件的内容,我会在后续专门讲解 Secret 的时候,再作进一步说明 接下来,咱们尝试一下建立这个 Pod:

my_pod.yaml 

kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: busybox
    imagePullPolicy: IfNotPresent
    stdin: true
    tty: true
    volumeMounts:
    - name: my-pod-vol
      mountPath: "/mypod-vol"
      readOnly: true
  volumes:
  - name: my-pod-vol
    projected:
      sources:
      - secret:
          name: mysecret

  

执行一下命令

kubectl apply -f my-secret.yaml

kubectl apply -f my_pod.yaml 

kubectl exec -it my-pod /bin/sh

cat /mypod-vol/user

cat /mypod-vol/pass

  

 

 从返回结果中,咱们能够看到,保存在 Etcd 里的用户名和密码信息,已经以文件的形式出如今了容器的 Volume 目录里。而这个文件的名字,就是 kubectl create secret 指定的 Key,或者说是 Secret 对象的 data 字段指定的 Key。

更重要的是,像这样经过挂载方式进入到容器里的 Secret,一旦其对应的 Etcd 里的数据被更新,这些 Volume 里的文件内容,一样也会被更新。其实,这是 kubelet 组件在定时维护这些 Volume。

须要注意的是,这个更新可能会有必定的延时。因此在编写应用程序时,在发起数据库链接的代码处写好重试和超时的逻辑,绝对是个好习惯。 与 Secret 相似的是 ConfigMap,它与 Secret 的区别在于,ConfigMap 保存的是不须要加密的、应用所需的配置信息。而 ConfigMap 的用法几乎与 Secret 彻底相同:你可使用 kubectl create configmap 从文件或者目录建立 ConfigMap,也能够直接编写 ConfigMap 对象的 YAML 文件。

ConfigMap 

好比,一个 Java 应用所需的配置文件(.properties 文件),就能够经过下面这样的方式保存在 ConfigMap 里:

 

# .properties 文件的内容
$ cat example/ui.properties
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice

# 从.properties 文件建立 ConfigMap
$ kubectl create configmap ui-config --from-file=example/ui.properties

# 查看这个 ConfigMap 里保存的信息 (data)
$ kubectl get configmaps ui-config -o yaml
apiVersion: v1
data:
  ui.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true
    how.nice.to.look=fairlyNice
kind: ConfigMap
metadata:
  name: ui-config
  ...

  

kubectl get -o yaml 这样的参数,会将指定的 Pod API 对象以 YAML 的方式展现出来。

 Downward API

接下来是 Downward API,它的做用是:让 Pod 里的容器可以直接获取到这个 Pod API 对象自己的信息。 举个例子:

apiVersion: v1
kind: Pod
metadata:
  name: test-downwardapi-volume
  labels:
    zone: us-est-coast
    cluster: test-cluster1
    rack: rack-22
spec:
  containers:
    - name: client-container
      image: busybox
      command: ["sh", "-c"]
      args:
      - while true; do
          if [[ -e /etc/podinfo/labels ]]; then
            echo -en '\n\n'; cat /etc/podinfo/labels; fi;
          sleep 5;
        done;
      volumeMounts:
        - name: podinfo
          mountPath: /etc/podinfo
          readOnly: false
  volumes:
    - name: podinfo
      projected:
        sources:
        - downwardAPI:
            items:
              - path: "labels"
                fieldRef:
                  fieldPath: metadata.labels

 

在这个 Pod 的 YAML 文件中,我定义了一个简单的容器,声明了一个 projected 类型的 Volume。只不过此次 Volume 的数据来源,变成了 Downward API。而这个 Downward API Volume,则声明了要暴露 Pod 的 metadata.labels 信息给容器。

经过这样的声明方式,当前 Pod 的 Labels 字段的值,就会被 Kubernetes 自动挂载成为容器里的 /etc/podinfo/labels 文件。

而这个容器的启动命令,则是不断打印出 /etc/podinfo/labels 里的内容。因此,当我建立了这个 Pod 以后,就能够经过 kubectl logs 指令,查看到这些 Labels 字段被打印出来,以下所示:

$ kubectl create -f dapi-volume.yaml
$ kubectl logs test-downwardapi-volume
cluster="test-cluster1"
rack="rack-22"
zone="us-est-coast"

目前,DownwardAPI支持的字段已经很是丰富了,好比:  

1. 使用 fieldRef 能够声明使用:
spec.nodeName - 宿主机名字
status.hostIP - 宿主机 IP
metadata.name - Pod 的名字
metadata.namespace - Pod 的 Namespace
status.podIP - Pod 的 IP
spec.serviceAccountName - Pod 的 Service Account 的名字
metadata.uid - Pod 的 UID
metadata.labels['<KEY>'] - 指定 <KEY> 的 Label 值
metadata.annotations['<KEY>'] - 指定 <KEY> 的 Annotation 值
metadata.labels - Pod 的全部 Label
metadata.annotations - Pod 的全部 Annotation

2. 使用 resourceFieldRef 能够声明使用:
容器的 CPU limit
容器的 CPU request
容器的 memory limit
容器的 memory request

  

上面这个列表的内容,随着 Kubernetes 项目的发展确定还会不断增长。因此这里列出来的信息仅供参考,你在使用 Downward API 时,仍是要记得去查阅一下官方文档。

不过,须要注意的是,Downward API 可以获取到的信息,必定是 Pod 里的容器进程启动以前就可以肯定下来的信息。而若是你想要获取 Pod 容器运行后才会出现的信息,好比,容器进程的 PID,那就确定不能使用 Downward API 了,而应该考虑在 Pod 里定义一个 sidecar 容器。

其实,Secret、ConfigMap,以及 Downward API 这三种 Projected Volume 定义的信息,大多还能够经过环境变量的方式出如今容器里。可是,经过环境变量获取这些信息的方式,不具有自动更新的能力。因此,通常状况下,我都建议你使用 Volume 文件的方式获取这些信息。

Service Account

在明白了 Secret 以后,我再为你讲解 Pod 中一个与它密切相关的概念:Service Account。 相信你必定有过这样的想法:我如今有了一个 Pod,我能不能在这个 Pod 里安装一个 Kubernetes 的 Client,这样就能够从容器里直接访问而且操做这个 Kubernetes 的 API 了呢?

这固然是能够的。不过,你首先要解决 API Server 的受权问题。 Service Account 对象的做用,就是 Kubernetes 系统内置的一种“服务帐户”,它是 Kubernetes 进行权限分配的对象。好比,Service Account A,能够只被容许对 Kubernetes API 进行 GET 操做,而 Service Account B,则能够有KubernetesAPI的全部操做的权限。像这样的ServiceAccount的受权信息和文件,实际上保存在它所绑定的一个特殊的Secret对象里的。

 

这个特殊的Secret对象,就叫做ServiceAccountToken。任何运行在Kubernetes集群上的应用,都必须使用这个ServiceAccountToken里保存的受权信息,也就是Token,才能够合法地访问APIServer。因此说,Kubernetes项目的ProjectedVolume其实只有三种,由于第四种ServiceAccountToken,只是一种特殊的Secret而已。另外,为了方便使用,Kubernetes已经为你提供了一个的默认“服务帐户”(defaultServiceAccount)。而且,任何一个运行在Kubernetes里的Pod,均可以直接使用这个默认的ServiceAccount,而无需显示地声明挂载它。

这是如何作到的呢?固然仍是靠ProjectedVolume机制。若是你查看一下任意一个运行在Kubernetes集群里的Pod,就会发现,每个Pod,都已经自动声明一个类型是Secret、名为default-token-xxxx的Volume,而后自动挂载在每一个容器的一个固定目录上。好比:

$ kubectl describe pod nginx-deployment-5c678cfb6d-lg9lw
Containers:
...
  Mounts:
    /var/run/secrets/kubernetes.io/serviceaccount from default-token-s8rbq (ro)
Volumes:
  default-token-s8rbq:
  Type:       Secret (a volume populated by a Secret)
  SecretName:  default-token-s8rbq
  Optional:    false

  

这个Secret类型的Volume,正是默认Service Account对应的Service AccountToken。因此说,Kubernetes其实在每一个Pod建立的时候,自动在它的spec.volumes部分添加上了默认Service AccountToken的定义,而后自动给每一个容器加上了对应的volumeMounts字段。这个过程对于用户来讲是彻底透明的。这样,一旦Pod建立完成,容器里的应用就能够直接从这个默认ServiceAccountToken的挂载目录里访问到受权信息和文件。这个容器内的路径在Kubernetes里是固定的,即:/var/run/secrets/kubernetes.io/serviceaccount,而这个Secret类型的Volume里面的内容以下所示:

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

  

因此,你的应用程序只要直接加载这些受权文件,就能够访问并操做KubernetesAPI了。并且,若是你使用的是Kubernetes官方的Client包(k8s.io/client-go)的话,它还能够自动加载这个目录下的文件,你不须要作任何配置或者编码操做。这种把Kubernetes客户端以容器的方式运行在集群里,而后使用defaultServiceAccount自动受权的方式,被称做“InClusterConfig”,也是我最推荐的进行KubernetesAPI编程的受权方式。

固然,考虑到自动挂载默认ServiceAccountToken的潜在风险,Kubernetes容许你设置默认不为Pod里的容器自动挂载这个Volume。除了这个默认的ServiceAccount外,咱们不少时候还须要建立一些咱们本身定义的ServiceAccount,来对应不一样的权限设置。这样,咱们的Pod里的容器就能够经过挂载这些Service Account对应的Service AccountToken,来使用这些自定义的受权信息。在后面讲解为Kubernetes开发插件的时候,咱们将会实践到这个操做。

接下来,咱们再来看Pod的另外一个重要的配置:容器健康检查和恢复机制。在Kubernetes中,你能够为Pod里的容器定义一个健康检查“探针”(Probe)。这样,kubelet就会根据这个Probe的返回值决定这个容器的状态,而不是直接以容器进行是否运行(来自Docker返回的信息)做为依据。这种机制,是生产环境中保证应用健康存活的重要手段。咱们一块儿来看一个Kubernetes文档中的例子。

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: test-liveness-exec
spec:
  containers:
  - name: liveness
    image: 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

 

在这个 Pod 中,咱们定义了一个有趣的容器。它在启动以后作的第一件事,就是在 /tmp 目录下建立了一个 healthy 文件,以此做为本身已经正常运行的标志。而 30 s 事后,它会把这个文件删除掉。 与此同时,咱们定义了一个这样的 livenessProbe(健康检查)。它的类型是 exec,这意味着,它会在容器启动后,在容器里面执行一句咱们指定的命令,好比:“cat /tmp/healthy”。这时,若是这个文件存在,这条命令的返回值就是 0,Pod 就会认为这个容器不只已经启动,并且是健康的。这个健康检查,在容器启动 5 s 后开始执行(initialDelaySeconds: 5),每 5 s 执行一次(periodSeconds: 5)。 如今,让咱们来具体实践一下这个过程。 首先,建立这个 Pod:  

$ kubectl create -f test-liveness-exec.yaml

而后,查看这个 Pod 的状态:  

$ kubectl get pod
NAME                READY     STATUS    RESTARTS   AGE
test-liveness-exec   1/1       Running   0          10s

能够看到,因为已经经过了健康检查,这个 Pod 就进入了 Running 状态。 而 30 s 以后,咱们再查看一下 Pod 的 Events:

$ kubectl describe pod test-liveness-exec

  

你会发现,这个 Pod 在 Events 报告了一个异常:  

FirstSeen LastSeen    Count   From            SubobjectPath           Type        Reason      Message
--------- --------    -----   ----            -------------           --------    ------      -------
2s        2s      1   {kubelet worker0}   spec.containers{liveness}   Warning     Unhealthy   Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory

  

显然,这个健康检查探查到 /tmp/healthy 已经不存在了,因此它报告容器是不健康的。那么接下 来会发生什么呢? 咱们不妨再次查看一下这个 Pod 的状态:

 

$ kubectl get pod test-liveness-exec
NAME           READY     STATUS    RESTARTS   AGE
liveness-exec   1/1       Running   1          1m

  

这时咱们发现,Pod 并无进入 Failed 状态,而是保持了 Running 状态。这是为何呢?

其实,若是你注意到 RESTARTS 字段从 0 到 1 的变化,就明白缘由了:这个异常的容器已经被 Kubernetes 重启了。在这个过程当中,Pod 保持 Running 状态不变。 须要注意的是:Kubernetes 中并无 Docker 的 Stop 语义。因此虽然是 Restart(重启),但实 际倒是从新建立了容器。 这个功能就是 Kubernetes 里的Pod 恢复机制,也叫 restartPolicy。它是 Pod 的 Spec 部分的一个 标准字段(pod.spec.restartPolicy),默认值是 Always,即:任什么时候候这个容器发生了异常,它 必定会被从新建立。

但必定要强调的是,Pod 的恢复过程,永远都是发生在当前节点上,而不会跑到别的节点上去。事 实上,一旦一个 Pod 与一个节点(Node)绑定,除非这个绑定发生了变化(pod.spec.node 字段 被修改),不然它永远都不会离开这个节点。这也就意味着,若是这个宿主机宕机了,这个 Pod 也 不会主动迁移到其余节点上去。 而若是你想让 Pod 出如今其余的可用节点上,就必须使用 Deployment 这样的“控制器”来管理 Pod,哪怕你只须要一个 Pod 副本。

即一个单 Pod 的 Deployment 与一个 Pod 最主要的区别。 而做为用户,你还能够经过设置 restartPolicy,改变 Pod 的恢复策略。除了 Always,它还有 OnFailure 和 Never 两种状况: 在实际使用时,咱们须要根据应用运行的特性,合理设置这三种恢复策略。 好比,一个 Pod,它只计算 1+1=2,计算完成输出结果后退出,变成 Succeeded 状态。这时,你 若是再用 restartPolicy=Always 强制重启这个 Pod 的容器,就没有任何意义了。

而若是你要关心这个容器退出后的上下文环境,好比容器退出后的日志、文件和目录,就须要将 restartPolicy 设置为 Never。由于一旦容器被自动从新建立,这些内容就有可能丢失掉了(被垃圾 回收了)。 值得一提的是,Kubernetes 的官方文档,把 restartPolicy 和 Pod 里容器的状态,以及 Pod 状态 的对应关系,

实际上,你根本不须要死记硬背这些对应关系,只要 记住以下两个基本的设计原理便可:

  • 1. 只要 Pod 的 restartPolicy 指定的策略容许重启异常的容器(好比:Always),那么这个 Pod 就会保持 Running 状态,并进行容器重启。不然,Pod 就会进入 Failed 状态 。
  • 2. 对于包含多个容器的 Pod,只有它里面全部的容器都进入异常状态后,Pod 才会进入 Failed 状 态。在此以前,Pod 都是 Running 状态。此时,Pod 的 READY 字段会显示正常容器的个数, 好比:
$ kubectl get pod test-liveness-exec
NAME           READY     STATUS    RESTARTS   AGE
liveness-exec   0/1       Running   1          1m

  

因此,假如一个 Pod 里只有一个容器,而后这个容器异常退出了。那么,只有当 restartPolicy=Never 时,这个 Pod 才会进入 Failed 状态。而其余状况下,因为 Kubernetes 均可 以重启这个容器,因此 Pod 的状态保持 Running 不变。

而若是这个 Pod 有多个容器,仅有一个容器异常退出,它就始终保持 Running 状态,哪怕即便 restartPolicy=Never。只有当全部容器也异常退出以后,这个 Pod 才会进入 Failed 状态。 其余状况,均可以以此类推出来。

如今,咱们一块儿回到前面提到的 livenessProbe 上来。 除了在容器中执行命令外,livenessProbe 也能够定义为发起 HTTP 或者 TCP 请求的方式,定义格 式以下:

...
livenessProbe:
     httpGet:
       path: /healthz
       port: 8080
       httpHeaders:
       - name: X-Custom-Header
         value: Awesome
       initialDelaySeconds: 3
       periodSeconds: 3

  

    ...
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20

  

因此,你的 Pod 其实能够暴露一个健康检查 URL(好比 /healthz),或者直接让健康检查去检测 应用的监听端口。这两种配置方法,在 Web 服务类的应用中很是经常使用。

在 Kubernetes 的 Pod 中,还有一个叫 readinessProbe 的字段。虽然它的用法与 livenessProbe 相似,但做用却大不同。readinessProbe 检查结果的成功与否,决定的这个 Pod 是否是能被通 过 Service 的方式访问到,而并不影响 Pod 的生命周期。这部份内容,我会留在讲解 Service 时再 重点介绍。 在讲解了这么多字段以后,想必你对 Pod 对象的语义和描述能力,已经有了一个初步的感受。

Pod 预设置

这时,你有没有产生这样一个想法:Pod 的字段这么多,我又不可能全记住,Kubernetes 能不能 自动给 Pod 填充某些字段呢? 这个需求实际上很是实用。好比,开发人员只须要提交一个基本的、很是简单的 Pod YAML, Kubernetes 就能够自动给对应的 Pod 对象加上其余必要的信息,好比 labels,annotations, volumes 等等。而这些信息,能够是运维人员事先定义好的。

这么一来,开发人员编写 Pod YAML 的门槛,就被大大下降了。 因此,这个叫做 PodPreset(Pod 预设置)的功能 已经出如今了 v1.11 版本的 Kubernetes 中。 举个例子,如今开发人员编写了以下一个 pod.yaml 文件:

pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
spec:
  containers:
    - name: website
      image: nginx
      ports:
        - containerPort: 80

  

做为 Kubernetes 的初学者,你确定眼前一亮:这不就是我最擅长编写的、最简单的 Pod 嘛。没 错,这个 YAML 文件里的字段,想必你如今闭着眼睛也能写出来。

但是,若是运维人员看到了这个 Pod,他必定会连连摇头:这种 Pod 在生产环境里根本不能用啊! 因此,这个时候,运维人员就能够定义一个 PodPreset 对象。在这个对象中,凡是他想在开发人员 编写的 Pod 里追加的字段,均可以预先定义好。好比这个

preset.yaml

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: allow-database
spec:
  selector:
    matchLabels:
      role: frontend
  env:
    - name: DB_PORT
      value: "6379"
  volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
    - name: cache-volume
      emptyDir: {}

在这个 PodPreset 的定义中,首先是一个 selector。这就意味着后面这些追加的定义,只会做用于 selector 所定义的、带有“role: frontend”标签的 Pod 对象,这就能够防止“误伤”。

而后,咱们定义了一组 Pod 的 Spec 里的标准字段,以及对应的值。好比,env 里定义了 DB_PORT 这个环境变量,volumeMounts 定义了容器 Volume 的挂载目录,volumes 定义了一 个 emptyDir 的 Volume。 接下来,咱们假定运维人员先建立了这个 PodPreset,而后开发人员才建立 Pod:  

$ kubectl create -f preset.yaml
$ kubectl create -f pod.yaml

  

这时,Pod 运行起来以后,咱们查看一下这个 Pod 的 API 对象:

$ kubectl get pod website -o yaml
apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
  annotations:
    podpreset.admission.kubernetes.io/podpreset-allow-database: "resource version"
spec:
  containers:
    - name: website
      image: nginx
      volumeMounts:
        - mountPath: /cache
          name: cache-volume
      ports:
        - containerPort: 80
      env:
        - name: DB_PORT
          value: "6379"
  volumes:
    - name: cache-volume
      emptyDir: {}

  

这个时候,咱们就能够清楚地看到,这个 Pod 里多了新添加的 labels、env、volumes 和 volumeMount 的定义,它们的配置跟 PodPreset 的内容同样。此外,这个 Pod 还被自动加上了 一个 annotation 表示这个 Pod 对象被 PodPreset 改动过。 须要说明的是,PodPreset 里定义的内容,只会在 Pod API 对象被建立以前追加在这个对象自己 上,而不会影响任何 Pod 的控制器的定义。 好比,咱们如今提交的是一个 nginx-deployment,那么这个 Deployment 对象自己是永远不会被 PodPreset 改变的,被修改的只是这个 Deployment 建立出来的全部 Pod。这一点请务必区分清 楚。 这里有一个问题:若是你定义了同时做用于一个 Pod 对象的多个 PodPreset,会发生什么呢?

实际上,Kubernetes 项目会帮你合并(Merge)这两个 PodPreset 要作的修改。而若是它们要作 的修改有冲突的话,这些冲突字段就不会被修改。

总结

在今天这篇文章中,我和你详细介绍了 Pod 对象更高阶的使用方法,但愿经过对这些实例的讲解, 你能够更深刻地理解 Pod API 对象的各个字段。 而在学习这些字段的同时,你还应该认真体会一下 Kubernetes“一切皆对象”的设计思想:好比应 用是 Pod 对象,应用的配置是 ConfigMap 对象,应用要访问的密码则是 Secret 对象。 因此,也就天然而然地有了 PodPreset 这样专门用来对 Pod 进行批量化、自动化修改的工具对 象。在后面的内容中,我会为你讲解更多的这种对象,还会和你介绍 Kubernetes 项目如何围绕着 这些对象进行容器编排。 在本专栏中,Pod 对象相关的知识点很是重要,它是接下来 Kubernetes 可以描述和编排各类复杂 应用的基石所在,但愿你可以继续多实践、多体会。

相关文章
相关标签/搜索