欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

K8S中的对象

程序员文章站 2022-03-12 11:56:33
...

1. K8S 中的对象

 Kubernetes 对象是持久化的实体,表示整个集群的状态,通常使用yaml文件来描述这些对象,主要用于描述下面的一些信息:

  • 哪些容器化应用在运行(以及在哪个 Node 上);
  • 可以被应用使用的资源;
  • 关于应用运行时表现的策略,比如重启策略、升级策略,以及容错策略;

操作(无论是创建、修改,或者删除) Kubernetes 对象都需要使用 Kubernetes API,比如,当使用 kubectl 命令行接口时,CLI 会执行必要的 Kubernetes API 调用,也可以在程序中直接调用 Kubernetes API。为了实现该目标,Kubernetes 当前提供了一个golang客户端库

注:kubernetes rest api中的所有对象都由一个名称(如some-name,名字最长应为253个字符,由小写字母、数字、-、和.组成)和一个 UID (K8S系统产生的唯一字符串)明确标识,对于用户提供的非唯一属性,k8s提供标签和注释。

1.1 对象的组成

 每个 Kubernetes 对象包含两个嵌套的对象字段,它们负责管理对象的配置:

  • 对象的spec(规约):必需,它描述了对象的期望状态(Desired State),希望对象所具有的特征,另外还有关于对象的一些基本信息(如名字);
  • 对象的status(状态):描述了对象的实际状态(Actual State),由 Kubernetes 系统提供和更新的;

Kubernetes 控制面任何时刻都尽力管理着对象的实际状态以与期望状态相匹配, 当使用 Kubernetes API 创建对象时(或者直接创建,或者基于kubectl),API 请求必须在请求体中包含 JSON 格式的信息,大多数情况下,需要在.yaml文件中为 kubectl 提供这些信息,kubectl 在发起 API 请求时,将这些信息转换成 JSON 格式,下面是一个示例文件:

nginx-deployment.yaml docs/concepts/overview/working-with-objects 

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

k8s对象的对应的.yaml文件,需要配置的字段有:

  • apiVersion:创建该对象所使用的 Kubernetes API 的版本;
  • kind:想要创建的对象的类型;
  • metadata:帮助识别对象唯一性的数据,包括一个name字符串、UID 和可选的namespace

在创建 Deployment 时,可以使用 kubectl 命令行接口(CLI) 的kubectl create命令将上述文件作为参数进行创建(比如):

kubectl create -f docs/user-guide/nginx-deployment.yaml --record

1.2 Namespaces 命名空间

 Kubernetes支持由同一物理集群支持的多个虚拟集群,这些虚拟集群称为命名空间Namespace(有点难理解)。Namespace用于多个用户(这里的用户是指K8S集群中的Namesapce划分的东西,并非指的通常的“用户”)分布在多个团队或项目中的环境中,对于拥有几十个用户的集群,根本不需要考虑创建Namespace,当需要Namespace提供的功能时,开始使用名称空间。

 Namespace为名字提供了区域,某一个Namesapce中资源的名字必须唯一!但对于所有的Namespace可能不是唯一的,Namespace不能彼此嵌套,并且每个kubernetes资源只能位于一个命名空间中。Namespace是一种在多个用户之间划分集群资源的方法(通过资源配额)。

注:不需要使用多个名称空间来分离稍那些只有稍微不同的资源,例如同一软件的不同版本,这种情况完全可以使用标签来区分同一名称空间中的资源。

下面是一些Namespace的操作命令:

1.查看集群中的命名空间

# 查看集群中的所有命名空间
kubectl get namespaces
# 结果
NAME          STATUS   AGE
default       Active   15d
kube-public   Active   15d
kube-system   Active   15d
sre           Active   8d

其中K8S内置的有3个命名空间:

  • default:供那些没有其他命名空间的对象使用,默认的命名空间;
  • kube-system:存放由K8S系统创建的对象的命名空间;
  • kube-publilc:该命名空间对所有用户可读(不管有没有授权),它主要是为集群的使用而保留的,以防某些资源在整个集群中都应该是可见和可读的。这个名称空间的公共方面只是一个约定,而不是一个要求。

注:sre是本地用于测试apollo的命名空间

2.为请求设置一个命名空间

