kubernetes对象

定义kubernetes对象        

创建 Kubernetes 对象时,必须提供对象的规约,用来描述该对象的期望状态, 以及关于对象的一些基本信息(例如名称)。 当使用 Kubernetes API 创建对象时(或者直接创建,或者基于kubectl), API 请求必须在请求体中包含 JSON 格式的信息。 大多数情况下,需要在 .yaml 文件中为 kubectl 提供这些信息kubectl 在发起 API 请求时,将这些信息转换成 JSON 格式。

这里有一个 .yaml 示例文件,展示了 Kubernetes Deployment 的必需字段和对象规约:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

然后使用kubectl命令创建该deployment,假设该文件名为nginx-deployment.yaml

kubectl apply -f nginx-deployment.yaml

必需字段 

在想要创建的 Kubernetes 对象对应的 .yaml 文件中,需要配置如下的字段:

  • apiVersion - 创建该对象所使用的 Kubernetes API 的版本
  • kind - 想要创建的对象的类别
  • metadata - 帮助唯一性标识对象的一些数据,包括一个 name 字符串、UID 和可选的 namespace
  • spec - 你所期望的该对象的状态

不同类别资源的spec字段是不同的,例如,Pod 参考文档详细说明了 API 中 Pod 的 spec 字段, Deployment 的参考文档则详细说明了 Deployment 的 spec 字段

对象名称和 IDs

集群中的每一个对象都有一个名称 来标识在同类资源中的唯一性。

每个 Kubernetes 对象也有一个UID 来标识在整个集群中的唯一性。

比如,在同一个名字空间 中有一个名为 myapp-1234 的 Pod, 但是可以命名一个 Pod 和一个 Deployment 同为 myapp-1234.

对于用户提供的非唯一性的属性,Kubernetes 提供了 标签(Labels)和 注解(Annotation)机制。

名称

某一时刻,只能有一个给定类型的对象具有给定的名称。但是,如果删除该对象,则可以创建同名的新对象。当对象所代表的是一个物理实体(例如代表一台物理主机的 Node)时, 如果在 Node 对象未被删除并重建的条件下,重新创建了同名的物理主机, 则 Kubernetes 会将新的主机看作是老的主机,这可能会带来某种不一致性。

DNS 子域名

很多资源类型需要可以用作 DNS 子域名的名称。 这一要求意味着名称必须满足如下规则:

  • 不能超过253个字符
  • 只能包含小写字母、数字,以及'-' 和 '.'
  • 须以字母数字开头
  • 须以字母数字结尾

路径分段名称 

某些资源类型要求名称能被安全地用作路径中的片段。 其名称不能是 ...,也不可以包含 / 或 % 这些字符。

UIDs

Kubernetes 系统生成的字符串,唯一标识对象。

在 Kubernetes 集群的整个生命周期中创建的每个对象都有一个不同的 uid,它旨在区分类似实体的历史事件。

Kubernetes UIDs 是全局唯一标识符(也叫 UUIDs)。

命名空间

名字空间为名称提供了一个范围。资源的名称需要在名字空间内是唯一的,但不能跨名字空间。 名字空间不能相互嵌套,每个 Kubernetes 资源只能在一个名字空间中。

名字空间是在多个用户之间划分集群资源的一种方法(通过资源配额)。

设置名字空间偏好

默认的命名空间为default,在创建资源时,如果不指定命名空间时,会将资源创建在default命名空间,设置默认命名空间后,如果不指定命名空间,将会把资源创在设置的命名空间。

kubectl config set-context --current --namespace=<名字空间名称>
# 验证之
kubectl config view | grep namespace:

名字空间和 DNS

当创建一个服务 时, Kubernetes 会创建一个相应的 DNS 条目

该条目的形式是 <服务名称>.<名字空间名称>.svc.cluster.local,这意味着如果容器只使用 <服务名称>,它将被解析到本地名字空间的服务,也就是默认命名空间。

并非所有资源都在命名空间

可通过以下命令查看

# 位于名字空间中的资源
kubectl api-resources --namespaced=true

# 不在名字空间中的资源
kubectl api-resources --namespaced=false

自动打标签

Kubernetes 控制面会为所有名字空间设置一个不可变更的 标签 kubernetes.io/metadata.name,只要 NamespaceDefaultLabelName 这一 特性门控 被启用,注意,在kunernetes 1.21版本中,该特性属于beta版本

标签和选择算符

标签(Labels) 是附加到 Kubernetes 对象(比如 Pods)上的键值对。只要符合命名规范,标签可以是任意定义,不直接对核心系统有语义含义,只对用户有意义,一般和标签选择器配套使用

命名规范

