使用 Volume 同步程式

Volume 也是 Docker 的元件,它提供 container 保存資料或共享資料的機制。

情境說明

在開始說明 volume 前,先來看下面這個情境。

昨天學到了如何在背景開啟 HTTP server,指令如下:

$ docker run -d --name web -p 8080:80 httpd
c30dfb2d3261170cd3fc4ed012e8ac441261292b13b95c1f203b8b0b4138d75f
$ curl http://localhost:8080/
<html><body><h1>It works!</h1></body></html>

Server 是開好了,但如果 server 的內容不能依需求修改的話,最終只是拿來玩 Hello world 而已。

因此現在有了新的目標--更新裡面的程式。可以使用 docker exec 加上 shell 進入 container:

# 啟動 Apache
docker run -d --name web -p 8080:80 httpd

# 確認 container 正在執行中
docker ps

# 使用 exec 進入 container
docker exec -it web bash

# 找出 Apache 回 curl 的 HTML
cat htdocs/index.html

docker exec 是在一個運行中的 container 上,再執行一個新的指令。參數為上例的 CONTAINER ID 與啟動 shell 的指令 bash,執行的結果是進入 Apache container 的世界裡,在裡面可以找得到 curl 取到的 HTML 原始文件。

只要修改這個檔案,即可讓 curl 獲得修改後的檔案。

# 使用 exec 進入 container
docker exec -it web bash

# 使用新的內容取代 index.html 並離開 container
echo Hello volume > htdocs/index.html && exit

# 離開並測試
curl http://localhost:8080/

上面這個範例,我們成功修改了 index.html 的內容。但先別開心,我們把舊的移除,然後用 docker run 跑一個新的 Apache container 看看:

# 確認內容
curl http://localhost:8080/

# 移除 container
docker rm -f web

# 再啟動一次
docker run -d --name web -p 8080:80 httpd

# 確認內容
curl http://localhost:8080/

這個實驗會發現,It works! 又回來了?原因很簡單,在介紹 port forwarding 的時候,有提到隔離特性,也有提到每個 container 都是各自獨立的,這也代表剛剛被砍掉的 container 與現在建立的 container 是不同一個。而使用 docker run 指令產生的 container,每次都會是全新跟重灌好一樣,這就是一次性的特性。

Bind Mount

只要開新的 container 就會被砍掉重練,那該如何讓我們寫好的程式出現在 container 裡面呢?方法有很多種,今天說明馬上就能使用的 Bind Mount

Bind Mount 的概念很簡單,它可以把本機的某個目錄或檔案,綁定在 container 裡的某個目錄或檔案。比方說把目前開發的程式,綁在 container 的 /source,那 container 就能在它的 /source 裡看到本機的檔案。

綁定使用 -v 選項,下面範例是把目前目錄綁定在 Apache container 的 /usr/local/apache2/htdocs 目錄下:

# 執行 container
docker run -d -it -v `pwd`:/usr/local/apache2/htdocs -p 8080:80 httpd

# 測試對應路徑
curl http://localhost:8080/test.html

這個方法可以簡單解決 docker run 產生新的 container 的情境下保有舊的資料。

指令補充說明

docker exec

在一個正在執行的 container 上執行指令,用法如下:

docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

docker rundocker exec 做的事很相似,決定性差異在於:docker run 會產生新的 container,而 docker exec 需要運行中的 container。

-i|--interactive-t|--tty 參數用法與 docker create 相同。

docker run

  • -v|--volume 掛載 volume 到這個 container 上,格式為 [/host]:[/container]:[參數]

今日自我回顧

  • 練習「進入」container 的方法
  • 練習在 container 讀取修改目錄或檔案