成为K8S专家必修之路

2022-05-29 11:41:55 浏览数 (1)

当2021年容器化 云原生炙手可热时代, 但凡想在云市场分一杯羹的云厂商,K8S已经成为所有云厂商重要的ALL in 项目之一。如果在2016年的时候 你是否还对Kubernetes 这么重要 是否swarm更加优秀,当时我研发老板对我说的,这个东西没有什么用,你好好做DBA 做好运维就可以的时候。我已经敏锐感知到运维时代在变化 。

随着K8S这一侧工作5年之后 个人借鉴了网上诸多大佬经验翻译及陆陆续续得出一些自己的经验看法写了这份文案,希望对大家帮忙。主要以下几个模块出发

  • 应用程序接口
  • 实现控制器
  • 组件及其协作
  • 资源
  • 网络
  • 监控
  • 访问控制
  • 云厂商K8S对比

1

应用程序接口

一、列出kube-apiserver的扩展机制

自定义资源:使用 OpenAPI 模式定义自定义资源

聚合层:配置反向代理服务器以提供额外的 API 组

入场网络钩子:在将资源保存到 etcd 之前验证或改变资源

身份验证网络钩子:使用外部身份验证服务器验证身份验证令牌

授权 webhook:使用外部授权服务器授权请求

二、准入控制的操作顺序

认证和授权

变异网络钩子

对象模式验证

验证网络钩子

将数据保存到 etcd

参见 Kubernetes 准入控制器指南

三、多个变异 webhooks 编辑同一个资源时的问题和解决方案

无法为 kube-apiserver 指定应用 mutating webhooks 的顺序。

假设我们有两个 mutating webhooks 来编辑 Pod,一个是给所有容器添加一个卷挂载配置,另一个是添加一个容器。为了让所有容器都有卷挂载配置,第一个 webhook 需要在第二个之后调用。

我们可以将第一个 webhook 的重新调用策略设置 为IfNeeded在第二个之后调用第一个。

四、当准入 webhook 调用失败时会发生什么

这取决于webhook的失败策略的设置。对于admissionregistration.k8s.io/v1,默认Fail为拒绝请求。

五、 kube-apiserver 如何防止资源编辑冲突

etcd 中保存的所有资源都有一个资源版本,每次编辑时都会更新。如果资源修订版与保存的修订版不同,kube-apiserver 会利用它来拒绝冲突的编辑请求。

这种机制称为乐观锁定,适用于所有 PUT(更新)请求。

参见 Kubernetes API Server 对象修改的乐观锁控制

六、列出并描述可用的 PATCH 方法

JSON 补丁:可用于内置和自定义资源。

JSON 合并补丁:同上。对于与 JSON 补丁的区别,请阅读http://erosb.github.io/post/json-patch-vs-merge-patch/。

战略合并补丁:只能用于内置资源。

服务器端应用:可用于内置和自定义资源。

这与其他人的工作方式大不相同。资源中的字段可能有所有者,所有者只管理他们的字段。

参见 PATCH 操作

参见。k8s.io/client-go 动态客户端使用示例

七、描述子资源

子资源是资源的部分元素,其 REST API 端点与主资源分开提供。最常见的子资源是/status代表status元素。

由于子资源具有一组独立的 API 端点和动词,因此它们具有独立于主要资源的 RBAC 权限。

参见 类型(种类)

八、什么是API的存储版本

每个 Kubernetes API 都是版本化的。当一个不兼容的更改被引入到 API 中时,它的版本会被颠簸。

当一个 API 资源保存在 etcd 中时,该资源被转换为特定版本的 API 并序列化。此特定版本称为API的存储版本。

九、如何逐步提升 Kubernetes API 版本

引入新的 API 版本。API 的存储版本保持旧版本。

待新版本稳定成熟后,将存储版本更换为新版本。

将 etcd 中保存的 API 资源更新到新版本(通过更新)。

弃用旧的 API 版本。告诉用户将他们的资源更新到新版本。

一段时间后删除旧的 API 版本。

参见 CRD 的未来——发展 API

十、为什么转换 webhook 必须实现往返转换

假设 API 将v1设置为其存储版本。

创建 API 资源为v2 时,转换 webhook 需要将资源从 v2 转换为 v1。kube-apiserver 然后在 etcd 中将资源保存为 v1。

当检索 API 资源为v2 时,转换 webhook 需要将保存的资源从 v1 转换回 v2。

显然,转换 webhook 需要实现往返转换。

十一、描述如何避免在往返转换中丢失信息

