{"msg":"操作成功","code":200,"data":{"createBy":"admin","createTime":"2021-07-22 17:46:08","updateBy":"admin","updateTime":"2021-07-22 17:46:08","remark":null,"id":66,"articleTitle":"Kubernetes（四）Pod","articleUrl":"k8s_pod","articleThumbnail":"https://www.asumimoe.com/imgfiles/20220906/f93daad129a04b8db74eed70cd45263b.png","articleFlag":"0","draftStatus":"1","reprintStatement":"1","articleSummary":"Pod是kubernetes中最小的资源管理组件，Pod也是最小化运行容器化应用的资源对象。一个Pod代表着集群中运行的一个进程。kubernetes中其他大多数组件都是围绕着Pod来进行支撑和扩展Pod功能的","articleContent":"## Pod介绍\n\nPod是kubernetes中最小的资源管理组件，Pod也是最小化运行容器化应用的资源对象。一个Pod代表着集群中运行的一个进程。kubernetes中其他大多数组件都是围绕着Pod来进行支撑和扩展Pod功能的，例如，用于管理Pod运行的StatefulSet和Deployment等控制器对象，用于暴露Pod应用的Service和Ingress对象，为Pod提供存储的PersistentVolume存储资源对象等。\n\n每个Pod都有一个特殊的被称为“根容器”的Pause容器。Pause容器对应的景象属于Kubernetes平台的一部分，除了Pause容器，每个Pod还包含了一个或多个紧密相关的用户业务容器。Pod的特殊设计有以下两个原因：\n\n- 在一组容器作为一个单元的情况下，我们难以简单的对“整体”进行判断及有效的行动。比如，一个容器死亡了，此时算是整体的死亡么？是N/M的死亡率吗？引入业务无关并且不易死亡的Pause容器作为Pod的根容器，以它的状态代表整组容器的状态就简单了。\n- Pod里多个业务容器共享Pause容器的IP，共享Pause容器挂载的Volume，这样即简化了密切关联的业务容器之间的通信问题，也很好地解决了他们之间的文件共享问题。\n\nPod其实有两种类型：普通的Pod及静态Pod（Static Pod）。后者比较特殊，它并没被存放在Kubernetes的etcd存储里，而是被存放在某个具体的Node上的一个具体文件中，并且只在此Node上启动、运行。而普通的Pod一旦被创建就会被放入etcd中存储，随后会被Kubernetes Master调度到某个具体的Node上并进行绑定（Binding），随后该Pod被对应的Node上的kubelet进程实例化为一组相关的Docker容器并启动。在默认情况下，当Pod里的某个容器停止时，Kubernetes会自动检测到这个问题并且重新启动这个Pod，如果Pod所在的Node宕机，就会将这个Node上的所有Pod重新调度到其他节点上。\n\n## 创建一个Pod\n\n### 1.命令行方式\n\n```shell\nkubectl run mynginx --image=nginx # 指定名称为mynginx，使用镜像nginx\npod/mynginx created\n\nkubectl get po # 查看pod，默认查看default名称空间的pod\nNAME                   READY   STATUS    RESTARTS   AGE\nmynginx                1/1     Running   0          71s\n\nkubectl describe po mynginx # 描述pod\nEvents:\n  Type    Reason     Age    From               Message\n  ----    ------     ----   ----               -------\n  Normal  Scheduled  2m14s  default-scheduler  Successfully assigned default/mynginx to node1\n  Normal  Pulling    2m10s  kubelet            Pulling image \"nginx\"\n  Normal  Pulled     100s   kubelet            Successfully pulled image \"nginx\" in 29.897761075s\n  Normal  Created    99s    kubelet            Created container mynginx\n  Normal  Started    99s    kubelet            Started container mynginx\n  \nkubectl delete po mynginx # 删除pod\npod \"mynginx\" deleted\n```\n\n### 2.配置文件方式\n\n```yaml\nnginx-pod.yml\napiVersion: v1\nkind: Pod\nmetadata:\n  labels:\n    run: mynginx\n  name: mynginx\nspec:\n  containers:\n  - image: nginx\n    name: mynginx\n```\n\n根据yml文件生成pod\n\n```shell\nkubectl apply -f nginx-pod.yml\n\nkubectl get po\nNAME                   READY   STATUS    RESTARTS   AGE\nmynginx                1/1     Running   0          1m10s\n\nkubectl delete -f nginx-pod.yml # 配置文件方式删除pod\n```\n\n### 3.多容器pod\n\n```yaml\napp-pod.yml\napiVersion: v1\nkind: Pod\nmetadata:\n  labels:\n    run: myapp\n  name: myapp\nspec:\n  containers:\n  - image: nginx\n    name: nginx\n  - image: tomcat:8.5.68\n    name: tomcat\n```\n\n生成pod\n\n```shell\nkubectl apply -f app-pod.yml \npod/myapp created\n\nkubectl get po -owide # 打印详细信息\nNAME    READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES\nmyapp   2/2     Running   0          15m   10.244.2.8   node1   <none>           <none>\n```\n\n进入pod\n\n```shell\nkubectl exec -it myapp -- /bin/bash # 不指定容器，默认进入第一个容器\nDefaulted container \"nginx\" out of: nginx, tomcat\nroot@myapp:/#\n\nkubectl exec -it myapp -c tomcat -- /bin/bash # -c指定容器名，进入指定容器\nroot@myapp:/usr/local/tomcat# \n```\n\n可以用podIP:80来访问nginx，podIP:8080来访问tomcat。\n\n**注意：**无法在同一个pod中启动两个nginx容器，会由于端口占用导致另一个nginx无法启动。\n\n## 静态Pod\n\n静态Pod是由kubelet进行管理的仅存在特定的Node上的Pod。它们不能通过API Server进行管理，无法与ReplicationController、Deployment或者DaemonSet进行关联，并且kubelet无法对它们进行健康检查。静态Pod总是由kubelet创建的。并总在kubelet所在的Node上运行。\n\n静态Pod有两种创建方式：配置文件方式和HTTP方式。\n\n### 1.配置文件方式\n\n首先，需要设置kubelet的启动参数“--pod-manfiest-path”或者在kubelet的配置文件中指定staticPodPath。后者也是新版本中推荐的方式。\n\n```yaml\ncat /var/lib/kubelet/config.yaml\napiVersion: kubelet.config.k8s.io/v1beta1\n...\nstaticPodPath: /etc/kubernetes/manifests # kubelet已经指定了默认的静态pod路径\n...\n```\n\n在master节点中，我们可以看到默认生成的yaml文件：\n\n```shell\n[root@master ~]# cd /etc/kubernetes/manifests\n[root@master manifests]# ls\netcd.yaml  kube-apiserver.yaml  kube-controller-manager.yaml  kube-scheduler.yaml\n```\n\n我们想创建自己的静态Pod，也可以在这个目录下写好yaml文件，容器就会自动启动。由于静态Pod无法通过API Server直接管理，使用delete命令删除时只会使该容器变为Pending状态而无法直接删除。只能将静态Pod目录中的yaml文件删除，Pod就自动被删除了。\n\n### 2.HTTP方式\n\n通过指定kubelet启动参数“--manifest-url”，kubelet会定期从该URL地址下载Pod的定义文件，并以yaml或json文件的格式进行解析，然后创建Pod。其实现方法和配置文件方式是一致的。\n\n## Pod调度策略\n\n在Kubernetes平台上，我们很少会直接创建一个Pod，大多数情况下会通过RC、Deployment、DaemonSet、Job等控制器完成对一组Pod的创建，调度及全生命周期的自动控制任务。\n\n大多数情况下，我们希望我们的Pod副本可以被调度到集群中任何一个可用的节点，而不必关心具体是哪一个节点。但是在真实的生产环境中，也存在一种需求：希望将某中Pod调度到特定节点上。例如，将MySQL服务调度到SSD节点中，此时Pod模板中的NodeSelector就开始发挥作用。我们只需将带有SSD磁盘的Node打上标签，NodeSelector可以将设定为disk:ssd的Pod调度到该节点上。但是仅此还不够满足所有的场景。比如，\n\n1）如果NodeSelector选择的Label不存在或者不符合条件，比如这些节点的资源不足；\n\n2）不同Pod间的亲和性，例如MySQL与Redis不能放在同一Node上；\n\n3）对于有状态集群，Zookeeper、Elasticsearch等集群，每个work节点都必须有明确的、不变的ID，而且需要持久化保存状态数据，所以不管该Pod在哪个Node节点上恢复，都必须挂载原来的Volume。\n\n接下来就来深入了解对于这些场景需要哪些调度来控制。\n\n### 1.Deployment或RC：全自动调度\n\nDeployment或RC的主要功能之一就是自动部署一个容器应用的多份副本，以及持续监控副本的数量，在集群内始终维持用户指定的副本数量。策略上来讲，Pod由系统完成全自动调度。\n\n关于Deployment的功能之后的文章会详细介绍。\n\n### 2.NodeSelector：定向调度\n\n可以通过给Node打上标签，通过与NodeSelector指定的属性相配，来将Pod调度到指定节点上。\n\n```yml\nkubectl label nodes node1 zone=north # 为名为node1的节点打上zone=north的标签\n\nvim nginx.yml\napiVersion: v1\nkind: ReplicationController\nspec:\n  template:\n    spec:\n    ...\n      nodeSelector: \n        zone: north\n```\n\n启动该Pod，scheduler就会将该Pod调度到拥有node=north标签的Node上。如果有多个Node都拥有这个标签，那么调度算法就会在这组Node上挑选一个可用Node进行调度。\n\n**注：**如果集群中不存在包含该标签的Node，那么即使集群中有正常可用的其他Node，该Pod也无法成功调度。\n\n### 3.NodeAffinity：Node亲和性调度\n\nNodeAffinity意为Node亲和性的调度策略，是用于替换NodeSelector的全新调度策略。目前有两种亲和性表达：\n\n- requiredDuringSchedulingIgnoredDuringExecution：必须需满足指定的规则才可以调度Pod到Node上。\n- preferredDuringSchedulingIgnoredDuringExecution：强调优先满足指定规则，但并不强求，相当于软限制。多个优先级规则还可以设置权重值，以定义执行的先后顺序。\n\nIgnoredDuringExecution意思是：如果一个Pod所在的节点在Pod运行期间标签发生了变更，不再符合该Pod的节点亲和性需求，则系统将忽略Node上Label的变化，该Pod能继续在该节点运行。\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n  name: nginx\nspec:\n  affinity:\n    nodeAffinity:\n      requiredDuringSchedulingIgnoredDuringExecution:\n        nodeSelectorTerms:\n        - matchExpressions:\n          - key: beta.kubernetes.io/arch\n            operator: In\n            values:\n              - amd64 # 只运行在amd64节点上\n      preferredDuringSchedulingIgnoredDuringExecution:\n      - weight: 1  \n        preference:\n          matchExpressions:\n          - key: disk-type\n            operator: In\n            values:\n              - ssd # 尽量运行在磁盘类型为ssd的节点上\n  containers:\n  - name: nginx\n    image: nginx\n```\n\nNodeAffinity语法支持的运算符包括In、NotIn、Exists、DoesNotExist、Gt、Lt。\n\n规则设置注意事项：\n\n- 如果同时定义了nodeSelector和nodeAffinity，那么必须两个条件都要得到满足；\n- 如果指定了多个nodeSelectorTerms，那么其中一个能够匹配成功即可；\n- 如果nodeSelectorTerms有多个matchExpressions，那么必须全部满足。\n\n### 4.PodAffinity：Pod亲和与互斥调度策略\n\nPod间的亲和与互斥在Kubernetes 1.4版本开始引入，实现根据节点上正在运行的Pod的标签进行判断和调。描述为如果在具有标签X的Node上运行了一个或多个符合条件Y的Pod，那么Pod应该（拒绝）运行在此节点上。\n\n这里的X指的是一个集群中的节点、机架、区域等概念，通过Kubernetes内置节点标签中的topologyKey进行声明。\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n  name: nginx\nspec:\n  affinity:\n    podAffinity: # 亲和性调度\n      requiredDuringSchedulingIgnoredDuringExecution:\n      - labelSelector:\n          matchExpressions:\n          - key: app\n            operator: In\n            values:\n              - tomcat # 与tomcat类型的Pod运行在同一个节点\n        topologyKey: kubernetes.io/hostname\n    podAntiAffinity: # 互斥性调度\n      requiredDuringSchedulingIgnoredDuringExecution:\n      - labelSelector:\n          matchExpressions:\n          - key: app\n            operator: In\n            values:\n              - mysql # 不与mysql类型的pod运行在同一个节点\n  containers:\n  - name: nginx\n    image: nginx\n```\n\n### 5.Taints和Tolerations：污点和容忍\n\n污点和亲和和反亲和不一样，污点是拒绝某些Pod调度到该节点。\n\n容忍度（Toleration）是应用于Pod上的，允许（但并不要求）Pod 调度到带有与之匹配的污点的节点上。比如说Master节点通过污点`node-role.kubernetes.io/master:NoSchedule`使得pod不会调度到master。\n\n```shell\n[root@master ~]# kubectl describe nodes master\nName:               master\nRoles:              control-plane,master\nLabels:             beta.kubernetes.io/arch=amd64\n                    beta.kubernetes.io/os=linux\n                    kubernetes.io/arch=amd64\n                    kubernetes.io/hostname=master\nTaints:             node-role.kubernetes.io/master:NoSchedule\n```\n\n污点影响策略有三种：\n\n- NoSchedule:只有拥有和这个污点相匹配的容忍度的Pod才能够被分配到该节点\n- PreferNoSchedule：NoSchedule的软策略版本，表示尽量不调度到污点节点上去\n- NoExecute：该选项意味着一旦Taint生效，如该节点内正在运行的 Pod 没有对应容忍（Tolerate）设置，则会直接被驱逐。配置了对应Toleration的Pod并且通过tolerationSeconds值，则会在指定时间后驱逐该Pod。\n\n```shell\n# 为node1节点设置一个taint，该taint的键为key，值为value，效果为NoSchedule。意味着除非Pod明确声明可以容忍这个Taint，否则不会调度到node1上。\nkubectl taint nodes node1 key=value:Noschedule\n# 去除污点\nkubectl taint nodes node1 key:Noschedule-\n# 去除所有污点\nkubectl taint nodes node1 key-\n```\n\n在Pod上声明Toleration。\n\n```yaml\ntolerations:\n- key: \"key\" # 空的key值配合Exists可以匹配所有的键和值\n  operator: \"Equal\" # 如果不指定，则默认为Equal\n  value: \"value\"\n  effect: \"Noschedule\" # 空的effect可以匹配所有的effect\n# 或者\ntolerations:\n- key: \"key\"\n  operator: \"Exists\"\n  effect: \"Noschedule\"\n```","categoryId":10,"viewCount":891,"categoryName":"Kubernetes","author":"球接子","authorAvatar":null,"tagIds":[16],"tagNames":["Kubernetes"]}}