使用--namespace标识可以暂时性的为一个request设置命名空间,如:

kubectl --namespace=<insert-namespace-name-here> run nginx --image=nginx
kubectl --namespace=<insert-namespace-name-here> get pods

3.设置命名空间的首选项

可以在该上下文中永久保存所有后续kubectl命令的名称空间:

kubectl config set-context $(kubectl config current-context) --namespace=<insert-namespace-name-here>
# Validate it
kubectl config view | grep namespace:

 当创建 Service 时,将会创建对应的DNS实体,DNS实体的形式为<service-name>.<namespace-name>.svc.cluster.local,如果某个容器仅仅使用<service-name>,他将会解析为命名空间本地的服务。这对于跨多个命名空间(如开发、分段和生产)使用相同的配置很有用,如果要跨命名空间访问,则需要使用完全限定的域名(fqdn)。

 虽然大部分的K8S资源都在命名空间中,但并不是所有的对象都在命名空间中的,而且命名空间资源本身不在命名空间中,以及一些低级资源(比如节点node、持久化存储卷)它们不在任何命名空间中,通过下面的命令可以具体查看:

# In a namespace
kubectl api-resources --namespaced=true

# Not in a namespace
kubectl api-resources --namespaced=false

1.2 标签和选择器

1.2.1 标签(Label)

 Label是依附在对象上(比如Pod)的键值对,用于特定对象的标识性属性,推荐这些将标签设置为和用户相关的(但不建议直接设置为核心系统的语义)。标签允许有效的查询和监控,非常适合在uis和clis中使用。Label可以组织对象,可以在创建对象时指定,并且可以随时添加和修改。每个对象都有一系列的标签,对于给定对象,标签的key值必须唯一,比如:

"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"

 标签都是键值对,合法键值对应当应该如下:

  • key值:由前缀(可选)和名字(必须)的形式构成,它们之间以正斜杠/分割,即prefix/name
    • prefix:前缀是可选参数,如果指定,必须是DNS的子域:由点.分隔的一系列DNS标签,总共不超过253个字符,后跟一个斜杠/kubernetes.io/k8s.io/是K8S保留前缀,禁止使用);
    • name:必选参数,由小于等于63个字符组成,可以是字母、数字、以及-_.,开头和结尾只能是字母(包含大、小写)或数字,如果前缀省略,标签的Key值则为用户私有,向终端用户(end-user)对象添加标签的自动化系统组件(如:kube-scheduler、kube-controller-manager、kube-apiserver、kube-apiserver、kubectl或第三方自动化)必须指定前缀。
  • value值:由小于等于63个字符组成,可以是字母、数字、以及-_.,开头和结尾只能是字母(包含大、小写)或数字;

1.2.2 标签选择器(Label selectors)

 标签并不要求唯一,理论上是希望由很多对象上是带有相同标签的,通过标签选择选择器,客户端可以指定一系列带有相同标签的对象,API提供了2种类型的选择器:equality-basedset-based,标签选择器可以由多个requirement构成(之间由用逗号,分割),在有多个要求的情况下,必须满足所有要求,因此逗号分隔符充当逻辑与(&&)运算符。如果不指定特定的选择器的话,将会依赖具体的语境,使用选择器的API应该记录有效性和含义。

Equality-basedrequirement】

equality/inequality-based的requirement可以根据标签的Key值和Value值进行过滤,只有含有指定的Key-Value的对象才能满足条件(这些对象可能还含有其他额外的标签),允许的操作符由===以及!=,前2个表示相等equality,后1个表示不相等inequality,比如:

# 选择器将选择带有key为environment,value为production标签的所有对象
environment = production
# 选择器将选择带有key为tier但value不是frontend、或没有key为tier的标签的所有对象
tier != frontend

使用equality/inequality-based的场景其中之一就是指定Pod分配到特定的node上,下面是一个示例(将Pod分配带有accelerator=nvidia-tesla-p100标签的节点上):

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

Set-basedrequirement】

Set-based的requirement将会根据一系列的value来过滤key,支持3种类型的操作:innotinexists,比如:

# 选择带有key为environment、value为production或qa的标签 对象
environment in (production, qa)
# 选择不带key为tier,或key为tier、key不为frontend和backend标签的对象
tier notin (frontend, backend)
# 选择所有带有key为partition标签(不管它的Value)的对象
partition
# 选择所有不带key为partition标签的对象
!partition

