Docker掛了,數據如何找回

docker在實際使用中,讓運維人員詬病的,除了安全問題外,大概就是數據的問題了

?

很多人在初用docker的時候,很多時候都忘記或不知道docker中需要保留的數據需要掛載到宿主機文件夾到容器內部對應目錄(當然除了掛載宿主機目錄,還有其他解決方案,我們后面會有文章介紹)

?

當容器因為某些原因掛掉、無法重新啟動的時候,他們就認為數據丟失了,找不回了,這也是很多人對docker的一個認識誤區,網上沒有一篇文章說docker數據的問題,今天詳細解釋下,docker數據在哪里

?

首先說一下這邊以docker-ce 19.03.4版本舉例,GraphDriver是overlay2

?

這里說明下,overlay技術是一種虛擬網絡技術,這里說的overlay是overlayfs,是一種聯合文件系統

?

我們通過docker info簡單查看Storage Driver

圖片

也可以通過docker inspect 查看鏡像或容器的詳細信息

圖片在GraphDriver部分可以看到使用的是什么文件系統,之前舊內核的系統中的docker的GraphDriver是使用DeviceMapper,由于overlay2性能比devicemapper好,而且新版本docker-ce默認采用,所以這里只研究overlay2

?

從上面的截圖可以看到GraphDriver的data部分有四部分,分別是LowerDir、MergerDir、UpperDir、WorkDir,解釋這幾個概念之前,先來回顧下docker的鏡像的分層原理

?

docker鏡像是一種輕量可執行的獨立軟件包,?用來打包軟件運行的環境和基于運行環境開發的軟件?,它包含運行某個軟件所需要的所有內容,包括代碼、運行時的庫、環境變量和配置文件

?

docker的鏡像實際上由一層一層的文件系統組成,這種層級的文件系統稱為聯合文件系統(unionFS)

?

UnionFS(聯合文件系統):union文件系統(unionFS)是一種分層、輕量級并且高性能的文件系統,它支持?對文件系統的修改作為一次提交來一層層的疊加?,同時可以將不同的目錄掛載到同一個虛擬文件系統下。union文件系統是docker鏡像的基礎。鏡像可以通過分層來進行繼承。基于基礎鏡像(沒有父鏡像),可以制作各種的應用鏡像

?

圖片

這種分層最大的好處就是資源共享

?

很多時候,你pull鏡像的時候,如果是來源于相同的base鏡像,你可以看到,pull的時候,底下的層是已經pulled,而且base64加密id是一樣的,這就是因為base鏡像資源已經下載,可以共享使用,不需要重復下載

?

在容器中,伴隨聯合文件系統的一個技術就是寫時復制(CoW),該技術是linux內核的一個技術,為了避免不必要的進程間復制操作,在父進程fork子進程后,父子進程共享同一副本,當子進程需要調用exec寫入的時候,數據才會被復制,從而父子進程各自有自己的副本

?

結合容器技術來看,當處于鏡像態的時候,所有的層級都是只讀的,但是當docker run啟動為容器態的時候,在基礎鏡像上添加了一層可讀寫層,這時肯定會在最上層,可讀寫層進行文件寫入,就需要將要寫入的文件從它存在的層復制到可讀寫層,然后進行讀寫,并隱藏只讀層的舊文件,這個就是利用了寫時復制技術

?

回顧了這些基礎之后,接著看下overlay2的基礎概念及原理

圖片

overlayfs在linux主機上只有兩層,一個目錄在下層,用來保存鏡像(docker),另外一個目錄在上層,用來存儲容器信息。在overlayfs中,底層的目錄叫做lowerdir,頂層的目錄稱之為upperdir,對外提供統一的文件系統為merged。當需要修改一個文件時,使用CoW將文件從只讀的Lower復制到可寫的Upper進行修改,這個復制出來的臨時目錄就是Workdir,結果也保存在Upper層

?

以上就是GraphDriver的data部分的四部分,可以從前面的圖中看到lowerdir,包含多個層,因為它就是rootfs,容器鏡像,也就是我們pull鏡像的時候看到的層級

