Replica Set Controller 源码分析

版本环境 kubernetes版本:kubernetes:v1.16.0 go环境:go version go1.13.4 darwin/amd64 前言 前面文章已经总结到,deployment controller通过replicaset来控制pod的创建和删除,进而实现更高级操作例如,滚动更新,回滚等。本文继续从源码角度 分析replicaset controller如何控制pod的创建和删除。 在分析源码前先考虑一下 replicaset 的使用场景,在平时的操作中其实我们并不会直接操作 replicaset,replicaset 也仅有几个简单的操作,创建、删除、更新等。 源码分析 入口 我们在上一篇文章中也说道controller manager是所有k8s 资源controller的管控中心,包含的主要逻辑就是高可用选择leader,然后 遍历所有的controllers,对每一个controller进行初始化并启动,也就是说只要集群启动,所有的controller也会都启动起来,开始list-watch api server,来准备创建资源。 cmd/kube-controller-manager/app/controllermanager.go:386 func NewControllerInitializers(loopMode ControllerLoopMode) map[string]InitFunc { controllers := map[string]InitFunc{} controllers["endpoint"] = startEndpointController controllers["endpointslice"] = startEndpointSliceController ... controllers["deployment"] = startDeploymentController controllers["replicaset"] = startReplicaSetController } 接下来进入startReplicaSetController, 发现通过NewReplicaSetController初始化了ReplicaSetController,并并调用run方法启动controller。 cmd/kube-controller-manager/app/apps.go:69 func startReplicaSetController(ctx ControllerContext) (http.Handler, bool, error) { if !ctx.AvailableResources[schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "replicasets"}] { return nil, false, nil } go replicaset.NewReplicaSetController( ctx.InformerFactory.Apps().V1().ReplicaSets(), ctx.InformerFactory.Core().V1().Pods(), ctx.ClientBuilder.ClientOrDie("replicaset-controller"), replicaset.BurstReplicas, ).Run(int(ctx.ComponentConfig.ReplicaSetController.ConcurrentRSSyncs), ctx.Stop) return nil, true, nil } 我们先分析NewReplicaSetController看一下初始化ReplicaSetController的具体步骤:发现他会监听rs的add,update,delete操作,和pod的add,update,delete操作。 当这两种资源发送变化时,将key(name+namespace)添加到queue队列中去。 //pkg/controller/replicaset/replica_set.go:126 func NewBaseController(rsInformer appsinformers.ReplicaSetInformer, podInformer coreinformers.PodInformer, kubeClient clientset.Interface, burstReplicas int, gvk schema.GroupVersionKind, metricOwnerName, queueName string, podControl controller.
Read more...

K8S Controller Manager 源码分析

版本环境 kubernetes版本:kubernetes:v1.16.0 go环境:go version go1.13.4 darwin/amd64 前言 Controller Manager内部包含Replication Controller、Node Controller、 ResourceQuota Controller、Namespace Controller、ServiceAccount Controller、Token Controller、Service Controller及Endpoint Controller这8种Controller, 每个Controller,它们通过API Server提供的(List-Watch)接口实时监控集群中特定资源的状态变化,当发生各种故障 导致某资源对象的状态发生变化时,Controller会尝试将其状态调整为期望的状态。 代码总体解析 入口 # cmd/kube-controller-manager/controller-manager.go func main() { rand.Seed(time.Now().UnixNano()) command := app.NewControllerManagerCommand() logs.InitLogs() defer logs.FlushLogs() if err := command.Execute(); err != nil { os.Exit(1) } } 进入NewControllerManagerCommand 函数,可以看到新建ControllerManager需要两步 启动参数配置,及Run函数,进入Run函数。 func NewControllerManagerCommand() *cobra.Command { s, err := options.NewKubeControllerManagerOptions() if err != nil { klog.Fatalf("unable to initialize command options: %v", err) } cmd := &cobra.Command{ Use: "kube-controller-manager", Run: func(cmd *cobra.Command, args []string) { verflag.PrintAndExitIfRequested() utilflag.PrintFlags(cmd.Flags()) c, err := s.Config(KnownControllers(), ControllersDisabledByDefault.List()) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.
Read more...

