kubelet
kubelet 负责以下工作。
- 创建、修改和删除 Pod 的容器。
- 负责处理活跃度、就绪度和启动探测。
- 负责通过读取 pod 配置并在主机上创建相应的目录来挂载卷以进行卷挂载。
- 通过调用 API 服务器来收集和报告节点和 Pod 状态。
Kubelet 的 Pod 管理器是 Kubelet 的核心组件之一,它确保节点上的容器和 Pod 处于正确的状态,并与其他组件协同工作,以维护整个集群的稳定性和可用性。 Pod 管理器与 Kubernetes 控制平面交互,以获取 Pod 的期望状态,并负责将节点上的实际状态与期望状态进行协调。这确保了容器应用程序在 Kubernetes 集群中可靠运行
创建pod的过程:
kubectl命令后,进行客户端验证;使用资源对象生成器generaor创建请求;
请求发送到api-server,进行认证鉴权admission controller后,写入etcd;;至此,对象已经在 etcd 中了,所有的初始化步骤也已经完成了。 下一步是设置资源拓扑(resource topology)。例如,一个 Deployment 其实就是一组 ReplicaSet,而一个 ReplicaSet 就是一组 Pod。 K8s 是如何根据一个 HTTP 请求创建出这个层级关系的呢?靠的是 K8s 内置的控制器(controllers)。 以上 controllers 执行完各自的处理之后,etcd 中已经有了一个 Deployment、一个 ReplicaSet 和三个 Pods,可以通过 kube-apiserver 查询到。scheduler 调度器 —— 负责调度到任何节点.到目前为止,我们看到的所有东西(状态),还只是存在于 etcd 中的元数据。 下一步就是将这些状态同步到计算节点上,然后计算节点上的 agent(kubelet)就开始干活了。 通过container runtime与具体的容器运行时交互,创建容器;(grpc实现)
- ClusterIP (默认) - 在集群的内部 IP 上公开 Service 。这种类型使得 Service 只能从集群内访问。
- NodePort - 使用 NAT 在集群中每个选定 Node 的相同端口上公开 Service 。使用
<NodeIP>:<NodePort>
从集群外部访问 Service。是 ClusterIP 的超集。 - LoadBalancer - 在当前云中创建一个外部负载均衡器(如果支持的话),并为 Service 分配一个固定的外部IP。是 NodePort 的超集。
- ExternalName - 通过返回带有该名称的 CNAME 记录,使用任意名称(由 spec 中的
externalName
指定)公开 Service。不使用代理。这种类型需要kube-dns
的v1.7或更高版本。
container runtime
于是,现代 docker 启动一个标准化容器需要经历这样的流程:
- runc负责容器生命周期管理和与linux内核的交互;;
containerd
提供了一个守护进程,用于管理容器的完整生命周期,container shim
作为容器的父进程,将信号向容器进程进行转发,container shim
在 Docker 中的主要作用是在容器的生命周期中保持一个持久的父进程。 ;不让runc作为容器父进程得,允许containerd
和runc
在容器启动后退出,并持续监视容器的生命周期,转发日志和信号,并收集容器的退出状态。
- k8s CRI shim 的作用就是适配或"转化"具体容器运行时的接口,使其符合 Kubernetes 的 CRI 标准。换句话说,CRI shim 的职责就是作为 Adapter 将各种容器运行时本身的接口适配到 Kubernetes 的 CRI 接口上。
package main
import (
"fmt"
"time"
)
func worker(quit chan struct{}) {
for {
select {
case <-quit: // 接收到退出信号
fmt.Println("Worker exiting...")
return // 退出goroutine
default:
fmt.Println("Worker working...")
time.Sleep(1 * time.Second) // 模拟工作
}
}
}
func main() {
quit := make(chan struct{}) // 创建一个退出通道
go worker(quit) // 启动worker goroutine
time.Sleep(5 * time.Second) // 让worker工作一段时间
close(quit) // 关闭退出通道,发出退出信号
time.Sleep(1 * time.Second) // 等待worker退出
fmt.Println("Done")
}
package main
import (
"context"
"flag"
"fmt"
"time"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
kubeconfig := flag.String("kubeconfig", "/path/to/kubeconfig", "path to kubeconfig file")
flag.Parse()
// 创建 Kubernetes 客户端
config, _ := clientcmd.BuildConfigFromFlags("", *kubeconfig)
clientset, _ := kubernetes.NewForConfig(config)
// 创建 Informer 工厂
informerFactory := informers.NewSharedInformerFactory(clientset, 30*time.Second)
// 获取 Pod Informer
podInformer := informerFactory.Core().V1().Pods().Informer()
// 设置事件处理器
podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
pod := obj.(*v1.Pod)
fmt.Printf("Pod Added: %s/%s\n", pod.Namespace, pod.Name)
},
DeleteFunc: func(obj interface{}) {
pod := obj.(*v1.Pod)
fmt.Printf("Pod Deleted: %s/%s\n", pod.Namespace, pod.Name)
},
UpdateFunc: func(oldObj, newObj interface{}) {
newPod := newObj.(*v1.Pod)
oldPod := oldObj.(*v1.Pod)
if newPod.ResourceVersion != oldPod.ResourceVersion {
fmt.Printf("Pod Updated: %s/%s\n", newPod.Namespace, newPod.Name)
}
},
})
// 启动 Informer
stopCh := make(chan struct{})
defer close(stopCh)
informerFactory.Start(stopCh)
// 阻塞直到被停止
<-stopCh
}
-
Informer 工厂:
informers.NewSharedInformerFactory
创建一个 Informer 工厂,你可以从中获取特定资源的 Informer。 -
事件处理器: 使用
AddEventHandler
或AddEventHandlerWithResyncPeriod
设置事件处理器,这些处理器在资源发生变化时被调用。 -
启动 Informer: 使用
informerFactory.Start
启动所有 Informer。它需要一个stopCh
,这个 channel 用于在程序应当停止时关闭所有 Informer。 -
<-stopCh被阻塞知道close(stopCh)