创建 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个字符
- 只能包含小写字母、数字,以及'-' 和 '.'
- 须以字母数字开头
- 须以字母数字结尾
某些资源类型要求名称能被安全地用作路径中的片段。 其名称不能是 .、..,也不可以包含 / 或 % 这些字符。
UIDsKubernetes 系统生成的字符串,唯一标识对象。
在 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-scheduler、kube-controller-manager、 kube-apiserver、kubectl 或其他第三方自动化工具)必须指定前缀。
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,和标签一样都是键值对,但标签是用来选择对象和查找满足某些条件的对象集合,而注解不用于标识和选择对象。 注解中的元数据,可以很小,也可以很大,可以是结构化的,也可以是非结构化的,能够包含标签不允许的字符。
一般用于存储资源的附加信息,或标识一些特殊的含义
Finalizersfinalizers在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条)