Minghsin University of Science and Technology
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try a Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

1

Local AI

--

Uedu Code

--

明新科大 AQI 70 24°C PM2.5 19
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 06

管理容器的資料

容器刪掉資料就不見:bind mount 與 volume
Interaction 20 minute(s)

Learning Objectives

  • 說明容器的可讀寫層:容器刪除後,寫在裡面的資料會一起消失
  • 比較 bind mount、volume 與 tmpfs 三種掛載方式,依情境選擇
  • 用 -v 或 --mount 把主機目錄掛進容器,讓主機與容器共用檔案
  • 用 docker volume create/ls/inspect 管理 volume,讓多個容器共用資料

容器刪掉,資料就不見了

第 03 課說過:容器停止不等於刪除,停止的容器裡檔案還在。可是一旦 docker container rm,容器裡寫入的所有檔案都會跟著消失。

原因在於容器的檔案系統是一層一層疊起來的:

[ 容器的可讀寫層 writable layer ]  ← 你在容器裡新增、修改的檔案都寫在這裡;rm 時一起刪除
[ 映像檔的層(唯讀)            ]
[ 映像檔的層(唯讀)            ]  ← 同一個映像檔建立的容器共用這些層

把資料只放在可讀寫層,會遇到三個問題:

問題 說明
容器刪除,資料就消失 資料庫、上傳的檔案、你寫的筆記本,都會跟著容器一起不見
很難拿出來給別人用 資料和這個容器綁在一起,主機上的其他程式或其他容器不容易讀到
效能較差 可讀寫層由儲存驅動程式(例如 overlay2)透過聯合檔案系統(union filesystem)管理,比直接寫進主機的檔案系統多一層轉換

解法是把資料放到容器外面,再「掛載」(mount)進容器。容器只是借用這個位置,容器刪掉了,資料還留著。

三種掛載方式

方式 資料放在哪裡 誰可以修改 適合的情境
bind mount 主機上你指定的任何目錄,例如 /home/student/notebooks 主機上的任何程式都能直接改,容器也能改 開發時讓主機的編輯器與容器共用原始碼、筆記本
volume 主機上由 Docker 管理的位置(Linux 上是 /var/lib/docker/volumes/) 透過 Docker 使用;不建議主機上的其他程式直接去動 資料庫的資料、多個容器要共用的資料;Docker 保存資料的建議方式
tmpfs mount 只放在主機的記憶體,不寫進硬碟 只有這個容器 暫存、不想留在硬碟上的敏感資料;容器停止就清空
主機                                   容器
/home/student/notebooks ──bind mount──▶ /home/jovyan/work
Docker 管理的 share-data ──volume─────▶ /share
記憶體 ─────────────────tmpfs─────────▶ /tmp/cache

在 Windows 與 macOS 的 Docker Desktop 上,Docker 其實跑在一台小型虛擬機裡,所以 volume 的實際位置在那台虛擬機裡面,不是你在檔案總管看得到的資料夾。用 Docker 指令操作 volume 就不必在意這個差別。

bind mount:主機目錄直接掛進容器

投影片的例子:建立一個 Jupyter 容器,讓筆記本(.ipynb)直接存在主機的目錄裡,容器刪掉也不怕。

mkdir -p ~/notebooks
cd ~/notebooks
docker container run -p 8800:8888 --mount type=bind,source=$PWD,target=/home/jovyan/work --name ds_test jupyter/datascience-notebook

$PWD 是目前所在的目錄(這裡是 ~/notebooks),掛到容器裡 Jupyter 的工作目錄 /home/jovyan/work。 用 docker container logs ds_test 找到帶 token 的網址,在瀏覽器打開(主機的 8800 埠),進入 work 目錄建立筆記本並存檔, 回到主機用 ls ~/notebooks 就看得到那個 .ipynb 檔。

同一件事也可以用比較短的 -v 寫:

docker container run -p 8801:8888 -v $PWD:/home/jovyan/work --name pyspark_test jupyter/pyspark-notebook
寫法 格式 主機目錄不存在時
-v 主機路徑:容器路徑 用冒號分隔,短 自動建立一個空目錄(擁有者是 root,常造成權限問題)
--mount type=bind,source=…,target=… 每個欄位都寫名稱,長但清楚 直接報錯,提醒你路徑打錯了

注意事項:

  • 冒號左邊是主機,右邊是容器;順序寫反了,就會把容器裡不存在的路徑當成主機路徑。
  • 容器裡的程式要有寫入主機目錄的權限。Jupyter 映像檔用一般使用者 jovyan 執行,如果存檔時出現 Permission denied,要調整主機目錄的權限(投影片用 chmod 開放 /share 的寫入權限)。
  • 在容器裡刪除掛載目錄中的檔案,主機上的檔案也會被刪除:它們是同一份檔案,不是複本。
  • Jupyter 的映像檔後來改放在 quay.io(例如 quay.io/jupyter/datascience-notebook),Docker Hub 上的 jupyter/… 版本較舊,觀念相同。

