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中