0%

一周撸完K8S基础概念Day2

博客:cbb777.fun

全平台账号:安妮的心动录

github: https://github.com/anneheartrecord

下文中我说的可能对,也可能不对,鉴于笔者水平有限,请君自辨。有问题欢迎大家找我讨论

K8S对象

什么是K8S对象

在k8s中,对象是持久化的实体,k8s使用这些实体去表示整个集群的状态,它们描述了以下信息

  • 哪些容器化应用正在运行
  • 可以被应用使用的资源
  • 关于应用运行时行为的策略,比如重启策略、升级策略以及容错策略

k8s对象是一种”意向表达(Record of Intent)”,一旦创建该对象,K8S系统将不断工作以确保该对象存在。最终系统应该达到K8S所谓的期望状态
我们操作K8S对象需要用到K8S的API,可以直接使用kubectl命令行,也可以在程序中使用客户端库,直接调用K8S API

对象规约(spec)与状态(status)

几乎每个Kubernetes对象都包含两个嵌套的字段,它们负责管理对象的配置,分别是specstatus
对于具有spec的对象,你必须在创建对象时设置其内容,描述希望对象所具有的特征:期望状态(desired state)
status描述了对象的当前状态(current state),它是由k8s系统和组件设置并更新的。
在任何时刻,控制平面都在管理对象的实际状态,以使其达成期望状态

描述K8S对象

创建K8S对象的时候必须提供对象的spec用来描述对象的期望状态,以及对象的 一些基本信息(name kind),当时用API创建独享的时候,API在请求主体中应该包含JSON格式的数据,大部分情况下我们提供的是.yaml文件来为kubectl提供这些信息,当kubectl发起API请求的时候,这些信息会被转换成JSON格式

下面是一个.yaml的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
apiVersion: apps/v1

kind: Deployment

metadata:

name: nginx-deployment

spec:

selector:

matchLabels:

app: nginx

replicas: 2 # 告知 Deployment 运行 2 个与该模板匹配的 Pod

template:

metadata:

labels:

app: nginx

spec:

containers:

- name: nginx

image: nginx:1.14.2

ports:

- containerPort: 80

除了通过.yaml这种声明式API的方式创建Deployment, 也可以通过kubectl命令行的方式,通过命令将.yaml文件作为参数进行创建,下面是一个栗子

1
2
3
4
kubectl apply -f https://k8s.io/examples/application/deployment.yaml //应用某yaml文件  

deployment.apps/nginx-deployment created // output

必需字段
在创建K8S对象中使用的.yaml文件里,需要配置的字段如下

  • apiVersion 创建对象使用的K8S API的版本
  • kind 想要创建的对象类型
  • metadata 帮助唯一标识对象的一些数据 比如name uid和可选的namespace
  • spec 所期望的该对象的状态

K8S对象管理

kubectl命令行工具支持多种不同的方式来创建和管理k8s对象,需要注意的是应该只使用一种技术来管理k8s对象,混合和匹配技术作用在同一对象上将会导致未被定义的行为

  • 指令式命令 作用于活跃对象 支持多个写者 难度低
  • 指令式对象配置 作用于单个文件 支持一个写者 难度中等
  • 声明式对象配置 作用于文件目录 支持多个写者 难度高

指令式命令

使用指令式命令时,用户可以在集群中的活动对象上进行操作,用户将操作传递给kubectl命令作为参数或者标志
推荐在开始的时候或者在集群中运行一次性任务使用这种方式,因为它直接作用在活动对象上,所以它不提供以前配置的历史记录
下面是一个创建deployment对象来运行nginx的实例

1
kubectl create deployment nginx --image nginx

指令式对象配置

kubectl命令制定操作,可选标志和至少一个文件名,文件内需要包含YAML或者JSON格式的对象的完整定义
下面是一些栗子

1
2
3
kubectl create -f nginx.yaml //创建配置文件中定义的对象
kubectl delete -f nginx.yaml -f redis.yaml //删除两个配置文件中定义的对象
kubectl replace -f nginx.yaml //覆盖配置文件中定义的对象

声明式对象配置

使用声明式对象配置时,用户对本地存储的对象配置文件进行操作,但是用户未定义要对文件执行的操作,kubectl会自动检测每个文件的创建、更新和删除操作,这使得配置可以在目录上工作,根据目录中配置文件对不同的对象执行不同的操作

