如何通過 Overlay2 或 Bind 進行ISO 重新構建

大雄45發表於2022-07-03
導讀 自從換了新工作之後,則開始負責 超融合產品[3] 叢集部署相關工作,因此也會接觸很多映象,不過這個映象是作業系統的 ISO 映象而不是容器映象 。雖然兩者都統稱為映象,但兩者有著本質的區別。

筆者之前在位元組跳動的時候是負責 PaaS 容器雲平臺的私有化部署相關的工作,所以經常會和一些容器映象打交道,對容器映象也有一些研究,之前還寫過不少部落格文章。比如 深入淺出容器映象的一生[1]、overlay2 在打包釋出流水線中的應用[2] 等等。

首先兩者構建的方式有本質的很大的區別,ISO 映象一般使用 mkisofs 或者 genisoimage 等 將一個包含作業系統安裝所有檔案目錄構建為一個 ISO 映象;而容器映象構建則是根據 Dockerfile 檔案使用相應的容器映象構建工具來一層一層構建;

另外 ISO 映象掛載後是隻讀的,這就意味著如果想要修改 ISO 映象中的一個檔案(比如 kickstart 檔案),則需要先將 ISO 映象中的所有內容複製到一個可以讀寫的目錄中,在這個讀寫的目錄中進行修改和重新構建 ISO 操作。

╭─root@esxi-debian-devbox ~/build
╰─# mount -o loop CentOS-7-x86_64-Minimal-2009.iso /mnt/iso
mount: /mnt/iso: WARNING: device write-protected, mounted read-only.
╭─root@esxi-debian-devbox ~/build
╰─# touch /mnt/iso/kickstart.cfg
touch: cannot touch '/mnt/iso/kickstart.cfg': Read-only file system

在日常工作中經常會對一些已有的 ISO 映象進行重新構建,重新構建 ISO 的效率根據不同的方式也會有所不同,本文就整理了三種不同重新構建 ISO 映象的方案供大家參考。

常規方式

以下是按照 RedHat 官方文件 WORKING WITH ISO IMAGES[4] 中的操作步驟進行 ISO 重新構建。

  • 首先我們下載一個 ISO 檔案,這裡以 CentOS-7-x86_64-Minimal-2009.iso[5] 為例,下載好之後將它掛載到本地 /mnt/iso 目錄下;
╭─root@esxi-debian-devbox ~/build
╰─# mount -o loop CentOS-7-x86_64-Minimal-2009.iso /mnt/iso
mount: /mnt/iso: WARNING: device write-protected, mounted read-only.
  • 將 ISO 裡的所有檔案複製到另一個目錄
╭─root@esxi-debian-devbox ~/build
╰─# rsync -avrut --force /mnt/iso/ /mnt/build/
  • 進入到該目錄下修改或新增檔案,然後重新構建 ISO 映象

# 使用 genisoimage  構建 ISO 映象,在 CentOS 上可以使用 mkisofs 命令,引數上會有一些差異

╭─root@esxi-debian-devbox ~/build
╰─# genisoimage -U -r -v -T -J -joliet-long -V "CentOS 7 x86_64" -volset "CentOS 7 x86_64" -A "CentOS 7 x86_64" -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -no-emul-boot -o /mnt/CentOS-7-x86_64-Minimal-2009-dev.iso .
Total translation table size: 124658
Total rockridge attributes bytes: 55187
Total directory bytes: 100352
Path table size(bytes): 140
Done with: The File(s) Block(s) 527985
Writing: Ending Padblock Start Block 528101
Done with: Ending Padblock Block(s) 150
Max brk space used a4000
528251 extents written (1031 MB)
# 給 ISO 映象生成 md5 校驗
╭─root@esxi-debian-devbox ~/build
╰─# implantisomd5 /mnt/CentOS-7-x86_64-Minimal-2009-dev.iso
Inserting md5sum into iso image...
md5 = 9ddf5277bcb1d8679c367dfa93f9b162
Inserting fragment md5sums into iso image...
fragmd5 = f39e2822ec1ae832a69ae399ea4bd3e891eeb31e9deb9c536f529c15bbeb
frags = 20
Setting supported flag to 0

