kubectl使用及源码阅读

目录

概述

k8s 版本 v1.24.16

kubectl的职责

  • 1.主要的工作是处理用户提交的东西(包括,命令行参数,yaml文件等)
  • 2.将用户提交的这些东西组织成一个数据结构体
  • 3.再将其发送给 api server

实践

文章名 链接
linux k8s 源码编译及单集群测试 地址
k8s源码debug 地址

样例

cat test/fixtures/doc-yaml/user-guide/pod.yaml

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
字段名 含义
kind Pod
metadata.name
spec.containers.name
spec.containers.image image名称:版本

对象规约(Spec) 与状态 (Status)

  • 几乎每个 Kubernetes 对象包含两个嵌套的对象字段,它们负责管理对象的配置:对象 spec (规约) 和对象 status (状态)
  • 对于具有 spec 的对象,必须在创建对象时设置具体内容,描述你希望对象所具有的特征:期望状态 (Desired State)

yaml 中的必须字段

  • 在想要创建的 Kubernetes 对象对应的 yaml 文件中,需要配置如下的字段:
    • apiVersion - 创建该对象所使用的 Kubernetes API 的版本
    • kind - 想要创建的对象的类别
    • metadata - 帮助唯一标识对象的一些数据,包括一个 name 字符串、UID和可选的 namespace
bash 复制代码
[root@test kubernetes]# ./cluster/kubectl.sh get pods
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          89s
字段名 含义
NAME nginx就是对应yaml中metadata.name
READY 就绪个数
STATUS 当前的状态,RUNNING表示运行中
RESTARTS 重启的次数,代表没有重启过
AGE 运行的时长

kubectl 代码原理

  • 1.从命令行和 yaml 文件中获取信息
  • 2.通过 Builder 模式并将其转成一系列的资源
  • 3.最后用 Visitor 模式来迭代处理这些 Resources

源码位置

kubectl 命令行设置pprof 抓取火焰图

kubectl 中的 cobra
  • 底层函数 NewKubectlCommand 解析
  • 在 PersistentPreRunE 设置 prrof 采集相关指令
  • 在 PersistentPostRunE 设置了 pprof 统计结果落盘
  • 执行采集 pprof cpu 的 kubelet 命令