如果需要使多个过滤条件,可以这么写:partition,environment notin (qa),表示的就是带有key为partition标签、且还带有key为environment和value不为qa标签的对象,其实=in相似、!=not in相似,Set-based也可以和equality-based的混合使用,比如:partition in (customerA, customerB),environment!=qa

 像Job、Deployment、Replica Set以及Daemon Set都是支持set-based,比如:

selector:
  matchLabels:
    component: redis
  matchExpressions:
    - {key: tier, operator: In, values: [cache]}
    - {key: environment, operator: NotIn, values: [dev]}

其中matchLabels是键值对的map,如果matchLabels中只有一对键值对,那这个map就和matchExpressions相等。其中matchExpressions中的key字段表示键值,operator字段表示行为,合法值包含InNotInExists以及DoesNotExistvalue表示的是数组,在operator字段为InNotIn时必须非空。

【附】

 可以在kubectl使用equality-based,使用-l参数指定标签,比如:

kubectl get pods -l environment=production,tier=frontend

如果使用set-based(推荐这种写法),可以这么写:

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

 Service指向的Pod是通过Label Selector指定的,相似的replicationcontroller管理的Pod也应该通过Label Selector来管理,在yaml文件中通常表现为:

selector:
    component: redis

1.2.3 注解(Annotations)

 可以使用标签或注释将元数据附加到kubernetes对象上,一些客户端可以通过这些元数据进行检索,标签可以用来选择特定的某些对象,相反的,注解并不用来标识或选择对象,注释中的元数据可以或大或小、结构化或者非结构化、可以包含Label中不被允许的标签,可以包含:

  • 由声明性配置层管理的字段,将这些字段附加到注释中,将其与客户机或服务器设置的默认值以及自动生成的字段和由自动调整大小或自动缩放系统设置的字段区分开来;
  • 构建、发布或镜像信息,如时间戳、发布ID、git分支、pr编号、映像哈希和注册表地址;
  • 指向日志记录、监视、分析或审计存储库的指针;
  • 可用于调试目的的客户端库或工具信息:例如,名称、版本和生成信息;
  • 用户或工具/系统来源信息,例如来自其他生态系统组件的相关对象的URL;
  • 轻量级卷展栏工具元数据:例如,配置或检查点;
  • 负责人的电话或寻呼机号码,或指定在何处可以找到该信息的目录条目,例如团队网站;
  • 从最终用户到实现的修改行为或使用非标准功能的指令;

如果不使用注释,可以将上述类型的信息存储在外部数据库或目录中,但这会使生成用于部署、管理、自省等的共享客户机库和工具变得更加困难。

【语法】

注解也是键值对,合法的注解的Key值有2个部分组成,可选的前缀和必选的name,之间用\分割,规则和1.2.1中的标签中key-value的规则一致。

下面是Annotation的一个示例:

"metadata": {
  "annotations": {
    "key1" : "value1",
    "key2" : "value2"
  }
}

1.2.4 字段选择器(Field Selectors)

 字段选择器可以用来基于资源字段的值来选择K8S资源,比如:

metadata.name=my-service
metadata.namespace!=default
status.phase=Pending

Kubectl命令可以使用--field-selector标识来使用字段选择器,如:

kubectl get pods --field-selector status.phase=Running

字段选择器本质上也是资源过滤器,默认是不使用字段选择器,表示所有类型的资源都会被选择,下面两个命令的效果是一样的:

kubectl get pods
kubectl get pods --field-selector ""

 具体字段选择器支持哪些字段,这会根据K8S资源的类型有所不同,但所有类型的资源都支持metadata.namemetadata.namespace字段。支持的操作行为有===以及!=,比如选择K8S中所有不在default命名空间中的Service:kubectl get services --field-selector metadata.namespace!=default。除此之外,字段选择器也是支持链式行为的(用逗号,分隔),比如选择status.phase不为Runningspec.restartPolicy等于Alwayskubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always。字段选择器可以选择多种资源类型,如选择所有不在default命名空间中的状态集(Statefulsets)和Service:kubectl get statefulsets,services --field-selector metadata.namespace!=default