K8S Api Server 源码分析

版本环境 kubernetes版本:kubernetes:v1.16.0 go环境:go version go1.13.4 darwin/amd64 Api Server架构 kubernetes api server 提供了增删改查,list,watch各类资源的接口,对请求进行验证,鉴权及admission controller, 请求成功后将结果更新到后端存储etcd(也可以是其他存储)中。 api server 架构从上到下可以分为以下几层: 1.Api层,主要包含三种api core api: 主要在/api/v1下 分组api: 其path为/apis/$NAME/$VERSION 暴露系统状态的api: 如/metrics,/healthz,/logs,/openapi等 $ curl -k https://127.0.0.1:56521 { "paths": [ "/api", "/api/v1", "/apis", "/apis/", "/apis/admissionregistration.k8s.io", "/apis/admissionregistration.k8s.io/v1beta1", ... "/healthz", "/healthz/autoregister-completion", "/healthz/etcd", ... "/logs", "/metrics", "/openapi/v2", "/swagger-2.0.0.json", "/swaggerapi", "/version" 2.访问控制层 当用户访问api接口时,访问控制层将会做如下校验: 对用户进行身份校验(authentication)–> 校验用户对k8s资源对象访问权限(authorization) –> 根据配置的资源访问许可逻辑(admission control),判断是否访问。 下面分别对这三种校验方式进行说明: 2.1 Authentication 身份校验 k8s提供了三种客户端身份校验方式:https双向证书认证,http token方式认证, http base 认证也就是用户名密码方式 a. 基于CA根证书签名的双向数字证书认证 client和server向CA机构申请证书 client->server,server下发服务端证书,client利用证书验证server是否合法 client发送客户端证书给server,server利用证书校验client是否合法 client和server利用随机密钥加密消息,然后通信 apiserver启动的时候通过–client-ca-file=XXXX配置签发client证书的CA,当client发送证书过来时,apiserver使用CA验证,如果证书合法,则可进行通信。 这种方式的优点是安全,缺点是无法撤销用户证书,创建集群就绑定了证书。 $ k get pods kube-apiserver-kind-control-plane -n kube-system -o yaml - command: - kube-apiserver - --authorization-mode=Node,RBAC - --advertise-address=172.17.0.2 - --allow-privileged=true - --client-ca-file=/etc/kubernetes/pki/ca.crt b.
Read more...

CoreDNS生产案:pod出现dns解析大量失败的问题

问题 收到阿里云K8S集群监控告警: CoreDNS 5分钟内NXDOMAIN响应百分比大于50% k8s.coredns.response[aliyun,172.22.82.25:9153,NXDOMAIN] 是coredns的172.22.82.25的这个pod出现dns解析大量失败的问题。(解析成功的日志是NOERROR,解析失败是:NXDMAIN) 分析 首先是查看这个coredns pod的日志: [root@iZbp16er8wkobo2a165ekzZ ~]# kubectl get pods -n kube-system -o wide | grep coredns |grep 172.22.82.25 coredns-57dc86754b-9schh 1/1 Running 0 17d 172.22.82.25 cn-hangzhou.xxx.xxx.xxx.xxx <none>[root@iZbp16er8wkobo2a165ekzZ ~]# kubectl logs -n kube-system coredns-57dc86754b-9schh | tail -10 2020-03-05T13:06:29.745Z [INFO] 172.22.0.66:54106 - 24311 "A IN metrics.cn-hangzhou.aliyuncs.com. udp 50 false 512" NOERROR qr,rd,ra 190 0.00003395s 2020-03-05T13:06:29.745Z [INFO] 172.22.0.66:56730 - 20278 "AAAA IN metrics.cn-hangzhou.aliyuncs.com. udp 50 false 512" NOERROR qr,rd,ra 232 0.000072002s 2020-03-05T13:06:29.748Z [INFO] 172.22.0.66:41047 - 53211 "AAAA IN metrics.cn-hangzhou.aliyuncs.com.kube-system.svc.cluster.local. udp 80 false 512" NXDOMAIN qr,rd,ra 173 0.00004196s 2020-03-05T13:06:29.748Z [INFO] 172.22.0.66:40581 - 40714 "A IN metrics.cn-hangzhou.aliyuncs.com.kube-system.svc.cluster.local. udp 80 false 512" NXDOMAIN qr,rd,ra 173 0.
Read more...

