对象管理
本节介绍对象的相关概念和管理机制。只有了解了这些机制,我们才能轻松的对k8s资源进行编排。
1 对象 Object
k8s对象
即是对应用程序、工作负载、存储、网络等资源的抽象表示,如image、pod、node、volume、service
等。集群中每个对象都有一个名称
来标识其在同类资源中
的唯一性
,同时拥有一个UID
来标识其在整个集群中
的唯一性
。
由于许多资源类型需要用作DNS子域名的名称,所以,对象命名需遵守RFC 1035定义的DNS标签标准。
对象命名规范
- 最多 63 个字符。
- 只能包含
小写
字母、数字
、‘-
’。有些资源名称也可以使用'
.'
- 必须以
字母
开头。- 必须以
字母
、数字
结尾。
2 命名空间 namespace
通过命名空间,将资源分组,分组间相互隔离。
同一命名空间
中的资源名称
需要唯一
。k8s会为所有命名空间
设置一个不可变的标签kubernetes.io/metadata.name: "<namespace_name>"
,标签值是命名空间
的名称,可使用标签运算符
快速定位到命名空间<namespace_name>
。
绝大多数的k8s对象都属于某一命名空间,但是也有一些资源(如:命名空间本身,节点,持久化卷
)不属于任何命名空间。
2.1 查看命名空间中的资源
# 查看 位于命名空间中的资源
kubectl api-resources --namespaced=true
# 查看 不在命名空间中的资源
kubectl api-resources --namespaced=false
2.2 创建命名空间
# Source: /myworkdir/myns.yaml
apiVersion: v1
kind: NameSpace
metadata:
name: myns
# 通过资源描述文件创建命名空间
kubectl create -f /myworkdir/myns.yaml
# 通过命令创建命名空间
kubectl create namespace myns
# 查看/删除命名空间
kubectl get ns
kubectl delete namespace myns
2.3 设置当前默认的命名空间
kubectl config set-context --current --namespace=<名字空间名称>
# 验证
kubectl config view --minify | grep namespace:
2.4 DNS解析
当创建一个Service时,k8s会创建一条DNS记录,格式为
<服务名称>.<名字空间名称>.svc.cluster.local
。
- 如果容器只使用
<服务名称>
访问Service,它会被解析到本地命名空间
中的Service。- 如果你想跨
命名空间
访问Service,则需要使用完全限定域名
(FQDN)。命名空间
名称必须满足RFC 1123 DNS名称规范。
3 标签 labels
标签
labels
,顾名思义就是给k8s对象做个标记,它是附加到k8s对象(如pod
)上的键值对
,用来标识对象属性。标签可以在创建时附加到对象上,也可以在创建后随时添加和修改。k8s中的对象标签
与名称
和UID
不同,不具有唯一性,主要用来分组和筛选。
3.1 标签键:
由前缀
+名称
两段组成,用斜杠/
分割,前缀是可选的,名称是必需的。如kubernetes.io/master
。
前缀段
的使用规范:
- 如果指定前缀,则必须是DNS子域,由’
.
'和一系列DNS标签组成,最多253个字符。前缀kubernetes.io/
和k8s.io/
是为k8s核心组件保留的。- 如果省略前缀,则认为标签键是用户私有的。
名称段
的命名规范:
- 最多 63 个字符。
- 只能包含字母、
数字
,破折号’-
‘、下划线’_
‘、点’.
'。- 以字母数字字符([a-z0-9A-Z])开头和结尾。
3.2 标签值:
- 可以为空。最多 63 个字符。
- 以字母数字字符([a-z0-9A-Z])开头和结尾。
- 只能包含字母、
数字
,破折号’-
‘、下划线’_
‘、点’.
'。
3.3 标签语法
# json格式
"metadata": {
"labels": {
"key1" : "value1",
"key2" : "value2"
}
}
# yaml格式
metadata:
labels:
key1: value1
key2: value2
3.4 示例:
apiVersion: v1
kind: Pod # 资源类型
metadata:
name: label-demo # 定义资源名称,在同类资源中唯一。
labels:
environment: production # 定义私有标签environment:production
app: nginx # 定义私有标签app:nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2 # 引用镜像版本。
ports:
- containerPort: 80
4 标签选择器 selector
一般我们会给
一批资源对象
打上相同的标签,然后通过标签选择器
进行匹配,选择满足匹配条件
的一组资源对象。标签选择器
的匹配方式可分为基于等值
和基于集合
两种方式。这两种方式既可以在REST客户端 kubeclt
中使用,也可以在k8s对象
中引用。
4.1 在REST客户端 kubeclt
中使用
# 基于等值:支持'='、'=='和'!='
kubectl get pods -l environment=production,tier=frontend # 查找标签为environment=production,tier=frontend的pod。
kubectl get pods -l environment!=production,tier==frontend
# 基于集合:支持'in' 'notin'
kubectl get pods -l 'environment in (production),tier in (frontend)'
kubectl get pods -l 'environment in (production, qa)' # 查看标签environment的值在(production, qa)中的pod。
kubectl get pods -l 'environment,environment notin (frontend)'
# 混合使用
kubectl get pods -l 'partition in (customerA, customerB),environment!=qa'
4.2 在k8s对象
中引用
# 基于等值
---
"selector": { # json格式
"component" : "redis",
"type": "Cluster"
}
selector: # yaml格式
component: redis
type: Cluster
nodeSelector: # 节点选择器 spec.nodeSelector
accelerator: nvidia-tesla-p100 # 选择带有该标签的节点。
# 基于集合
---
selector:
# 集合形式,由{key,value}对组成的映射。类似于matchExpressions的In操作。
matchLabels:
component: redis
# 列表形式,支持运算符:In NotIn Exists DoesNotExist。
matchExpressions:
- { key: tier, operator: In, values: [cache] }
- { key: environment, operator: NotIn, values: [dev] }
4.3 根据标签查找
# 使用-L key查看所有具有key标签的pod。
$ kubectl get pods -Lapp -Ltier -Lrole
NAME READY STATUS RESTARTS AGE APP TIER ROLE
guestbook-fe-4nlpb 1/1 Running 0 1m guestbook frontend <none>
guestbook-redis-master-5pg3b 1/1 Running 0 1m guestbook backend master
guestbook-redis-replica-2q2yf 1/1 Running 0 1m guestbook backend replica
guestbook-redis-replica-qgazl 1/1 Running 0 1m guestbook backend replica
my-nginx-divi2 1/1 Running 0 29m nginx <none> <none>
# 指定标签键值
$ kubectl get pods -lapp=guestbook,role=replica
NAME READY STATUS RESTARTS AGE
guestbook-redis-replica-2q2yf 1/1 Running 0 3m
guestbook-redis-replica-qgazl 1/1 Running 0 3m
4.4 更新标签
# 根据"app=nginx"过滤所有的Pod,然后用打上"tier=fe"标签
$ kubectl label pods -l app=nginx tier=fe
pod/my-nginx-2035384211-j5fhi labeled
pod/my-nginx-2035384211-u2c7e labeled
# 查看刚设置了标签的Pod
$ kubectl get pods -l app=nginx -L tier # -L 表示查看所有键为tier的pod。
NAME READY STATUS RESTARTS AGE TIER
my-nginx-2035384211-j5fhi 1/1 Running 0 23m fe
my-nginx-2035384211-u2c7e 1/1 Running 0 23m fe
5 注解 annotations标签
和注解
都是为k8s对象
附加元数据。但是,标签
可以用来选择对象
和查找
满足某些条件的对象集合。注解
附加的是非标识
元数据,不用于标识
和选择
对象。
5.1 注解语法
注解
和标签
一样,也是键/值对
。
注解的键
也由前缀
+名称
两段组成,用斜杠/
分割,前缀是可选的,名称是必需的。键的命名规范同标签的键。注解的值
大小没有限制,结构没有规定,能够包含标签不允许的字符,客户端程序(例如工具和库)能够获取这些元数据信息,然后进行加工和处理。
# json格式
"metadata": {
"annotations": {
"key1" : "value1",
"key2" : "value2"
}
# yaml格式
metadata:
annotations:
key1: value1
key2: value2
5.2 示例
apiVersion: v1
kind: Pod
metadata:
name: annotations-demo
annotations:
imageregistry: "https://hub.docker.com/" # 定义注解内容
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
6 字段选择器
字段选择器常用在
REST客户端
中,根据字段值筛选k8s对象
。支持的字段有metadata.name、metadata.namespace、status.phase
等,使用不被支持的字段时选择器会报错。
# 筛选出status.phase字段值为Running的所有Pod
$ kubectl get pods --field-selector status.phase=Running
# 使用不支持的字段,选择器报错
$ kubectl get ingress --field-selector foo.bar=baz
Error from server (BadRequest): Unable to find "ingresses" that match label selector "", field selector "foo.bar=baz": "foo.bar" is not a known field selector: only "metadata.name", "metadata.namespace"
# 支持'='、'=='和'!='
$ kubectl get services --all-namespaces --field-selector metadata.namespace!=default # 筛选非defualt命名空间的svc
# 链式选择器,同标签选择器一样,可以使用逗号分隔的列表组成一个选择链。
kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always
# 查看多种资源类型
kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default
7 属主与附属机制
7.1 基本概念
一些
对象
是其他对象
的属主
,称为属主对象
。具有属主
的对象
是属主对象
的附属
,简称附属对象
。例如,ReplicaSet
是一组Pod
的属主
,Pod
是ReplicaSet
的附属
。
7.2 属主引用
附属对象
有一个metadata.ownerReferences
字段,用来引用
其属主对象
,这种引用方式就称为属主引用
。属主引用
定义了对象间的附属关系
,k8s对象
大多都是通过属主引用
链接到彼此的。metadata.ownerReferences
字段中,包含在同一个命名空间
下的属主对象名称
和属主对象UID
。通常,k8s会自动
给附属对象
设置属主引用
值,这些对象包含ReplicaSet、DaemonSet、Deployment、Job、CronJob、ReplicationController等
。当然,也可以手动修改该字段的值。
7.3 垃圾回收
k8s会检查并删除不再拥有
属主引用
的附属对象
。例如,属主对象ReplicaSet
被删除之后留下来的附属对象Pod
,将会被k8s自动清理。
7.4 级联删除
附属对象
还有一个ownerReferences.blockOwnerDeletion
字段(布尔值
),用来控制附属对象
是否阻止属主对象
被回收删除。k8s会自动将该字段设置为true,也可手动更改。当删除一个附属对象
时,k8s将根据该字段的值判断是否删除该对象的属主对象
,默认情况下,该字段为true,表示不删除属主对象
。比如,默认情况下,删除附属对象Pod
时,属主对象ReplicaSet
不会被删除。
7.5 与标签选择器不同
属主引用
定义了对象间的附属关系
,而标签选择器
只是定义了对象间的调用关系
,这种调用关系
是松耦合的
,属主引用
则是对象间的强绑定关系
。例如,Service
会通过标签选择器
选择满足条件的EndpointSlice对象
,同时,每个EndpointSlice对象
都有一个属主引用
属性,指定了其附属于哪些Service。
Pod原理
- 工作负载Pod
概述:
Pod
是 k8s 系统中可以创建和管理的最小单元
,k8s 不会直接处理容器
,而是通过Pod
管理容器
,通过控制器
管理Pod
,这些控制器
有ReplicaSet、Job、CronJob、Deployment、StatefulSet、DaemonSet等
。
1.1 Pod
结构
Pod
中都包含一个Infra容器
,至少一个应用容器
,以及零或多个init容器
和sidecar容器
,除init容器
外,它们共享存储
和网络资源
。
1.2 Infra/Pause容器
基础设施容器
Infra容器
创建完成后就会进入Pause状态
,所以也叫做Pause容器
。它是Pod
的根容器,Pod中其他的容器都会被加入到Pause
容器中,成为它的子容器。容器技术参见我的另一篇文章:《Docker企业级应用(架构原理+工作流)》
容器之间是通过
命名空间
进行隔离的,为了让Pod
中的容器共享资源,就需要打破命名空间
的隔离。所以,在Pod
初始化时会首先创建一个Infra容器
,然后再将创建的应用容器
加入到Infra容器
中,这样它们就共享同一套资源了。
容器运行时
可以通过创建父子容器的方式,控制容器组间共享级别。即先创建一个父容器Infra,然后在创建子容器myapp时,指定需要加入的父容器Infra,如docker run -d --name myapp --pip=container:InfraId --net=container:InfraId --ipc=container:InfraId myImage
。
1.2 应用容器及回调
用户的
应用程序
就运行在这些应用容器
中。此外,我们可以为应用容器设置回调函数,在容器启动和终止时操作。通过spec.containers.lifecycle字段
定义回调函数PostStart和PreStop
。回调函数的作用:
- PostStart
在容器被创建之后立即被执行。但是,不能保证回调会在容器入口点(ENTRYPOINT)之前执行。 没有参数传递给处理程序。- PreStop
在容器因API 请求
或者管理事件
(诸如存活态探针、启动探针失败、资源抢占、资源竞争
等) 而被终止之前,此回调会被调用。 如果容器已经处于已终止或者已完成状态,则对 preStop回调的调用将失败。停止容器的TERM 信号
被发出之前,回调必须执行结束。Pod 的终止宽限周期在PreStop 回调
被执行之前即开始计数, 所以无论回调函数的执行结果如何,容器最终都会在 Pod 的终止宽限期内被终止。 没有参数会被传递给处理程序。
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
spec:
dnsPolicy: Default
containers:
- name: myapp-container
image: busybox:1.28
lifecycle:
postStart:
exec:
# command: ["/bin/sh", "-c", "do_postStart.sh"]
command: ["/bin/sh", "-c", "echo Hello postStart> /usr/share/message"]
preStop:
exec:
# command: ["/bin/sh", "-c", "do_preStop.sh"]
command: ["/bin/sh","-c","while killall -0 myapp; do sleep 1; done"]
1.3 Init容器
Pod中可以有多个
init容器
,init容器
会在应用容器
启动之前,依次逐个运行,每个init容器
运行成功后才能执行下一个init容器
。当所有的init容器
都运行成功后,才会初始化应用容器
。当init容器运行完成后,它的生命周期也就结束了,然后被k8s回收。
- 与普通容器不同:
Init容器不支持lifecycle、livenessProbe、readinessProbe或者startupProbe
字段,Init容器必须在Pod准备就绪之前完成启动。Init 容器与应用容器
共享资源(CPU、内存、网络
),但不直接与主应用容器进行交互。不过这些容器可以使用共享卷进行数据交换。- 用途:
1.init容器拥有独立的文件系统视图,可以访问应用容器不能访问的Secret。
2.init容器在应用容器启动之前运行完成,所以可以使用init容器完成一些先决条件,等到前置条件满足才会运行应用容器。
3.方便运行应用程序中不能有的工具,如编译工具、sed、awk等。
# Source: /myworkdir/mypod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app.kubernetes.io/name: MyApp
spec:
# 应用容器定义
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
# init容器定义
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
# init容器定义
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
1.4 Sidecar容器
Sidecar容器
是与应用容器
在同一个 Pod 中运行的辅助容器。这些容器通过提供额外的服务或功能(如日志记录、监控、安全性或数据同步)来增强或扩展应用容器
的功能, 而无需直接修改主应用代码
。
- 与常规容器不同:
1.Sidecar容器
具有独立的生命周期。它们可以独立于应用容器
启动、停止和重启。 这意味着你可以更新、扩展或维护Sidecar容器
,而不影响主应用。
2.可以直接与主应用容器进行交互,共享相同的网络命名空间、文件系统和环境变量。- 与Init容器不同:
1.init容器运行完成后就是被k8s回收,而Sidecar容器有独立的生命周期。
2.sidecar容器支持lifecycle、livenessProbe、readinessProbe或者startupProbe
字段。
apiVersion: apps/v1
kind: Pod
metadata:
name: myapp
labels:
app: myapp
spec:
# 应用容器定义
containers:
- name: myapp
image: alpine:latest
command: ['sh', '-c', 'echo "logging" > /opt/logs.txt']
volumeMounts:
- name: data
mountPath: /opt
# 通过initContainers字段定义Sidecar容器
initContainers:
- name: logshipper
image: alpine:latest
restartPolicy: Always # Pod整个生命周期
command: ['sh', '-c', 'tail /opt/logs.txt'] # tail命令保持进程不退出。
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
emptyDir: {}
1.5 Pod生命周期
Pod在其生命周期内只能被调度一次,一旦Pod被调度到某个节点上,将一直运行到被终止。每个Pod都有一个唯一的UID值。Pod自身不具备自愈能力,如果Pod所在节点出现故障,Pod会被删除。所以,k8s使用
控制器
来管理这些相对临时性的Pod。
Pod在其生命周期中所处的状态:文章来源:https://www.toymoban.com/news/detail-851132.html
Pod状态值 | 描述 |
---|---|
Pending | Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。 |
ContainerCreating | Pod 已经绑定到了某个节点。正在创建容器。 |
Running | Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。 |
Succeeded | Pod 中的所有容器都已成功终止,并且不会再重启。 |
Failed | Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。 |
Unknown | 因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。 |
1.6 外部访问Pod容器的应用程序文章来源地址https://www.toymoban.com/news/detail-851132.html
curl -ivh -k https://${POD_IP}:${CONTAINER_PORT}/path -w %{http_code}
到了这里,关于k8s企业级应用系列(二):对象管理及Pod原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!