当前位置: 首页 > Linux

K8S实战(三)-Pod的本质

时间:2023-04-07 01:11:56 Linux

前言上一节发布了一个容器到K8S,但实际上实际操作的是Pod,那么为什么是Pod而不是容器呢。更新历史20200531-初稿-左成礼原文地址-https://blog.zuolinux.com/2020/05/22/about-pod.htmlPod的本质Pod封装了一个或多个容器。Pod是K8S的最小执行单元。Pod是K8S中的一个进程。Pod可以打包Docker,也支持打包其他类型的容器。Pod包含封装的容器、存储资源、网络资源以及指示容器如何运行的配置。容器可以理解为没有挂钩的裸容器。K8S这种大船,不能直接挂载。通过给容器(container)加上一个hook(IP地址)就形成了一个Pod,方便K8S的操作。Pod也可以理解为传统的虚拟机,而容器就是运行在传统虚拟机中的程序,只不过虚拟机是一个实体,Pod是一个逻辑概念。K8S通过排列Pod来调度容器,而不是直接操作容器。K8S不能直接操作容器。Pod中的共享资源Pod为运行在其中的多个容器提供共享网络、存储资源和命名空间。网络Pod具有唯一的IP地址,Pod中的多个容器共享一个IP地址、网口等网络资源。Pod中的多个容器可以使用localhost进行通信。Pod中的容器与外界通信时,需要多个容器协调容器获取Pod中的网络端口。系统主机名与为Pod配置的名称相同。存储Pod可以指定一组存储卷。Pod中的多个容器可以访问存储卷,从而可以相互共享数据。可以持久化Pod中的共享卷,防止容器重启丢失数据。特性如果使用kind:Pod的yaml文件创建Pod,当前节点服务器发生故障后,Pod不能自动调度到其他可用的服务器。一般使用kind:Deployment的yaml来创建Pod。Deployment是一个控制器,可用于创建和管理Pod。例如,创建一个多副本的Pod,并以滚动的方式更新Pod。当Pod所在的节点出现问题时,Deploymentcontroller可以在集群的其他节点上启动新的Pod。Pod模板apiVersion:v1kind:Podmetadata:name:myapp-podlabels:app:myappspec:containers:-name:myapp-containerimage:busyboxcommand:['sh','-c','echo你好Kubernetes!&&sleep3600']如果不指定镜像拉取策略,则imagePullPolicy为Always,即kubelet会尝试从指定仓库拉取每一个镜像。如果容器属性imagePullPolicy设置为IfNotPresent,则将首先使用本地图像。如果容器属性imagePullPolicy设置为IfNotPresentNever,则必须使用本地镜像。apiVersion:v1kind:Podmetadata:name:private-image-test-1spec:containers:-name:uses-private-imageimage:nginximagePullPolicy:Alwayscommand:["echo","SUCCESS"]Pod公共参数NodeSelector函数:willPod绑定到NodeapiVersion:v1kind:Pod...spec:nodeSelector:disktype:ssdPod只能运行在带有“disktype:ssd”标签(Label)的节点上。如果没有这个标签的节点,调度就会失败。NodeName字段一般由调度器设置,但我们可以在测试时手动设置该字段,让调度器认为Pod已经被调度。HostAliase设置Pod中各个容器的/etc/hosts文件内容apiVersion:v1kind:Pod......spec:hostAliases:-ip:"10.20.20.20"hostnames:-"test1.com"-"test2.com》进入容器查看[root@master01~]#kubectlexec-itnginx--bashroot@nginx:/#cat/etc/hosts......#HostAliases.10.20.20.20test1添加的条目.com测试2。comshareProcessNamespace定义了参数shareProcessNamespace=true,那么Pod中的所有容器都会共享PIDNamespace来创建一个包含两个容器的Pod[root@master01~]#catnginx.yamlapiVersion:v1kind:Podmetadata:name:nginxspec:shareProcessNamespace:truecontainers:-name:nginximage:nginx-name:shellimage:busyboxstdin:truetty:true查看运行状态[root@master01~]#kubectlgetpods-owideNAMEREADYSTATUSRESTARTSAGEIPNODENOMINATEDNODEREADINESSGATESnginx2/2running0117s192.10.137.131work03在Podnginx中进入名为shell的容器[root@master01~]#kubectlattach-itnginx-cshell如果您没有看到命令提示符,请尝试按回车键。/#psauxPIDUSERTIMECOMMAND1root0:00/pause6root0:00nginx:masterprocessnginx-gdaemonoff;331010:00nginx:workerprocess34root0:00sh39root0:00psaux可以看到在shell容器中可以看到nginx容器的进程Pod的预设参数PodPreset。我们可以预先设置一些常用的配置。当用户提交自己的个性化Pod配置时,PodPreset可以自动将通用配置附加到相应Pod上PodPreset中定义的内容中,只会附加到创建前的PodAPI对象本身,不会影响任何Pod的Controller定义。比如我们提交的是一个nginx-deployment,那么这个Deployment对象本身是不会被PodPreset改变的,只会修改这个Deployment创建的所有Pod。当PodPreset特性未启用时#kubectlgetpodpreseterror:theserverdoesn'thavearesourcetype"podpresets"启用PodPreset特性修改[/etc/kubernetes/manifests/kube-apiserver.yaml]中的spec.containers.command:修改原来的---runtime-config=api/all=true为---runtime-config=api/all=true,settings.k8s.io/v1alpha1=true新增一行---enable-admission-plugins=PodPreset3MASTER两者都执行restartkubeletsystemctlrestartkubelet预设值配置preset.yamlapiVersion:settings.k8s.io/v1alpha1kind:PodPresetmetadata:name:allow-tz-envspec:selector:matchLabels:env:-name:TZvalue:Asia/ShanghaiPod配置nginx。yamlapiVersion:v1kind:Podmetadata:name:nginxspec:containers:-name:nginximage:nginxcreatePodPreset#kubectlgetpodpresetNoresourcesfoundindefaultnamespace.#kubectlapply-fpodpreset.yamlpodpreset.settings.k8s.io/allow-tz-复制代码envcreated#kubectlgetpodpresetNAMECREATEDATallow-tz-envcreatePod[root@master01~]#kubectlapply-fnginx.yamlpod/nginxcreated查看Pod是否注入#kubectlgetpodnginx-oyaml...省略spec:containers:-env:-name:TZvalue:Asia/Shanghaiimage:nginximagePullPolicy:Alwaysname:nginxresources:{}...省略可以看到Pod是注入一个名为TZ的envInit容器具有一个Init容器,该容器在Pod内的应用程序容器启动之前运行。一个Pod可以有一个或多个Init容器。每个Init容器运行都必须完成。如果Init容器运行失败,K8S会不断重启Pod,直到Init容器运行成功。但是如果Pod对应的restartPolicy值为Never,则不会重启。如果一个Pod有多个InitContainer,这些容器将一个接一个地依次运行。每个Init容器必须在下一个运行之前成功运行。init容器可以包含一些实用程序或个性化代码,这些实用程序或个性化代码在安装期间不存在于应用程序容器中。例如,无需FROM映像生成新映像,只需在安装期间使用sed、awk、python或dig等工具即可。init容器可以安全地运行这些工具,防止它们危及应用程序映像的安全性。应用镜像的创建者和部署者可以独立工作,无需共同构建单一的应用镜像。Init容器可以使用与Pod中的应用程序容器不同的文件系统视图运行。因此,Init容器可以访问Secrets,但应用程序容器不能。由于init容器必须在应用程序容器启动之前运行完成,因此init容器提供了一种机制来阻止或延迟应用程序容器的启动,直到满足一组先决条件。一旦满足前提条件,Pod中的所有应用程序容器将并行启动。在所有Init容器都失败之前,Pod不会变为Ready。对init容器镜像的更改将导致Pod重启,而对应用程序容器镜像的更改只会重启应用程序容器。在Pod中的每个容器副本启动之前,都会执行一次Init容器。如何定义具有2个Init容器的Pod。初始化容器是myservice和mydb。两个Init容器都启动了,Pod可以启动spec区的应用容器myapp-container。创建Pod的YAML文件:catmyapp.yamlapiVersion:v1kind:Podmetadata:name:myapp-podlabels:app:myappspec:containers:-name:myapp-containerimage:busybox:1.28command:['sh','-c','echo应用程序正在运行!&&sleep3600']initContainers:-name:init-myserviceimage:busybox:1.28command:['sh','-c',"untilnslookupmyservice.$(cat/var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local;doechowaitingformyservice;sleep2;done"]-name:init-mydbimage:busybox:1.28command:['sh','-c',"untilnslookupmydb.$(cat/var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local;doechowaitingformydb;sleep2;done"]创建两个服务的YAML文件,mydb和myservice:catmyservice.yamlkind:ServiceapiVersion:v1metadata:name:myservicespec:ports:-protocol:TCPport:80targetPort:9376---kind:ServiceapiVersion:v1metadata:name:mydbspec:ports:-protocol:TCPport:80targetPort:9377要启动这个Pod,你可以执行以下命令:kubectlapply-fmyapp.yamlpod/myapp-podcreated检查它的状态:kubectlget-fmyapp.yamlNAMEREADYSTATUSRESTARTSAGEmyapp-pod0/1Init:0/206m使用以下命令查看更多详细信息:kubectldescribe-fmyapp.yamlName:myapp-podNamespace:default[...]标签:app=myappStatus:Pending[...]InitContainer:init-myservice:[...]State:Running[...]init-mydb:[...]State:WaitingReason:PodInitializingReady:False[...]Containers:myapp-container:[...]State:WaitingReason:PodInitializingReady:False[...]查看Pod中Init容器的日志$kubectllogsmyapp-pod-cinit-myservice$kubectllogsmyapp-pod-cinit-mydb此时Init容器会一直等待,直到找到名为mydb和myservice的Service创建mydb和myservice的服务:$kubectlcreate-fservices.yamlservice"myservice"createdservice"mydb"created可以看到执行了这些Init容器,然后my-app的Pod转为Running状态:$kubectlget-f我的应用程序。yamlNAMEREADYSTATUSRESTARTSAGEmyapp-pod1/1Running09m只有我们启动mydb和myservice这两个服务,并且Init容器完成,才能创建myapp-pod。DebugPod如果Pod被终止,可以使用如下命令查看原因kubectldescribepodpodnamekubectlgetpod-ogo-template='{{range.status.containerStatuses}}{{"ContainerName:"}}{{.name}}{{"\r\nLastState:"}}{{.lastState}}{{end}}'podnameconclusionPod对容器进行包装,K8S通过操作Pod来操作容器。Pod可以包含多个应用程序容器和多个Init容器。直接手动创建的Pod在服务器节点故障时没有自愈能力,需要使用控制器来解决这个问题。微信联系我:zuolinux_com