run函數流程很簡單linux
func runDaemon(opts daemonOptions) error {
if opts.version { // 若是是查詢版本,直接顯示版本信息
showVersion()
return nil
}
daemonCli := NewDaemonCli() // daemon.go 新建一個daemoncli
.... // windows 的特殊處理
err = daemonCli.start(opts) // daemon.go 關鍵語句,開始運行daemon
notifyShutdown(err) // 進程退出前的處理,只是windows系統在使用
return err
}docker
看下start的處理明顯複雜不少json
func (cli *DaemonCli) start(opts daemonOptions) (err error) {
stopc := make(chan bool) // 建立一個通道,看上去退出時候阻塞用的
defer close(stopc) // 函數結束時候關閉通道
// warn from uuid package when running the daemon
uuid.Loggerf = logrus.Warnf
opts.common.SetDefaultOptions(opts.flags) // 同client,設置默認參數
if cli.Config, err = loadDaemonCliConfig(opts); err != nil { // 從opt裏面將參數導入到config
return err
}
cli.configFile = &opts.configFile // "/etc/docker/daemon.json"
cli.flags = opts.flags
.... //config 的一些處理
// Create the daemon root before we create ANY other files (PID, or migrate keys)
// to ensure the appropriate ACL is set (particularly relevant on Windows)
if err := daemon.CreateDaemonRoot(cli.Config); err != nil { // daemon/daemon.go 先建立daemon 的root路徑,linux 爲 /var/lib/docker
return err
}
if cli.Pidfile != "" { // "/var/run/docker.pid " 非空則建立一個pidfile
pf, err := pidfile.New(cli.Pidfile)
if err != nil {
return fmt.Errorf("Error starting daemon: %v", err)
}
defer func() { //start函數結束的時候清除文件
if err := pf.Remove(); err != nil {
logrus.Error(err)
}
}()
}
serverConfig := &apiserver.Config{ /// server 的config文件建立以及一些賦值
Logging: true,
SocketGroup: cli.Config.SocketGroup,
Version: dockerversion.Version,
EnableCors: cli.Config.EnableCors,
CorsHeaders: cli.Config.CorsHeaders,
}
.....
api := apiserver.New(serverConfig) // api/server/server.go 新建一個server的實例
cli.api = apiwindows
if len(cli.Config.Hosts) == 0 {
cli.Config.Hosts = make([]string, 1)
}api
for i := 0; i < len(cli.Config.Hosts); i++ { // 循環根據配置文件裏面全部host增長server的監聽
.......
api.Accept(addr, ls...)
}
if err := migrateKey(cli.Config); err != nil { // 把 key.json 移動到 /etc/docker 路徑
return err
}
......
registryService := registry.NewService(cli.Config.ServiceOptions) // registry/service.go 新建一個default的registryserver
containerdRemote, err := libcontainerd.New(cli.getLibcontainerdRoot(), cli.getPlatformRemoteOptions()...) // libcontainerd/remote_unix.goapp
// /var/run/docker路徑 ,建立 containerd Remote,container相關處理啓動grpc的client api,事件監控等less
....
signal.Trap(func() { // start時收到異常信息量的處理,關閉cli,其餘地方處理結束纔會給通道一個消息結束
cli.stop()
<-stopc // wait for daemonCli.start() to return
})
// Notify that the API is active, but before daemon is set up.
preNotifySystem() // 只是window系統有用
d, err := daemon.NewDaemon(cli.Config, registryService, containerdRemote) // daemon/daemon.go 新建daemon的全部東西,比較複雜,待後續分析
.....
if cli.Config.MetricsAddress != "" { // metrics 地址存在的話,起一個metrics server 監聽
if !d.HasExperimental() {
return fmt.Errorf("metrics-addr is only supported when experimental is enabled")
}
if err := startMetricsServer(cli.Config.MetricsAddress); err != nil {
return err
}
}
name, _ := os.Hostname()
c, err := cluster.New(cluster.Config{ // daemon/cluster/cluster.go 新建一個cluster 實例
Root: cli.Config.Root,
Name: name,
Backend: d,
NetworkSubnetsProvider: d,
DefaultAdvertiseAddr: cli.Config.SwarmDefaultAdvertiseAddr,
RuntimeRoot: cli.getSwarmRunRoot(),
})
......
// Restart all autostart containers which has a swarm endpoint
// and is not yet running now that we have successfully
// initialized the cluster.
d.RestartSwarmContainers() // daemon/daemon.go 重啓 container ,條件見函數內
......
cli.d = d
// initMiddlewares needs cli.d to be populated. Dont change this init order.
if err := cli.initMiddlewares(api, serverConfig); err != nil { // 給apiserver初始化中間件,要求cli.d必須被賦值
logrus.Fatalf("Error creating middlewares: %v", err)
}
d.SetCluster(c) // d.cluster = c
initRouter(api, d, c) // 註冊api消息處理函數,daemon命令的處理能夠在這裏面查
cli.setupConfigReloadTrap() // 設置一個系統調用從新加載配置
// The serve API routine never exits unless an error occurs
// We need to start it as a goroutine and wait on it so
// daemon doesn't exit
serveAPIWait := make(chan error) // 等待錯誤的通道
go api.Wait(serveAPIWait) // 起server的協程,出現錯誤向serveAPIWait通道寫入信息
// after the daemon is done setting up we can notify systemd api
notifySystem() // 通知系統daemon 已經起來
// Daemon is fully initialized and handling API traffic
// Wait for serve API to complete
errAPI := <-serveAPIWait // 利用通道阻塞等待 server退出
c.Cleanup() // 關閉cluster
shutdownDaemon(d) // 關閉daemon
containerdRemote.Cleanup() // 關閉 container
......
return nil
}ide