go 复制代码
kubectl.go --> command := cmd.NewDefaultKubectlCommand()
	cmd.go --> return NewDefaultKubectlCommandWithArgs(KubectlOptions{ -->cmd := NewKubectlCommand(o)
bash 复制代码
# cpu.pprof 文件在当前命令执行目录下
kubectl get node --profile=cpu --profile-output=cpu.pprof
# ll
# 使用 go 工具将 pprof 转换成 svg  火焰图
go tool pprof -svg cpu.pprof > kubectl_get_node_cpu.svg
# 下载下来,在浏览器打开

七大分组命令

go 复制代码
kubectl.go --> command := cmd.NewDefaultKubectlCommand()
	cmd.go --> var defaultConfigFlags = genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag().WithDiscoveryBurst(300).WithDiscoveryQPS(50.0) --> f := cmdutil.NewFactory(matchVersionKubeConfigFlags) --> 	proxyCmd := proxy.NewCmdProxy(f, o.IOStreams)
	proxyCmd.PreRun = func(cmd *cobra.Command, args []string) {
		kubeConfigFlags.WrapConfigFn = nil
	}
go 复制代码
groups := templates.CommandGroups{
	{
		Message: "Basic Commands (Beginner):",
		Commands: []*cobra.Command{
			create.NewCmdCreate(f, o.IOStreams),
			expose.NewCmdExposeService(f, o.IOStreams),
			run.NewCmdRun(f, o.IOStreams),
			set.NewCmdSet(f, o.IOStreams),
		},
	},
	{
		Message: "Basic Commands (Intermediate):",
		Commands: []*cobra.Command{
			explain.NewCmdExplain("kubectl", f, o.IOStreams),
			getCmd,
			edit.NewCmdEdit(f, o.IOStreams),
			delete.NewCmdDelete(f, o.IOStreams),
		},
	},
	{
		Message: "Deploy Commands:",
		Commands: []*cobra.Command{
			rollout.NewCmdRollout(f, o.IOStreams),
			scale.NewCmdScale(f, o.IOStreams),
			autoscale.NewCmdAutoscale(f, o.IOStreams),
		},
	},
	{
		Message: "Cluster Management Commands:",
		Commands: []*cobra.Command{
			certificates.NewCmdCertificate(f, o.IOStreams),
			clusterinfo.NewCmdClusterInfo(f, o.IOStreams),
			top.NewCmdTop(f, o.IOStreams),
			drain.NewCmdCordon(f, o.IOStreams),
			drain.NewCmdUncordon(f, o.IOStreams),
			drain.NewCmdDrain(f, o.IOStreams),
			taint.NewCmdTaint(f, o.IOStreams),
		},
	},
	{
		Message: "Troubleshooting and Debugging Commands:",
		Commands: []*cobra.Command{
			describe.NewCmdDescribe("kubectl", f, o.IOStreams),
			logs.NewCmdLogs(f, o.IOStreams),
			attach.NewCmdAttach(f, o.IOStreams),
			cmdexec.NewCmdExec(f, o.IOStreams),
			portforward.NewCmdPortForward(f, o.IOStreams),
			proxyCmd,
			cp.NewCmdCp(f, o.IOStreams),
			auth.NewCmdAuth(f, o.IOStreams),
			debug.NewCmdDebug(f, o.IOStreams),
		},
	},
	{
		Message: "Advanced Commands:",
		Commands: []*cobra.Command{
			diff.NewCmdDiff(f, o.IOStreams),
			apply.NewCmdApply("kubectl", f, o.IOStreams),
			patch.NewCmdPatch(f, o.IOStreams),
			replace.NewCmdReplace(f, o.IOStreams),
			wait.NewCmdWait(f, o.IOStreams),
			kustomize.NewCmdKustomize(o.IOStreams),
		},
	},
	{
		Message: "Settings Commands:",
		Commands: []*cobra.Command{
			label.NewCmdLabel(f, o.IOStreams),
			annotate.NewCmdAnnotate("kubectl", f, o.IOStreams),
			completion.NewCmdCompletion(o.IOStreams.Out, ""),
		},
	},
}

kubectl create

go 复制代码
// 进入口
create.NewCmdCreate(f, o.IOStreams)

// 核心的cmd.Run函数
// 校验文件参数
if cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames, o.FilenameOptions.Kustomize) {
	ioStreams.ErrOut.Write([]byte("Error: must specify one of -f and -k\n\n"))
	defaultRunFunc := cmdutil.DefaultSubCommandRun(ioStreams.ErrOut)
	defaultRunFunc(cmd, args)
	return
}

// 完善并填充所需字段 
cmdutil.CheckErr(o.Complete(f, cmd))
// 校验参数
cmdutil.CheckErr(o.ValidateArgs(cmd, args))
// 核心的RunCreate
// 发送请求与 api server 通信
cmdutil.CheckErr(o.RunCreate(f, cmd))

createCmd中的builder模式

createCmd中的builder建造者设计模式

go 复制代码
// 快速定位代码
cmdutil.CheckErr(o.RunCreate(f, cmd)) -->
r := f.NewBuilder().
		Unstructured().
		Schema(schema).
		ContinueOnError().
		NamespaceParam(cmdNamespace).DefaultNamespace().
		FilenameParam(enforceNamespace, &o.FilenameOptions).
		LabelSelectorParam(o.Selector).
		Flatten().
		Do()

createCmd中的visitor访问者模式

  • 访问都模式(Visitor Pattern) 是一种将数据结构与数据操作分离的设计模式
  • 指封装一些作用于某种数据结构中的各元素的操作
  • 可以在不改变数据结构的前提下定义作用于这些元素的新的操作
  • 属于行为型设计模式

使用场景:

  • 数据结构稳定,作用于数据结构的操作经常变化的场景
  • 需要数据结构与数据操作分享的场景
  • 需要对不同数据类型(元素)进行操作,而不使用分支判断具体类型的场景
go 复制代码
// 快速定位代码
cmdutil.CheckErr(o.RunCreate(f, cmd)) --> err = r.Visit(func(info *resource.Info, err error) error {

// 注意 Visit 是由 Builder 中 FilenameParam 构建的
r := f.NewBuilder().
		...
		// 构建 Visit
		FilenameParam(enforceNamespace, &o.FilenameOptions).
		...
		// 创建 Visit
		Do()
// 定位
FilenameParam --> b.Path(recursive, matches...) --> visitors, err := ExpandPathsToFileVisitors(b.mapper, p, recursive, FileExtensions, b.schema) -->
		visitor := &FileVisitor{
			Path:          path,
			StreamVisitor: NewStreamVisitor(nil, mapper, path, schema),
		}

FilenameParam --> b.Path(recursive, matches...) 位置

go 复制代码
// NewStreamVisitor is a helper function that is useful when we want to change the fields of the struct but keep calls the same.
func NewStreamVisitor(r io.Reader, mapper *mapper, source string, schema ContentValidator) *StreamVisitor {
	return &StreamVisitor{
		Reader: r,
		mapper: mapper,
		Source: source,
		Schema: schema,
	}
}

// 解析 yaml 或者 json 配置
// Visit implements Visitor over a stream. StreamVisitor is able to distinct multiple resources in one stream.
func (v *StreamVisitor) Visit(fn VisitorFunc) error {
	d := yaml.NewYAMLOrJSONDecoder(v.Reader, 4096)
	for {
		ext := runtime.RawExtension{}
		if err := d.Decode(&ext); err != nil {
			if err == io.EOF {
				return nil
			}
			return fmt.Errorf("error parsing %s: %v", v.Source, err)
		}
		// TODO: This needs to be able to handle object in other encodings and schemas.
		ext.Raw = bytes.TrimSpace(ext.Raw)
		if len(ext.Raw) == 0 || bytes.Equal(ext.Raw, []byte("null")) {
			continue
		}
		if err := ValidateSchema(ext.Raw, v.Schema); err != nil {
			return fmt.Errorf("error validating %q: %v", v.Source, err)
		}
		info, err := v.infoForData(ext.Raw, v.Source)
		if err != nil {
			if fnErr := fn(info, err); fnErr != nil {
				return fnErr
			}
			continue
		}
		if err := fn(info, nil); err != nil {
			return err
		}
	}
}
go 复制代码
// 上面方法中,重点如下代码
info, err := v.infoForData(ext.Raw, v.Source)

// obj 代表 k8s的对象
// gvk 代表 Group/Version/Kind 的缩写
obj, gvk, err := m.decoder.Decode(data, nil, nil)

外层VisitorFunc分析

  • 如查出错即返回错误
  • DryRunStrategy 代表试运行策略
    • 默认为 None 代表不试运行
    • client 代表客户端试运行,不发送请求至 server
    • server 点服务端试运行,发送请求,但是如果会改变状态的话就不做
go 复制代码
err = r.Visit(func(info *resource.Info, err error) error { --> if o.DryRunStrategy != cmdutil.DryRunClient {  --> Create(info.Namespace, true, info.Object)(最终创建资源)

结束

kubectl使用及进阶 至此结束。

相关推荐
技术-hxy2 天前
由于centos停更,yum、docker等不支持,采用阿里云仓库搭建K8S
centos·k8s
工业互联网专业2 天前
Python毕业设计选题:基于python的豆瓣电影数据分析可视化系统-flask+spider
vue.js·python·数据分析·flask·毕业设计·源码·课程设计
KubeSphere 云原生4 天前
云原生周刊:Kubernetes v1.32 要来了
云计算·k8s·容器平台·kubesphere
工业互联网专业4 天前
Python毕业设计选题:基于Spark的国漫推荐系统的设计与实现-django+spider
vue.js·python·spark·django·毕业设计·源码·课程设计
工业互联网专业6 天前
Python毕业设计选题:基于django+vue的二手物品交易系统
vue.js·python·django·毕业设计·源码·课程设计
工业互联网专业6 天前
Python毕业设计选题:基于BS架构的在线学习与推荐系统的设计与实现-django
vue.js·python·django·毕业设计·源码·课程设计
运维小文7 天前
K8S资源限制之resources
云原生·k8s·资源限制·resources
xcLeigh7 天前
VUE3实现简洁的特色美食网站源码
前端·源码·vue3
程序猿麦小七8 天前
今天给在家介绍一篇基于jsp的旅游网站设计与实现
java·源码·旅游·景区·酒店
小安运维日记8 天前
CKA认证 | Day3 K8s管理应用生命周期(上)
运维·云原生·容器·kubernetes·云计算·k8s