?

overlay2存儲在/var/lib/docker/overlay2目錄中,如果你只有少數鏡像,比較好查看,多個鏡像的時候,就只能通過docker inspect的方式查找對應鏡像的層級id,然后通過這個id去overlay2目錄去找對應的overlayfs目錄

?

在該目錄下有個“l”目錄,這個目錄是存放所有overlayfs目錄的短名稱的,通過軟連接的方式與overlyafs目錄下的所有目錄鏈接,這個是為了在mount掛載的時候避免參數太長,達到頁面大小限制

圖片

?

接著我們分別看下LowerDir、MergerDir、UpperDir、WorkDir

?

我這里通過個redis容器來說明,首先是lowerdir,lowerdir因為有多個,你可以一個一個進去看一下,就能夠看明白它每個層級存儲的東西,如下:

"LowerDir": "/var/lib/docker/overlay2/3d56c8ea55a05f092442c3cdf01c49556a71b8f089a5772413ef566ec68bca31-init/diff

圖片

:/var/lib/docker/overlay2/7e6a11d051174f5a71ce038268e6fa8a310d046032ed435b10ed7846f9eb2d92/diff

圖片

:/var/lib/docker/overlay2/bbcd520d1d0d62323bcac4a66328164b99fa1704974ceffc412d348c6f7b55e9/diff

圖片

/var/lib/docker/overlay2/dee456318494848b5ea4182ddb8f67f25969b121580afa9ff8aa73cf9c0d256e/diff

圖片

:/var/lib/docker/overlay2/a45bb32d7cd7d2386d12826e4d8e524b410616d06cf1ec29f2eab03ba3eb80b2/diff

圖片

:/var/lib/docker/overlay2/085f1022334a3727171e3d038ed59f69cb0c6199b93a84afeb1e0b1b8674abf1/diff"

圖片

?

從上面可以看出來,diff就是存儲該層rootfs的目錄,而每個層級里面的link文件里面存儲的就是l文件夾下的短名稱的超鏈接,除了最底層,上層都有一個lower文件,該文件里面就存儲了它上層的短名稱

圖片

而work目錄,用來聯合掛載指定的工作目錄

?

圖片

接著看MergedDir、UpperDir、WorkDir其實是指向一個層級id,只是目錄不同,是不是覺得這個id這么熟悉,其實在LowerDir的最上層的id就是這個,只不過它最后面有個init,這個init稍后介紹,先來看下這三個目錄

圖片

mergedir對外提供統一的視圖,這里可以看到整合了所有lowerdir層級的文件

因為是新啟動的容器,upperdir目錄沒有內容,workdir目錄因為寫時復制很快,所以通常也無法看到,后面進入容器寫入文件進行會在upperdir目錄看到內容

關于init層

init層是以一個uuid+-init結尾表示,夾在只讀層和讀寫層之間,作用是專門存放/etc/hosts、/etc/resolv.conf等信息,需要這一層的原因是當容器啟動時候,這些本該屬于image層的文件或目錄,比如hostname,用戶需要修改,但是image層又不允許修改,所以啟動時候通過單獨掛載一層init層,通過修改init層中的文件達到修改這些文件目的。而這些修改往往只在當前容器生效,而在docker commit提交為鏡像時候,并不會將init層提交。該層文件存放的目錄為/var/lib/docker/overlay2/<init_id>/diff

?

從上面這部分可以看到,所有容器或者鏡像的層級目錄都存在overlay2目錄下,那么一個容器或者鏡像是怎么把這些整合起來的?答案是元數據關聯,元數據分為image元數據和layer元數據

?

鏡像元數據存儲在了/var/lib/docker/image/<storage_driver>/imagedb/content/sha256/目錄下,名稱是以鏡像ID命名的文件,鏡像ID可通過docker images查看,這些文件以json的形式保存了該鏡像的rootfs信息、鏡像創建時間、構建歷史信息、所用容器、包括啟動的Entrypoint和CMD等等,比如剛才的redis鏡像

圖片

