通過使用者指定的鏡像名和tag,在tagstore中查找image_id,擷取image對象(本地的image json檔案裡有鏡像資訊)
檢查鏡像layer數(不超過127),鏡像層數太多會造成性能問題
将runconfig.config和image.config合并
建立{container.id}-init和container.id鏡像的目錄,在init layer建立.dockerinit、/etc/hosts、/etc/hostname等, container.id鏡像是read-write layer
将container對象持久化到path.join(container.id, “config.json”)
在daemon.idindex中注冊container.id,在daemon.contstore中記錄container.id和container對象的映射關系
通過container.id從daemon.contstore中擷取container對象
配置容器的dns位址/etc/resolv.conf
将所有祖先鏡像挂載到path.join(graphdriver.root, “mnt”, container.id)
初始化容器的hosts檔案/etc/hosts
檢查主機是否開啟cgroup記憶體限制、swap記憶體限制、ipv4轉發
将容器内挂在目錄和主控端目錄的映射關系存入container.volume
将容器的link資訊存入graphdb中,基于sqllite的圖模型的資料庫
通過iptables開啟link容器間的通信,并env化
擷取容器運作的目前目錄,擷取使用者指定的環境變量
建構execdriver的command對象,包括程序指令、network、mount、resources、workingdir,用于容器的啟動和配置
将command對象持久化到path.join(config.root, “execdriver/native/container.json”)
通過execdriver.run啟動command對象
dockerinit是daemon啟動容器運作的第一個程序,類似linux的init程序
初始化容器的network資源、mount資源、設定使用者、設定環境變量等在daemon程序中做不到事情
daemon執行流程
建立syncpipe用于跨namespace的通信
execdriver.run建立一個exec.cmd對象來執行dockerinit指令
exec.cmd.args代表dockerinit的執行參數,native表示execdriver類型,pipe表示同步管道的檔案描述符,root表示容器- 配置檔案container.json和state.json所在目錄,args表示使用者指定的指令
exec.cmd.sysprocattr攜帶需要為程序建立新namespace參數cloneflags,包括newns、newuts、newipc、newpid、newnet
調用exec.cmd.start()啟動dockerinit程序
調用namespaces.setupcgroups為dockerinit配置cgroup(cpu、iops、memory、freezer)
調用namespaces.initializenetworking為dockerinit建立網絡棧
調用syncpipe.sendtochild(networkstate)将需要dockerinit完成的剩餘網絡配置發給dockerinit
調用syncpipe.readfromchild與dockerinit同步
dockerinit執行流程
從參數中讀取root配置檔案所在目錄
從path.join(root, “container.json”)中讀取daemon傳過來的execdriver.command對象,擷取容器的配置資訊
調用mount.initializemountnamespace完成挂載資源的初始化,包括rootfs根檔案系統,挂載點volume,裝置檔案
調用namespaces.finalizenamespace完成剩餘的配置,包括關閉除0/1/2以外的檔案句柄,為容器建立新的使用者id、組id,切換到工作目錄
調用syscall.exec将容器主程序的執行權交給使用者程式