通過docker cli 源碼跟蹤docker鏡像簽名

Docker代碼更新很快,Docker項目更名爲moby,然後很多組件又從moby中拆分了出來。其中docker client的源碼如下:
https://github.com/docker/cli 目前最新的版本是18.09,可直接下載或通過gitclone下載。將項目放在如下目錄:cli-master

1、入口文件在cmd/docker/docker.go

func main() {	
     dockerCli, err := command.NewDockerCli()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	logrus.SetOutput(dockerCli.Err())
	if err := runDocker(dockerCli); err != nil {
		if sterr, ok := err.(cli.StatusError); ok {
			if sterr.Status != "" {	
			fmt.Fprintln(dockerCli.Err(), sterr.Status)
			}
			// StatusError should only be used for errors, and all errors should
			// have a non-zero exit status, so never exit with 0
			if sterr.StatusCode == 0 {
				os.Exit(1)
			}
			os.Exit(sterr.StatusCode)
		}
		fmt.Fprintln(dockerCli.Err(), err)
		os.Exit(1)
	}
}

2、跳到上面的runDocker(dockerCli)函數中:

func newDockerCommand(dockerCli *command.DockerCli) *cobra.Command {
    opts := cliflags.NewClientOptions()
    var flags *pflag.FlagSet

    cmd := &cobra.Command{
        Use:              "docker [OPTIONS] COMMAND [ARG...]",
        Short:            "A self-sufficient runtime for containers",
        SilenceUsage:     true,
        SilenceErrors:    true,
        TraverseChildren: true,
        Args:             noArgs,
        RunE: func(cmd *cobra.Command, args []string) error {
            return command.ShowHelp(dockerCli.Err())(cmd, args)
        },
        PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
            // flags must be the top-level command flags, not cmd.Flags()
            opts.Common.SetDefaultOptions(flags)
            dockerPreRun(opts)
            if err := dockerCli.Initialize(opts); err != nil {
                return err
            }
            return isSupported(cmd, dockerCli)
        },
        Version:               fmt.Sprintf("%s, build %s", cli.Version, cli.GitCommit),
        DisableFlagsInUseLine: true,
    }
    //將cmd裏的設置爲root命令
    cli.SetupRootCommand(cmd)

    flags = cmd.Flags()
    flags.BoolP("version", "v", false, "Print version information and quit")
    flags.StringVar(&opts.ConfigDir, "config", cliconfig.Dir(), "Location of client config files")
    opts.Common.InstallFlags(flags)

    setFlagErrorFunc(dockerCli, cmd, flags, opts)

    setHelpFunc(dockerCli, cmd, flags, opts)

    cmd.SetOutput(dockerCli.Out())
    //添加子命令,cmd裏是root命令
    commands.AddCommands(cmd, dockerCli)

    disableFlagsInUseLine(cmd)
    setValidateArgs(dockerCli, cmd, flags, opts)

    return cmd
}

3、commands.AddCommands(cmd, dockerCli)跳轉到cli/command/commands/commands.go

