k8s - kubectl 기능 소스 분석

9589 단어 hadoop
kubernetes 의 명령 행 인 터 페 이 스 는 kubectl 이 라 고 합 니 다. kubernetes 군집 을 제어 하 는 데 사 용 됩 니 다. 추적 할 명령 은 kubectl create - f - 지정 한 파일 에서 k8s 자원 을 만 듭 니 다. 우리 가 만 들 자원 은 nginx 기본 미 러 를 사용 한 단일 복사 본 pod 입 니 다.
우선 kubectl 명령 의 생 성 입 니 다. / cmd / kubectl / kubectl. go 파일 에서 kubectl 명령 의 생 성 을 실 현 했 습 니 다.
func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	command := cmd.NewDefaultKubectlCommand()

	// TODO: once we switch everything over to Cobra commands, we can go back to calling
	// utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
	// normalize func and add the go flag set by hand.
	pflag.CommandLine.SetNormalizeFunc(utilflag.WordSepNormalizeFunc)
	pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
	// utilflag.InitFlags()
	logs.InitLogs()
	defer logs.FlushLogs()

	if err := command.Execute(); err != nil {
		fmt.Fprintf(os.Stderr, "%v
", err) os.Exit(1) } }

main 함수 에서 NewDefault KubectlCommand 함 수 를 호출 했 습 니 다. 이 함수 의 실현 은:
/ pkg / kubectl / cmd / cmd. go 중:
func NewDefaultKubectlCommand() *cobra.Command {
	return NewKubectlCommand(os.Stdin, os.Stdout, os.Stderr)
}

이 함 수 는 cmd. go 파일 에 있 는 NewKubectlCommand 함 수 를 호출 합 니 다:
// NewKubectlCommand creates the `kubectl` command and its nested children.
func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
	// Parent command to which all subcommands are added.
	cmds := &cobra.Command{
		Use:   "kubectl",
		Short: i18n.T("kubectl controls the Kubernetes cluster manager"),
		Long: templates.LongDesc(`
      kubectl controls the Kubernetes cluster manager.

      Find more information at:
            https://kubernetes.io/docs/reference/kubectl/overview/`),
		Run: runHelp,
		BashCompletionFunction: bashCompletionFunc,
	}

	flags := cmds.PersistentFlags()
	flags.SetNormalizeFunc(utilflag.WarnWordSepNormalizeFunc) // Warn for "_" flags

이 함수 의 역할 은 kubectl 과 하위 명령 을 만 드 는 것 입 니 다.
다음은 kubectl create 서브 명령 을 실현 하 는 원본 코드 를 살 펴 보 겠 습 니 다.
/pkg/kubectl/cmd/create/create.go
func NewCmdCreate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
	o := NewCreateOptions(ioStreams)

	cmd := &cobra.Command{
		Use: "create -f FILENAME",
		DisableFlagsInUseLine: true,
		Short:   i18n.T("Create a resource from a file or from stdin."),
		Long:    createLong,
		Example: createExample,
		Run: func(cmd *cobra.Command, args []string) {
			if cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames) {
				defaultRunFunc := cmdutil.DefaultSubCommandRun(ioStreams.ErrOut)
				defaultRunFunc(cmd, args)
				return
			}
			cmdutil.CheckErr(o.Complete(f, cmd))
			cmdutil.CheckErr(o.ValidateArgs(cmd, args))
			cmdutil.CheckErr(o.RunCreate(f, cmd))
		},
	}

......

그 중에서 호출 된 RunCreate 함 수 는 create 의 주요 실현 입 니 다.이 함수 도 이 파일 에 있 습 니 다:
func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error {
	// raw only makes sense for a single file resource multiple objects aren't likely to do what you want.
	// the validator enforces this, so
	if len(o.Raw) > 0 {
		return o.raw(f)
	}

	if o.EditBeforeCreate {
		return RunEditOnCreate(f, o.RecordFlags, o.IOStreams, cmd, &o.FilenameOptions)
	}
	schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
	if err != nil {
		return err
	}

	cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
	if err != nil {
		return err
	}

	r := f.NewBuilder().
		Unstructured().
		Schema(schema).
		ContinueOnError().
		NamespaceParam(cmdNamespace).DefaultNamespace().
		FilenameParam(enforceNamespace, &o.FilenameOptions).
		LabelSelectorParam(o.Selector).
		Flatten().
		Do()

이 함 수 는 NewBuilder, Schema 등 일련의 함 수 를 호출 했 습 니 다. 이 코드 가 하 는 일 은 명령 행 에서 받 은 매개 변 수 를 자원 의 열 로 바 꾸 는 것 입 니 다.모든 자원 을 교체 방문 할 수 있 는 Visitor 구 조 를 만 드 는 것 도 책임 집 니 다.이 명령 은 Builder 모드 의 변종 을 사용 하여 독립 된 함수 로 각자 의 데이터 초기 화 작업 을 하기 때문에 복잡 합 니 다.함수 Schema, ContinueOnError, NamespaceParam, DefaultNamespace, FilenameParam, SelectorParam, Flatten 은 모두 Builder 구 조 를 가리 키 는 지침 을 도입 하여 수정 을 실행 하고 이 구조 체 를 호출 체인 의 다음 방법 으로 되 돌려 줍 니 다.이 함수 들 은 모두 이 파일 에 있 습 니 다:
/pkg/kubectl/genericclioptions/resource/builder.go
모든 초기 화가 완료 되면 resource. NewBuilder 함 수 는 Do 함 수 를 호출 합 니 다.이 Do 함 수 는 매우 중요 합 니 다. Result 대상 을 되 돌려 주 고 자원 에 대한 생 성 을 실행 합 니 다.Do 함 수 는 또한 Visitor 대상 을 만 들 고 resource. NewBuilder 실행 과정 과 관련 된 모든 자원 을 옮 겨 다 닐 수 있 습 니 다.Do 함수 의 구현 은 다음 과 같 습 니 다.
builder. go 에 도 있어 요.
// Do returns a Result object with a Visitor for the resources identified by the Builder.
// The visitor will respect the error behavior specified by ContinueOnError. Note that stream
// inputs are consumed by the first execution - use Infos() or Object() on the Result to capture a list
// for further iteration.
func (b *Builder) Do() *Result {
	r := b.visitorResult()
	r.mapper = b.Mapper()
	if r.err != nil {
		return r
	}
	if b.flatten {
		r.visitor = NewFlattenListVisitor(r.visitor, b.objectTyper, b.mapper)
	}
	helpers := []VisitorFunc{}
	if b.defaultNamespace {
		helpers = append(helpers, SetNamespace(b.namespace))
	}
	if b.requireNamespace {
		helpers = append(helpers, RequireNamespace(b.namespace))
	}
	helpers = append(helpers, FilterNamespace)
	if b.requireObject {
		helpers = append(helpers, RetrieveLazy)
	}
	r.visitor = NewDecoratedVisitor(r.visitor, helpers...)
	if b.continueOnError {
		r.visitor = ContinueOnErrorVisitor{r.visitor}
	}
	return r
}

새 DecoratedVisitor 를 만 들 고 Builder Do 함수 로 되 돌아 오 는 Result 의 일부분 입 니 다.이 Decorated Visitor 에는 Visit 함수 가 있 습 니 다.
/pkg/kubectl/genericclioptions/resource/visitor.go
// NewDecoratedVisitor will create a visitor that invokes the provided visitor functions before
// the user supplied visitor function is invoked, giving them the opportunity to mutate the Info
// object or terminate early with an error.
func NewDecoratedVisitor(v Visitor, fn ...VisitorFunc) Visitor {
	if len(fn) == 0 {
		return v
	}
	return DecoratedVisitor{v, fn}
}

// Visit implements Visitor
func (v DecoratedVisitor) Visit(fn VisitorFunc) error {
	return v.visitor.Visit(func(info *Info, err error) error {
		if err != nil {
			return err
		}
		for i := range v.decorators {
			if err := v.decorators[i](info, nil); err != nil {
				return err
			}
		}
		return fn(info, nil)
	})
}

즉, Do 함수 로 되 돌아 가면 r 대상 은 Do 에서 되 돌아 오고 Decorated Visitor 를 호출 하 는 함수 Visit, 즉 위의 Visit 가 있 습 니 다.이것 은 create. go 의 RunCreate 함수 에서 실제 최종 호출 된 익명 함수, 그리고 API Server 가 호출 된 createAndRefresh 함 수 를 찾 았 습 니 다.
RunCreate 함수 로 돌아 가 Do 를 호출 한 후,
		Do()
	err = r.Err()
	if err != nil {
		return err
	}

	count := 0
	err = r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}
		if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info.Object, cmdutil.InternalVersionJSONEncoder()); err != nil {
			return cmdutil.AddSourceToErr("creating", info.Source, err)
		}

		if err := o.Recorder.Record(info.Object); err != nil {
			glog.V(4).Infof("error recording current command: %v", err)
		}

		if !o.DryRun {
			if err := createAndRefresh(info); err != nil {
				return cmdutil.AddSourceToErr("creating", info.Source, err)
			}
		}

