Docker - Storage drivers

為了能有效率的使用 storage drivers,一定要先了解 Docker builds 以及 stores images,container如何使用images。

Storage drivers可以允許你在容器可寫入層(container writable layer) 建立資料

但是,在 Storage driver 操作資料,有這些缺點:

  • 讀寫效率很差
  • 停止運行container之後,這些資料並不會保存

通常會透過 volumes 來保存資料以及改善效能問題

一個 storage driver 負責處理各layer之間的互動

container 與 image 最大的差別就在於頂層可寫入層,在container新增或修改的資料都會存在可寫入層,當container刪除,這個可寫入層就會一併刪除,這底層的 image 則不會影響。

主要是因為每一個 container 都擁有自己的可寫入層,而多個 containers 可以共享同一個 image

例如: 這裡顯示多個 containers 共享同一個 Ubuntu 15.04 image

因此,Storage driver 用來管理 image layers 以及 可寫入層的內容,

雖然所有的 sotrage dirver 處理的方式各有差異,但所有的 driver 使用的都是同樣的 image 堆疊,以及寫入時複製策略(copy-on-write (CoW) strategy)。

可以透過下方指令檢查目前 可寫入層的使用量

docker ps -s

寫入時複製策略 copy-on-write (CoW) strategy

若某一個資料位於底層image,

多個container 可直接訪問及讀取同一個檔案,當某個container修改內容時,系統會複製一個副本給這個container使用

此時,這個container修改的是副本檔案,其他 container 讀取的仍是原本的檔案

通常,若container沒有修改資源,這些多個呼叫者同時都只會讀取同一個檔案,以節省資源

共享 images

當執行 docker pull 或者建立container 發現 image 不存在需要額外 pull down時

新的 image 並不會儲存在 container,而是會儲存在Docker 在 local 的儲存空間,通常會位於 /var/lib/docker/

因此,首先執行的 Dockfiles 會先下載需要的 image (在image不存在local情況下)

接下來其他 Dockerfiles 執行,就會發現於 local 已經存在需要的 image,就會直接使用,而不需要再額外 pull image

可以透過 docker image ls 以及 docker history 檢驗 ID來自於同一個來源

複製策略讓 containers 更有效率

啟動 container時,會同時增加一個 container 可寫入層,在 container 對於資料變更修改都會儲存在這個地方

在原本 image 的原有存在的檔案則不會有任何改變,

若有變更檔案,則會複製一份出來,避免影響其他container

底下是官方參考步驟,來驗證這個流程

  1. 從terminal 執行 5個 docker run ,啟動5個 container ,同時執行完畢會列出這些 container ID
$ docker run -dit --name my_container_1 acme/my-final-image:1.0 bash \
  && docker run -dit --name my_container_2 acme/my-final-image:1.0 bash \
  && docker run -dit --name my_container_3 acme/my-final-image:1.0 bash \
  && docker run -dit --name my_container_4 acme/my-final-image:1.0 bash \
  && docker run -dit --name my_container_5 acme/my-final-image:1.0 bash

  c36785c423ec7e0422b2af7364a7ba4da6146cbba7981a0951fcc3fa0430c409
  dcad7101795e4206e637d9358a818e5c32e13b349e62b00bf05cd5a4343ea513
  1e7264576d78a3134fbaf7829bc24b1d96017cf2bc046b7cd8b08b5775c33d0c
  38fa94212a419a082e6a6b87a8e2ec4a44dd327d7069b85892a707e3fc818544
  1a174fc216cccf18ec7d4fe14e008e30130b11ede0f0f94a87982e310cf2e765
  1. 執行 docker ps 驗證這 5 個 container 確實有執行
$ docker ps
CONTAINER ID      IMAGE                     COMMAND     CREATED              STATUS              PORTS      NAMES
1a174fc216cc      acme/my-final-image:1.0   "bash"      About a minute ago   Up About a minute              my_container_5
38fa94212a41      acme/my-final-image:1.0   "bash"      About a minute ago   Up About a minute              my_container_4
1e7264576d78      acme/my-final-image:1.0   "bash"      About a minute ago   Up About a minute              my_container_3
dcad7101795e      acme/my-final-image:1.0   "bash"      About a minute ago   Up About a minute              my_container_2
c36785c423ec      acme/my-final-image:1.0   "bash"      About a minute ago   Up About a minute              my_container_1
  1. 列出 local 儲存的資料夾位置
$ sudo ls /var/lib/docker/containers

會看到這5個container ID 為名的資料夾

1a174fc216cccf18ec7d4fe14e008e30130b11ede0f0f94a87982e310cf2e765
1e7264576d78a3134fbaf7829bc24b1d96017cf2bc046b7cd8b08b5775c33d0c
38fa94212a419a082e6a6b87a8e2ec4a44dd327d7069b85892a707e3fc818544
c36785c423ec7e0422b2af7364a7ba4da6146cbba7981a0951fcc3fa0430c409
dcad7101795e4206e637d9358a818e5c32e13b349e62b00bf05cd5a4343ea513
  1. 檢查 size
$ sudo du -sh /var/lib/docker/containers/*
32K  /var/lib/docker/containers/1a174fc216cccf18ec7d4fe14e008e30130b11ede0f0f94a87982e310cf2e765
32K  /var/lib/docker/containers/1e7264576d78a3134fbaf7829bc24b1d96017cf2bc046b7cd8b08b5775c33d0c
32K  /var/lib/docker/containers/38fa94212a419a082e6a6b87a8e2ec4a44dd327d7069b85892a707e3fc818544
32K  /var/lib/docker/containers/c36785c423ec7e0422b2af7364a7ba4da6146cbba7981a0951fcc3fa0430c409
32K  /var/lib/docker/containers/dcad7101795e4206e637d9358a818e5c32e13b349e62b00bf05cd5a4343ea513

這些資料大小都是32k

因此,當我們啟動 container 時,Docker 不需要產生完整的image檔案,只需要建立一個輕薄的容器可寫入層,藉由這種方式獲得極大的效率