<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Pod 一直停留在 Terminating 狀態(tài),我等得花兒都謝了~

          共 15076字,需瀏覽 31分鐘

           ·

          2020-11-22 07:53


          更多奇技淫巧歡迎訂閱博客:https://fuckcloudnative.io

          前言

          近期,彈性云線上集群發(fā)生了幾起特殊的容器漂移失敗事件,其特殊之處在于容器處于 Pod Terminating 狀態(tài),而宿主則處于 Ready 狀態(tài)。

          宿主狀態(tài)為 Ready 說明其能夠正常處理 Pod 事件,但是 Pod 卻卡在了退出階段,說明此問題并非由 kubelet 引起,那么 docker 就是 1 號(hào)犯罪嫌疑人了。

          下文將詳細(xì)介紹問題的排查與分析全過程。

          2. 抽絲剝繭

          2.1 排除 kubelet 嫌疑

          Pod 狀態(tài)如下:

          [stupig@master?~]$?kubectl?get?pod?-owide
          pod-976a0-5??????????????0/1?????Terminating????????0??????????112m

          盡管 kubelet 的犯罪嫌疑已經(jīng)很小,但是我們還是需要排查 kubelet 日志進(jìn)一步確認(rèn)。截取 kubelet 關(guān)鍵日志片段如下:

          I1014?10:56:46.492682???34976?kubelet_pods.go:1017]?Pod?"pod-976a0-5_default(f1e03a3d-0dc7-11eb-b4b1-246e967c4efc)"?is?terminated,?but?some?containers?have?not?been?cleaned?up:?{ID:{Type:docker?ID:41020461ed4d801afa8d10847a16907e65f6e8ca34d1704edf15b0d0e72bf4ef}?Name:stupig?State:exited?CreatedAt:2020-10-14?10:49:57.859913657?+0800?CST?StartedAt:2020-10-14?10:49:57.928654495?+0800?CST?FinishedAt:2020-10-14?10:50:28.661263065?+0800?CST?ExitCode:0?Hash:2101852810?HashWithoutResources:2673273670?RestartCount:0?Reason:Completed?Message:?Resources:map[CpuQuota:200000?Memory:2147483648?MemorySwap:2147483648]}
          E1014?10:56:46.709255???34976?remote_runtime.go:250]?RemoveContainer?"41020461ed4d801afa8d10847a16907e65f6e8ca34d1704edf15b0d0e72bf4ef"?from?runtime?service?failed:?rpc?error:?code?=?Unknown?desc?=?failed?to?remove?container?"41020461ed4d801afa8d10847a16907e65f6e8ca34d1704edf15b0d0e72bf4ef":?Error?response?from?daemon:?container?41020461ed4d801afa8d10847a16907e65f6e8ca34d1704edf15b0d0e72bf4ef:?driver?"overlay2"?failed?to?remove?root?filesystem:?unlinkat?/home/docker_rt/overlay2/e5dab77be213d9f9cfc0b0b3281dbef9c2878fee3b8e406bc8ab97adc30ae4d5/merged:?device?or?resource?busy
          E1014?10:56:46.709292???34976?kuberuntime_gc.go:126]?Failed?to?remove?container?"41020461ed4d801afa8d10847a16907e65f6e8ca34d1704edf15b0d0e72bf4ef":?rpc?error:?code?=?Unknown?desc?=?failed?to?remove?container?"41020461ed4d801afa8d10847a16907e65f6e8ca34d1704edf15b0d0e72bf4ef":?Error?response?from?daemon:?container?41020461ed4d801afa8d10847a16907e65f6e8ca34d1704edf15b0d0e72bf4ef:?driver?"overlay2"?failed?to?remove?root?filesystem:?unlinkat?/home/docker_rt/overlay2/e5dab77be213d9f9cfc0b0b3281dbef9c2878fee3b8e406bc8ab97adc30ae4d5/merged:?device?or?resource?busy

          日志顯示 kubelet 處于 Pod Terminating 狀態(tài)的原因很清楚:清理容器失敗。

          kubelet 清理容器的命令是 docker rm -f ,其失敗的原因在于刪除容器目錄 xxx/merged 時(shí)報(bào)錯(cuò),錯(cuò)誤提示為 device or resource busy 。

          除此之外,kubelet 無法再提供其他關(guān)鍵信息。

          登陸宿主,我們驗(yàn)證對(duì)應(yīng)容器的狀態(tài):

          [stupig@hostname?~]$?sudo?docker?ps?-a?|?grep?pod-976a0-5
          41020461ed4d????????????Removal?In?Progress????????????????????????????k8s_stupig_pod-976a0-5_default_f1e03a3d-0dc7-11eb-b4b1-246e967c4efc_0
          f0a75e10b252????????????Exited?(0)?2?minutes?ago???????????????????????k8s_POD_pod-976a0-5_default_f1e03a3d-0dc7-11eb-b4b1-246e967c4efc_0
          [stupig@hostname?~]$?sudo?docker?rm?-f?41020461ed4d
          Error?response?from?daemon:?container?41020461ed4d801afa8d10847a16907e65f6e8ca34d1704edf15b0d0e72bf4ef:?driver?"overlay2"?failed?to?remove?root?filesystem:?unlinkat?/home/docker_rt/overlay2/e5dab77be213d9f9cfc0b0b3281dbef9c2878fee3b8e406bc8ab97adc30ae4d5/merged:?device?or?resource?busy

          問題已然清楚,現(xiàn)在我們有兩種排查思路:

          • 參考 Google 上解決 device or resource busy 問題的思路
          • 結(jié)合現(xiàn)象分析代碼

          2.2 Google 大法

          有問題找 Google!所以,我們首先咨詢了 Google,檢索結(jié)果顯示很多人都碰到了類似的問題。

          而網(wǎng)絡(luò)上主流的解決方案:配置 docker 服務(wù) MountFlags 為 slave,避免 docker 掛載點(diǎn)信息泄漏到其他 mnt 命名空間,詳細(xì)原因請(qǐng)參閱:docker device busy 問題解決方案[1]

          這么簡(jiǎn)單???顯然不能,檢查發(fā)現(xiàn) docker 服務(wù)當(dāng)前已配置 MountFlags 為 slave。網(wǎng)絡(luò)銀彈再次失去功效。

          so,我們還是老老實(shí)實(shí)結(jié)合現(xiàn)場(chǎng)分析代碼吧。

          2.3 docker 處理流程

          在具體分析 docker 代碼之前,先簡(jiǎn)單介紹下 docker 的處理流程,避免作為一只無頭蒼蠅處處碰壁。

          清楚了 docker 的處理流程之后,我們?cè)賮矸治霈F(xiàn)場(chǎng)。

          2.4 提審 docker

          問題發(fā)生在 docker 清理階段,docker 清理容器讀寫層出錯(cuò),報(bào)錯(cuò)信息為 device or resource busy,說明 docker 讀寫層并沒有被正確卸載,或者是沒有完全卸載。下面的命令可以驗(yàn)證這個(gè)結(jié)論:

          [stupig@hostname?~]$?grep?-rwn?'/home/docker_rt/overlay2/e5dab77be213d9f9cfc0b0b3281dbef9c2878fee3b8e406bc8ab97adc30ae4d5/merged'?/proc/*/mountinfo
          /proc/22283/mountinfo:50:386?542?0:92?/?/home/docker_rt/overlay2/e5dab77be213d9f9cfc0b0b3281dbef9c2878fee3b8e406bc8ab97adc30ae4d5/merged?rw,relatime?-?overlay?overlay?rw,lowerdir=XXX,upperdir=XXX,workdir=XXX
          /proc/22407/mountinfo:50:386?542?0:92?/?/home/docker_rt/overlay2/e5dab77be213d9f9cfc0b0b3281dbef9c2878fee3b8e406bc8ab97adc30ae4d5/merged?rw,relatime?-?overlay?overlay?rw,lowerdir=XXX,upperdir=XXX,workdir=XXX
          /proc/28454/mountinfo:50:386?542?0:92?/?/home/docker_rt/overlay2/e5dab77be213d9f9cfc0b0b3281dbef9c2878fee3b8e406bc8ab97adc30ae4d5/merged?rw,relatime?-?overlay?overlay?rw,lowerdir=XXX,upperdir=XXX,workdir=XXX
          /proc/28530/mountinfo:50:386?542?0:92?/?/home/docker_rt/overlay2/e5dab77be213d9f9cfc0b0b3281dbef9c2878fee3b8e406bc8ab97adc30ae4d5/merged?rw,relatime?-?overlay?overlay?rw,lowerdir=XXX,upperdir=XXX,workdir=XXX

          不出所料,容器讀寫層仍然被以上四個(gè)進(jìn)程所掛載,進(jìn)而導(dǎo)致 docker 在清理讀寫層目錄時(shí)報(bào)錯(cuò)。

          隨之而來的問題是,為什么 docker 沒有正確卸載容器讀寫層?我們先展示下 docker stop 中卸載容器讀寫層掛載的相關(guān)部分代碼:

          func?(daemon?*Daemon)?Cleanup(container?*container.Container)?{
          ???if?err?:=?daemon.conditionalUnmountOnCleanup(container);?err?!=?nil?{
          ??????if?mountid,?err?:=?daemon.imageService.GetLayerMountID(container.ID,?container.OS);?err?==?nil?{
          ?????????daemon.cleanupMountsByID(mountid)
          ??????}
          ???}
          }
          func?(daemon?*Daemon)?conditionalUnmountOnCleanup(container?*container.Container)?error?{
          ???return?daemon.Unmount(container)
          }
          func?(daemon?*Daemon)?Unmount(container?*container.Container)?error?{
          ???if?container.RWLayer?==?nil?{
          ??????return?errors.New("RWLayer?of?container?"?+?container.ID?+?"?is?unexpectedly?nil")
          ???}
          ???if?err?:=?container.RWLayer.Unmount();?err?!=?nil?{
          ??????logrus.Errorf("Error?unmounting?container?%s:?%s",?container.ID,?err)
          ??????return?err
          ???}

          ???return?nil
          }
          func?(rl?*referencedRWLayer)?Unmount()?error?{
          ???return?rl.layerStore.driver.Put(rl.mountedLayer.mountID)
          }
          func?(d?*Driver)?Put(id?string)?error?{
          ???d.locker.Lock(id)
          ???defer?d.locker.Unlock(id)
          ???dir?:=?d.dir(id)
          ???mountpoint?:=?path.Join(dir,?"merged")
          ???logger?:=?logrus.WithField("storage-driver",?"overlay2")
          ???if?err?:=?unix.Unmount(mountpoint,?unix.MNT_DETACH);?err?!=?nil?{
          ??????logger.Debugf("Failed?to?unmount?%s?overlay:?%s?-?%v",?id,?mountpoint,?err)
          ???}
          ???if?err?:=?unix.Rmdir(mountpoint);?err?!=?nil?&&?!os.IsNotExist(err)?{
          ??????logger.Debugf("Failed?to?remove?%s?overlay:?%v",?id,?err)
          ???}
          ???return?nil
          }

          代碼處理流程清晰明了,最終 docker 會(huì)發(fā)起 SYS_UMOUNT2 系統(tǒng)調(diào)用卸載容器讀寫層。

          但是,docker 在清理容器讀寫層時(shí)卻提示錯(cuò)誤,并且容器讀寫層掛載信息也出現(xiàn)在其他進(jìn)程中。難不成 docker 沒有執(zhí)行卸載操作?結(jié)合 docker 日志分析:

          Oct?14?10:50:28?hostname?dockerd:?time="2020-10-14T10:50:28.769199725+08:00"?level=debug?msg="Failed?to?unmount?e5dab77be213d9f9cfc0b0b3281dbef9c2878fee3b8e406bc8ab97adc30ae4d5?overlay:?/home/docker_rt/overlay2/e5dab77be213d9f9cfc0b0b3281dbef9c2878fee3b8e406bc8ab97adc30ae4d5/merged?-?invalid?argument"?storage-driver=overlay2
          Oct?14?10:50:28?hostname?dockerd:?time="2020-10-14T10:50:28.769213547+08:00"?level=debug?msg="Failed?to?remove?e5dab77be213d9f9cfc0b0b3281dbef9c2878fee3b8e406bc8ab97adc30ae4d5?overlay:?device?or?resource?busy"?storage-driver=overlay2

          日志顯示 docker 在執(zhí)行卸載容器讀寫層命令時(shí)出錯(cuò),提示 invalid argument。結(jié)合 umount2[2] 文檔可知,容器讀寫層并非是 dockerd(docker 后臺(tái)進(jìn)程)的掛載點(diǎn)???

          現(xiàn)在,回過頭來分析擁有容器讀寫層掛載信息的進(jìn)程,我們發(fā)現(xiàn)一個(gè)驚人的信息:

          [stupig@hostname?~]$?ps?-ef|grep?-E?"22283|22407|28454|28530"
          root??????22283??????1??0?10:48??????????00:00:00?docker-containerd-shim?-namespace?moby
          root??????22407??????1??0?10:48??????????00:00:00?docker-containerd-shim?-namespace?moby
          root??????28454??????1??0?10:49??????????00:00:00?docker-containerd-shim?-namespace?moby
          root??????28530??????1??0?10:49??????????00:00:00?docker-containerd-shim?-namespace?moby

          容器讀寫層掛載信息沒有出現(xiàn)在 dockerd 進(jìn)程命名空間中,卻出現(xiàn)在其他容器的托管服務(wù) shim 進(jìn)程的命名空間內(nèi),推斷 dockerd 進(jìn)程發(fā)生了重啟,對(duì)比進(jìn)程啟動(dòng)時(shí)間與命名空間詳情可以進(jìn)行驗(yàn)證:

          [stupig@hostname?~]$?ps?-eo?pid,cmd,lstart|grep?dockerd
          ?34836?/usr/bin/dockerd?--storage-?Wed?Oct?14?10:50:15?2020

          [stupig@hostname?~]$?sudo?ls?-la?/proc/$(pidof?dockerd)/ns
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?ipc?->?ipc:[4026531839]
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?mnt?->?mnt:[4026533327]
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?net?->?net:[4026531968]
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?pid?->?pid:[4026531836]
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?user?->?user:[4026531837]
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?uts?->?uts:[4026531838]

          [stupig@hostname?~]$?ps?-eo?pid,cmd,lstart|grep?-w?containerd|grep?-v?shim
          ?34849?docker-containerd?--config??Wed?Oct?14?10:50:15?2020

          [stupig@hostname?~]$?sudo?ls?-la?/proc/$(pidof?docker-containerd)/ns
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?ipc?->?ipc:[4026531839]
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?mnt?->?mnt:[4026533327]
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?net?->?net:[4026531968]
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?pid?->?pid:[4026531836]
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?user?->?user:[4026531837]
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?uts?->?uts:[4026531838]

          [stupig@hostname?~]$?ps?-eo?pid,cmd,lstart|grep?-w?containerd-shim
          ?22283?docker-containerd-shim?-nam?Wed?Oct?14?10:48:50?2020
          ?22407?docker-containerd-shim?-nam?Wed?Oct?14?10:48:55?2020
          ?28454?docker-containerd-shim?-nam?Wed?Oct?14?10:49:53?2020
          ?28530?docker-containerd-shim?-nam?Wed?Oct?14?10:49:53?2020

          [stupig@hostname?~]$?sudo?ls?-la?/proc/28454/ns
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?ipc?->?ipc:[4026531839]
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?mnt?->?mnt:[4026533200]
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?net?->?net:[4026531968]
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?pid?->?pid:[4026531836]
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?user?->?user:[4026531837]
          lrwxrwxrwx?1?root?root?0?Oct?14?10:50?uts?->?uts:[4026531838]

          [stupig@hostname?~]$?sudo?ls?-la?/proc/$$/ns
          lrwxrwxrwx?1?panpeilong?panpeilong?0?Oct?14?21:49?ipc?->?ipc:[4026531839]
          lrwxrwxrwx?1?panpeilong?panpeilong?0?Oct?14?21:49?mnt?->?mnt:[4026531840]
          lrwxrwxrwx?1?panpeilong?panpeilong?0?Oct?14?21:49?net?->?net:[4026531968]
          lrwxrwxrwx?1?panpeilong?panpeilong?0?Oct?14?21:49?pid?->?pid:[4026531836]
          lrwxrwxrwx?1?panpeilong?panpeilong?0?Oct?14?21:49?user?->?user:[4026531837]
          lrwxrwxrwx?1?panpeilong?panpeilong?0?Oct?14?21:49?uts?->?uts:[4026531838]

          結(jié)果驗(yàn)證了我們推斷的正確性?,F(xiàn)在再補(bǔ)充下 docker 組件的進(jìn)程樹模型,用以解釋這個(gè)現(xiàn)象,模型如下:

          dockerd 進(jìn)程啟動(dòng)時(shí),會(huì)自動(dòng)拉起 containerd 進(jìn)程;當(dāng)用戶創(chuàng)建并啟動(dòng)容器時(shí),containerd 會(huì)啟動(dòng) containerd-shim 進(jìn)程用于托管容器進(jìn)程,最終由 containerd-shim 調(diào)用 runc 啟動(dòng)容器進(jìn)程。runc 負(fù)責(zé)初始化進(jìn)程命名空間,并 exec 容器啟動(dòng)命令。

          上述模型中 shim 進(jìn)程存在的意義是:允許 dockerd/containerd 升級(jí)或重啟,同時(shí)不影響已運(yùn)行容器。docker 提供了 live-restore 的能力,而我們的集群也的確啟用了該配置。

          此外,由于我們?cè)?systemd 的 docker 配置選項(xiàng)中配置了 MountFlags=slave,參考systemd 配置說明[3],systemd 在啟動(dòng) dockerd 進(jìn)程時(shí),會(huì)創(chuàng)建一個(gè)新的 mnt 命名空間。

          至此,問題已基本定位清楚:

          • systemd 在啟動(dòng) dockerd 服務(wù)時(shí),將 dockerd 安置在一個(gè)新的 mnt 命名空間中
          • 用戶創(chuàng)建并啟動(dòng)容器時(shí),dockerd 會(huì)在本 mnt 命名空間內(nèi)掛載容器讀寫層目錄,并啟動(dòng) shim 進(jìn)程托管容器進(jìn)程
          • 由于某種原因,dockerd 服務(wù)發(fā)生重啟,systemd 會(huì)將其安置在另一個(gè)新的 mnt 命名空間內(nèi)
          • 用戶刪除容器時(shí),容器退出時(shí),dockerd 在清理容器讀寫層掛載時(shí)報(bào)錯(cuò),因?yàn)閽燧d并非在當(dāng)前 dockerd 的 mnt 命名空間內(nèi)

          后來,我們?cè)?docker issue 中也發(fā)現(xiàn)了官方給出的說明[4]MountFlags=slavelive-restore 確實(shí)不能同時(shí)使用。

          2.5 一波又起

          還沒當(dāng)我們沉浸在解決問題的喜悅之中,另一個(gè)疑問接踵而來。我們線上集群好多宿主同時(shí)配置了 MountFlags=slavelive-restore=true,為什么問題直到最近才報(bào)出來呢?

          當(dāng)我們分析了幾起 Pod Terminating 的涉事宿主后,發(fā)現(xiàn)它們的一個(gè)通性是 docker 版本為 18.06.3-ce,而我們當(dāng)前主流的版本仍然是 1.13.1。

          難道是新版本中才引入的問題?我們首先在測(cè)試環(huán)境中對(duì) 1.13.1 版本的 docker 進(jìn)行了驗(yàn)證,Pod 確實(shí)沒有被阻塞在 Terminating 狀態(tài),這是不是說明低版本 docker 不存在掛載點(diǎn)泄漏的問題呢?

          事實(shí)并非如此。當(dāng)我們?cè)俅芜M(jìn)行驗(yàn)證時(shí),在刪除 Pod 前記錄了測(cè)試容器的讀寫層,之后發(fā)送刪除 Pod 指令,Pod 順利退出,但此時(shí),我們登錄 Pod 之前所在宿主,發(fā)現(xiàn) docker 日志中同樣也存在如下日志:

          Oct?14?22:12:43?hostname2?dockerd:?time="2020-10-14T22:12:43.730726978+08:00"?level=debug?msg="Failed?to?unmount?fb41efa2cfcbfbb8d90bd1d8d77d299e17518829faf52af40f7a1552ec8aa165?overlay:?/home/docker_rt/overlay2/fb41efa2cfcbfbb8d90bd1d8d77d299e17518829faf52af40f7a1552ec8aa165/merged?-?invalid?argument"

          同樣存在卸載問題的情況下,高低版本的 docker 卻呈現(xiàn)出了不同的結(jié)果,這顯然是 docker 的處理邏輯發(fā)生了變更,這里我們對(duì)比源碼能夠很快得出結(jié)論:

          //?1.13.1?版本處理邏輯
          func?(daemon?*Daemon)?cleanupContainer(container?*container.Container,?forceRemove,?removeVolume?bool)?(err?error)?{
          ???//?If?force?removal?is?required,?delete?container?from?various
          ???//?indexes?even?if?removal?failed.
          ???defer?func()?{
          ??????if?err?==?nil?||?forceRemove?{
          ?????????daemon.nameIndex.Delete(container.ID)
          ?????????daemon.linkIndex.delete(container)
          ?????????selinuxFreeLxcContexts(container.ProcessLabel)
          ?????????daemon.idIndex.Delete(container.ID)
          ?????????daemon.containers.Delete(container.ID)
          ?????????if?e?:=?daemon.removeMountPoints(container,?removeVolume);?e?!=?nil?{
          ????????????logrus.Error(e)
          ?????????}
          ?????????daemon.LogContainerEvent(container,?"destroy")
          ??????}
          ???}()

          ???if?err?=?os.RemoveAll(container.Root);?err?!=?nil?{
          ??????return?fmt.Errorf("Unable?to?remove?filesystem?for?%v:?%v",?container.ID,?err)
          ???}

          ???//?When?container?creation?fails?and?`RWLayer`?has?not?been?created?yet,?we
          ???//?do?not?call?`ReleaseRWLayer`
          ???if?container.RWLayer?!=?nil?{
          ??????metadata,?err?:=?daemon.layerStore.ReleaseRWLayer(container.RWLayer)
          ??????layer.LogReleaseMetadata(metadata)
          ??????if?err?!=?nil?&&?err?!=?layer.ErrMountDoesNotExist?{
          ?????????return?fmt.Errorf("Driver?%s?failed?to?remove?root?filesystem?%s:?%s",?daemon.GraphDriverName(),?container.ID,?err)
          ??????}
          ???}

          ???return?nil
          }


          //?18.06.3-ce?版本處理邏輯
          func?(daemon?*Daemon)?cleanupContainer(container?*container.Container,?forceRemove,?removeVolume?bool)?(err?error)?{
          ???//?When?container?creation?fails?and?`RWLayer`?has?not?been?created?yet,?we
          ???//?do?not?call?`ReleaseRWLayer`
          ???if?container.RWLayer?!=?nil?{
          ??????err?:=?daemon.imageService.ReleaseLayer(container.RWLayer,?container.OS)
          ??????if?err?!=?nil?{
          ?????????err?=?errors.Wrapf(err,?"container?%s",?container.ID)
          ?????????container.SetRemovalError(err)
          ?????????return?err
          ??????}
          ??????container.RWLayer?=?nil
          ???}

          ???if?err?:=?system.EnsureRemoveAll(container.Root);?err?!=?nil?{
          ??????e?:=?errors.Wrapf(err,?"unable?to?remove?filesystem?for?%s",?container.ID)
          ??????container.SetRemovalError(e)
          ??????return?e
          ???}

          ???linkNames?:=?daemon.linkIndex.delete(container)
          ???selinuxFreeLxcContexts(container.ProcessLabel)
          ???daemon.idIndex.Delete(container.ID)
          ???daemon.containers.Delete(container.ID)
          ???daemon.containersReplica.Delete(container)
          ???if?e?:=?daemon.removeMountPoints(container,?removeVolume);?e?!=?nil?{
          ??????logrus.Error(e)
          ???}
          ???for?_,?name?:=?range?linkNames?{
          ??????daemon.releaseName(name)
          ???}
          ???container.SetRemoved()
          ???stateCtr.del(container.ID)
          ???return?nil
          }

          改動(dòng)一目了然,官方在清理容器變更[5]中給出了詳細(xì)的說明。也即在低版本 docker 中,問題并非不存在,僅僅是被隱藏了,并在高版本中被暴露出來。

          3. 問題影響

          既然所有版本的 docker 都存在這個(gè)問題,那么其影響是什么呢?

          在高版本 docker 中,其影響是顯式的,會(huì)引起容器清理失敗,進(jìn)而造成 Pod 刪除失敗。

          而在低版本 docker 中,其影響是隱式的,造成掛載點(diǎn)泄漏,進(jìn)而可能會(huì)造成的影響如下:

          • inode 被打滿:由于掛載點(diǎn)泄漏,容器讀寫層不會(huì)被清理,長(zhǎng)時(shí)間累計(jì)可能會(huì)造成 inode 耗盡問題,但是是小概率事件
          • 容器 ID 復(fù)用:由于掛載點(diǎn)未被卸載,當(dāng) docker 復(fù)用了原來已經(jīng)退出的容器 ID 時(shí),在掛載容器 init 層與讀寫層時(shí)會(huì)失敗。由于 docker 生成容器 ID 是隨機(jī)的,因此也是小概率事件

          4. 解決方案

          問題已然明確,如何解決問題成了當(dāng)務(wù)之急。思路有二:

          1. 治標(biāo):對(duì)標(biāo) 1.13.1 版本的處理邏輯,修改 18.06.3-ce 處理代碼
          2. 治本:既然官方也提及 MountFlags=slavelive-restore 不能同時(shí)使用,那么我們修改兩個(gè)配置選項(xiàng)之一即可

          考慮到 重啟 docker 不重啟容器 這樣一個(gè)強(qiáng)需求的存在,似乎我們唯一的解決方案就是關(guān)閉 MountFlags=slave 配置。關(guān)閉該配置后,與之而來的疑問如下:

          • 能夠解決本問題?
          • 網(wǎng)傳其他 systemd 托管服務(wù)啟用 PrivateTmp 是否會(huì)造成掛載點(diǎn)泄漏?

          欲知后事如何,且聽下回分解!

          參考資料

          [1]

          docker device busy 問題解決方案: https://blog.terminus.io/docker-device-is-busy/

          [2]

          umount2: https://man7.org/linux/man-pages/man2/umount.2.html

          [3]

          systemd 配置說明: https://freedesktop.org/software/systemd/man/systemd.exec.html#MountFlags=

          [4]

          官方給出的說明: https://github.com/moby/moby/issues/35873#issuecomment-386467562

          [5]

          清理容器變更: https://github.com/moby/moby/pull/31012


          原文鏈接:https://www.likakuli.com/posts/docker-pod-terminating/


          你可能還喜歡

          點(diǎn)擊下方圖片即可閱讀

          如何在五分鐘內(nèi)裝好 WireGuard?!

          云原生是一種信仰??



          碼關(guān)注公眾號(hào)

          后臺(tái)回復(fù)?k8s?獲取史上最方便快捷的 Kubernetes 高可用部署工具,只需一條命令,連 ssh 都不需要!



          點(diǎn)擊?"閱讀原文"?獲取更好的閱讀體驗(yàn)!

          ??給個(gè)「在看」,是對(duì)我最大的支持??
          瀏覽 124
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  囯产精品久久久久久久久搜平片 | 天天综合二网 | 岛国小电影 一区二区三区 | 手机看5689669AV | 综合久久五月天 |