r. Visit 함 수 를 호출 했 습 니 다. 이 함수 의 실현 은 바로 위의 visitor. go 중의 Visit 함수 입 니 다.
그리고 createAndRefresh 함 수 를 호출 했 습 니 다:
이 함 수 는 create, go 파일 에 있 습 니 다:
// createAndRefresh creates an object from input info and refreshes info with that object
func createAndRefresh(info *resource.Info) error {
	obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
	if err != nil {
		return err
	}
	info.Refresh(obj, true)
	return nil
}

이 createAndRefresh 함 수 는 NewHelper 함 수 를 호출 했 습 니 다. 이 함 수 는:
/pkg/kubectl/genericclioptions/resource/helper.go
// NewHelper creates a Helper from a ResourceMapping
func NewHelper(client RESTClient, mapping *meta.RESTMapping) *Helper {
	return &Helper{
		Resource:        mapping.Resource.Resource,
		RESTClient:      client,
		NamespaceScoped: mapping.Scope.Name() == meta.RESTScopeNameNamespace,
	}
}

이 코드 는 새로운 Helper 대상 을 되 돌려 줍 니 다.
createAndRefresh 함수 로 돌아 가서 NewHelper 함 수 를 호출 하고 Create 함 수 를 호출 했 습 니 다.
/ pkg / kubectl / genericclioptions / resource / helper. go 에서
func (m *Helper) Create(namespace string, modify bool, obj runtime.Object) (runtime.Object, error) {
	if modify {
		// Attempt to version the object based on client logic.
		version, err := metadataAccessor.ResourceVersion(obj)
		if err != nil {
			// We don't know how to clear the version on this object, so send it to the server as is
			return m.createResource(m.RESTClient, m.Resource, namespace, obj)
		}
		if version != "" {
			if err := metadataAccessor.SetResourceVersion(obj, ""); err != nil {
				return nil, err
			}
		}
	}

	return m.createResource(m.RESTClient, m.Resource, namespace, obj)
}

func (m *Helper) createResource(c RESTClient, resource, namespace string, obj runtime.Object) (runtime.Object, error) {
	return c.Post().NamespaceIfScoped(namespace, m.NamespaceScoped).Resource(resource).Body(obj).Do().Get()
}
Create 함수 가 createresource 함 수 를 호출 한 것 을 볼 수 있 습 니 다.그리고 실제 API Server 에 보 내 는 Yml 파일 설명 을 만 드 는 자원 의 REST 호출 입 니 다.

좋은 웹페이지 즐겨찾기