KUBERNETES之Kubernetes Workloads(Kubernetes 作业管理)二

文章目录

    • 六、Kubernetes Workloads(Kubernetes 作业管理)
        • 1.5 Pod模板
          • 1.5.1 NodeSeletor 是一个供用户将 Pod 与 Node 进行绑定的字段
          • 1.5.2 HostAliases 定义了 Pod 的 hosts 文件(比如 /etc/hosts)里的内容
          • 1.5.3 shareProcessNamespace Pod 里的容器要共享 PID Namespace
          • 1.5.4 Containers(重要) 对容器进行定义,与initContainer基本类似,只不过后者是在所有容器前启动
        • 1.6 Pod的生命周期
        • 1.7 Projected Volume
          • 1.7.1 Secret
          • 1.7.2 ConfigMap
          • 1.7.3 Downward API
          • 1.7.4 ServiceAccountToken
        • 1.8 容器健康检查与恢复机制
          • 1.8.1 健康检查
          • 1.8.2 恢复机制
        • 1.9 readinessProbe
        • 1.10 PodPreset
        • 1.11 为什么把Pod作为调度基本单位?而不是容器呢?

六、Kubernetes Workloads(Kubernetes 作业管理)

1.5 Pod模板

Pod 模板是包含在其他对象中的 Pod 规范,例如 ReplicaSet、 Jobs 和 DaemonSets。 控制器使用 Pod 模板来制作实际使用的 Pod。

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
  • apiVersion 当前配置格式版本

  • kind 创建的资源类型,这里是Pod

  • metadata 是该资源的元数据,name是必须的数据项

  • spec 该Pod的规格说明

 
 
其他重要字段

1.5.1 NodeSeletor 是一个供用户将 Pod 与 Node 进行绑定的字段

例子

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

意味着这个 Pod 永远只能运行在携带了“disktype: ssd”标签(Label)的节点上;否则,它将调度失败。

kubectl label nodes <node-name> <label-key>=<label-value>
kubectl get nodes --show-labels 
  • NodeName 一旦 Pod 的这个字段被赋值,Kubernetes 项目就会被认为这个 Pod 已经经过了调度,调度的结果就是赋值的节点名字。

 
 

1.5.2 HostAliases 定义了 Pod 的 hosts 文件(比如 /etc/hosts)里的内容

例子

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

pod启动后hosts文件

cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
...
10.244.135.10 hostaliases-pod
10.1.2.3 foo.remote
10.1.2.3 bar.remote

 
 

1.5.3 shareProcessNamespace Pod 里的容器要共享 PID Namespace

例子

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  shareProcessNamespace: true
  containers:
  - name: nginx
    image: nginx
  - name: shell
    image: busybox
    stdin: true
    tty: true

kubectl attach -it nginx -c shell

ps ax

  • hostNetwork: true 共享宿主机网络 namespace

  • hostIPC: true 共享宿主机IPC namespace

  • hostPID: true 共享宿主机PID namespace

 
 

1.5.4 Containers(重要) 对容器进行定义,与initContainer基本类似,只不过后者是在所有容器前启动
  • Image(镜像)

  • Command(启动命令)

  • workingDir(容器的工作目录)

  • Ports(容器要开发的端口)

  • volumeMounts(容器要挂载的 Volume)

  • ImagePullPolicy 镜像拉取的策略,默认ifNotPresent

    Always 每次创建 Pod 都重新拉取一次镜像

    Never Pod 永远不会主动拉取这个镜像

    IfNotPresent 只在宿主机上不存在这个镜像时才拉取

  • Lifecycle

    容器生命周期钩子Container Lifecycle Hooks 是在容器状态发生变化时触发一系列“钩子”

例子

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 from the postStart handler > /usr/share/message"]
      preStop:
        exec:
          command: ["/usr/sbin/nginx","-s","quit"]
  • postStart 在容器启动后,立刻执行一个指定的操作。

    • 容器启动后执行,注意由于是异步执行,它无法保证一定在ENTRYPOINT之后运行。如果失败,容器会被杀死,并根据RestartPolicy决定是否重启
  • preStop preStop 发生的时机,则是容器被杀死之前(比如,收到了 SIGKILL 信号)。

    • 容器停止前执行,常用于资源清理。如果失败,容器同样也会被杀死

 
 

1.6 Pod的生命周期

Pod 生命周期的变化,主要体现在 Pod API 对象的 Status 部分,这是它除了 Metadata 和 Spec 之外的第三个重要字段。其中,pod.status.phase,就是 Pod 的当前状态

kubectl explain pod.status.phase

Pod 对象的 Status 字段,还可以再细分出一组 Conditions。这些细分状态的值包括:PodScheduled、Ready、Initialized,以及 Unschedulable。它们主要用于描述造成当前 Status 的具体原因是什么。

kubectl get pods -o yaml

  • Pending

    这个状态意味着,Pod 的 YAML 文件已经提交给了 Kubernetes,API 对象已经被创建并保存在 Etcd 当中。但是,这个 Pod 里有些容器因为某种原因而不能被顺利创建。比如,调度不成功。

  • Running

    这个状态下,Pod 已经调度成功,跟一个具体的节点绑定。它包含的容器都已经创建成功,并且至少有一个正在运行中。

  • Succeeded

    这个状态意味着,Pod 里的所有容器都正常运行完毕,并且已经退出了。这种情况在运行一次性任务时最为常见。

  • Failed

    这个状态下,Pod 里至少有一个容器以不正常的状态(非 0 的返回码)退出。这个状态的出现,意味着你得想办法 Debug 这个容器的应用,比如查看 Pod 的 Events 和日志。

  • Unknown

    这是一个异常状态,意味着 Pod 的状态不能持续地被 kubelet 汇报给 kube-apiserver,这很有可能是主从节点(Master 和 Kubelet)间的通信出现了问题。

 
 