常用的技术是将缺失的信息保存为注释。例如,HorizontalPodAutoscaler 将 v2 中添加的字段保存为 v1 中的注释。

参见 水平 Pod 自动缩放器

十二、描述 kube-apiserver 和聚合 API 服务器如何相互认证/授权

它们使用 TLS 相互验证。阅读身份验证流程 了解详细信息。

至于授权,需要通过 kube-apiserver 授予聚合 API 服务器创建 SubjectAccessReview 资源。要授予权限,绑定称为内置角色的系统extension-apiserver-authentication-reader中kube-system命名空间聚集API服务器的ServiceAccount

2

实现控制器

一、描述什么是事件资源以及它们在 kube-apiserver 中的存在时间

事件是记录发生在目标资源上的事件的资源。kubectl describe pods NAME以可读的方式显示 Pod 的事件。

事件通常在 kube-apiserver 中只存在一小时。

参见 发射、消费和呈现:事件生命周期

二、Node等集群资源的事件应该使用什么命名空间?

default 命名空间。

三、什么是 Kubernetes 中的协调

reconciliation是确保世界的实际状态与期望状态相匹配的过程。换句话说,和解是声明式 API 的实现。

参见 什么是“reconciliation”?

四、描述如何在kube-apiserver中查看资源

kube-apiserver 提供了一种称为watch的方法来将所有 API 对象资源的更改提供给客户端。Watch 比定期轮询 kube-apiserver 更有效。

Efficient detection of changes

https://kubernetes.io/docs/reference/using-api/api-concepts/#efficient-detection-of-changes

五、描述删除 REST API 的工作原理

删除 REST API开始删除给定资源。REST API 调用完成并不一定意味着从 kube-apiserver 中删除了资源。

kubectl delete通过观察 kube-apiserver 等待删除完成,直到资源被删除。用--wait=false,kubectl delete不等待完成。

六、描述什么是什么metadata.deletionTimestamp以及它是如何工作的

metadata.deletionTimestamp通常不设置。当资源不能立即删除时设置。时间戳表示删除的时间表。

对于 Pod,该字段用于实现优雅终止。容器在设置删除时间戳后立即获取 SIGTERM,并在时间戳过期后获取 SIGKILL。Pod 资源本身不会被删除,直到 kubelet 完成删除 Pod 进程。

七、描述什么是什么metadata.finalizers以及它是如何工作的

当metadata.finalizers不为空时,也会设置删除时间戳,如下所述。

参见Metadata

https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata

八、描述k8s.io/client-go/tools/leaderelection是如何工作的

该包通过使用 kube-apiserver 资源实现领导者选举。目前,推荐使用的资源是Lease.

此包不保证只有一个客户端充当领导者(又名围栏)。

实现示例:

https : //github.com/kubernetes/client-go/blob/master/examples/leader-election/main.go

九、描述什么是什么metadata.ownerReferences以及它是如何工作的

垃圾收集器使用该字段来实现资源的级联删除。

控制器还使用该字段来标识父资源。

参见 垃圾收集

十、当 StatefulSet 被删除时,从 StatefulSet 实例化的 PersistentVolumeClaims 会发生什么?

他们保留下来。

如果要删除 PVC 和 StatefulSet,请将 PVC 设置metadata.ownerReference为 StatefulSet 或其他内容。

例如,Elastic Cloud on Kubernetes (ECK) 将 PVC 的所有者设置为 Elasticsearch 自定义资源。

3

控制组件及其协作

一、描述一下下列组件

etcd

kube-apiserver

kube-controller-manager

kube-scheduler

kubelet

kube-proxy

containerd

CoreDNS

etcd:持久存储资源对象。

kube-apiserver:访问 etcd 并为其他组件提供 REST API。

kube-controller-manager:是一组控制器,用于观察和编辑 kube-apiserver 中的资源。

kube-scheduler:将新 Pod 调度到节点。

kubelet:在每个节点上运行 Pod。

kube-proxy:在每个节点上为服务配置网络规则。

containerd:接受来自 kubelet 的CRI请求并运行容器。

CoreDNS:为服务名称提供内部 DNS。

CoreDNS: to provide internal DNS for Service names.

二、描述每个组件从创建 Pod 到运行内部容器的行为

1、kube-apiserver 在 etcd 中保存一个新的 Pod 资源

2、kube-scheduler 找到新的 Pod

3、kube-scheduler 根据可用资源等条件为新的 Pod 分配一个 Node

4、已分配节点上的 kubelet 找到新的 Pod

5、kubelet 初始化 Pod 运行时如下:

