【Day 3】Docker Container(容器)與 Volume(數據卷)


# 前言

本篇分為:「關於容器」、「容器常用操作」、「留下容器資料:數據卷(Volume)以及掛載宿主目錄/文件」三部分。

首先回憶一下前面提過的容器概念,再進入容器相關指令的解析。最後介紹 volume 以及宿主目錄的掛載,可用於留存執行過程中產生的容器資料,避免資料伴隨容器的移除一起消失。


# 關於容器

關於什麼是容器、為什麼需要容器、它跟虛擬機有什麼不同等困惑,已在【Day 1】Docker 基本概念中釐清過。

容器的本質就是程序(porcess)。
——《Docker——從入門到實踐》

簡單來說,容器的目的就是要在一個獨立的環境(沙盒),執行一項應用程式,而容器的本質就是一個程序(應用程式),當程序執行結束,容器的任務就結束,便退出執行(Exit)

容器環境的獨立性,就如同 Docker 鯨魚上頭承載的那一盒盒貨櫃箱(containers),貨櫃間彼此獨立,同時與底部乘載它的鯨魚區隔(以宿主為基礎,但與宿主環境區隔,每個容器擁有自己獨立的檔案系統、網路配置等等)。

上一篇提到 image 是容器的樣版,包含了應用程式執行所需的完整條件(即包含除了底層 kernel 以外,像是應用程式、依賴庫等資源)。當 docker run 指令把 image 實體化為容器時,會以這個靜態樣板 image(唯讀)為基礎疊加一層容器存儲層(可讀寫),用以存儲任何容器執行期間產生的資料,另外再加上一些容器相關配置(如容器與宿主機器間的接口、容器的 IP 位址等等)。

馬上來看看怎麼操作容器吧。


# 容器常用的操作:

  1. 啟動容器(把 image 實體化)----- docker run
  2. 手動終止容器的運行 --------------- docker stop
  3. 再次啟動已終止的容器 ------------- docker start
  4. 重新啟動執行中的容器 ------------- docker restart(= stop + start)
  5. 進入運行中的容器進行操作 ------------ docker exec -itdocker attach
  6. 列出(所有)本地容器 ------------- docker ps (-a)
  7. (強制)刪除容器 ------------------ docker rm (-f)
  8. 一鍵移除所有已終止的容器 -------- $ docker container prune

1. 啟動容器(把 image 實體化):$ docker run <image>

  • 當下令 docker run 時,docker 背後做了一系列操作:
    (擷取自《Docker——從入門到實踐》)

    1. 檢查本地是否有指定的<image>,若無就從 registry 下載
    2. 用<image>建立一個容器,並啟動
    3. 分配一個檔案系統,在 image(唯讀)外頭 mount 一層容器存儲層(可讀寫)
    4. 從宿主主機配置的網橋接口中橋接一個虛擬接口到容器去
    5. 從地址持配置一個 ip 位址給容器
    6. 執行指定的應用程序
    7. 執行完畢後,容器被終止
  • docker run 可分為 foreground(前台)和 detached(分離)兩種模式。

    • foreground(預設):
      • 直接在當前宿主機上執行,並印出執行過程的 logs。
    • detached(加上 -d 參數 docker run -d <image>):
      • 僅回傳所運行的 container_ID,不會印出 logs。
      • 欲查看 logs,則要用 docker container logs <container>
    • 無論是以 foreground 或 detached 方式執行,容器都會在指定的程序執行結束時,自動終止運作。

2. 手動終止容器的運行:$ docker stop <container>

  • 終止容器運行,但所做變更仍存在於容器存儲層。

3. 再次啟動已終止的容器:$ docker start <container>

  • 把終止狀態的 container 再次執行。

A stopped container can be restarted with all its previous changes intact using docker start.
—— 官網(docker run)

  • docker start 再次執行已終止的 container 時,之前對 container 的變更都還會完整存在。因預設情況下,變更會存在掛載的容器存儲層,容器終止時,容器存儲層仍存在。直到 container 被移除(docker rm <container>),容器存儲層才會跟著 container 一起被移除。

4. 重新啟動執行中的容器:$ docker restart <container>

  • 等同於 docker stop + docker start。重新啟動不會移除之前對 container 的變更(跟 docker start 一樣)。

5. 進入運行中的容器進行操作: $ docker exec -it <running_state_container>$ docker attach <running_state_container>

(1) docker exec -it

  • 指令說明(docker 的參數是可以合併的,故-it 等同於 -i -t):

    • -i(--interactive):容器的輸出會接到當前的畫面(我們才得以看到命令執行結果)。
    • -t(--tty):pseudo tty(pseudo terminal,偽終端),允許我們發送 input 給容器。
  • 指令意涵:

    • 在執行中的容器上,開新一個程序。像是 docker exec -it <container_ID> bash 就是在運行中的容器裡,執行 bash。
    • 這時若使用 exit 離開/終止,僅終止 exec 所執行的程序(像是 bash),不是終止容器。所以從 exec exit 不會中斷容器的運作
  • 範例:

$ docker run -dit ubuntu              # -d 在背後執行容器;-it 容器互動模式
$ docker exec -it <container> bash    # 進入容器
root@container_ID:/#

(2) docker attach

  • 指令意涵:

    • attach(附加)」標準輸入、標準輸出、標準錯誤到執行中的 container,而不是在上面另開新程序
    • 若使用 exit 離開/終止,則會終止 container。因為是進入到執行中的 container 用 attach 的標準輸入輸出與它互動
    • 一個運作中的 container 只能被 attach 一次(只會有一個標準輸入輸出的實體)。即使一次從多個終端 attach,也只會看到相同的輸出(其中一個終端輸入的命令卡住,所有終端都卡住)。
  • 官方範例:

$ docker run -d --name topdemo ubuntu /usr/bin/top -b
$ docker attach topdemo
root@container_ID:/#

6. 列出(所有)本地容器:$ docker ps (-a)

  • -a(--all):列出所有容器(包含終止狀態的)

7.(強制)刪除容器:$ docker rm (-f) <container>

  • -f(--force):強制刪除執行中的容器(docker 會發送 SIGKILL 信號給容器,kill process 後再刪除)
  • docker rm <container> 把容器從本地移除時,此容器的存儲層就會一起被刪掉。

8. 一鍵移除所有已終止的容器:$ docker container prune

  • 因為輕量的容器很方便創建,一不注意本地可能堆積一些已終止且用不到的容器,docker container prune可一鍵清理掉。
  • 效果等同於把它們一個個分別 docker rm

# 留下容器資料:數據卷(Volume)以及掛載宿主目錄/文件

容器創建時,在唯讀的 Image 上會疊加一層可讀寫的容器存儲層,用來記錄運行過程中讀寫的資料。然而容器存儲層會隨著 docker rm <container> 而一起被刪除。

為了保存容器執行過程中產生的資料,可以指定把資料存在 Volume 或指定的宿主機目錄。

#1 數據卷(Volume)

Volume 其實就類似 mount 宿主機的目錄/文件,一個 volume 也可以被多個容器共享。只是比起 mount 宿主目錄/文件,docker 還提供 volume 其他功能或指令,方便管理。

Volume 相關指令:

  1. 創建一個 volume -------------------------- docker volume create <volume_name>
  2. 查看所有 volumes ------------------------- docker volume ls
  3. 查看特定 volume 的詳情 ------------------ docker volume inspect <volume_name>
  4. 運行容器時,把 volume 掛載到容器上 --- docker run 時加入 --mount-v
    docker run -d -P \
     --name <container_name>
     --mount source=<volume_name>,target=<target_path_in_container> \
     # 或 -v <volume_name>:<target_path_in_container> \
     <image> \
     <command>
    
  5. 藉由容器查看掛載的 volume --------------- docker inspect <container>(裡頭的 Mounts 項目)
  6. 清除所有無主的 volumes ------------------- docker volume prune
    (※無主:建立了,但沒被掛載在任何容器上)
  7. 移除容器的同時移除掛載的 volume -------- docker rm -v <container>

#2 掛載宿主機目錄/文件

掛載的方式與 volume 差不多:

docker run -d -P \
    --name <container_name>
    --mount type=bind,source=<local_src_path>,target=<target_path_in_container>(,readonly) \
    # 或 -v <local_src_path>:<target_path_in_container> \
    <image> \
    <command>
  • 掛載的宿主目錄預設為可讀寫,若加上 readonly 則為唯讀,變更該項目會報錯。
  • 也可以掛載單一文件。即上例中的 <local_src_path> 與 <target_path_in_container> 都替換為文件 path,很適合用來記錄容器執行過程的 log 檔案。

# 以 -v 或 --mount 掛載的差別

  • 若 <local_src_path> 不存在,-v 會自動創建,--mount 會報錯
  • 作者建議對 docker 尚不熟悉者優先使用 --mount

# 結語

容器是 docker 的核心觀念,本文主要從應用層面切入了解容器。像是 docker run 背後的一系列操作;docker execdocker attach 兩者雖都可以進入容器,但因途徑不同而產生不同行為;藉由掛載 volume 或宿主目錄文件,可避免容器運行資料被移除掉等等。

另外,「容器的本質是程序(process),指定的程序一旦執行完畢,容器的生命週期就結束」也是這本書強調的觀念之一。

關於 docker 究竟如何實現容器技術,就下一篇再討論吧(docker 底層運作)。

#docker #container #volume #Docker從入門到實踐 #docker run #mount







你可能感興趣的文章

從前端傳資料給後端(GET, POST)、從 PHP 連線到 MySQL 資料庫

從前端傳資料給後端(GET, POST)、從 PHP 連線到 MySQL 資料庫

Deep Learning on 3D object detection paper 閱讀路徑

Deep Learning on 3D object detection paper 閱讀路徑

JS30 Day 23 筆記

JS30 Day 23 筆記






留言討論





2
2
2