volume:交給 Docker 管理的資料空間

volume 有名字,由 Docker 建立與管理:

指令 作用
docker volume create share-data 建立名為 share-data 的 volume
docker volume ls 列出所有 volume
docker volume inspect share-data 查看詳細資訊,例如實際位置 Mountpoint
docker volume rm share-data 刪除 volume(還有容器在用時不能刪)
docker volume prune 刪除沒有任何容器使用的 volume(請先確定裡面沒有要保留的資料)
docker volume create share-data
docker volume inspect share-data
[
    {
        "Driver": "local",
        "Mountpoint": "/var/lib/docker/volumes/share-data/_data",
        "Name": "share-data",
        "Scope": "local"
    }
]

建立容器時把 volume 掛進去,兩種寫法效果相同:

docker container run -it --name test1_env -v share-data:/share ubuntu:24.04
docker container run -it --name test1_env --mount 'type=volume,src=share-data,dst=/share' ubuntu:24.04

-v 冒號左邊如果是名字(share-data)就是 volume;如果是路徑(以 / 或 $PWD 開頭)就是 bind mount。 指定的 volume 還不存在時,Docker 會自動建立一個。

多個容器共用同一個 volume:test1_env 在 /share 寫入檔案後,即使把 test1_env 刪掉,再建立 test2_env 掛上同一個 share-data, /share 裡的檔案還在。在主機上(Linux)也可以用 ls /var/lib/docker/volumes/share-data/_data 看到同一份檔案(需要 root 權限)。

互動練習:資料在哪裡

依右下角的四個任務操作。先建立 test1 並進入容器(綠色按鈕是在容器裡才能用的指令),用 echo hello > /data.txt 寫一個檔案,exit 離開後把 test1 刪掉;再建立 test2,用 cat /data.txt 看看檔案還在不在。接著建立 volume share-data,讓 test1_env 把檔案寫進 /share,離開並刪除 test1_env 之後,建立 test2_env 讀讀看 /share/data.txt。最後可以用 docker volume ls 與 inspect 看看 volume 的資訊。

什麼時候用哪一種

情境 建議 理由
開發網站,想用主機上的編輯器改程式,容器立刻讀到新版 bind mount 主機與容器看到的是同一個目錄
Jupyter 筆記本要留在自己電腦的資料夾,方便備份或用 Git 管理 bind mount 檔案就在你指定的位置
MySQL 的資料庫檔案 volume 由 Docker 管理,不怕主機上的程式誤改,搬移與備份有一致的做法
兩個容器要讀寫同一批資料 volume 容器之間共用,與哪個容器活著無關
暫存檔、不想寫進硬碟的資料 tmpfs 只放在記憶體,容器停止就消失

預告:Dockerfile 的 VOLUME 指令。 下一課開始寫 Dockerfile。映像檔的作者可以在 Dockerfile 裡寫:

VOLUME ["/share"]

意思是「/share 是放資料的地方,請不要把資料留在可讀寫層」。執行容器時如果你沒有用 -v 指定, Docker 會自動建立一個匿名 volume(名字是一長串亂碼)掛在那裡。MySQL 的官方映像檔就宣告了 VOLUME /var/lib/mysql, 所以實際使用時建議自己取名掛上:-v mysql-data:/var/lib/mysql,之後才找得到、管得動。

想一想:資料存在哪裡

1.

在容器裡建立 /data.txt(沒有掛載任何東西),然後 exit 並 docker container rm 這個容器。/data.txt 會怎樣?

2.

docker container run -v $PWD:/app ubuntu:24.04 用的是哪一種掛載?

3.

要存放 MySQL 容器的資料庫檔案,最建議用哪一種方式?

第 1 次作答

想一想:volume 指令

1.

test1_env 掛載 share-data:/share 並寫入 /share/data.txt,之後 test1_env 被刪除。新建的 test2_env 也掛載 share-data:/share,執行 cat /share/data.txt 會?

2.

想知道 volume share-data 在主機上的實際位置,用哪個指令?

第 1 次作答

重點精華回顧

  • 容器裡新增或修改的檔案寫在可讀寫層,docker container rm 之後就一起消失;要保留的資料要放在容器外面再掛載進來。
  • 三種掛載:bind mount(主機任意目錄)、volume(Docker 管理,保存資料的建議方式)、tmpfs(只在記憶體)。
  • bind mount 用 -v $PWD:/容器路徑 或 --mount type=bind,source=…,target=…;主機與容器看到的是同一份檔案。
  • volume 用 docker volume create/ls/inspect 管理,掛載時寫 -v share-data:/share 或 --mount 'type=volume,src=share-data,dst=/share'。
  • 多個容器掛載同一個 volume,就能共用資料;容器刪除後,volume 裡的資料還在。
  • Dockerfile 的 VOLUME 宣告資料存放的位置;沒有指定時 Docker 會建立匿名 volume,實務上建議自己取名掛載。
這一課完成了!
Next lesson:寫 Dockerfile
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。