1
2
kubectl diff -f configs/ //查看configs目录下所有对象配置文件要进行的更改
kubectl apply -f configs/ //将configs目录下要进行的更改应用

对象名称与ID

集群中的每一个对象都有一个名称来标识其在同类资源中的唯一性
每个K8S对象也有一个UID来标识在整个集群中的唯一性
比如同一个namespace下只能有一个名为abc的pod,但是可以命名一个pod和一个deployment同为abc

名称

是客户端提供的字符串,引用资源URL中的对象,如/api/v1/pods/xxx
某一时刻,只能有一个给定类型的对象具有给定的名称。但是如果删除该对象就可以创建同名的新对象
名称在同一资源的所有API版本中必须是唯一的,这些API资源通过各自的API组、资源类型、命名空间和名称来区分,也就是说API版本在上下文中不相关的
资源命名约束有DNS子域名RFC 1123标签名RFC 1035标签名路径分段名称这四种命名约束

UID

uid是系统生成的字符串,唯一标识对象,在K8S集群中每个生命周期中创建的每个对象都有一个不同的UID

标签与选择算法

标签(Labels)是附加到K8S对象(比如Pod)上的键值对,旨在指定对用户有意义并且相关的对象的标识属性,但不直接对核心系统有语义含义。标签可以用于组织和选择对象的子集,可以在创建时附加到对象,随后可以随便添加和修改,每个对象都可以定义一组键值标签,每个键对于给定的对象必须是唯一的

1
2
3
4
5
6
"metadata": {
"labels": {
"key1" : "value1",
"key2" : "value2"
}
}

标签能够允许用户以松耦合的方式将他们自己的组织结构映射到系统对象,而无需客户端存储这些映射
常见标签

  • “release” : “stable”, “release” : “canary”
  • “environment” : “dev”, “environment” : “qa”, “environment” : “production”
  • “tier” : “frontend”, “tier” : “backend”, “tier” : “cache”
  • “partition” : “customerA”, “partition” : “customerB”
  • “track” : “daily”, “track” : “weekly”

下面是一个lables带有enviroment和app两个标签的pod

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Pod
metadata:
name: label-demo
labels:
environment: production
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80

标签选择算符
与名称和UID不同的是,标签不支持唯一性,通常我们希望许多对象携带相同的标签
通过标签选择算符,客户端/用户可以识别一组对象
API目前支持两种类型的选择算符:等值和集合

等值支持三个运算符 分别是 = == != 前两者表示相等,含义相同,后者表示不相等
例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
environment = production  //environment label等于xx 
tier != fronted // tier label != xx

//pod选择accelerator = nvidia
apiVersion: v1
kind: Pod
metadata:
name: cuda-test
spec:
containers:
- name: cuda-test
image: "registry.k8s.io/cuda-vector-add:v0.1"
resources:
limits:
nvidia.com/gpu: 1
nodeSelector:
accelerator: nvidia-tesla-p100

基于集合的标签允许通过一组值来过滤间 支持三种操作符 in notin 和 exists

1
2
3
4
environment in (a,b) //env = a 或 b 
tirer notin (a,b) // tire != a & tirer != b
partition //包含了partition标签
!partition //没包含partition标签

API

1
2
kubectl get pods -l environment=production,tier=frontend 
kubectl get pods -l 'environment in (production),tier in (frontend)'

命名空间

Namespace提供了一种机制,将同一集群中的资源划分为相互隔离的组,同一Namespace内的资源名称要唯一,每个K8s资源只能在一个Namespace中,这其实是在多个用户之间划分集群资源的一种方法
初始命名空间
k8s启动的时候会创建四个初始化命名空间

  • default k8s包含这个命名空间,以便于你无需创建新的命名空间就可以使用新集群
  • kube-node-lease 包含用于各个节点关联的Lease租约对象,节点租约允许kubelet发送心跳,由此控制面板能够检测到结点故障
  • kube-public 所有的客户端(包括未经身份验证的客户端)都可以读取该命名空间,该命名空间主要预留为集群使用,以便某些资源可以在整个集群中可见可读
  • kube-system 用于k8s系统创建的对象
1
2
kubectl get namespace //列出集群中现存的namespace 
kubectl run nginx --image=nginx --namespace=<namespacename>

当创建一个服务的时候,k8s会创建一个相应的DNS条目
该条目的形式是<服务名称>.<名字空间名称>.svc.cluster.local,这意味着如果容器只使用服务名称,就会被解析到本地命名空间的服务
大多数对象都存在namespace中,比如pod、service 等,但是namespace的资源本身并不在namespace中,而且底层资源,比如node和持久化卷,不属于任何命名空间