有效的标签键有两个段:可选的前缀和名称,用斜杠(/)分隔。 名称段是必需的,必须小于等于 63 个字符,以字母数字字符([a-z0-9A-Z])开头和结尾, 带有破折号(-),下划线(_),点( .)和之间的字母数字。 前缀是可选的。如果指定,前缀必须是 DNS 子域:由点(.)分隔的一系列 DNS 标签,总共不超过 253 个字符, 后跟斜杠(/)。

如果省略前缀,则假定标签键对用户是私有的。 向最终用户对象添加标签的自动系统组件(例如 kube-schedulerkube-controller-manager、 kube-apiserverkubectl 或其他第三方自动化工具)必须指定前缀。

kubernetes.io/ 和 k8s.io/ 前缀是为 Kubernetes 核心组件保留的

示例

nodeSelector字段表示该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

比较新的资源,例如 Job、 Deployment、 Replica Set 和 DaemonSet , 也支持 基于集合的 需求。表示会匹配key为tier,value为cache或者cache2并且key为enviroment,value不等于dev的资源

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

注解

注解,也就是annotations,和标签一样都是键值对,但标签是用来选择对象和查找满足某些条件的对象集合,而注解不用于标识和选择对象。 注解中的元数据,可以很小,也可以很大,可以是结构化的,也可以是非结构化的,能够包含标签不允许的字符。

一般用于存储资源的附加信息,或标识一些特殊的含义

Finalizers

finalizers在matedata字段里,如果某个资源的metadata.finalizers不为空,则表示告诉控制器,尽管用户已经对该资源进行了delete操作,但该资源还不能被删除,而是让它将入 Terminating 状态,等到该字段为空时才能被删除。

finalizers工作原理,当试图删除一个资源时,管理该资源的控制器会注意到 finalizers 字段中的值, 并进行以下操作:

  • 修改对象,将你开始执行删除的时间添加到 metadata.deletionTimestamp 字段。
  • 将该对象标记为只读,直到其 metadata.finalizers 字段为空。

这里用kubebuilder示例里使用finalizers的一段代码来描述

func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    log := r.Log.WithValues("cronjob", req.NamespacedName)

    var cronJob *batchv1.CronJob
    if err := r.Get(ctx, req.NamespacedName, cronJob); err != nil {
        log.Error(err, "unable to fetch CronJob")
        return ctrl.Result{}, client.IgnoreNotFound(err)
    }

    // finalizer名字,可以自定义
    myFinalizerName := "batch.tutorial.kubebuilder.io/finalizer"

    // 在删除资源时,k8s会将开始执行删除的时间添加到 metadata.deletionTimestamp 字段,这样会 
    // 触发一个 Update 动作, 我们的控制器就会监听到这个更新动作。

    // 说明如果该字段为0,那么当前操作就不是删除操作,我们把自定义的finalizer添加到 
    // metadata.finalizers字段中
    if cronJob.ObjectMeta.DeletionTimestamp.IsZero() {
        if !containsString(cronJob.GetFinalizers(), myFinalizerName) {
            controllerutil.AddFinalizer(cronJob, myFinalizerName)
            if err := r.Update(ctx, cronJob); err != nil {
                return ctrl.Result{}, err
            }
        }
    } else {
        // 否则就是一个删除操作,先判断该对象有没有我们自己定义的finalizer,如果有,先做一些收尾 
        // 工作,也就是deleteExternalResources
        if containsString(cronJob.GetFinalizers(), myFinalizerName) {
            if err := r.deleteExternalResources(cronJob); err != nil {            
                return ctrl.Result{}, err
            }
            // 然后将自定义的metadata.finalizers字段中我们自定义的finalizer删掉,删掉之后 
            // finalizers如果为空,k8s就不会阻止垃圾收集删除该资源了
            controllerutil.RemoveFinalizer(cronJob, myFinalizerName)
            if err := r.Update(ctx, cronJob); err != nil {
                return ctrl.Result{}, err
            }
        }

        return ctrl.Result{}, nil
    }

    // Your reconcile logic

    return ctrl.Result{}, nil
}

func (r *Reconciler) deleteExternalResources(cronJob *batch.CronJob) error {
    //
    // delete any external resources associated with the cronJob
    //
    // Ensure that delete implementation is idempotent and safe to invoke
    // multiple times for same object.
}

// Helper functions to check and remove string from a slice of strings.
func containsString(slice []string, s string) bool {
    for _, item := range slice {
        if item == s {
            return true
        }
    }
    return false
}

func removeString(slice []string, s string) (result []string) {
    for _, item := range slice {
        if item == s {
            continue
        }
        result = append(result, item)
    }
    return
}

属主引用

在某些情况下,Finalizers 会阻止依赖对象的删除, 这可能导致目标属主对象,保持在只读状态的时间比预期的长,且没有被完全删除。 在这些情况下,你应该检查目标属主和附属对象上的 Finalizers 和属主引用,来排查原因。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值