发布一个k8s部署视频:https://edu.csdn.net/course/detail/26967
课程内容:各种k8s部署方式。包括minikube部署,kubeadm部署,kubeasz部署,rancher部署,k3s部署。包括开发测试环境部署k8s,和生产环境部署k8s。
腾讯课堂连接地址https://ke.qq.com/course/478827?taid=4373109931462251&tuin=ba64518
第二个视频发布 https://edu.csdn.net/course/detail/27109
腾讯课堂连接地址https://ke.qq.com/course/484107?tuin=ba64518
介绍主要的k8s资源的使用配置和命令。包括configmap,pod,service,replicaset,namespace,deployment,daemonset,ingress,pv,pvc,sc,role,rolebinding,clusterrole,clusterrolebinding,secret,serviceaccount,statefulset,job,cronjob,podDisruptionbudget,podSecurityPolicy,networkPolicy,resourceQuota,limitrange,endpoint,event,conponentstatus,node,apiservice,controllerRevision等。
第三个视频发布:https://edu.csdn.net/course/detail/27574
详细介绍helm命令,学习helm chart语法,编写helm chart。深入分析各项目源码,学习编写helm插件
第四个课程发布:https://edu.csdn.net/course/detail/28488
本课程将详细介绍k8s所有命令,以及命令的go源码分析,学习知其然,知其所以然
加qq群,请联系:
————————————————
type GetOptions struct {//get结构体
PrintFlags *PrintFlags
ToPrinter func(*meta.RESTMapping, *bool, bool, bool) (printers.ResourcePrinterFunc, error)
IsHumanReadablePrinter bool
PrintWithOpenAPICols bool
CmdParent string
resource.FilenameOptions
Raw string
Watch bool
WatchOnly bool
ChunkSize int64
OutputWatchEvents bool
LabelSelector string
FieldSelector string
AllNamespaces bool
Namespace string
ExplicitNamespace bool
ServerPrint bool
NoHeaders bool
Sort bool
IgnoreNotFound bool
Export bool
genericclioptions.IOStreams
}
func NewGetOptions(parent string, streams genericclioptions.IOStreams) *GetOptions {
return &GetOptions{//初始化结构体
PrintFlags: NewGetPrintFlags(),
CmdParent: parent,
IOStreams: streams,
ChunkSize: 500,
ServerPrint: true,
}
}
//创建get命令
func NewCmdGet(parent string, f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := NewGetOptions(parent, streams)//初始化结构体
cmd := &cobra.Command{//创建cobra命令
Use: "get [(-o|--output=)json|yaml|wide|custom-columns=...|custom-columns-file=...|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=...] (TYPE[.VERSION][.GROUP] [NAME | -l label] | TYPE[.VERSION][.GROUP]/NAME ...) [flags]",
DisableFlagsInUseLine: true,
Short: i18n.T("Display one or many resources"),
Long: getLong + "\n\n" + cmdutil.SuggestAPIResources(parent),
Example: getExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))//准备
cmdutil.CheckErr(o.Validate(cmd))//校验
cmdutil.CheckErr(o.Run(f, cmd, args))//运行
},
SuggestFor: []string{"list", "ps"},
}
o.PrintFlags.AddFlags(cmd)//打印选项
cmd.Flags().StringVar(&o.Raw, "raw", o.Raw, "Raw URI to request from the server. Uses the transport specified by the kubeconfig file.")//raw选项
cmd.Flags().BoolVarP(&o.Watch, "watch", "w", o.Watch, "After listing/getting the requested object, watch for changes. Uninitialized objects are excluded if no object name is provided.")//watch选项
cmd.Flags().BoolVar(&o.WatchOnly, "watch-only", o.WatchOnly, "Watch for changes to the requested object(s), without listing/getting first.")//watch-only选项
cmd.Flags().BoolVar(&o.OutputWatchEvents, "output-watch-events", o.OutputWatchEvents, "Output watch event objects when --watch or --watch-only is used. Existing objects are output as initial ADDED events.")//output-watch-events选项
cmd.Flags().Int64Var(&o.ChunkSize, "chunk-size", o.ChunkSize, "Return large lists in chunks rather than all at once. Pass 0 to disable. This flag is beta and may change in the future.")//chunk-size选项
cmd.Flags().BoolVar(&o.IgnoreNotFound, "ignore-not-found", o.IgnoreNotFound, "If the requested object does not exist the command will return exit code 0.")//ignore-not-found选项
cmd.Flags().StringVarP(&o.LabelSelector, "selector", "l", o.LabelSelector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")//selector选项
cmd.Flags().StringVar(&o.FieldSelector, "field-selector", o.FieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.")//field-selector选项
cmd.Flags().BoolVarP(&o.AllNamespaces, "all-namespaces", "A", o.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")//all-namespace选项
cmdutil.AddIncludeUninitializedFlag(cmd)
addOpenAPIPrintColumnFlags(cmd, o)
addServerPrintColumnFlags(cmd, o)//server-print选项
cmd.Flags().BoolVar(&o.Export, "export", o.Export, "If true, use 'export' for the resources. Exported resources are stripped of cluster-specific information.")
cmd.Flags().MarkDeprecated("export", "This flag is deprecated and will be removed in future.")
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "identifying the resource to get from a server.")//文件选项
return cmd
}
//准备方法
func (o *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
if len(o.Raw) > 0 {
if len(args) > 0 {//如果指定了raw,args大于0个则报错
return fmt.Errorf("arguments may not be passed when --raw is specified")
}
return nil
}
var err error
o.Namespace, o.ExplicitNamespace, err = f.ToRawKubeConfigLoader().Namespace()//设置namespace和enforceNamespace
if err != nil {
return err
}
if o.AllNamespaces {//如果指定了all-namespaces,则explicitNamespace为false
o.ExplicitNamespace = false
}
sortBy, err := cmd.Flags().GetString("sort-by")//获取sort-by选项
if err != nil {
return err
}
o.Sort = len(sortBy) > 0//设置sort
o.NoHeaders = cmdutil.GetFlagBool(cmd, "no-headers")//设置noHeaders
// TODO (soltysh): currently we don't support custom columns
// with server side print. So in these cases force the old behavior.
outputOption := cmd.Flags().Lookup("output").Value.String()//获取output
if outputOption == "custom-columns" {//如果output为custom-columns,则serverPrint为false
o.ServerPrint = false
}
templateArg := ""
if o.PrintFlags.TemplateFlags != nil && o.PrintFlags.TemplateFlags.TemplateArgument != nil {
templateArg = *o.PrintFlags.TemplateFlags.TemplateArgument//获取template
}
// human readable printers have special conversion rules, so we determine if we're using one.
if (len(*o.PrintFlags.OutputFormat) == 0 && len(templateArg) == 0) || *o.PrintFlags.OutputFormat == "wide" {
o.IsHumanReadablePrinter = true
}
o.ToPrinter = func(mapping *meta.RESTMapping, outputObjects *bool, withNamespace bool, withKind bool) (printers.ResourcePrinterFunc, error) {//设置toPrinter函数
// make a new copy of current flags / opts before mutating
printFlags := o.PrintFlags.Copy()
if mapping != nil {
if !cmdSpecifiesOutputFmt(cmd) && o.PrintWithOpenAPICols {
if apiSchema, err := f.OpenAPISchema(); err == nil {
printFlags.UseOpenAPIColumns(apiSchema, mapping)
}
}
printFlags.SetKind(mapping.GroupVersionKind.GroupKind())
}
if withNamespace {
printFlags.EnsureWithNamespace()
}
if withKind {
printFlags.EnsureWithKind()
}
printer, err := printFlags.ToPrinter()//printflag转printer
if err != nil {
return nil, err
}
if o.Sort {//如果sort为true,包装printer为sortingPrinter
printer = &SortingPrinter{Delegate: printer, SortField: sortBy}
}
if outputObjects != nil {//如果outputObject不为空,则包装printer为skipPrinter
printer = &skipPrinter{delegate: printer, output: outputObjects}
}
if o.ServerPrint {//如果serverPrint为true,则包装为TablePrinter
printer = &TablePrinter{Delegate: printer}
}
return printer.PrintObj, nil//返回printObj函数
}
switch {
case o.Watch || o.WatchOnly:
if o.Sort {//如果watch或watchOnly为true、则sort被忽略
fmt.Fprintf(o.IOStreams.ErrOut, "warning: --watch or --watch-only requested, --sort-by will be ignored\n")
}
default:
if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(o.Filenames, o.Kustomize) {//如果参数个数为0个,并且文件没指定
fmt.Fprintf(o.ErrOut, "You must specify the type of resource to get. %s\n\n", cmdutil.SuggestAPIResources(o.CmdParent))//打印错误
fullCmdName := cmd.Parent().CommandPath()
usageString := "Required resource not specified."
if len(fullCmdName) > 0 && cmdutil.IsSiblingCommandExists(cmd, "explain") {
usageString = fmt.Sprintf("%s\nUse \"%s explain \" for a detailed description of that resource (e.g. %[2]s explain pods).", usageString, fullCmdName)
}
return cmdutil.UsageErrorf(cmd, usageString)//返回错误
}
}
// openapi printing is mutually exclusive with server side printing
if o.PrintWithOpenAPICols && o.ServerPrint {//指定了PrintWithOpenAPICols ,ServerPrint 将被忽略,打印告警
fmt.Fprintf(o.IOStreams.ErrOut, "warning: --%s requested, --%s will be ignored\n", useOpenAPIPrintColumnFlagLabel, useServerPrintColumns)
}
return nil
}
//校验
func (o *GetOptions) Validate(cmd *cobra.Command) error {
if len(o.Raw) > 0 {//如果raw有值
if o.Watch || o.WatchOnly || len(o.LabelSelector) > 0 || o.Export {//watch,watchonly,labelSelector,export不能和raw同时存在
return fmt.Errorf("--raw may not be specified with other flags that filter the server request or alter the output")
}
if len(cmdutil.GetFlagString(cmd, "output")) > 0 {//raw和output是互斥的
return cmdutil.UsageErrorf(cmd, "--raw and --output are mutually exclusive")
}
if _, err := url.ParseRequestURI(o.Raw); err != nil {//raw url必须正确
return cmdutil.UsageErrorf(cmd, "--raw must be a valid URL path: %v", err)
}
}
if cmdutil.GetFlagBool(cmd, "show-labels") {//如果指定了show-labels
outputOption := cmd.Flags().Lookup("output").Value.String()
if outputOption != "" && outputOption != "wide" {//如果output不为空或wide则报错
return fmt.Errorf("--show-labels option cannot be used with %s printer", outputOption)
}
}
if o.OutputWatchEvents && !(o.Watch || o.WatchOnly) {//如果指定o了utput-watch-events则watch或watchOnly必须指定
return cmdutil.UsageErrorf(cmd, "--output-watch-events option can only be used with --watch or --watch-only")
}
return nil
}
//运行
func (o *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
if len(o.Raw) > 0 {//如果是raw直接运行rawhttp。rawGet
restClient, err := f.RESTClient()
if err != nil {
return err
}
return rawhttp.RawGet(restClient, o.IOStreams, o.Raw)
}
if o.Watch || o.WatchOnly {//如果指定了watch,watchOnly则运行watch函数
return o.watch(f, cmd, args)
}
chunkSize := o.ChunkSize
if o.Sort {//如果指定了sort则disablechunksize
// TODO(juanvallejo): in the future, we could have the client use chunking
// to gather all results, then sort them all at the end to reduce server load.
chunkSize = 0
}
r := f.NewBuilder().
Unstructured().
NamespaceParam(o.Namespace).DefaultNamespace().AllNamespaces(o.AllNamespaces).
FilenameParam(o.ExplicitNamespace, &o.FilenameOptions).
LabelSelectorParam(o.LabelSelector).
FieldSelectorParam(o.FieldSelector).
ExportParam(o.Export).
RequestChunksOf(chunkSize).
ResourceTypeOrNameArgs(true, args...).
ContinueOnError().
Latest().
Flatten().
TransformRequests(o.transformRequests).
Do()构造info对象
if o.IgnoreNotFound {
r.IgnoreErrors(kapierrors.IsNotFound)
}
if err := r.Err(); err != nil {
return err
}
if !o.IsHumanReadablePrinter {//如果humanReadablePrinter为false,则打印generic
return o.printGeneric(r)
}
allErrs := []error{}
errs := sets.NewString()
infos, err := r.Infos()//获取info
if err != nil {
allErrs = append(allErrs, err)
}
printWithKind := multipleGVKsRequested(infos)
objs := make([]runtime.Object, len(infos))
for ix := range infos {
objs[ix] = infos[ix].Object//获取info中的Object
}
sorting, err := cmd.Flags().GetString("sort-by")//获取sort-by
if err != nil {
return err
}
var positioner OriginalPositioner
if o.Sort {//如果指定了sort
sorter := NewRuntimeSorter(objs, sorting)//构造RuntimeSorter
if err := sorter.Sort(); err != nil {//培训
return err
}
positioner = sorter
}
var printer printers.ResourcePrinter
var lastMapping *meta.RESTMapping
// track if we write any output
trackingWriter := &trackingWriterWrapper{Delegate: o.Out}
// output an empty line separating output
separatorWriter := &separatorWriterWrapper{Delegate: trackingWriter}
w := utilprinters.GetNewTabWriter(separatorWriter)
for ix := range objs {//遍历objs
var mapping *meta.RESTMapping
var info *resource.Info
if positioner != nil {
info = infos[positioner.OriginalPosition(ix)]
mapping = info.Mapping
} else {
info = infos[ix]
mapping = info.Mapping
}
printWithNamespace := o.AllNamespaces//是否打印名称空间
if mapping != nil && mapping.Scope.Name() == meta.RESTScopeNameRoot {
printWithNamespace = false//如果对象是全局的,则不打印名称空间
}
if shouldGetNewPrinterForMapping(printer, lastMapping, mapping) {
w.Flush()
w.SetRememberedWidths(nil)
// add linebreaks between resource groups (if there is more than one)
// when it satisfies all following 3 conditions:
// 1) it's not the first resource group
// 2) it has row header
// 3) we've written output since the last time we started a new set of headers
if lastMapping != nil && !o.NoHeaders && trackingWriter.Written > 0 {
separatorWriter.SetReady(true)
}
printer, err = o.ToPrinter(mapping, nil, printWithNamespace, printWithKind)//获取printObj函数
if err != nil {
if !errs.Has(err.Error()) {
errs.Insert(err.Error())
allErrs = append(allErrs, err)
}
continue
}
lastMapping = mapping
}
// ensure a versioned object is passed to the custom-columns printer
// if we are using OpenAPI columns to print
if o.PrintWithOpenAPICols {
printer.PrintObj(info.Object, w)打印结果
continue
}
printer.PrintObj(info.Object, w)//打印结果
}
w.Flush()
if trackingWriter.Written == 0 && !o.IgnoreNotFound && len(allErrs) == 0 {//打印资源未找到
// if we wrote no output, and had no errors, and are not ignoring NotFound, be sure we output something
if !o.AllNamespaces {
fmt.Fprintln(o.ErrOut, fmt.Sprintf("No resources found in %s namespace.", o.Namespace))
} else {
fmt.Fprintln(o.ErrOut, fmt.Sprintf("No resources found"))
}
}
return utilerrors.NewAggregate(allErrs)
}
//watch函数
func (o *GetOptions) watch(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
r := f.NewBuilder().
Unstructured().
NamespaceParam(o.Namespace).DefaultNamespace().AllNamespaces(o.AllNamespaces).
FilenameParam(o.ExplicitNamespace, &o.FilenameOptions).
LabelSelectorParam(o.LabelSelector).
FieldSelectorParam(o.FieldSelector).
ExportParam(o.Export).
RequestChunksOf(o.ChunkSize).
ResourceTypeOrNameArgs(true, args...).
SingleResourceType().
Latest().
TransformRequests(o.transformRequests).
Do()//构造info对象
if err := r.Err(); err != nil {
return err
}
infos, err := r.Infos()//获取infos
if err != nil {
return err
}
if multipleGVKsRequested(infos) {//只能监控一种资源
return i18n.Errorf("watch is only supported on individual resources and resource collections - more than 1 resource was found")
}
info := infos[0]
mapping := info.ResourceMapping()
outputObjects := utilpointer.BoolPtr(!o.WatchOnly)//如果是watchOnly则不输出对象
printer, err := o.ToPrinter(mapping, outputObjects, o.AllNamespaces, false)//获取printer
if err != nil {
return err
}
obj, err := r.Object()
if err != nil {
return err
}
// watching from resourceVersion 0, starts the watch at ~now and
// will return an initial watch event. Starting form ~now, rather
// the rv of the object will insure that we start the watch from
// inside the watch window, which the rv of the object might not be.
rv := "0"
isList := meta.IsListType(obj)//判断是否是List
if isList {//如果是List
// the resourceVersion of list objects is ~now but won't return
// an initial watch event
rv, err = meta.NewAccessor().ResourceVersion(obj)//获取resrouceVersion
if err != nil {
return err
}
}
writer := utilprinters.GetNewTabWriter(o.Out)
// print the current object
var objsToPrint []runtime.Object
if isList {
objsToPrint, _ = meta.ExtractList(obj)
} else {
objsToPrint = append(objsToPrint, obj)
}
for _, objToPrint := range objsToPrint {//遍历对象
if o.OutputWatchEvents {//如果打印事件,则包装对象
objToPrint = &metav1.WatchEvent{Type: string(watch.Added), Object: runtime.RawExtension{Object: objToPrint}}
}
if err := printer.PrintObj(objToPrint, writer); err != nil {//打印对象
return fmt.Errorf("unable to output the provided object: %v", err)
}
}
writer.Flush()
if isList {
// we can start outputting objects now, watches started from lists don't emit synthetic added events
*outputObjects = true
} else {
// suppress output, since watches started for individual items emit a synthetic ADDED event first
*outputObjects = false
}
// print watched changes
w, err := r.Watch(rv)//获取监控对象
if err != nil {
return err
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
intr := interrupt.New(nil, cancel)
intr.Run(func() error {
_, err := watchtools.UntilWithoutRetry(ctx, w, func(e watch.Event) (bool, error) {//监控
objToPrint := e.Object
if o.OutputWatchEvents {//包装对象
objToPrint = &metav1.WatchEvent{Type: string(e.Type), Object: runtime.RawExtension{Object: objToPrint}}
}
if err := printer.PrintObj(objToPrint, writer); err != nil {//打印对象
return false, err
}
writer.Flush()
// after processing at least one event, start outputting objects
*outputObjects = true
return false, nil
})
return err
})
return nil
}