kubelet 向 CRI 运行时(例如 containerd)发送 CRI 请求以创建基础架构容器

CRI 运行时调用 CNI 插件来初始化 Pod 的网络命名空间

6、kubelet依次请求 CRI 运行时运行spec.initContainers(如果有)

7、kubelet同时请求 CRI 运行时运行spec.containers

三、描述谁default在每个命名空间中创建ServiceAccount 以及何时创建

default创建命名空间后 ,ServiceAccount 不会立即存在。

该defaultServiceAccount由KUBE-控制器管理器创建一个小创建命名空间之后。同样,defaultServiceAccount的 Secret 令牌在创建后由 kube-controller-managerdefault创建。

因此,在新创建的命名空间中创建 Pod 有时会失败。改为创建部署是安全的。

四、当运行 Pod 的 kubelet 或 Node 无法与 kube-apiserver 通信时,Pod 会发生什么

kube-apiserver 通过接收定期的心跳来监视 kubelet。如果心跳停止,kube-apiserver 会向 Node 资源添加污点。

Pod 可以容忍长达 300 秒的污点,因为它们默认具有以下容忍度:

代码语言:javascript复制
tolerations:
 - effect: NoExecute
   key: node.kubernetes.io/not-ready
   operator: Exists
   tolerationSeconds: 300
 - effect: NoExecute
   key: node.kubernetes.io/unreachable
   operator: Exists
   tolerationSeconds: 300

300 秒过后,将启动正常终止。由于spec.terminationGracePeriodSeconds是默认为30秒,metadata.deletionTimestamp通常是从现在设置为30秒。

当额外的 30 秒过去后,Pod 转换到Terminating状态。但是,由于 kubelet 无法看到 Pod 的状态,因此 Pod 将保持运行。

参见 按条件污染节点 ,基于污染的驱逐

https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/#taint-nodes-by-condition

https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/#taint-based-evictions

五、如果 Pod 正在终止,描述 ReplicaSet 控制器如何工作

ReplicaSet 控制器通常会及时添加新的 Pod。

六、描述 StatefulSet 控制器在 Pod 终止时如何工作

StatefulSet 控制器无法添加新 Pod,因为 StatefulSet 中的 Pod 具有stable network IDs.

七、为什么在删除节点资源之前隔离失败的节点很重要

当 kubelet 无法与 kube-apiserver 通信时,节点上的 Pod 将变为 Terminating 但不会被删除。如果从 kube-apiserver 中删除 Node 资源,则可以删除此类 Pod。

但是,如果问题仅仅是 kubelet 和 kube-apiserver 之间的通信,Pod 进程可能仍然存在。在这种情况下,删除节点和 Pod 可能会导致脑裂综合症,因为具有与 StatefulSet 相同 ID 的新 Pod 将在另一个节点上运行。

为避免此类事件,在删除节点资源之前,应使用STONITH或类似方法终止出现故障的节点。

4

资源

一、解释容器resources.limits和resources.requests容器的区别

resources.limits 使用 Linux cgroups 为容器设置资源使用上限。

resources.requestskube-scheduler 使用它来选择可用的节点。resources.requests.cpu还用于在使用 CFS 共享的容器之间分配 CPU 时间。

参见 在 Kubernetes 中设置正确的请求和限制

https://learnk8s.io/setting-cpu-memory-limits-requests

二、容器只会发生什么时候 resources.limits.memory?

容器被修改为具有resources.requests.memory相同的值resources.limits.memory。

这对于resources.limits.cpu.

三、当容器消耗的内存超过请求的内存时会发生什么?

当 Node 内存不足时,过度使用内存的 Pod 会成为驱逐的候选对象。

参见 Pod 优先级和服务质量之间的相互作用

https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#interactions-of-pod-priority-and-qos

四、描述 Pod 的服务质量类

共有三个类,即保证、突发和尽力而为。

对 CPU 和内存都有请求和限制,并且请求和限制具有相同值的 Pod 被归类为有保证的。除非在特殊情况下,保证的 Pod 不会被驱逐。

至少有一个资源请求的 Pod 被归类为 Burstable。其他 Pod 归入 BestEffort。Burstable Pod 比 BestEffort Pod 被驱逐的可能性更小。

参见 驱逐最终用户 Pod

五、描述 Pod 的 PriorityClass

kube-scheduler 使用 PriorityClass 来执行 Pod 抢占。抢占是从一个节点中移除一个低优先级的 Pod 并将一个高优先级的 Pod 调度到该节点上的操作。