打開該文件,是一個json格式文件,但是沒有vim默認沒有格式化,通過:%!python -m json.tool工具轉換成json格式查看

圖片

其中rootfs部分

圖片

可以看到對應前面的6層overlayfs,其排列也是有順序的,從上到下依次表示鏡像層的最低層到最頂層

diff_id如何關聯進行層?具體說來,docker 利用 rootfs 中的每個diff_id 和歷史信息計算出與之對應的內容尋址的索引(chainID) ,而chaiID則關聯了layer層,進而關聯到每一個鏡像層的鏡像文件

?

layer元數據中layer對應鏡像層的概念,在 docker 1.10 版本以前,鏡像通過一個 graph 結構管理,每一個鏡像層都擁有元數據,記錄了該層的構建信息以及父鏡像層 ID,而最上面的鏡像層會多記錄一些信息作為整個鏡像的元數據。graph 則根據鏡像 ID(即最上層的鏡像層 ID) 和每個鏡像層記錄的父鏡像層 ID 維護了一個樹狀的鏡像層結構。

?

在 docker 1.10 版本后,鏡像元數據管理巨大的改變之一就是簡化了鏡像層的元數據,鏡像層只包含一個具體的鏡像層文件包。用戶在 docker 宿主機上下載了某個鏡像層之后,docker 會在宿主機上基于鏡像層文件包和 image 元數據構建本地的 layer 元數據,包括 diff、parent、size 等。而當 docker 將在宿主機上產生的新的鏡像層上傳到 registry 時,與新鏡像層相關的宿主機上的元數據也不會與鏡像層一塊打包上傳。  

?

Docker 中定義了 Layer 和 RWLayer 兩種接口,分別用來定義只讀層和可讀寫層的一些操作,又定義了 roLayer 和 mountedLayer,分別實現了上述兩種接口。其中,roLayer 用于描述不可改變的鏡像層,mountedLayer 用于描述可讀寫的容器層。具體來說,roLayer 存儲的內容主要有索引該鏡像層的 chainID、該鏡像層的校驗碼 diffID、父鏡像層 parent、storage_driver 存儲當前鏡像層文件的 cacheID、該鏡像層的 size 等內容。這些元數據被保存在 /var/lib/docker/image/<storage_driver>/layerdb/sha256/<chainID>/ 文件夾下

圖片

每個chainID目錄下會存在三個文件cache-id、diff、zize:

圖片

cache-id文件:

docker隨機生成的uuid,內容是保存鏡像層的目錄索引,也就是/var/lib/docker/overlay2/中的目錄,這就是為什么通過chainID能找到對應的layer目錄

圖片

如圖對應的overlay目錄為/var/lib/docker/overlay2/e701317468246c6188f1bff4f9b9c159648d86108bb02e0ef5f224fd49efd1f0

diff文件:

保存了鏡像元數據中的diff_id(與元數據中的diff_ids中的uuid對應)

圖片

size文件:

保存了鏡像層的大小

圖片

在 layer 的所有屬性中,diffID 采用 SHA256 算法,基于鏡像層文件包的內容計算得到。而 chainID 是基于內容存儲的索引,它是根據當前層與所有祖先鏡像層 diffID 計算出來的,具體算如下:

  • 如果該鏡像層是最底層(沒有父鏡像層),該層的 diffID 便是 chainID。

  • 該鏡像層的 chainID 計算公式為 chainID(n)=SHA256(chain(n-1) diffID(n)),也就是根據父鏡像層的 chainID 加上一個空格和當前層的 diffID,再計算 SHA256 校驗碼。?

    ?

綜合上述一個完整的容器層如下圖:圖片

回到開頭,啟動后的容器數據存在哪里?

?

可以肯定的是在可讀寫層,結合overlayfs原理看,就是在upperdir,也就是可讀寫層中的diff目錄,比如我們進入容器,在home目錄下寫入個測試文件,然后查看diff目錄

圖片

圖片

在mergedir目錄下同樣也有該文件

圖片

?

