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中