對於 ISO 映象比較小或者該操作不是很頻繁的情況下按照這種方式是最省事兒的,但如果是 ISO 映象比較大,或者是在 CI/CD 流水線中頻繁地重新構建映象,每次都要 cp 複製原 ISO 映象的內容確實比較浪費時間。那有沒有一個更加高效的方法呢 ?️

經過一番摸索,折騰出來兩種可以避免使用 cp 複製這種佔用大量 IO 操作的構建方案,可以根據不同的場景進行選擇。

overlay2

熟悉 docker 映象的應該都知道映象是隻讀的,使用映象的時候則是通過聯合掛載的方式將映象的每一層 layer 掛載為只讀層,將容器實際執行的目錄掛載為讀寫層,而容器執行期間在讀寫層的所有操作不會影響到映象原有的內容。容器映象掛載的方式使用最多的是 overlay2 技術,在 overlay2 在打包釋出流水線中的應用[6] 和 ?深入淺出容器映象的一生 中我們曾對它進行過比較深入的研究和使用,對 overlay2 技術感興趣的可以翻看一下這兩篇部落格,本文就不再詳解其中的技術原理了,只對使用 overlay2 技術重新構建 ISO 映象的可行性進行一下分析。

  • 首先是建立 overlay2 掛載所需要的幾個目錄
╭─root@esxi-debian-devbox ~
╰─# mkdir -p /mnt/overlay2/{lower,upper,work,merged}
╭─root@esxi-debian-devbox ~
╰─# cd /mnt/overlay2
  • 接著將 ISO 映象掛載到 overlay2 的只讀層 lower 目錄
╭─root@esxi-debian-devbox /mnt/overlay2
╰─# mount -o loop /root/build/CentOS-7-x86_64-Minimal-2009.iso lower
mount: /mnt/overlay2/lower: WARNING: device write-protected, mounted read-only.
  • 使用 mount 命令掛載 overlay2 檔案系統,掛載點為 merged 目錄
╭─root@esxi-debian-devbox /mnt/overlay2
╰─# mount -t overlay overlay -o lowerdir=lower,upperdir=upper,workdir=work merged
╭─root@esxi-debian-devbox /mnt/overlay2
╰─# cd merged
  • 新增一個 kickstart.cfg 檔案,然後重新構建 ISO 映象
╭─root@esxi-debian-devbox /mnt/overlay2/merged
╰─# echo '# this is a kickstart config file' > kickstart.cfg
╭─root@esxi-debian-devbox /mnt/overlay2/merged
╰─# genisoimage -U -r -v -T -J -joliet-long -V "CentOS 7 x86_64" -volset "CentOS 7 x86_64" -A "CentOS 7 x86_64" -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -no-emul-boot -o /mnt/CentOS-7-x86_64-Minimal-2009-dev.iso .
Total translation table size: 124658
Total rockridge attributes bytes: 55187
Total directory bytes: 100352
Path table size(bytes): 140
Done with: The File(s) Block(s) 527985
Writing: Ending Padblock Start Block 528101
Done with: Ending Padblock Block(s) 150
Max brk space used a4000
528251 extents written (1031 MB)
  • 掛載新的 ISO 映象驗證後發現確實可行
╭─root@esxi-debian-devbox /mnt/overlay2/merged
╰─# mount -o loop /mnt/CentOS-7-x86_64-Minimal-2009-dev.iso /mnt/newiso
mount: /mnt/newiso: WARNING: device write-protected, mounted read-only.
╭─root@esxi-debian-devbox /mnt/overlay2/merged
╰─# cat /mnt/newiso/kickstart.cfg
# this is a kickstart config file
mount --bind

前面講到了使用 overlay2 的方式避免複製原映象內容進行重新構建映象的方案,但是 overlay2 對於不是很熟悉的人來講還是比較複雜,光 lowerdir、upperdir、workdir、mergeddir 這四個資料夾的作用和原理就把人直接給整不會了。那麼還有沒有更為簡單一點的方式呢?

