|
| 1 | +--- |
| 2 | +title: 透過 Docker Image 理解 OverlayFS |
| 3 | +date: 2024-11-19 13:33:00 |
| 4 | +--- |
| 5 | + |
| 6 | +在日常的開發或是部署當中,我們很常使用 Docker 來免去環境設定還有跨平台的困擾,那你有沒有好奇過:如果我們的電腦裡面有很多 Docker Image,會不會佔用很多電腦的硬碟空間嗎?Docker 是如何儲存這些 Image 的? |
| 7 | + |
| 8 | +## :whale: Dockerfile 與 Image Layer 實現原理 |
| 9 | + |
| 10 | +日常開發中,經常會看到這樣的 Dockerfile: |
| 11 | + |
| 12 | +```dockerfile |
| 13 | +FROM ubuntu:20.04 |
| 14 | +RUN apt-get update && apt-get install -y nginx |
| 15 | +COPY ./app /app |
| 16 | +CMD ["nginx", "-g", "daemon off;"] |
| 17 | +``` |
| 18 | + |
| 19 | +當我們執行 `docker build` 的時候,每個指令都會產生一個新的 layer: |
| 20 | + |
| 21 | +```bash |
| 22 | +[+] Building 33.8s (8/8) FINISHED |
| 23 | +=> [internal] load build definition from Dockerfile |
| 24 | +=> => transferring dockerfile: 172B |
| 25 | +=> [internal] load metadata for docker.io/library/ubuntu:20.04 |
| 26 | +=> [1/3] FROM docker.io/library/ubuntu:20.04 |
| 27 | +=> [2/3] RUN apt-get update && apt-get install -y nginx |
| 28 | +=> [3/3] COPY ./app /var/www/html |
| 29 | +=> exporting to image |
| 30 | +=> => writing image sha256:5d8f96da221d162a0937f2241bd9236e7dfc90872cda77498c467369fc885b6 |
| 31 | +``` |
| 32 | + |
| 33 | +可以使用 `docker history` 來查看這些 layer 的組成: |
| 34 | + |
| 35 | +```bash |
| 36 | +IMAGE CREATED CREATED BY SIZE COMMENT |
| 37 | +5d8f96da221d 47 seconds ago CMD ["nginx" "-g" "daemon off;"] 0B buildkit.dockerfile.v0 |
| 38 | +<missing> 47 seconds ago COPY ./app /var/www/html # buildkit 27B buildkit.dockerfile.v0 |
| 39 | +<missing> 47 seconds ago RUN /bin/sh -c apt-get update && apt-get... 114MB buildkit.dockerfile.v0 |
| 40 | +<missing> 5 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0B |
| 41 | +<missing> 5 weeks ago /bin/sh -c #(nop) ADD file:74861... 72.8MB |
| 42 | +``` |
| 43 | + |
| 44 | +你有沒有好奇過,為什麼每個指令都會產生一個新的層?這些層是如何組合在一起的?更重要的是,為什麼我們在容器裡修改檔案時,不會影響到原本的映像檔? |
| 45 | +每個 Docker Image 都是由多個層堆疊而成的。以上面的例子來說: |
| 46 | + |
| 47 | +- 最底層是 Ubuntu 20.04 的基礎映像檔(72.8MB),包含了基本的作業系統檔案 |
| 48 | +- 接著是執行 apt-get install nginx 產生的層(114MB),包含了 nginx 相關的檔案 |
| 49 | +- 然後是 COPY 指令產生的層(27B),包含了我們的應用程式檔案 |
| 50 | +- 最後是 CMD 指令產生的層(0B),只包含了啟動指令的設定 |
| 51 | + |
| 52 | +這種分層設計帶來了很多好處: |
| 53 | + |
| 54 | +- 空間利用率:多個容器可以共享相同的基礎層。想像一下,如果有 10 個專案都是基於 Ubuntu 20.04,這些專案的容器就可以共用同一個基礎映像層,而不是每個專案都儲存一份完整的作業系統檔案。 |
| 55 | +- 建構效率:Docker 會快取每一層。如果只是修改了應用程式的程式碼,重新建構時只需要從 COPY 指令開始,前面的層都可以直接複用。這大幅減少了開發過程中的等待時間。 |
| 56 | + |
| 57 | +當我們執行 `docker run` 啟動容器時,Docker 會在最上層添加一個可寫入的容器層。這就是為什麼我們可以在容器內新增或修改檔案,但這些變更不會影響到原本的映像檔。讓我們實際試試: |
| 58 | + |
| 59 | +```bash |
| 60 | +docker run -it ubuntu:20.04 bash |
| 61 | +root@container:/# touch newfile |
| 62 | +root@container:/# echo "hello" > /etc/motd |
| 63 | +``` |
| 64 | + |
| 65 | +這些修改只會寫入到容器層,而且當容器被刪除時,這些變更也會跟著消失。如果你希望保存這些變更,就需要使用 `docker commit` 將容器的當前狀態儲存為新的映像檔。 |
| 66 | + |
| 67 | +但這樣的分層機制是如何實現的呢?這就要談到 Linux 核心中的 OverlayFS 了。它不只是一個簡單的檔案系統,而是專門設計用來處理多層檔案系統疊加的解決方案。 |
| 68 | + |
| 69 | +## :whale: 從 UnionFS 到 OverlayFS 的演進 |
| 70 | + |
| 71 | +## :whale: OverlayFS 核心機制實作解析 |
| 72 | + |
| 73 | +## :whale: OverlayFS 在實務上的其他應用 |
| 74 | + |
| 75 | +## :whale: Resource |
| 76 | + |
| 77 | +- [OverlayFS storage driver | Docker Docs](https://docs.docker.com/engine/storage/drivers/overlayfs-driver/) |
| 78 | +- [Overlay Filesystem — The Linux Kernel documentation](https://docs.kernel.org/filesystems/overlayfs.html) |
| 79 | +- [Overlay filesystem - ArchWiki](https://wiki.archlinux.org/title/Overlay_filesystem) |
| 80 | +- [OverlayFS and its use in Yocto Project - Vyacheslav Yurkov, Precitec GmbH & Co. KG](https://www.youtube.com/watch?v=03sOH9GaKO4) |
0 commit comments