hugo+gitpage搭建个人博客

安装hugo brew install hugo hugo version 生成blog根目录 hugo new site blog config.toml 是配置文件,在里面可以定义博客地址、构建配置、标题、导航栏等等。 themes 是主题目录,可以去 themes.gohugo.io 下载喜欢的主题。 content 是博客文章的目录。 安装主题 https://themes.gohugo.io/whiteplain/ 使用hugo写文章 hugo new post/my-first-post.md 设置文章相关属性 title: "My First Post" date: 2017-12-14T11:18:15+08:00 weight: 70 markup: mmark draft: false keywords: ["hugo"] description: "第一篇文章" tags: ["hugo", "pages"] categories: ["pages"] author: "" 预览 hugo server -D 确保本地网站正常,hugo server运行后在本地打开localhost:1313检查网站效果和内容,注意hugo server这个命令不会构建草稿,所以如果有草稿需要发布,将文章中的draft设置为false。 将hugo部署在gitpage 在Github创建一个仓库,例如名字叫blog,可以是私有的,这个仓库用来存放网站内容和源文件。 再创建一个名称为.github.io的仓库,username为GitHub用户名,这个仓库用于存放最终发布的网站内容。 进入本地网站目录,将本地网站全部内容推送到远程blog仓库。 cd blog git init git remote add origin git@github.com:wukaiying/blog.git git add -A git commit -m "first commit" git push -u origin master 删除本地网站目录下的public文件夹 创建public子模块 git submodule add -b master git@github.com:wukaiying/wukaiying.github.io.git public 然后就可以执行hugo命令,此命令会自动将网站静态内容生成到public文件夹,然后提交到远程blog仓库 cd public git status git add . git commit -m "first commit" git push -u orgin master 过一会就可以打开.
Read more...

Kubernetes中leaderelection实现组件高可用

在Kubernetes中,通常kube-schduler和kube-controller-manager都是多副本进行部署的来保证高可用,而真正在工作的实例其实只有一个。 这里就利用到 leaderelection 的选主机制,保证leader是处于工作状态,并且在leader挂掉之后,从其他节点选取新的leader保证组件正常工作。今天就来看看这个包的使用以及它内部是如何实现的。 基本使用 以下是一个简单使用的例子,编译完成之后同时启动多个进程,但是只有一个进程在工作,当把leader进程kill掉之后,会重新选举出一个leader进行工作,即执行其中的 run 方法: /* 例子来源于client-go中的example包中, */ package main import ( "context" "flag" "os" "os/signal" "syscall" "time" "github.com/google/uuid" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" clientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/leaderelection" "k8s.io/client-go/tools/leaderelection/resourcelock" "k8s.io/klog" ) func buildConfig(kubeconfig string) (*rest.Config, error) { if kubeconfig != "" { cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfig) if err != nil { returnnil, err } return cfg, nil } cfg, err := rest.InClusterConfig() if err != nil { returnnil, err } return cfg, nil } func main() { klog.InitFlags(nil) var kubeconfig string var leaseLockName string var leaseLockNamespace string var id string flag.StringVar(&kubeconfig, "kubeconfig", "", "absolute path to the kubeconfig file") flag.
Read more...