you are better than you think

docker源码快速阅读

· by thur · Read in about 4 min · (652 Words)
docker18.06 ||容器

阅读前准备

git: https://github.com/moby/moby.git
branch: v18.06.3-ce
ide: goland2020.2 

配置goland的build tag build tag

一起见证docker 代码中套路 exec.Command=> cmd.Start() => cmd.Wait()

进程模型

docker   
  |      
  V       
dockerd -> containerd ---> shim -> runc -> runc init -> process1
                      |--> shim -> runc -> runc init -> process2
                      +--> shim -> runc -> runc init -> process3

1.docker && containerd

cmd/dockerd/docker.go

52func main() {
53	if reexec.Init() {
54		return
55	}
56
57	// Set terminal emulation based on platform as required.
58	_, stdout, stderr := term.StdStreams()
59
60	// @jhowardmsft - maybe there is a historic reason why on non-Windows, stderr is used
61	// here. However, on Windows it makes no sense and there is no need.
62	if runtime.GOOS == "windows" {
63		logrus.SetOutput(stdout)
64	} else {
65		logrus.SetOutput(stderr)
66	}
67
68	cmd := newDaemonCommand() // 跳
69	cmd.SetOutput(stdout)
70	if err := cmd.Execute(); err != nil {
71		fmt.Fprintf(stderr, "%s\n", err)
72		os.Exit(1)
73	}
74}
18func newDaemonCommand() *cobra.Command {
19	opts := newDaemonOptions(config.New())
20
21	cmd := &cobra.Command{
22		Use:           "dockerd [OPTIONS]",
23		Short:         "A self-sufficient runtime for containers.",
24		SilenceUsage:  true,
25		SilenceErrors: true,
26		Args:          cli.NoArgs,
27		RunE: func(cmd *cobra.Command, args []string) error {
28			opts.flags = cmd.Flags()
29			return runDaemon(opts) // 跳
30		},
31		DisableFlagsInUseLine: true,
32		Version:               fmt.Sprintf("%s, build %s", dockerversion.Version, dockerversion.GitCommit),
33	}
34	cli.SetupRootCommand(cmd)
35
36	flags := cmd.Flags()
37	flags.BoolP("version", "v", false, "Print version information and quit")
38	flags.StringVar(&opts.configFile, "config-file", defaultDaemonConfigFile, "Daemon configuration file")
39	opts.InstallFlags(flags)
40	installConfigFlags(opts.daemonConfig, flags)
41	installServiceFlags(flags)
42
43	return cmd
44}

cmd/dockerd/docker_unix.go

5func runDaemon(opts *daemonOptions) error {
6	daemonCli := NewDaemonCli()
7	return daemonCli.start(opts) // 跳
8}
cmd/dockerd/daemon.go

74func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
75	stopc := make(chan bool)
76	defer close(stopc)
77    ...
143	rOpts, err := cli.getRemoteOptions()
144	if err != nil {
145		return fmt.Errorf("Failed to generate containerd options: %v", err)
146	}
147	containerdRemote, err := libcontainerd.New(filepath.Join(cli.Config.Root, "containerd"), filepath.Join(cli.Config.ExecRoot, "containerd"), rOpts...) // 跳
148	if err != nil {
149		return err
150	}
151	signal.Trap(func() {
152		cli.stop()
153		<-stopc // wait for daemonCli.start() to return
154	}, logrus.StandardLogger())
155    ...

libcontainerd/remote_daemon.go

61// New creates a fresh instance of libcontainerd remote.
62func New(rootDir, stateDir string, options ...RemoteOption) (rem Remote, err error) {
63	defer func() {
64		if err != nil {
65			err = errors.Wrap(err, "Failed to connect to containerd")
66		}
67	}()
68    ...

93   ...
94	if r.startDaemon {
95		os.Remove(r.GRPC.Address)
96		if err = r.startContainerd(); err != nil { // 跳
97			return
98		}
99		defer func() {
100			if err != nil {
101				r.Cleanup()
102			}
103		}()
104	}
105    ...

205func (r *remote) startContainerd() error {
206	pid, err := r.getContainerdPid()
207	if err != nil {
208		return err
209    }
210    ...
222    ...
223	args := []string{"--config", configFile}
224	cmd := exec.Command(binaryName, args...) // 注意binaryName
225	// redirect containerd logs to docker logs
226	cmd.Stdout = os.Stdout
227	cmd.Stderr = os.Stderr
228	cmd.SysProcAttr = containerdSysProcAttr()
229	// clear the NOTIFY_SOCKET from the env when starting containerd
230	cmd.Env = nil
231	for _, e := range os.Environ() {
232		if !strings.HasPrefix(e, "NOTIFY_SOCKET") {
233			cmd.Env = append(cmd.Env, e)
234		}
235	}
236	if err := cmd.Start(); err != nil {
237		return err
238	}
239
240	r.daemonWaitCh = make(chan struct{})
241	go func() {
242		// Reap our child when needed
243		if err := cmd.Wait(); err != nil {
244			r.logger.WithError(err).Errorf("containerd did not exit successfully")
245		}
246		close(r.daemonWaitCh)
247	}()
拉起containerd 用到了exec.Command() => cmd.Start() => cmd.Wait()

再看一下binaryName的定义

27const (
28	maxConnectionRetryCount = 3
29	healthCheckTimeout      = 3 * time.Second
30	shutdownTimeout         = 15 * time.Second
31	configFile              = "containerd.toml"
32	binaryName              = "docker-containerd"
33	pidFile                 = "docker-containerd.pid"
34)

docker-container-shim

再来看下shim部分 vendor/github.com/containerd/containerd/runtime/linux/runtime.go runtime.go

vendor/github.com/containerd/containerd/runtime/linux/bundle.go bundle.go bundle.go

vendor/github.com/containerd/containerd/runtime/shim/client/client.go client.go

拉起shim 用到了exec.Command() => cmd.Start() => cmd.Wait()

docker-runc

vendor/github.com/containerd/containerd/runtime/shim/service.go service.go

vendor/github.com/containerd/containerd/runtime/linux/proc/init.go init.go init.go NewRunc只是返回了一个Runc实例,还要继续看一下p.runtime.Create

vendor/github.com/containerd/go-runc/runc.go runc.go r.Command=>Monitor.Start=>Monitor.Wait 套路也依然是 exec.Command=> cmd.Start() => cmd.Wait()

vendor/github.com/containerd/go-runc/command_linux.go command_linux.go

最后看看exec.CommandContext上面的DefaultCommand的定义 vendor/github.com/containerd/go-runc/runc.go runc.go

版权所有,转载请注明作者和出处

Comments