注解

可以通过注解给对象添加任意的非标识的元数据,客户端可以获取这些元数据信息,注解只是添加一些元数据信息,不用来表示和选择对象,类似于编程中的注释,不过这是对于K8S对象的注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
"metadata": {
"annotations": {
"key1" : "value1",
"key2" : "value2"
}
}

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

通常我们可以用注解来记录以下这些信息

  • 由声明性配置所管理的字段。 将这些字段附加为注解,能够将它们与客户端或服务端设置的默认值、 自动生成的字段以及通过自动调整大小或自动伸缩系统设置的字段区分开来。
  • 构建、发布或镜像信息(如时间戳、发布 ID、Git 分支、PR 数量、镜像哈希、仓库地址)。
  • 指向日志记录、监控、分析或审计仓库的指针。
  • 可用于调试目的的客户端库或工具信息:例如名称、版本和构建信息。
  • 用户或者工具/系统的来源信息,例如来自其他生态系统组件的相关对象的 URL。
  • 轻量级上线工具的元数据信息:例如配置或检查点。
  • 负责人员的电话或呼机号码,或指定在何处可以找到该信息的目录条目,如团队网站。
  • 从用户到最终运行的指令,以修改行为或使用非标准功能。

字段选择器

字段选择器Field Selectors允许你根据一个或者多个资源字段的值筛选K8S对象

1
kubectl get pods --field-selector status.phase=Running //筛出来status.phase字段值为runnning的所有Pod

不同的k8s资源类型支持不同的字段选择器,所有资源类型都支持metadata.namemetadata.namespace字段,使用不被支持的字段选择器会产生错误

终结器

终结器(Finalizer)是带有命名空间的键,告诉k8s等到特定的条件被满足后,再完全删除被标记为删除的资源,Finalizer提醒控制器清理被删除的对象拥有的资源

当你告诉K8S删除一个指定了Finalizer的对象时,K8S API通过填充.metadata.deletionTimestamp来标记要删除的对象,并返回202状态码使其进入只读状态,此时控制平面或者其他组件会采取Finalizer所定义的行动,而目标对象仍然处于终止中(Terminating)的状态,这些行为完成后,控制器会删除目标对象相关的Finalizer。当metadata.finalizers字段为空时,kubernetes认为删除已完成并删除对象

工作原理
当使用清单文件创建资源的时候,可以在metadata.finalizers中指定Finalizers。当视图删除该资源的时候,处理删除请求的API服务器会注意到finalizers字段中的值,并进行以下操作

  • 修改对象 将开始执行删除的时间添加到metadata.deletionTimestamp字段
  • 禁止对象被删除,直到其metadata.finalizers字段为空
  • 返回202状态码

属主与附属

在K8S中,一些对象是其他对象的Owner。例如ReplicaSet是一组Pod的属主,具有属主的对象是属主的附属(Dependent)
附属对象中有一个metadata.ownerReferences字段,用于引用其属主对象,一个有效的属主引用,包含与属主对象同在一个命名空间下的对象名称和一个UID,K8S自动为一些对象的附属资源设置属主引用的值,这些对象包含了ReplicaSet DaemonSet Deployment Job CronJob ReplicationController

推荐使用的标签

除了kubectldashboard之外,还可以使用其他工具来可视化和管理K8S对象,一组通用的标签可以让多个工具之间相互操作,用所有工具都能理解的通用方式描述对象
元数据围绕应用的概念进行组织,K8S不是平台即服服务,应用程序是非正式的,并且使用元数据进行描述,应用程序包含的定义应该是送伞的
共享标签和注解都是用同一个前缀:app.kubernetes.io,没有前缀的标签是用户私有的,共享前缀可以确保共享标签不会干扰用户自定义的标签

描述 示例 类型
app.kubernetes.io/name 应用程序的名称 mysql 字符串
app.kubernetes.io/instance 用于唯一确定应用实例的名称 mysql-abcxzy 字符串
app.kubernetes.io/version 应用程序的当前版本(例如语义版本 1.0
、修订版哈希等) 5.7.21 字符串
app.kubernetes.io/component 架构中的组件 database 字符串
app.kubernetes.io/part-of 此级别的更高级别应用程序的名称 wordpress 字符串
app.kubernetes.io/managed-by 用于管理应用程序的工具 helm 字符串