別說還真有,只不過這種方式的用途比較侷限。如果僅僅是用於修改 ISO 中的一個檔案或者目錄,可以將該檔案或目錄以 bind 掛載的方式將它掛載到 ISO 目錄目錄對應的檔案上。

原理就是雖然 ISO 目錄本身是隻讀的,但它裡面的檔案和目錄是可以作為一個掛載點的。也就是說我把檔案 A 掛載到檔案 B,並不是在修改檔案 B,這就是 Unix/Linux 檔案系統十分奇妙的地方。同樣運用 bind 掛載的還有 docker 的 volume 以及 pod 的 volume 也是運用同樣的原理,以 bind 的方式將宿主機上的目錄或檔案掛載到容器執行對應的目錄上。對於修改只讀 ISO 裡的檔案/目錄我們當然也可以這樣做。廢話不多說來實踐驗證一下:

  • 首先依舊是將 ISO 映象掛載到 /mn/iso 目錄
╭─root@esxi-debian-devbox ~/build
╰─# mount -o loop CentOS-7-x86_64-Minimal-2009.iso /mnt/iso
mount: /mnt/iso: WARNING: device write-protected, mounted read-only.
  • 接著建立一個 /mnt/files/ks.cfg 檔案,並寫入我們需要的內容
╭─root@esxi-debian-devbox ~/build
╰─# mkdir -p /mnt/files
╭─root@esxi-debian-devbox ~/build
╰─# echo '# this is a kickstart config file' > /mnt/files/ks.cfg
  • 接著以 mount --bind 的方式掛載新建的檔案到 ISO 的 EULA 檔案
╭─root@esxi-debian-devbox /mnt/build
╰─# mount --bind /mnt/files/ks.cfg /mnt/iso/EULA
╭─root@esxi-debian-devbox /mnt/build
╰─# cat /mnt/iso/EULA
# this is a kickstart config file

可以看到原來 ISO 檔案中的 EULA 檔案已經被成功替換成了我們修改的檔案,然後再重新構建一下該 ISO 映象

╭─root@esxi-debian-devbox /mnt/iso
╰─# genisoimage -U -r -v -T -J -joliet-long -V "CentOS 7 x86_64" -volset "CentOS 7 x86_64" -A "CentOS 7 x86_64" -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -no-emul-boot -o /mnt/CentOS-7-x86_64-Minimal-2009-dev.iso .
然後我們再重新掛載新的 ISO 檔案驗證一下是否可以
╭─root@esxi-debian-devbox /mnt/iso
╰─# mkdir /mnt/newiso
╭─root@esxi-debian-devbox /mnt/iso
╰─# mount -o loop /mnt/CentOS-7-x86_64-Minimal-2009-dev.iso /mnt/newiso
mount: /mnt/newiso: WARNING: device write-protected, mounted read-only.
╭─root@esxi-debian-devbox /mnt/iso
╰─# cat /mnt/newiso/EULA
# this is a kickstart config file

驗證通過,確實可以!不過這種方式很侷限,比較適用於修改單個檔案如 kickstart.cfg,如果是要新增檔案那還是使用上文提到的 overlay2 的方式更為方便一些。

收穫

雖然 ISO 映象和容器映象二者有著本質的差別,但對於只讀和聯合掛載的這些特性二者可以相互借鑑滴。

不止如此 overlay2 這種聯合掛載的特性,還可以用在其他地方。比如我有一個公共的 NFS 共享伺服器,共享著一些目錄,所有人都可以以 root 使用者並以讀寫的許可權進行 NFS 掛載。這種情況下很難保障一些重要的檔案和資料被誤刪。這時候就可以使用 overlay2 的方式將一些重要的檔案資料掛載為 overlay2 的 lowerdir 只讀層,保證這些資料就如容器映象一樣,每次掛載使用的時候都作為一個只讀層。所有的讀寫操作都在 overlay2 的 merged 那一層,不會真正影響到只讀層的內容。

原文來自:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2903967/,如需轉載,請註明出處,否則將追究法律責任。

相關文章