從實際中看,并不是所有數據都在這個目錄,當啟動容器的時候通過掛載本地目錄的形式映射容器內部目錄的時候,數據不再存儲在overlayfs,而是直接存儲在本地映射的目錄

?

另外一種情況是,當使用dockerfile指定workdir的情況下,啟動容器會自動掛載一個volume目錄到workdir目錄

圖片

那么這個時候,存在workdir目錄下的數據會存在自動映射的Source目錄下

?

總結如下:

只要不刪除容器,數據完全可以找回

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/535403.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/535403.shtml
英文地址,請注明出處:http://en.pswp.cn/news/535403.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

TCP總結

TCP這些東西&#xff0c;基本每個程序猿都或多或少是掌握的了。雖然感覺在實際開發中沒有什么用武之處&#xff0c;但&#xff0c;面試他要問啊 而最近大家伙過完年&#xff0c;也都在準備春招&#xff0c;我也一樣。閱讀了一些okHttp源碼之后&#xff0c;又屁顛屁顛地跑回來重…

Shell 中各種括號的作用

一、小括號&#xff0c;圓括號&#xff08;&#xff09; 1、單小括號 () ①命令組。括號中的命令將會新開一個子shell順序執行&#xff0c;所以括號中的變量不能夠被腳本余下的部分使用。括號中多個命令之間用分號隔開&#xff0c;最后一個命令可以沒有分號&#xff0c;各命令和…

linux基線核查腳本

#!/bin/bash #version 2.0cat <<EOF ************************************************************************************* ***** linux基線檢查腳本 ***** ************************************************************************************* *…

LDAP命令介紹---dsreplication

可以使用此實用程序來配置服務器之間的復制, 以使服務器數據保持同步。要正確進行復制, 必須先使用 enable 子命令啟用復制, 然后再使用 initialize 子命令將一個服務器的內容初始化為另一個服務器的內容用法: dsreplication {子命令} {選項}可用子命令:disable對指定服務器中…

LDAP命令介紹---dsconfig

此實用程序可用于定義目錄服務器的基本配置 用法: dsconfig {子命令} {選項} 獲取子命令用法列表: --help-distribution 顯示與 分發 相關的子命令 --help-general-configuration 顯示與 一般配置 相關的子命令 --help-integration 顯示與 集成 相關的子命令 --…

LDAP命令介紹---dsconfig子命令----help-distribution顯示與分發相關的子命令

此實用程序可用于定義目錄服務器的基本配置用法: dsconfig {子命令} {選項}可用子命令:create-distribution-algorithm創建分發算法create-distribution-partition創建分發分區create-workflow-element --type distribution創建分發工作流元素create-global-index創建全局索引…

LDAP命令介紹---ldappasswordmodify口令修改操作

此實用程序可用于在目錄服務器中執行 LDAP 口令修改操作用法: ldappasswordmodify {選項}其中 {選項} 包括:-a, --authzID {authzID}應更改口令的用戶條目的授權 ID -A, --provideDNForAuthzID將綁定 DN 用作口令修改操作的授權 ID -n, --newPassword {newPassword}為目標用戶…

LDAP命令介紹---dstune

此實用程序可用于幫助您優化 OUD 目錄服務器。 您可以選擇自動或基于其他標準 (例如, 內存限制或服務器將包含的數據) 優化服務器用法: dstune {子命令} {選項}可用子命令:data-based使用描述目錄服務器將包含的數據的信息優化服務器。使用 --ldifFile 可基于 LDIF 文件的內容…

LDAP命令介紹---dsreplication--initialize

initialize 將目標服務器中指定基礎 DN 下的數據內容初始化為源服務器的內容。要正確進行復制, 在啟用復制后必須執行該操作 (也可以使用 initialize-all 達到該目的) initialize-all 對于正在復制其內容的所有服務器, 將它們指定基礎 DN 下的數據內容初始化為指定…

LDAP命令介紹---dsreplication--enable:DISABLE