1.7 Projected Volume

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

 

1.7.1 Secret

把 Pod 想要访问的加密数据,存放到 Etcd 中。通过在 Pod 的容器里挂载 Volume 的方式,访问到这些 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

通过Volume的方式使用secret支持动态更新

通过环境变量的方式则不支持

  • 创建secret对象

  • kubectl get secrets 查看secret信息

    • 从普通文件中创建secret

      echo haha >> username

      echo password >> password

      kubectl create secret generic user --from-file=username

      kubectl create secret generic pass --from-file=password

    • 通过secret对象的yaml文件创建secret

      对内容进行转码

      • echo -n ‘haha’ | base64
      • echo -n ‘MWYyZDF’ | base64 --decode

      secret_test.yaml

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

      kubectl create-f secret_test.yaml

 
 

1.7.2 ConfigMap

ConfigMap 保存的是不需要加密的、应用所需的配置信息。而 ConfigMap 的用法几乎与 Secret 完全相同:你可以使用 kubectl create configmap 从文件或者目录创建 ConfigMap,也可以直接编写 ConfigMap 对象的 YAML 文件。

  • 创建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
  ...

 
 

1.7.3 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: k8s.gcr.io/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

$ kubectl create -f dapi-volume.yaml

$ kubectl logs test-downwardapi-volume

  • cluster=“test-cluster1”
  • rack=“rack-22”
  • zone=“us-est-coast”

Downward API 支持的字段

  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[’’] - 指定的Label值
    metadata.annotations[’’] - 指定的Annotation值
    metadata.labels - Pod的所有Label
    metadata.annotations - Pod的所有Annotation

  2. 使用resourceFieldRef可以声明使用:
    容器的CPU limit
    容器的CPU request
    容器的memory limit
    容器的memory request

 
 

1.7.4 ServiceAccountToken

我现在有了一个 Pod,我能不能在这个 Pod 里安装一个 Kubernetes 的 Client,这样就可以从容器里直接访问并且操作这个 Kubernetes 的 API 了呢?

Service Account 对象的作用,就是 Kubernetes 系统内置的一种“服务账户”,它是 Kubernetes 进行权限分配的对象。比如,Service Account A,可以只被允许对 Kubernetes API 进行 GET 操作,而 Service Account B,则可以有 Kubernetes API 的所有操作权限。

查看ServiceAccountToken

  • kubectl get secrets -o wide
  • kubectl describe secrets default-token-lfztc

 
 

1.8 容器健康检查与恢复机制

1.8.1 健康检查

在 Kubernetes 中,你可以为 Pod 里的容器定义一个健康检查“探针”(Probe)。这样,kubelet 就会根据这个 Probe 的返回值决定这个容器的状态,而不是直接以容器进行是否运行(来自 Docker 返回的信息)作为依据。

  • 例子
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
    • livenessProbe 健康检查
    • exec 容器启动后执行命令
    • initialDelaySeconds: 5 容器启动后5s执行
    • periodSeconds: 5 每隔5s运行一次探针
  • LivenessProbe:探测应用是否处于健康状态,如果不健康则删除重建改容器

  • ReadinessProbe:探测应用是否启动完成并且处于正常服务状态,如果不正常则更新容器的状态

  • 其他类型探针

HTTP

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

TCP

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

 
 

1.8.2 恢复机制

也叫 restartPolicy。它是 Pod 的 Spec 部分的一个标准字段(pod.spec.restartPolicy),默认值是 Always,即:任何时候这个容器发生了异常,它一定会被重新创建。

  • restartPolicy

    Always:在任何情况下,只要容器不在运行状态,就自动重启容器;

    OnFailure: 只在容器 异常时才自动重启容器;

    Never: 从来不重启容器。

 
 

1.9 readinessProbe

readinessProbe 检查结果的成功与否,决定的这个 Pod 是不是能被通过 Service 的方式访问到,而并不影响 Pod 的生命周期。

1.10 PodPreset

 
 

1.11 为什么把Pod作为调度基本单位?而不是容器呢?

第一个原因,Kubernetes通过CRI这个抽象层,支持除Docker之外的其他容器运行时,比如rkt甚至支持客户自定义容器运行时。因此,借助CRI这个抽象层,使得Kubernetes不依赖于底层某一种具体的容器运行时实现技术,而是直接操作pod,pod内部再管理多个业务上紧密相关的用户业务容器,这种架构便于Kubernetes做扩展。

第二个原因,我们假设Kubernetes没有pod的概念,而是直接管理容器,那么一组容器作为一个单元,假设其中一个容器死亡了,此时这个单元的状态应该如何定义呢?应该理解成整体死亡,还是个别死亡?

这个问题不易回答的原因,是因为包含了这一组业务容器的逻辑单元,没有一个统一的办法来代表整个容器组的状态,这就是Kubernetes引入pod的概念,并且每个pod里都有一个Kubernetes系统自带的pause容器的原因,通过引入pause这个与业务无关并且作用类似于Linux操作系统守护进程的Kubernetes系统标准容器,以pause容器的状态来代表整个容器组的状态。

第三也就是最后一个原因,pod里所有的业务容器共享pause容器的IP地址,以及pause容器mount的Volume,通过这种设计,业务容器之间可以直接通信,文件也能够直接彼此共享。

你可能感兴趣的:(KUBERNETES)