控制器管理的 Pod:
生产环境中可以用控制器创建和管理多个 pod。控制器在 pod 失败的情况下可以处理副本、更新以
及自动修复。控制器可以指定创建的 pod 副本数,使其管理的 pod 始终维持在指定副本数量,例如,如
果某个节点发生故障,则控制器会注意到该节点上的 Pod 已停止工作,并创建一个新的 pod 替换有故障
的 Pod。调度程序将替换的 Pod 放置到健康的节点上。可以使用 Deployment、Statefulset、Daemonset、Job 等控制器管理 pod。如何通过控制器管理 Pod?
控制器是通过创建 pod 模板来创建和管理 pod 的,PodTemplate 是用于创建 pod 的规范,并且
包含在 Deployment 等控制器中。每个控制器使用自己内部的 Pod 模板来创建实际的 Pod。下面的示
例是一个简单的 Job 的清单,包含一个 podtemplate,这个是用来生成 pod 的模板。该 Pod 中的容器
会打印一条消息,然后暂停。
pod资源清单基础配置
在创建 pod 的时候,可以通过写资源清单文件去实现,Pod 资源清单文件中有几个重要的部分:
apiVersion、kind、metadata、spec 以及 status,其中 apiVersion 和 kind 是比较固定的,status是运行时的状态,所以最重要的就是 metadata 和 spec 两个部分。
#查看 pod 中包含哪些字段,可以使用 kubectl explain 命令:[root@god63 ~]# kubectl explain pods
apiVersion: v1
#属性名:属性值;
v1 表示我们定义的 pod 属于 k8s 哪个 api 的版本,一般 apiversion 后面的值的格式是
group/version,如果 group 省略,表示的是核心组,那么 v1 就是核心组上的资源。
#查看 k8s 中有哪些 api 版本[root@xuegod63 ~]# kubectl api-versions
上面可以显示 api 的群组和版本,v1 是核心群组,同一个组有很多版本,为什么分组进行管理:如
果不分组,那么更新一个,所有的都更新,分组以后,某一个组改变了,只需要改变一个,其他不需要改
变;分组之后同一个群组的不通版本号也能并存;因为 pod 是最核心的资源,因此属于核心群组 v1。控
制器 deployment,replicatset 都属于应用程序广义的核心资源,属于 apps/v1 这个群组
注:apps 有下面三个版本,v1 是表示测试通过的稳定版本,beta1 是公测版本,不稳定,有可能
被改变,alpha 内测版本,不能使用
apps/v1
apps/v1beta1
apps/v1beta2
kind: Pod
资源类别,告诉我们要创建的资源是什么?如创建一个 pod 还是 service 还是 deployment,
这些不能随意定义,一般都是内建的或者用户自定义的,需要按照固定语法格式自定义。
metadata
元数据,元数据下面可以定义资源的名字和所属的名称空间,以及资源的标签,通过 kubectl
explain 可以查看元数据下的所有子字段:
[root@god63 ~]# kubectl explain pods.metadata
KIND: Pod
VERSION: v1
RESOURCE: metadata
DESCRIPTION:
Standard object's metadata. More info:https://git.k8s.io/community/contributors/devel/sig-architecture/api-
conventions.md#metadata
ObjectMeta is metadata that all persisted resources must have, whichincludes all objects users must create.
FIELDS: #这里我只是列举了一些常用的字段annotations <map[string]string> #资源的注解
Annotations is an unstructured key value map stored with a resource that
may be set by external tools to store and retrieve arbitrary metadata. They
are not queryable and should be preserved when modifying objects. More
info: http://kubernetes.io/docs/user-guide/annotations
labels <map[string]string> #标签,给定义的资源打个标签
Map of string keys and values that can be used to organize and categorize
(scope and select) objects. May match selectors of replication controllers
and services. More info: http://kubernetes.io/docs/user-guide/labels
name <string> #名字,给定义的资源起个名字
Name must be unique within a namespace. Is required when creating
resources, although some resources may allow a client to request the
generation of an appropriate name automatically. Name is primarily intended
for creation idempotence and configuration definition. Cannot be updated.
More info: http://kubernetes.io/docs/user-guide/identifiers#names
namespace <string> #创建资源的时候分配的名称空间
Namespace defines the space within which each name must be unique. An
spec(非常重要的字段)
spec 中需要嵌套很多二级字段和三级字段,不同的资源类型 spec 需要嵌套的字段各不相同
如果某个字段的标题属性是 require(必选字段),剩下的都是可选字段,我们系统会给它赋予
默认值,不同的资源类型 spec 值是各不相同的,它是用户定义的期望状态。[root@god63 ~]# kubectl explain pods.spec
资源清单编写
#查看pod资源包含哪些字段
[root@god63 ~]#kubectl explain pods
KIND: Pod
VERSION: v1
DESCRIPTION:
Pod is a collection of containers that canrun on a host. This resource is
created by clients and scheduled ontohosts.
FIELDS:
apiVersion
kind
metadata #object表示对象,那么说明里面会嵌套很多字段
spec
status #状态,不需要我们定义
#查看pod资源中metadata字段如何定义
[root@god63 ~]#kubectl explain pods.metadata
KIND: Pod
VERSION: v1
RESOURCE: metadata
DESCRIPTION:
Standard object's metadata. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
ObjectMeta is metadata that all persistedresources must have, which
includes all objects users must create.
FIELDS:
annotations #map表示由众多的key/value组成一个json数组
clusterName
creationTimestamp
deletionGracePeriodSeconds
deletionTimestamp
finalizers <[]string>
generateName
generation
labels
managedFields <[]Object>#对象列表,每个对象可以有多个字段,这个对象也可以有多个
name
namespace
ownerReferences <[]Object>
resourceVersion
selfLink
uid
从0开始创建一个pod资源
kubectl explain pods
#创建一个demo-pod.yaml文件,写入如下内容
[root@god63 ~]# cat demo-pod.yaml
apiVersion: v1 #pod属于k8s核心组v1
kind: Pod #创建的是一个Pod资源
metadata: #元数据
name: demo-pod #pod名字
namespace: default #pod所属的名称空间
labels:
app: myapp #pod具有的标签
env: dev #pod具有的标签
spec:
containers: #定义一个容器,容器是对象列表,下面可以有多个name
- name: tomcat-pod-java #容器的名字
ports:
- containerPort: 8080
image: tomcat:8.5-jre8-alpine #容器使用的镜像
imagePullPolicy: IfNotPresent
- name: busybox
image: busybox:latest
command: #command是一个列表,定义的时候下面的参数加横线
- "/bin/sh"
- "-c"
- "sleep 3600"
#更新yaml文件
[root@god63 ~]# kubectl apply -f demo-pod.yaml
pod/demo-pod created
#查看刚才创建的pod
[root@god63 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
demo-pod 2/2 Running 0 22s
#查看pod的详细信息
[root@god63 ~]# kubectl describe pods demo-pod
Name: demo-pod
Namespace: default
…
Containers:
tomcat-pod-java:
Image: tomcat:8.5-jre8-alpine
Port: 8080/TCP
Host Port: 0/TCP
busybox:
Image: busybox:latest
Port: <none>
Host Port: <none>
Command:
/bin/sh
-c
sleep 3600
…
Normal Scheduled 78s default-scheduler Successfully assigned default/demo-pod to node1
Normal Pulled 78s kubelet Container image "tomcat:8.5-jre8-alpine" already present on machine
Normal Created 78s kubelet Created container tomcat-pod-java
Normal Started 77s kubelet Started container tomcat-pod-java
Normal Pulling 77s kubelet Pulling image "busybox:latest"
Normal Pulled 74s kubelet Successfully pulled image "busybox:latest" in 3.717087525s
Normal Created 74s kubelet Created container busybox
Normal Started 74s kubelet Started container busybox
#查看pod中busybox容器的日志
[root@god63 ~]# kubectl logs demo-pod -c busybox
#以交互式形式进入到pod中的busybox容器
[root@god63 ~]# kubectl exec -it demo-pod -c busybox -- /bin/sh
/ # exit
#删除demo-pod.yaml中定义的资源
方法一:
[root@god63 ~]# kubectl delete -f demo-pod.yaml
pod "demo-pod" deleted
方法二:
[root@god63 ~]# kubectl delete pods demo-pod
8.4 pod.spec字段详解
[root@god63 ~]# kubectl explain pods.spec
FIELDS:
containers <[]Object> -required-
List of containers belonging to the pod. Containers cannot currently be
added or removed. There must be at least one container in a Pod. Cannot be
updated.
#containers是一个对象列表,下面的值是由多个key:value键值对组成的
[root@god63 ~]# kubectl explain pods.spec.containers
KIND: Pod
VERSION: v1
RESOURCE: containers <[]Object>
DESCRIPTION:
List of containers belonging to the pod. Containers cannot currently be
added or removed. There must be at least one container in a Pod. Cannot be
updated.
A single application container that you want to run within a pod.
FIELDS:
args <[]string>
command <[]string>
image <string>
imagePullPolicy <string>
Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always
if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated.
More info:
https://kubernetes.io/docs/concepts/containers/images#updating-images
name <string> -required-
#imagePullPolicy: <string> #镜像拉取策略,有下面几种方式:
Always,Never,IfNotPresent
Always:无论本地有没有镜像,都是是到docker hub仓库下载
Never:本地有镜像就用本地的,本地没有镜像就等着,不从仓库下载
IfNotPresent:本地有镜像,就使用本地的,本地没有镜像就从仓库下载
[root@god63 ~]# kubectl explain pods.spec.containers.ports
KIND: Pod
VERSION: v1
RESOURCE: ports <[]Object>
DESCRIPTION:
FIELDS:
containerPort <integer> -required-
hostIP <string>
hostPort <integer>
name <string>
protocol <string>
#ports是一个对象列表,定义容器内需要暴露的端口时,可以是多个,而且每一个端口还应该有多个属性来定义,比如说端口的名称(给端口起个名字,接下来可以根据端口名称去引用它)。端口号,协议,暴露端口号只是给系统添加一个额外信息的,并不一定是真的暴露;如果我们定义这个字段,客户可以知道我们的应用程序对外提供的端口是哪些,就算是这没指定暴露的端口,pod中的应用程序的端口也是暴露出去的。
在ports字段下可以配置上面几个端口,一般我们只需要指定containerPort(容器端口)即可;有必要的话也可以指定name(由字母,数字或者下划线组成);protocol(默认协议是tcp);hostIP(绑定节点ip,这个一般不需要指定,因为pod调度到哪个节点我们不确定的,就没法指定节点ip,如果要指定,只需要指定0.0.0.0这个ip即可)
举例子说明:
ports:
- name: http
containerPort:80
- name:htpps
containerPort:443
#ports是一个列表对象,下面可以有多个值,下面的值不需要缩进,前面加上-即可
[root@god63 ~]# kubectl explain pods.spec.containers.command
KIND: Pod
VERSION: v1
FIELD: command <[]string>
[root@god63 ~]# kubectl explain pods.spec.containers.args
KIND: Pod
VERSION: v1
FIELD: args <[]string>
command :表示要运行的程序,但是不提供/bin/sh命令行,需要我们自己指定,如果只定义了command,而没有定义args,那么只运行command后面的指令,而不运行entrypoint,cmd等指令;如果没有提供command,而我们docker镜像在制作时有entrypoint指定,那么它就会运行镜像里的entrypoint的命令;
command:
- "/bin/sh" #这个就是自己指定的/bin/sh
- "-c"
- "sleep 3600"
args:表示传递参数的,如果没有给args,而我们镜像中又有entrypoint指令,又有cmd指令,那么镜像自己cmd指令给定的参数将作为参数传递给entrypoint后面的代码;如果给定了args,那么我们镜像中cmd字段后面所指定的参数将不再作为参数传递,而传递的参数是args中所定义的内容。
https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container
这个链接里列举了command和args的关系,相关的关系图如下:
1:如果只定义了镜像里的entrypoint,镜像里的cmd,那么我们运行pod容器时使用的命令和参数就是镜像里的命令和参数
2:如果我们定义了容器的command,那么我们pod使用的命令就是command后面的命令
3:如果我们只定义了args参数,那么我们pod使用的命令就是镜像的entrypoint+args参数
4:如果我们定义了command的命令和args的参数,那么我们运行pod时使用的就是command命令+args参数
8.5 label标签使用技巧
8.5.1 pod资源标签使用技巧
在k8s之上,每一种资源都可以有一个标签,现实中用到的pod数量可能越来越多,我们期望能够分类进行管理,最简单和直接的效果就是把pod分成很多不同的小组,无论对于开发还是运维来讲都能显著提高管理效率,更何况我们控制器,我们service资源也需要使用标签来识别它们所管控或关联到的资源,当我们给pod或者任何资源设定标签时,都可以使用标签查看,删除等对其执行相应的管理操作;简单来说所谓的标签就是附加在我们所对应的对象之上的键值对,一个资源之上可以存在多个标签,每个标签都是键值对,而且每个标签都可以被标签选择器进行匹配度检查从而完成资源挑选,通常情况下一个资源对象可使用多个标签,反之,一个标签也可以被添加到多个资源对像上;标签既可以在资源对象创建的时候指定,也可以在资源对象创建之后使用命令来进行管理,这个管理既包括添加,也包括删除,还包括修改;实践中我们通常给资源附加不同维度的标签,来进行不同维度的管理,比方说labels下面的标签app: myapp 用来指明当前的应用程序(可能是nginx,tomcat,http,mysql,redis等)是什么,我们也可以分层打标签,如前端frontend,后端backend,开发环境dev等;也可以对版本打标签。
labels:
app: myapp
tier: frontend
标签:
key: value (key和value最多63个字符,key只能使用字母,数字,下划线组成,只能以字母或数字开头,不能为空值;value可以为空,也是只能以字母或数字开头和结尾,中间可使用字母,数字,下划线)
我们在查看pod或任何类型资源时,也可以直接指定标签选择器来选择能显示哪些标签的
查看所有pod资源对象的标签
[root@god63 ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
my-nginx-5b56ccd65f-thnqt 1/1 Running 0 119m pod-template-hash=5b56ccd65f,run=my-nginx
my-nginx-5b56ccd65f-wd6wv 1/1 Running 0 117m pod-template-hash=5b56ccd65f,run=my-nginx
查看所有资源对象下拥有run这个标签的标签值
[root@god63 ~]# kubectl get pods -L run
NAME READY STATUS RESTARTS AGE RUN
my-nginx-5b56ccd65f-thnqt 1/1 Running 0 121m my-nginx
my-nginx-5b56ccd65f-wd6wv 1/1 Running 0 119m my-nginx
nfs-provisioner-7d57c9896d-zdst9 1/1 Running 1 22h
storage-0 1/1 Running 0 22h
storage-1 1/1 Running 0 22h
查看拥有run这个标签的pod资源对象
[root@god63 ~]# kubectl get pods -l run
NAME READY STATUS RESTARTS AGE
my-nginx-5b56ccd65f-thnqt 1/1 Running 0 123m
my-nginx-5b56ccd65f-wd6wv 1/1 Running 0 121m
查看拥有run这个标签的资源对象,并且把标签显示出来
[root@god63 ~]# kubectl get pods -l run --show-labels
NAME READY STATUS RESTARTS AGE LABELS
my-nginx-5b56ccd65f-thnqt 1/1 Running 0 128m pod-template-hash=5b56ccd65f,run=my-nginx
my-nginx-5b56ccd65f-wd6wv 1/1 Running 0 126m pod-template-hash=5b56ccd65f,run=my-nginx
想修改资源的标签,比方说想给my-nginx-5b56ccd65f-thnqt加上个release标签
给资源对象打标签要使用label命令,指定给某个类型下的某个资源打标签,key/value可以是多个,因此在my-nginx-5b56ccd65f-thnqt这个资源下再打个标签release,用如下命令
[root@god63 ~]# kubectl label pods my-nginx-5b56ccd65f-thnqt release=canary
pod/my-nginx-5b56ccd65f-thnqt labeled
查看标签是否打成功:
[root@god63 ~]# kubectl get pods -l release --show-labels
NAME READY STATUS RESTARTS AGE LABELS
my-nginx-5b56ccd65f-thnqt 1/1 Running 0 131m pod-template-hash=5b56ccd65f,release=canary,run=my-nginx
修改标签,把release=canary改成release=stable
kubectl label pods my-nginx-5b56ccd65f-thnqt release=stable --overwrite
查看标签,显示如下:
[root@god63 ~]# kubectl get pods -l release --show-labels
NAME READY STATUS RESTARTS AGE LABELS
my-nginx-5b56ccd65f-thnqt 1/1 Running 0 132m pod-template-hash=5b56ccd65f,release=stable,run=my-nginx
查看既有release标签,又有run标签的pod资源有哪些
kubectl get pods -l release,run
[root@god63 ~]# kubectl get pods -l release,run
NAME READY STATUS RESTARTS AGE
my-nginx-5b56ccd65f-thnqt 1/1 Running 0 133m
8.5.2 给node节点打标签
能使用标签的不只是pod,node节点也可以打标签:
查看nodes节点的标签
[root@god63 ~]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
master1 Ready master 69d v1.19.6 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master1,kubernetes.io/os=linux,node-role.kubernetes.io/master=
node1 Ready <none> 69d v1.19.6 a=b,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node1,kubernetes.io/os=linux
给node节点打标签
[root@god63 ~]# kubectl label nodes node1 xuegod=IT
node/node1 labeled
查看node节点标签
[root@god63 ~]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
master1 Ready master 69d v1.19.6 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master1,kubernetes.io/os=linux,node-role.kubernetes.io/master=
node1 Ready <none> 69d v1.19.6 a=b,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node1,kubernetes.io/os=linux,xuegod=IT
8.6 pod资源清单详细解读
apiVersion: v1 #版本号,例如v1
kind: Pod #资源类型,如Pod
metadata: #元数据
name: string # Pod名字
namespace: string # Pod所属的命名空间
labels: #自定义标签
- name: string #自定义标签名字
annotations: #自定义注释列表
- name: string
spec: # Pod中容器的详细定义
containers: # Pod中容器列表
- name: string #容器名称
image: string #容器的镜像名称
imagePullPolicy: [Always | Never | IfNotPresent] #获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
command: [string] #容器的启动命令列表,如不指定,使用打包时使用的启动命令
args: [string] #容器的启动命令参数列表
workingDir: string #容器的工作目录
volumeMounts: #挂载到容器内部的存储卷配置
- name: string #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
mountPath: string #存储卷在容器内mount的绝对路径,应少于512字符
readOnly: boolean #是否为只读模式
ports: #需要暴露的端口库号
- name: string #端口号名称
containerPort: int #容器需要监听的端口号
hostPort: int #容器所在主机需要监听的端口号,默认与Container相同
protocol: string #端口协议,支持TCP和UDP,默认TCP
env: #容器运行前需设置的环境变量列表
- name: string #环境变量名称
value: string #环境变量的值
resources: #资源限制和请求的设置
limits: #资源限制的设置
cpu: string #cpu的限制,单位为core数
memory: string #内存限制,单位可以为Mib/Gib
requests: #资源请求的设置
cpu: string #cpu请求,容器启动的初始可用数量
memory: string #内存请求,容器启动的初始可用内存
livenessProbe: #对Pod内个容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
exec: #对Pod容器内检查方式设置为exec方式
command: [string] #exec方式需要制定的命令或脚本
httpGet: #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
path: string
port: number
host: string
scheme: string
HttpHeaders:
- name: string
value: string
tcpSocket: #对Pod内个容器健康检查方式设置为tcpSocket方式
port: number
initialDelaySeconds: 0 #容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 0 #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds: 0 #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold: 0
failureThreshold: 0
securityContext:
privileged:false
restartPolicy: [Always | Never | OnFailure]#Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
nodeSelector: obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定
imagePullSecrets: #Pull镜像时使用的secret名称,以key:secretkey格式指定
- name: string
hostNetwork:false #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
volumes: #在该pod上定义共享存储卷列表
- name: string #共享存储卷名称 (volumes类型有很多种)
emptyDir: {} #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
hostPath: string #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
path: string #Pod所在宿主机的目录,将被用于同期中mount的目录
secret: #类型为secret的存储卷,挂载集群与定义的secre对象到容器内部
scretname: string
items:
- key: string
path: string
configMap: #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
name: string
items:
- key: string
path: string