参见 Pod 优先级和抢占

六、当 Node 的 CPU 时间用完时,Pod 是否被驱逐?

不。

会设置适当的 CPU 请求对于生产环境很重要。

5

网络

一、描述 Service 的类型,即 ClusterIP、NodePort 和 LoadBalancer

ClusterIP 是最基本的服务类型。它为服务消费者提供虚拟 IP 地址以访问后端 Pod。

NodePort 还提供了一个端口号。服务消费者可以通过使用端口号连接任何节点来访问后端 Pod。

LoadBalancer 告诉外部负载均衡器分配一个虚拟 IP 地址并将数据包路由到虚拟地址到后端 Pod

二、解释Service和Endpoints(EndpointSlices)的关系

每个服务都伴随着一个同名的端点(切片)。Endpoint(Slice)s 表示后端 Pod 的地址。

Endpoint(Slice)s 由 kube-controller-manager 自动创建和更新,如果 Service 有一个 Pod 选择器。如果不是,则需要通过其他方式维护 Endpoint(Slice)s。

三、描述spec.containers.ports Pods 和EXPOSE Dockerfiles 的用法

如果使用名称定义,spec.containers.ports则可以在livenessProbe、 readinessProbe或 Service 的targetPort字段中使用以通过名称引用端口。

代码语言:javascript复制
containers:
 - ports:
   - name: health
     containerPort: 8080
     protocol: TCP
 livenessProbe:
   httpGet:
     port: health
     path: /healthz

EXPOSE 在 Dockerfiles 中只是一个文档。

他们俩实际上都没有发布端口。容器可以侦听指定端口以外的其他端口。此外,容器可能不会侦听指定的端口。

解释来自外部的数据包如何到达 Pods 如果服务spec.externalTrafficPolicy设置为Local

spec.externalTrafficPolicy主要是针对 LoadBalancer 类型的服务。如果此字段为空或Cluster(默认),kube-proxy 将数据包的源地址重写为节点地址,并将它们转发到目标 Pod。在这种模式下,目标 Pod 可能正在另一个节点上运行。

如果该字段为Local,kube-proxy 不会重写源地址。在这种模式下,目标 Pod 必须在运行 kube-proxy 的同一节点上运行。因此,外部负载均衡器仅将数据包路由到运行目标 Pod 的节点。

例如,MetalLB 仅从运行目标 Pod 的节点通告虚拟地址。

参见 保留客户端源IP

6

监控

一、描述当 readinessProbe 失败时会发生什么

eadinessProbe 检查容器是否准备好接受请求。

如果 readinessProbe 失败,Pod 将变为未就绪状态并被排除在服务负载平衡目标之外。

二、描述 livenessProbe 失败时会发生什么

livenessProbe 检查容器是否存活。

如果 livenessProbe 失败,则容器进程将被终止并重新启动。

7

访问控制

一、角色(不是 ClusterRole)能否授予对集群范围资源的访问权限?

不。

二、ClusterRole 能否授予对命名空间范围内资源的访问权限?

是的。这样的 ClusterRole 可用于授予对任何命名空间中的资源的访问权限。

参见 了解 Kubernetes RBAC

三、编辑defaultServiceAccount的权限是个好主意吗?

不。

该defaultServiceAccount是由不指定任何ServiceAccount吊舱使用。编辑defaultServiceAccount的权限会导致意外行为。

四、描述 kube-apiserver 如何防止权限提升

kube-apiserver 检查主题(用户或 ServiceAccount)何时创建或更新(集群)RoleBinding。如果主体没有与它要授予其他实体相同的权限,kube-apiserver 将拒绝该操作。

如果您正在实现一个动态授予其他 ServiceAccount 某些特权的控制器,请确保控制器的 ServiceAccount 具有相同的特权。

参见 权限提升预防和引导

五、描述什么是用户模拟

如果被授予,用户可以通过 HTTP 请求标头充当另一个用户和/或属于另一个组。仅应为集群管理员授予用户模拟权限。

使用kubectl,--as=USER和--as-group=GROUP命令行标志时设置模拟标头。

用户模拟

六、描述view, edit,admin集群角色

这些称为聚合 ClusterRoles。聚合的 ClusterRole 合并具有特殊标签的其他 ClusterRoles 的权限。

定义新的自定义资源时,请考虑将适当的权限聚合到这些 ClusterRoles 中。

面向用户的角色

参考

https://ymmt2005.hatenablog.com/entry/k8s-things

https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/#taint-based-evictions

8

云厂商K8S对比

0 人点赞