国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【博客618】docker容器重啟后讀寫層數(shù)據(jù)并不丟失的原理

這篇具有很好參考價(jià)值的文章主要介紹了【博客618】docker容器重啟后讀寫層數(shù)據(jù)并不丟失的原理。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

docker容器重啟后讀寫層數(shù)據(jù)并不丟失的原理

1、場(chǎng)景

當(dāng)我們對(duì)docker容器執(zhí)行restart后,其實(shí)容器中原本讀寫層里對(duì)臨時(shí)數(shù)據(jù)還在。只有我們刪除了這個(gè)容器,重新創(chuàng)建的容器是基于鏡像的只讀層然后掛載上新的空的讀寫層,此時(shí)臨時(shí)數(shù)據(jù)是不在的

2、前置知識(shí)

鏡像,靜態(tài)容器,運(yùn)行時(shí)容器之間的區(qū)別
  • Image:統(tǒng)一只讀文件系統(tǒng))

  • 靜態(tài)容器 :未運(yùn)行的容器,統(tǒng)一可讀寫文件系統(tǒng)

  • 運(yùn)行時(shí)容器:運(yùn)行中的容器,進(jìn)程空間(包括進(jìn)程)+ 統(tǒng)一可讀寫文件系統(tǒng)

docker run,create,start之間的區(qū)別

docker run相當(dāng)于執(zhí)行了兩步操作:將鏡像放入容器中(docker create),然后將容器啟動(dòng),使之變成運(yùn)行時(shí)容器(docker start)。而docker start的作用是,重新啟動(dòng)已存在的鏡像。也就是說(shuō),如果使用這個(gè)命令,我們必須事先知道這個(gè)容器的ID,或者這個(gè)容器的名字,我們可以使用docker ps找到這個(gè)容器的信息。
【博客618】docker容器重啟后讀寫層數(shù)據(jù)并不丟失的原理

docker常見命令的區(qū)別:
  • docker create < image-id >

    該命令即為在只讀文件系統(tǒng)上添加一層可讀寫層「Top Layer」,并生成可讀寫文件系統(tǒng)。該命令狀態(tài)下容器為靜態(tài)容器,并沒有運(yùn)行。

  • docker start | restart < container-id >

    該命令即為在可讀寫文件系統(tǒng)添加一個(gè)進(jìn)程空間和運(yùn)行的進(jìn)程,并生成一個(gè)動(dòng)態(tài)容器。

  • docker run < image-id >

    docker run = docker create + docker start

  • docker stop < container-id >

    該指令向運(yùn)行中的容器發(fā)一個(gè) SIGTERM 信號(hào),然后停止所有的進(jìn)程。即為 docker start 的逆過程。

  • docker kill < container-id >

    該指令向容器發(fā)送一個(gè)不友好的 SIGKILL 信號(hào),相當(dāng)于快速?gòu)?qiáng)制關(guān)閉容器。與 docker stop 的區(qū)別是 docker stop 是先發(fā) SIGTERM 信號(hào)來(lái)清理進(jìn)程,然后再發(fā) SIGKILL 信號(hào)退出,整個(gè)進(jìn)程是正常關(guān)閉的。

  • docker pause < container-id >

    該指令用作暫停容器中的所有進(jìn)程,使用 cgroup 的 freezer 順序暫停容器里的所有進(jìn)程。

  • docker commit < container-id >

    該指令用作把容器的可讀寫層轉(zhuǎn)化成只讀層,即從容器狀態(tài)「可讀寫文件系統(tǒng)」變?yōu)殓R像狀態(tài)「只讀文件系統(tǒng)」,可理解為固化。

  • docker build

    docker build = docker run 「運(yùn)行容器 + 進(jìn)程修改數(shù)據(jù)」+ docker commit「固化數(shù)據(jù)」,整個(gè)過程不斷循環(huán)直至生成所需鏡像。循環(huán)一次便會(huì)形成一個(gè)新的層(新鏡像 = 原鏡像層 + 已固化的可讀寫層)。docker build 過程一般通過 dockerfile 文件來(lái)實(shí)現(xiàn)。