func AddCommands(cmd *cobra.Command, dockerCli command.Cli) {
   cmd.AddCommand(
       // checkpoint
       checkpoint.NewCheckpointCommand(dockerCli),

       // config
       config.NewConfigCommand(dockerCli),

       // container
       container.NewContainerCommand(dockerCli),
       container.NewRunCommand(dockerCli),

       // image
       image.NewImageCommand(dockerCli),
       image.NewBuildCommand(dockerCli),

       // builder
       builder.NewBuilderCommand(dockerCli),

       // manifest
       manifest.NewManifestCommand(dockerCli),

       // network
       network.NewNetworkCommand(dockerCli),

       // node
       node.NewNodeCommand(dockerCli),

       // plugin
       plugin.NewPluginCommand(dockerCli),

       // registry
       registry.NewLoginCommand(dockerCli),
       registry.NewLogoutCommand(dockerCli),
       registry.NewSearchCommand(dockerCli),

       // secret
       secret.NewSecretCommand(dockerCli),

       // service
       service.NewServiceCommand(dockerCli),

       // system
       system.NewSystemCommand(dockerCli),
       system.NewVersionCommand(dockerCli),

       // stack
       stack.NewStackCommand(dockerCli),
       stack.NewTopLevelDeployCommand(dockerCli),

       // swarm
       swarm.NewSwarmCommand(dockerCli),

       // trust
       trust.NewTrustCommand(dockerCli),

       // volume
       volume.NewVolumeCommand(dockerCli),

       // legacy commands may be hidden
       hide(system.NewEventsCommand(dockerCli)),
       hide(system.NewInfoCommand(dockerCli)),
       hide(system.NewInspectCommand(dockerCli)),
       hide(container.NewAttachCommand(dockerCli)),
       hide(container.NewCommitCommand(dockerCli)),
       hide(container.NewCopyCommand(dockerCli)),
       hide(container.NewCreateCommand(dockerCli)),
       hide(container.NewDiffCommand(dockerCli)),
       hide(container.NewExecCommand(dockerCli)),
       hide(container.NewExportCommand(dockerCli)),
       hide(container.NewKillCommand(dockerCli)),
       hide(container.NewLogsCommand(dockerCli)),
       hide(container.NewPauseCommand(dockerCli)),
       hide(container.NewPortCommand(dockerCli)),
       hide(container.NewPsCommand(dockerCli)),
       hide(container.NewRenameCommand(dockerCli)),
       hide(container.NewRestartCommand(dockerCli)),
       hide(container.NewRmCommand(dockerCli)),
       hide(container.NewStartCommand(dockerCli)),
       hide(container.NewStatsCommand(dockerCli)),
       hide(container.NewStopCommand(dockerCli)),
       hide(container.NewTopCommand(dockerCli)),
       hide(container.NewUnpauseCommand(dockerCli)),
       hide(container.NewUpdateCommand(dockerCli)),
       hide(container.NewWaitCommand(dockerCli)),
       hide(image.NewHistoryCommand(dockerCli)),
       hide(image.NewImagesCommand(dockerCli)),
       hide(image.NewImportCommand(dockerCli)),
       hide(image.NewLoadCommand(dockerCli)),
       hide(image.NewPullCommand(dockerCli)),
       hide(image.NewPushCommand(dockerCli)),
       hide(image.NewRemoveCommand(dockerCli)),
       hide(image.NewSaveCommand(dockerCli)),
       hide(image.NewTagCommand(dockerCli)),
   )
   if runtime.GOOS == "linux" {
       // engine
       cmd.AddCommand(engine.NewEngineCommand(dockerCli))
   }
}
4、通過 image.NewImageCommand(dockerCli),跳轉到cli/command/image/cmd.go

  func NewImageCommand(dockerCli command.Cli) *cobra.Command {
    cmd := &cobra.Command{
        Use:   "image",
        Short: "Manage images",
        Args:  cli.NoArgs,
        RunE:  command.ShowHelp(dockerCli.Err()),
    }
    cmd.AddCommand(
        NewBuildCommand(dockerCli),
        NewHistoryCommand(dockerCli),
        NewImportCommand(dockerCli),
        NewLoadCommand(dockerCli),
        NewPullCommand(dockerCli),
        NewPushCommand(dockerCli),
        NewSaveCommand(dockerCli),
        NewTagCommand(dockerCli),
        newListCommand(dockerCli),
        newRemoveCommand(dockerCli),
        newInspectCommand(dockerCli),
        NewPruneCommand(dockerCli),
    )
    return cmd
}    

5、通過    NewPushCommand(dockerCli)進行跳轉cli/command/image/push.go

func NewPushCommand(dockerCli command.Cli) *cobra.Command 
	var opts pushOptions
	cmd := &cobra.Command{
		Use:   "push [OPTIONS] NAME[:TAG]",
		Short: "Push an image or a repository to a registry",
		Args:  cli.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			opts.remote = args[0]
			return RunPush(dockerCli, opts)
		},
	}
	flags := cmd.Flags()
	command.AddTrustSigningFlags(flags, &opts.untrusted, dockerCli.ContentTrustEnabled())
	return cmd
}

func RunPush(dockerCli command.Cli, opts pushOptions) error {

ref, err := reference.ParseNormalizedNamed(opts.remote)

if err != nil {

return err

}

// Resolve the Repository name from fqn to RepositoryInfo

repoInfo, err := registry.ParseRepositoryInfo(ref)

if err != nil {

return err

}

ctx := context.Background()

// Resolve the Auth config relevant for this server

authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)

requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "push")

//通過opts.untrusted判斷是否對進行進行簽名

if !opts.untrusted {

return TrustedPush(ctx, dockerCli, repoInfo, ref, authConfig, requestPrivilege)

}

// TrustedPush handles content trust pushing of an image

通過TrustedPush(ctx, dockerCli, repoInfo, ref, authConfig, requestPrivilege)跳轉到cli/command/image/trust.go

func TrustedPush(ctx context.Context, cli command.Cli, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig types.AuthConfig, requestPrivilege types.RequestPrivilegeFunc) error {
	responseBody, err := imagePushPrivileged(ctx, cli, authConfig, ref, requestPrivilege)	if err != nil {
		return err
}	
defer responseBody.Close()	
return PushTrustedReference(cli, repoInfo, ref, authConfig, responseBody)
}

通過PushTrustedReference完成與notary的通信,完成鏡像的簽名。

RunPush函數中還有另外一個方法:

responseBody, err := imagePushPrivileged(ctx, dockerCli, authConfig, ref, requestPrivilege)	
 
if err != nil {
		
    return err	
}

通過imagePushPrivileged方法將鏡像推送到registry中

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章