enable 用法: dsreplication enable {選項} 更新服務器的配置以復制指定基礎 DN 下的數據。如果某個指定的服務器正在復制其他服務器中基礎 DN 下的數據, 執行此子命令將會更新所有服務器的配置 (因此, 對于每個添加到復制拓撲中的服務器, 將都能執行一次命令行)全局選項:請參…

LDAP命令介紹---import-ldif

[oracleoud bin]$ ./import-ldif --help 此實用程序可用于將 LDIF 數據導入目錄服務器后端用法: import-ldif {選項}其中 {選項} 包括:-l, --ldifFile {ldifFile}要導入的 LDIF 文件的路徑 -A, --templateFile {templateFile}用于生成導入數據的 MakeLDIF 模板的路徑 -a, --ap…

LDAP命令介紹---verify-index--驗證索引

[oraclelocalhost bin]$ ./verify-index -b "DCCOM" telephoneNumber 在解析命令行參數時出現錯誤: 參數 "telephoneNumber" 沒有以一個或兩個破折號開頭, 并且不允許未命名的結尾參數 此實用程序可用于確保基于 Berkeley DB Java Edition 的后端中的索引…

LDAP----manage-account

[oraclelocalhost bin]$ ./manage-account -D "cndirectory manager" -j pwd-file get-all \ > > --targetDN uidkvaughan,ouPeople,dcexample,dccom 在解析命令行參數時出現錯誤: 無法接受為參數 -j 提供的值 "pwd-file": 為參數 bindpwfile 指定…

LDAP組的概念以及命令

Oracle統一目錄支持組&#xff0c;組是作為單個對象管理的條目集合。通常&#xff0c;目錄管理員配置打印機組、軟件應用程序組、員工組等。在為一組用戶分配特殊訪問權限時&#xff0c;組尤其有用。例如&#xff0c;您可以配置一組訪問管理器&#xff0c;并分配權限&#xff0…

oracle中修改process

可以用如下命令查看數據庫連接的消耗情況 select b.MACHINE, b.PROGRAM, b.USERNAME, count(*) from v$process a, v$session b where a.ADDR b.PADDR and b.USERNAME is not null group by b.MACHINE, b.PROGRAM, b.USERNAME order by count(*) desc 在 oracle中&…

V$LICENSE表結構

V$LICENSE V$LICENSE 顯示有關許可限制的信息。 列名 數據類型 描述 SESSIONS_MAX NUMBER 實例允許的最大并發用戶會話數 SESSIONS_WARNING NUMBER 實例的并發用戶會話的警告限制 SESSIONS_CURRENT NUMBER 當前并發用戶會話數 SESSIONS_HIGHWATER NUMBER 自實…

升級ssl和ssh

#/bin/bash#需要手動修改的變量 version"ssh_8.6p1" #定義版本號 soft_dir$(cd "$(dirname "$0")"; pwd) # 上傳安裝包的目錄 ssl_media"openssl-1.1.1k.tar.gz" #ssl軟件包名 ssh_media"openssh-8.6p1.tar.gz" # ssh軟件…

zabbix5.2安裝-linux

一.編譯安裝httpd1.刪除舊版httprpm -qa | grep httpd rpm -e --nodeps rpm -qa | grep httpd find / -name httpd --delete find / -name httpd -help find / -name httpd -exec rm -rf {} \; 2.安裝httpd-2.4.38.tar.gz http://httpd.apache.org/download 安裝apr-1.6.2.…

安裝python3.9

GCC版本 這個版本的編譯器不適合編譯Python3.9&#xff0c;在編譯時會產生如下的錯誤。我們用這個老版本編譯器編譯一個新的GCC 9.2版。 Could not import runpy module Traceback (most recent call last):File "Python-3.8.1/Lib/runpy.py", line 15, in <mod…

備份程序包腳本

#! /bin/bash if [ $# ! 1 ];thenecho "USAGE: sh $0 /路徑/包名"exit 1 elsePackage_Path_Full$1Dir_Path${Package_Path_Full%/*}Package_Name${Package_Path_Full##*/}if [ -e $Package_Path_Full ];thenif [ -d $Dir_Path/bak ];thenif [ -d $Dir_Path/bak/date …