docker容器生命周期

【博客618】docker容器重啟后讀寫層數(shù)據(jù)并不丟失的原理

3、docker容器重啟后讀寫層數(shù)據(jù)并不丟失的原理

容器創(chuàng)建與啟動(dòng)的流程:
【博客618】docker容器重啟后讀寫層數(shù)據(jù)并不丟失的原理

docker創(chuàng)建容器和運(yùn)行容器源碼剖析:

docker run命令其實(shí)是由兩部分組成:create和start:

  • 創(chuàng)建容器的邏輯(create):

    • 獲取鏡像ID GetImage

    • 合并容器配置

    • 合并日志配置

    • 創(chuàng)建容器對(duì)象 newContainer

      if container, err = daemon.newContainer(params.Name, params.Config, imgID, managed); err != nil {
      return nil, err
      }

    • 設(shè)置安全選項(xiàng)

    • 設(shè)置容器讀寫層

      if err := daemon.setRWLayer(container); err != nil {
      return nil, err
      }

    • 創(chuàng)建文件夾保存容器配置信息

      //創(chuàng)建文件夾,用于保存容器的配置信息,在/var/lib/docker/containers/id下,并賦予容器進(jìn)程的讀寫權(quán)限
      if err := idtools.MkdirAs(container.Root, 0700, rootUID, rootGID); err != nil {
      return nil, err
      }

      //把配置文件保存到磁盤
      if err := daemon.setHostConfig(container, params.HostConfig); err != nil {
      return nil, err
      }

    • 保存到硬盤

      if err := daemon.updateContainerNetworkSettings(container, endpointsConfigs); err != nil {
      return nil, err
      }

    • 注冊(cè)到daemon

  • 啟動(dòng)容器的邏輯(start):

    • 找到容器對(duì)象實(shí)例

      container, err := daemon.GetContainer(name)
      if err != nil {
      return err
      }

    • 判斷如果暫停的容器不能啟動(dòng),先unpause再啟動(dòng)

      if container.IsPaused() {
      return fmt.Errorf(“Cannot start a paused container, try unpause instead.”)
      }

    • 判斷如果是運(yùn)行的容器不用啟動(dòng)

      if container.IsRunning() {
      err := fmt.Errorf(“Container already started”)
      return errors.NewErrorWithStatusCode(err, http.StatusNotModified)
      }

    • 確認(rèn)hostconfig與當(dāng)前系統(tǒng)是否一致

      if _, err = daemon.verifyContainerSettings(container.HostConfig, nil, false, validateHostname); err != nil {
      return err
      }

    • 調(diào)整舊版容器設(shè)置:主要是cpu、內(nèi)存限制的校驗(yàn)和設(shè)置

      if err := daemon.adaptContainerSettings(container.HostConfig, false); err != nil {
      return err
      }

    • 開始啟動(dòng)容器

      • 容器對(duì)象加鎖

        container.Lock()
        defer container.Unlock()

      • 狀態(tài)校驗(yàn),如該已經(jīng)運(yùn)行,直接返回

        if container.Running {
        return nil
        }

      • 掛載讀寫層

        dir, err := container.RWLayer.Mount(container.GetMountLabel())
        if err != nil {
        return err
        }

      • 初始化網(wǎng)絡(luò)

      • containerd 調(diào)用runc

      • 進(jìn)入runc啟動(dòng)容器

4、創(chuàng)建容器讀寫層源碼

func (daemon *Daemon) setRWLayer(container *container.Container) error {
       var layerID layer.ChainID
       if container.ImageID != "" {
              img, err := daemon.stores[container.Platform].imageStore.Get(container.ImageID)
              layerID = img.RootFS.ChainID()
       }

       rwLayerOpts := &layer.CreateRWLayerOpts{
              MountLabel: container.MountLabel,
              InitFunc:   daemon.getLayerInit(),
              StorageOpt: container.HostConfig.StorageOpt,
       }

       rwLayer, err := daemon.stores[container.Platform].layerStore.CreateRWLayer(container.ID, layerID, rwLayerOpts)
       container.RWLayer = rwLayer

       return nil
}
func (ls *layerStore) CreateRWLayer(name string, parent ChainID, opts *CreateRWLayerOpts) (RWLayer, error) {
       if opts != nil {
              mountLabel = opts.MountLabel
              storageOpt = opts.StorageOpt
              initFunc = opts.InitFunc
       }

       ls.mountL.Lock()
       defer ls.mountL.Unlock()
       m, ok := ls.mounts[name]

       if string(parent) != "" {
              p = ls.get(parent)
              if p == nil {
                     return nil, ErrLayerDoesNotExist
              }
              pid = p.cacheID
       }

       m = &mountedLayer{
              name:       name,
              parent:     p,
              mountID:    ls.mountID(name),
              layerStore: ls,
              references: map[RWLayer]*referencedRWLayer{},
       }

       if initFunc != nil {
              pid, err = ls.initMount(m.mountID, pid, mountLabel, initFunc, storageOpt)
              m.initID = pid
       }

       createOpts := &graphdriver.CreateOpts{
              StorageOpt: storageOpt,
       }

       if err = ls.driver.CreateReadWrite(m.mountID, pid, createOpts); err != nil {
     
       if err = ls.saveMount(m); err != nil {
     
       return m.getReference(), nil
}
func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc MountInit, storageOpt map[string]string) (string, error) {
       // Use "<graph-id>-init" to maintain compatibility with graph drivers
       // which are expecting this layer with this special name. If all
       // graph drivers can be updated to not rely on knowing about this layer
       // then the initID should be randomly generated.
       initID := fmt.Sprintf("%s-init", graphID)

       createOpts := &graphdriver.CreateOpts{
              MountLabel: mountLabel,
              StorageOpt: storageOpt,
       }

       if err := ls.driver.CreateReadWrite(initID, parent, createOpts); err != nil {
              return "", err
       }
       p, err := ls.driver.Get(initID, "")
       if err != nil {
              return "", err
       }

       if err := initFunc(p); err != nil {
              ls.driver.Put(initID)
              return "", err
       }

       if err := ls.driver.Put(initID); err != nil {
              return "", err
       }

       return initID, nil
}

CreateReadWrite 函數(shù)如下, 在 /var/lib/docker/aufs 目錄下創(chuàng)建兩個(gè)文件 mnt 和 diff,創(chuàng)建 /var/lib/docker/aufs/layers/${id} 文件,獲得該層的父層,記錄所有父層 id 該文件

func (a *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
       return a.Create(id, parent, opts)
}

// Create three folders for each id
// mnt, layers, and diff
func (a *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error{
       if err := a.createDirsFor(id); err != nil {
              return err
       }
       // Write the layers metadata
       f, err := os.Create(path.Join(a.rootPath(), "layers", id))

       if parent != "" {
              ids, err := getParentIDs(a.rootPath(), parent)

              if _, err := fmt.Fprintln(f, parent); err != nil {
         
              for _, i := range ids {
                     if _, err := fmt.Fprintln(f, i); err != nil {
                    
       }

       return nil
}

saveMount 函數(shù)是在 /var/lib/image/aufs/layerdb/mounts目錄下操作,如下所示:

func (ls *layerStore) saveMount(mount *mountedLayer) error {
       if err := ls.store.SetMountID(mount.name, mount.mountID); err != nil {
   
       if mount.initID != "" {
              if err := ls.store.SetInitID(mount.name, mount.initID); err != nil {

       if mount.parent != nil {
              if err := ls.store.SetMountParent(mount.name, mount.parent.chainID); err != nil {

       ls.mounts[mount.name] = mount

       return nil
}

SetMountID 函數(shù)位置 layer/filestore.go,主要是在 /var/lib/docker/image/aufs/layerdb/mounts 目錄下創(chuàng)建層,將 ${mount-id} 寫入 mount-id 文件

func (fms *fileMetadataStore) SetMountID(mount string, mountID string) error {
       if err := os.MkdirAll(fms.getMountDirectory(mount), 0755); err != nil {
              return err
       }
       return ioutil.WriteFile(fms.getMountFilename(mount, "mount-id"), []byte(mountID), 0644)
}

SetInitID 主要是在 ${mount-id}-init 寫入 init-id 文件

func (fms *fileMetadataStore) SetInitID(mount string, init string) error {
       if err := os.MkdirAll(fms.getMountDirectory(mount), 0755); err != nil {
              return err
       }
       return ioutil.WriteFile(fms.getMountFilename(mount, "init-id"), []byte(init), 0644)
}

SetMountParent 將父層 image 記錄 parent 文件

func (fms *fileMetadataStore) SetMountParent(mount string, parent ChainID) error {
       if err := os.MkdirAll(fms.getMountDirectory(mount), 0755); err != nil {
              return err
       }
       return ioutil.WriteFile(fms.getMountFilename(mount, "parent"), []byte(digest.Digest(parent).String()), 0644)
}

總結(jié)

docker run的時(shí)候其實(shí)是由create和start來(lái)完成的,create創(chuàng)建容器的時(shí)候會(huì)調(diào)用setRWLayer(container)創(chuàng)建讀寫層,start的時(shí)候會(huì)調(diào)用container.RWLayer.Mount(container.GetMountLabel())掛載讀寫層。restart的時(shí)候,則會(huì)使用新的鏡像只讀層 + 掛載當(dāng)前容器的讀寫層,因?yàn)槿萜髦貑⒉⒉粫?huì)丟失那些臨時(shí)修改文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-429551.html

到了這里,關(guān)于【博客618】docker容器重啟后讀寫層數(shù)據(jù)并不丟失的原理的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • docker 設(shè)置容器總是重啟,重啟策略(記錄)

    docker 設(shè)置容器總是重啟,重啟策略(記錄)

    在創(chuàng)建 Docker 容器時(shí),我們可以通過添加 --restart always 參數(shù)來(lái)使容器在出現(xiàn)問題時(shí)自動(dòng)重啟。但是有時(shí)候我們可能會(huì)忘記設(shè)置這個(gè)參數(shù),這時(shí)候可以使用 docker update 命令來(lái)修改容器的重啟策略。 使用以下命令可以將容器的重啟策略設(shè)置為 always: docker update --restart always 上述命

    2024年02月16日
    瀏覽(101)
  • docker容器重啟策略

    當(dāng)使用docker run命令運(yùn)行一個(gè)容器的時(shí)候,使用--restart選項(xiàng)可以配置該容器的重啟策略。 no 不要自動(dòng)重啟容器(默認(rèn)) on-failure[:max-retries] 如果容器發(fā)生錯(cuò)誤導(dǎo)致退出(非0退出狀態(tài)),則重啟該容器??梢允褂?:max-retries 選項(xiàng)限制嘗試重啟的次數(shù)。 always 如果容器退出了,總是

    2023年04月18日
    瀏覽(101)
  • docker容器重啟故障

    強(qiáng)殺docker進(jìn)程后,重啟docker。docker中的容器無(wú)法啟動(dòng)并報(bào)錯(cuò) docker restart XXXXXXX Error response from daemon: Cannot restart container XXXXXXX: container ‘XXXXXXXXXXXXXXXX’: already exists 原因:舊容器未安全退出 解決方式: docker-containerd-ctr --address /run/docker/containerd/docker-containerd.sock --namespace c rm 容器

    2024年04月13日
    瀏覽(231)
  • docker重啟容器

    docker重啟容器

    2024年02月16日
    瀏覽(97)
  • docker—啟動(dòng)、停止、重啟容器實(shí)例

    docker—啟動(dòng)、停止、重啟容器實(shí)例

    先查看已經(jīng)暫停的容器實(shí)例信息 docker ps -a 通過 docker start xxx 啟動(dòng)容器 通過 docker ps 查看當(dāng)前啟動(dòng)的容器 1、docker stop 此方式常常被翻譯為優(yōu)雅的停止容器 docker stop 容器ID或容器名 參數(shù) -t:關(guān)閉容器的限時(shí),如果超時(shí)未能關(guān)閉則用kill強(qiáng)制關(guān)閉,默認(rèn)值10s,這個(gè)時(shí)間用于容器的

    2024年02月09日
    瀏覽(98)
  • Docker 容器設(shè)置為 自動(dòng)重啟

    有時(shí)Docker服務(wù)出現(xiàn)異常,或者服務(wù)器出現(xiàn)異常,需要重啟Docker服務(wù)或者服務(wù)器; 如果希望有一部分基礎(chǔ)的或者常用的容器,在服務(wù)或者服務(wù)器重啟的時(shí)候,可以實(shí)現(xiàn)自動(dòng)啟動(dòng),僅需使用命令進(jìn)行簡(jiǎn)單配置即可實(shí)現(xiàn)。 Docker 容器設(shè)置為自動(dòng)重啟,分為兩種情況:新建容器時(shí)設(shè)置

    2024年02月07日
    瀏覽(92)
  • Docker 容器設(shè)置為自動(dòng)重啟

    Docker 容器設(shè)置為自動(dòng)重啟

    ?Docker自動(dòng)重啟原因 Docker自動(dòng)重啟通常是由以下幾個(gè)原因?qū)е碌模?程序崩潰 系統(tǒng)內(nèi)存不足 系統(tǒng)進(jìn)程使用過多CPU和RAM導(dǎo)致的阻塞 docker容器被殺死或重新啟動(dòng),導(dǎo)致應(yīng)用程序中斷 網(wǎng)絡(luò)中斷 當(dāng)這些問題出現(xiàn)時(shí),Docker會(huì)自動(dòng)重啟運(yùn)行中的服務(wù)來(lái)嘗試解決問題。 docker update --restart

    2024年02月03日
    瀏覽(93)
  • Docker 查詢、停止、刪除和重啟容器

    docker 列出所有容器ID docker 查看所有運(yùn)行容器 docker 查看正在運(yùn)行容器 docker 停止指定的 container (容器) 溫馨提示:刪除 container (容器) 的鏡像文件,必須先停止 container (容器) 運(yùn)行 。 知識(shí)拓展:停止docker 所有容器(包含正在運(yùn)行) container (容器) docker 刪除指定的

    2024年02月03日
    瀏覽(107)
  • 無(wú)法停止刪除容器,Mac重啟Docker

    不能停止、殺死、刪除容器,使用以下命令得到錯(cuò)誤消息: 無(wú)法停止、殺死、刪除容器,因?yàn)闆]有接收退出事件“receive an exit event”。 沒有找到強(qiáng)制停止容器的方法,只能重啟容器:

    2024年02月07日
    瀏覽(86)
  • docker篇---重啟策略 + run 容器常用參數(shù)

    container runctime 負(fù)責(zé)的是容器的生命周期管理 OCI :(open container initiative)開源容器協(xié)議, 包含兩個(gè)規(guī)范:運(yùn)行規(guī)范(runctime spec)-對(duì)容器狀態(tài)、創(chuàng)建、刪除、查看定義 鏡像規(guī)范(image-spec)-如何創(chuàng)建一個(gè)OCI 運(yùn)行時(shí)的系統(tǒng)包 CRI (container run interface) 容器運(yùn)行接口 隔開了各個(gè)

    2024年02月12日
    瀏覽(89)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包