執行中的容器
Docker 在隔離的容器中執行程序。容器是在主機上執行的程序。主機可以是本機或遠端。當您執行 docker run 時,執行的容器程序是隔離的,它擁有自己的檔案系統、自己的網路以及獨立於主機的程序樹。
本頁詳細說明如何使用 docker run 命令來執行容器。
一般形式
docker run 命令的格式如下:
$ docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]
docker run 命令必須指定一個 映像檔參考 來建立容器。
映像檔參考
映像檔參考是映像檔的名稱和版本。您可以使用映像檔參考來建立或執行基於該映像檔的容器。
docker run IMAGE[:TAG][@DIGEST]docker create IMAGE[:TAG][@DIGEST]
映像檔標籤是映像檔版本,省略時預設為 latest。使用標籤可以從特定版本的映像檔執行容器。例如,要執行 ubuntu 映像檔的 24.04 版本:docker run ubuntu:24.04。
映像摘要
使用 v2 或更新版本映像檔格式的映像檔具有一個稱為「摘要」(digest) 的內容可定址識別碼。只要用於產生映像檔的輸入未更改,摘要值就是可預測的。
以下範例從 alpine 映像檔執行一個容器,其摘要為 sha256:9cacb71397b640eca97488cf08582ae4e4068513101088e9f96c9814bfda95e0
$ docker run alpine@sha256:9cacb71397b640eca97488cf08582ae4e4068513101088e9f96c9814bfda95e0 date
選項
[OPTIONS] 讓您可以設定容器的選項。例如,您可以為容器指定名稱 (--name),或將其作為背景程序執行 (-d)。您也可以設定選項來控制資源限制和網路等事項。
命令與引數
您可以使用 [COMMAND] 和 [ARG...] 位置引數來指定容器啟動時要執行的命令和引數。例如,您可以指定 sh 作為 [COMMAND],並結合 -i 和 -t 旗標,在容器中啟動一個互動式 shell (如果您選擇的映像檔在 PATH 中有 sh 可執行檔)。
$ docker run -it IMAGE sh
注意根據您的 Docker 系統配置,您可能需要為
docker run命令加上sudo前綴。為了避免在使用docker命令時需要使用sudo,您的系統管理員可以建立一個名為docker的 Unix 群組並將使用者加入其中。有關此配置的更多資訊,請參閱您作業系統的 Docker 安裝文件。
前景與背景
當您啟動容器時,容器預設會在前景執行。如果您想將容器在背景執行,可以使用 --detach (或 -d) 旗標。這會在不佔用終端機視窗的情況下啟動容器。
$ docker run -d <IMAGE>
當容器在背景執行時,您可以使用其他 CLI 命令與容器互動。例如,docker logs 讓您可以檢視容器的日誌,而 docker attach 則將其帶到前景。
$ docker run -d nginx
0246aa4d1448a401cabd2ce8f242192b6e7af721527e48a810463366c7ff54f1
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0246aa4d1448 nginx "/docker-entrypoint.…" 2 seconds ago Up 1 second 80/tcp pedantic_liskov
$ docker logs -n 5 0246aa4d1448
2023/11/06 15:58:23 [notice] 1#1: start worker process 33
2023/11/06 15:58:23 [notice] 1#1: start worker process 34
2023/11/06 15:58:23 [notice] 1#1: start worker process 35
2023/11/06 15:58:23 [notice] 1#1: start worker process 36
2023/11/06 15:58:23 [notice] 1#1: start worker process 37
$ docker attach 0246aa4d1448
^C
2023/11/06 15:58:40 [notice] 1#1: signal 2 (SIGINT) received, exiting
...
有關 docker run 旗標與前景和背景模式相關的更多資訊,請參閱:
docker run --detach:在背景執行容器docker run --attach:連接到stdin、stdout和stderrdocker run --tty:分配一個偽終端機 (pseudo-tty)docker run --interactive:即使未連接也保持stdin開啟
有關重新連接到背景容器的更多資訊,請參閱 docker attach。
容器識別
您可以透過三種方式識別容器:
| 識別碼類型 | 範例值 |
|---|---|
| UUID 長識別碼 | f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778 |
| UUID 短識別碼 | f78375b1c487 |
| 名稱 | evil_ptolemy |
UUID 識別碼是由守護程序 (daemon) 分配給容器的隨機 ID。
守護程序會自動為容器產生隨機字串名稱。您也可以使用 --name 旗標 定義自訂名稱。定義 name 是為容器增加意義的便捷方式。如果您指定 name,可以在使用者定義的網路中引用容器時使用它。這適用於背景和前景 Docker 容器。
容器識別碼與映像檔參考不同。映像檔參考指定了您執行容器時要使用的映像檔。您不能執行 docker exec nginx:alpine sh 來在基於 nginx:alpine 映像檔的容器中開啟 shell,因為 docker exec 預期的是容器識別碼 (名稱或 ID),而不是映像檔。
雖然容器使用的映像檔不是容器的識別碼,但您可以使用 --filter 旗標找出使用某個映像檔的容器 ID。例如,以下 docker ps 命令獲取所有基於 nginx:alpine 映像檔執行的容器 ID:
$ docker ps -q --filter ancestor=nginx:alpine
有關使用過濾器的更多資訊,請參閱 過濾。
容器網路
容器預設啟用網路,並且可以建立對外連線。如果您執行多個需要相互通訊的容器,您可以建立自訂網路並將容器連接到該網路。
當多個容器連接到相同的自訂網路時,它們可以使用容器名稱作為 DNS 主機名稱進行通訊。以下範例建立一個名為 my-net 的自訂網路,並執行兩個連接到該網路的容器。
$ docker network create my-net
$ docker run -d --name web --network my-net nginx:alpine
$ docker run --rm -it --network my-net busybox
/ # ping web
PING web (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.326 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.257 ms
64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.281 ms
^C
--- web ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.257/0.288/0.326 ms
有關容器網路的更多資訊,請參閱 網路概覽
檔案系統掛載
預設情況下,容器中的資料儲存在一個短暫的、可寫的容器層中。移除容器也會移除其資料。如果您想在容器中使用持久性資料,可以使用檔案系統掛載將資料持久儲存到主機系統上。檔案系統掛載還可以讓您在容器和主機之間共用資料。
Docker 支援兩種主要類型的掛載:
- 磁碟區掛載
- 繫結掛載
磁碟區掛載非常適合持久儲存容器的資料,以及在容器之間共用資料。而綁定掛載 (Bind mounts) 則用於在容器和主機之間共用資料。
您可以使用 docker run 命令的 --mount 旗標為容器新增檔案系統掛載。
以下章節顯示了如何建立磁碟區和綁定掛載的基本範例。有關更深入的範例和說明,請參閱文件中 儲存區 的章節。
磁碟區掛載
若要建立磁碟區掛載:
$ docker run --mount source=<VOLUME_NAME>,target=[PATH] [IMAGE] [COMMAND...]
在此情況下,--mount 旗標接受兩個參數:source 和 target。source 參數的值是磁碟區的名稱。target 的值是磁碟區在容器內部的掛載位置。一旦建立磁碟區,您寫入其中的任何資料都會持久儲存,即使您停止或移除容器也是如此。
$ docker run --rm --mount source=my_volume,target=/foo busybox \
echo "hello, volume!" > /foo/hello.txt
$ docker run --mount source=my_volume,target=/bar busybox
cat /bar/hello.txt
hello, volume!
target 必須始終是絕對路徑,例如 /src/docs。絕對路徑以 / (斜線) 開頭。磁碟區名稱必須以字母數字字元開頭,後面可以跟 a-z0-9、_ (底線)、. (句點) 或 - (連字號)。
繫結掛載
若要建立綁定掛載:
$ docker run -it --mount type=bind,source=[PATH],target=[PATH] busybox
在此情況下,--mount 旗標接受三個參數。一個類型 (bind),以及兩個路徑。source 路徑是您希望綁定掛載到容器中的主機上的位置。target 路徑是容器內部的掛載目標。
綁定掛載預設是讀寫的,這表示您可以從容器讀取和寫入檔案到掛載位置。您所做的更改,例如新增或編輯檔案,會反映在主機檔案系統上。
$ docker run -it --mount type=bind,source=.,target=/foo busybox
/ # echo "hello from container" > /foo/hello.txt
/ # exit
$ cat hello.txt
hello from container
結束狀態
docker run 的結束代碼提供了容器為何未能執行或為何結束的資訊。以下章節描述了不同容器結束代碼值的含義。
125
結束代碼 125 表示錯誤出在 Docker 守護程序本身。
$ docker run --foo busybox; echo $?
flag provided but not defined: --foo
See 'docker run --help'.
125
126
結束代碼 126 表示指定的容器內命令無法被呼叫。以下範例中的容器命令是:/etc。
$ docker run busybox /etc; echo $?
docker: Error response from daemon: Container command '/etc' could not be invoked.
126
127
結束代碼 127 表示找不到容器內的命令。
$ docker run busybox foo; echo $?
docker: Error response from daemon: Container command 'foo' not found or does not exist.
127
其他結束代碼
任何非 125、126 和 127 的結束代碼都代表所提供的容器命令的結束代碼。
$ docker run busybox /bin/sh -c 'exit 3'
$ echo $?
3
資源執行時限制
操作員也可以調整容器的效能參數:
| 選項 | 描述 |
|---|---|
-m, --memory="" | 記憶體限制 (格式:<number>[<unit>])。數字為正整數。單位可以是 b、k、m 或 g 之一。最小值為 6M。 |
--memory-swap="" | 總記憶體限制 (記憶體 + 緩衝區交換空間,格式:<number>[<unit>])。數字為正整數。單位可以是 b、k、m 或 g 之一。 |
--memory-reservation="" | 記憶體軟限制 (格式:<number>[<unit>])。數字為正整數。單位可以是 b、k、m 或 g 之一。 |
--kernel-memory="" | 核心記憶體限制 (格式:<number>[<unit>])。數字為正整數。單位可以是 b、k、m 或 g 之一。最小值為 4M。 |
-c, --cpu-shares=0 | CPU 共享 (相對權重) |
--cpus=0.000 | CPU 數量。數字為浮點數。0.000 表示無限制。 |
--cpu-period=0 | 限制 CPU CFS (完全公平排程器) 週期 |
--cpuset-cpus="" | 允許執行任務的 CPU (0-3, 0,1) |
--cpuset-mems="" | 允許執行任務的記憶體節點 (MEMs) (0-3, 0,1)。僅在 NUMA 系統上有效。 |
--cpu-quota=0 | 限制 CPU CFS (完全公平排程器) 配額 |
--cpu-rt-period=0 | 限制 CPU 即時週期。單位為微秒。要求設定父 cgroups 且不能高於父級。同時檢查 rtprio ulimits。 |
--cpu-rt-runtime=0 | 限制 CPU 即時執行時間。單位為微秒。要求設定父 cgroups 且不能高於父級。同時檢查 rtprio ulimits。 |
--blkio-weight=0 | 區塊 IO 權重 (相對權重) 接受介於 10 到 1000 之間的權重值。 |
--blkio-weight-device="" | 區塊 IO 權重 (相對裝置權重,格式:DEVICE_NAME:WEIGHT) |
--device-read-bps="" | 限制從裝置讀取速率 (格式:<device-path>:<number>[<unit>])。數字為正整數。單位可以是 kb、mb 或 gb 之一。 |
--device-write-bps="" | 限制寫入裝置速率 (格式:<device-path>:<number>[<unit>])。數字為正整數。單位可以是 kb、mb 或 gb 之一。 |
--device-read-iops="" | 限制從裝置讀取速率 (每秒 IO 數) (格式:<device-path>:<number>)。數字為正整數。 |
--device-write-iops="" | 限制寫入裝置速率 (每秒 IO 數) (格式:<device-path>:<number>)。數字為正整數。 |
--oom-kill-disable=false | 是否禁用容器的 OOM Killer。 |
--oom-score-adj=0 | 調整容器的 OOM 偏好 (-1000 到 1000) |
--memory-swappiness="" | 調整容器的記憶體換頁性行為。接受介於 0 到 100 之間的整數。 |
--shm-size="" | /dev/shm 的大小。格式為 <number><unit>。number 必須大於 0。單位是可選的,可以是 b (位元組)、k (千位元組)、m (百萬位元組) 或 g (十億位元組)。如果省略單位,系統會使用位元組。如果完全省略大小,系統會使用 64m。 |
使用者記憶體限制
我們有四種設定使用者記憶體使用量的方式:
| 選項 | 結果 |
|---|---|
| memory=inf, memory-swap=inf (預設) | 容器沒有記憶體限制。容器可以使用所需的所有記憶體。 |
| memory=L<inf, memory-swap=inf | (指定記憶體並將 memory-swap 設定為 -1) 容器不允許使用超過 L 位元組的記憶體,但可以使用所需的所有緩衝區交換空間 (如果主機支援緩衝區交換記憶體)。 |
| memory=L<inf, memory-swap=2*L | (未指定 memory-swap 的情況下指定記憶體) 容器不允許使用超過 L 位元組的記憶體,緩衝區交換空間加上記憶體使用量為其兩倍。 |
| memory=L<inf, memory-swap=S<inf, L<=S | (同時指定記憶體和 memory-swap) 容器不允許使用超過 L 位元組的記憶體,緩衝區交換空間加上記憶體使用量受 S 限制。 |
範例
$ docker run -it ubuntu:24.04 /bin/bash
我們沒有設定任何記憶體參數,這表示容器中的程序可以使用所需的所有記憶體和緩衝區交換記憶體。
$ docker run -it -m 300M --memory-swap -1 ubuntu:24.04 /bin/bash
我們設定了記憶體限制並禁用了緩衝區交換記憶體限制,這表示容器中的程序可以使用 300M 記憶體和所需的緩衝區交換記憶體 (如果主機支援緩衝區交換記憶體)。
$ docker run -it -m 300M ubuntu:24.04 /bin/bash
我們只設定了記憶體限制,這表示容器中的程序可以使用 300M 記憶體和 300M 緩衝區交換記憶體。預設情況下,總虛擬記憶體大小 (--memory-swap) 將設定為記憶體的兩倍。在本例中,記憶體 + 緩衝區交換空間將為 2*300M,因此程序也可以使用 300M 的緩衝區交換記憶體。
$ docker run -it -m 300M --memory-swap 1G ubuntu:24.04 /bin/bash
我們同時設定了記憶體和緩衝區交換記憶體,因此容器中的程序可以使用 300M 記憶體和 700M 緩衝區交換記憶體。
記憶體保留是一種記憶體軟限制,允許記憶體更大程度的共用。在正常情況下,容器可以使用所需的所有記憶體,並且僅受 -m/--memory 選項設定的硬限制約束。當設定記憶體保留時,Docker 會偵測記憶體爭用或低記憶體狀況,並強制容器將其消耗限制在保留限制內。
始終將記憶體保留值設定在硬限制之下,否則硬限制將優先。保留為 0 與未設定保留相同。預設情況下 (未設定保留時),記憶體保留與硬記憶體限制相同。
記憶體保留是一個軟限制功能,不保證不會超出限制。相反,此功能嘗試確保在記憶體嚴重爭用時,記憶體根據保留提示/設定進行分配。
以下範例將記憶體 (-m) 限制為 500M 並將記憶體保留設定為 200M。
$ docker run -it -m 500M --memory-reservation 200M ubuntu:24.04 /bin/bash
在此配置下,當容器消耗的記憶體超過 200M 但少於 500M 時,下一個系統記憶體回收嘗試會將容器記憶體縮小到 200M 以下。
以下範例將記憶體保留設定為 1G,沒有硬記憶體限制。
$ docker run -it --memory-reservation 1G ubuntu:24.04 /bin/bash
容器可以使用所需的所有記憶體。記憶體保留設定確保容器不會長時間消耗過多記憶體,因為每次記憶體回收都會將容器的消耗縮減到保留限制。
預設情況下,如果發生記憶體不足 (OOM) 錯誤,核心會終止容器中的程序。要改變這種行為,請使用 --oom-kill-disable 選項。僅在同時設定 -m/--memory 選項的容器上禁用 OOM killer。如果未設定 -m 旗標,這可能導致主機記憶體耗盡,並需要終止主機的系統程序來釋放記憶體。
以下範例將記憶體限制為 100M 並禁用此容器的 OOM killer。
$ docker run -it -m 100M --oom-kill-disable ubuntu:24.04 /bin/bash
以下範例說明了使用此旗標的危險方式:
$ docker run -it --oom-kill-disable ubuntu:24.04 /bin/bash
容器擁有無限記憶體,這可能導致主機記憶體耗盡,並需要終止系統程序來釋放記憶體。可以更改 --oom-score-adj 參數,以選擇當系統記憶體不足時哪些容器將被終止的優先級,負分數使其較不可能被終止,正分數則較可能被終止。
核心記憶體限制
核心記憶體與使用者記憶體本質上不同,因為核心記憶體無法被交換出去。無法交換使得容器有可能透過消耗過多的核心記憶體來阻擋系統服務。核心記憶體包括:
- 堆疊頁面
- slab 頁面
- socket 記憶體壓力
- TCP 記憶體壓力
您可以設定核心記憶體限制來約束這些類型的記憶體。例如,每個程序都會消耗一些堆疊頁面。透過限制核心記憶體,您可以在核心記憶體使用量過高時防止新程序建立。
核心記憶體從未完全獨立於使用者記憶體。相反,您是在使用者記憶體限制的背景下限制核心記憶體。假設「U」是使用者記憶體限制,「K」是核心限制。有三種可能的限制設定方式:
| 選項 | 結果 |
|---|---|
| U != 0, K = inf (預設) | 這是使用核心記憶體之前已經存在的標準記憶體限制機制。核心記憶體完全被忽略。 |
| U != 0, K < U | 核心記憶體是使用者記憶體的一個子集。這種設定在每個 cgroup 的記憶體總量過度配置的部署中很有用。不建議過度配置核心記憶體限制,因為主機仍然可能耗盡不可回收的記憶體。在此情況下,您可以配置 K,使所有群組的總和永遠不大於總記憶體。然後,自由設定 U,但可能會犧牲系統的服務品質。 |
| U != 0, K > U | 由於核心記憶體費用也會計入使用者計數器,並且對容器的兩種記憶體都會觸發回收。此配置為管理員提供了統一的記憶體視圖。對於只想追蹤核心記憶體使用量的人來說也很有用。 |
範例
$ docker run -it -m 500M --kernel-memory 50M ubuntu:24.04 /bin/bash
我們設定了記憶體和核心記憶體,因此容器中的程序總共可以使用 500M 記憶體,其中核心記憶體最多為 50M。
$ docker run -it --kernel-memory 50M ubuntu:24.04 /bin/bash
我們設定了核心記憶體而沒有 -m,因此容器中的程序可以隨意使用記憶體,但只能使用 50M 的核心記憶體。
換頁性限制
預設情況下,容器的核心可以將一部分匿名頁面交換出去。要為容器設定此百分比,請指定介於 0 到 100 之間的 --memory-swappiness 值。值為 0 會關閉匿名頁面交換。值為 100 會將所有匿名頁面設定為可交換。預設情況下,如果您未使用 --memory-swappiness,記憶體換頁性值將從父級繼承。
例如,您可以設定:
$ docker run -it --memory-swappiness=0 ubuntu:24.04 /bin/bash
當您想要保留容器的工作集並避免交換帶來的效能損失時,設定 --memory-swappiness 選項會很有幫助。
CPU 共享限制
預設情況下,所有容器獲得相同比例的 CPU 週期。可以透過更改容器的 CPU 共享權重相對於所有其他正在執行的容器的權重來修改此比例。
要從預設值 1024 修改此比例,請使用 -c 或 --cpu-shares 旗標將權重設定為 2 或更高。如果設定為 0,系統將忽略該值並使用預設值 1024。
此比例僅在 CPU 密集型程序執行時適用。當一個容器中的任務閒置時,其他容器可以使用剩餘的 CPU 時間。實際的 CPU 時間量會因系統上執行中的容器數量而異。
例如,考慮三個容器,一個的 CPU 共享為 1024,另外兩個的 CPU 共享設定為 512。當所有三個容器中的程序嘗試使用 100% 的 CPU 時,第一個容器將獲得總 CPU 時間的 50%。如果您新增第四個 CPU 共享為 1024 的容器,則第一個容器僅獲得 33% 的 CPU。其餘容器分別獲得 16.5%、16.5% 和 33% 的 CPU。
在多核心系統上,CPU 時間的共享分佈在所有 CPU 核心上。即使容器的 CPU 時間限制小於 100%,它仍然可以使用每個單獨 CPU 核心的 100%。
例如,考慮一個擁有超過三個核心的系統。如果您啟動一個 -c=512 的容器 {C0} 執行一個程序,以及另一個 -c=1024 的容器 {C1} 執行兩個程序,這可能會導致以下 CPU 共享劃分:
PID container CPU CPU share
100 {C0} 0 100% of CPU0
101 {C1} 1 100% of CPU1
102 {C1} 2 100% of CPU2
CPU 週期限制
預設的 CPU CFS (完全公平排程器) 週期為 100ms。我們可以使用 --cpu-period 來設定 CPU 週期以限制容器的 CPU 使用量。通常 --cpu-period 應與 --cpu-quota 配合使用。
範例
$ docker run -it --cpu-period=50000 --cpu-quota=25000 ubuntu:24.04 /bin/bash
如果只有 1 個 CPU,這表示容器每 50ms 可以獲得相當於 50% CPU 的執行時間。
除了使用 --cpu-period 和 --cpu-quota 來設定 CPU 週期限制外,也可以使用浮點數指定 --cpus 來達到相同的目的。例如,如果只有 1 個 CPU,那麼 --cpus=0.5 將會達到與設定 --cpu-period=50000 和 --cpu-quota=25000 (50% CPU) 相同的結果。
--cpus 的預設值是 0.000,這表示沒有限制。
有關更多資訊,請參閱 CFS 頻寬限制文件。
CPU 集限制
我們可以設定允許容器執行的 CPU。
範例
$ docker run -it --cpuset-cpus="1,3" ubuntu:24.04 /bin/bash
這表示容器中的程序可以在 CPU 1 和 CPU 3 上執行。
$ docker run -it --cpuset-cpus="0-2" ubuntu:24.04 /bin/bash
這表示容器中的程序可以在 CPU 0、CPU 1 和 CPU 2 上執行。
我們可以設定允許容器執行的記憶體節點。僅在 NUMA 系統上有效。
範例
$ docker run -it --cpuset-mems="1,3" ubuntu:24.04 /bin/bash
此範例將容器中的程序限制為僅使用記憶體節點 1 和 3 的記憶體。
$ docker run -it --cpuset-mems="0-2" ubuntu:24.04 /bin/bash
此範例將容器中的程序限制為僅使用記憶體節點 0、1 和 2 的記憶體。
CPU 配額限制
--cpu-quota 旗標限制了容器的 CPU 使用量。預設值 0 允許容器佔用 100% 的 CPU 資源 (1 個 CPU)。CFS (完全公平排程器) 處理執行中程序的資源分配,並且是核心使用的預設 Linux 排程器。將此值設定為 50000 可將容器限制為 50% 的 CPU 資源。對於多個 CPU,請根據需要調整 --cpu-quota。有關更多資訊,請參閱 CFS 頻寬限制文件。
區塊 IO 頻寬 (Blkio) 限制
預設情況下,所有容器獲得相同比例的區塊 IO 頻寬 (blkio)。此比例為 500。要修改此比例,請使用 --blkio-weight 旗標更改容器的 blkio 權重,使其相對於所有其他正在執行的容器的權重。
注意blkio 權重設定僅適用於直接 IO。目前不支援緩衝 IO。
--blkio-weight 旗標可以將權重設定為 10 到 1000 之間的值。例如,以下命令建立兩個具有不同 blkio 權重的容器:
$ docker run -it --name c1 --blkio-weight 300 ubuntu:24.04 /bin/bash
$ docker run -it --name c2 --blkio-weight 600 ubuntu:24.04 /bin/bash
如果您同時在兩個容器中進行區塊 IO,例如:
$ time dd if=/mnt/zerofile of=test.out bs=1M count=1024 oflag=direct
您會發現時間比例與兩個容器的 blkio 權重比例相同。
--blkio-weight-device="DEVICE_NAME:WEIGHT" 旗標設定特定裝置的權重。DEVICE_NAME:WEIGHT 是包含冒號分隔的裝置名稱和權重的字串。例如,將 /dev/sda 裝置權重設定為 200:
$ docker run -it \
--blkio-weight-device "/dev/sda:200" \
ubuntu
如果您同時指定 --blkio-weight 和 --blkio-weight-device,Docker 會將 --blkio-weight 用作預設權重,並使用 --blkio-weight-device 覆寫特定裝置上的此預設值。以下範例使用預設權重 300,並在 /dev/sda 上將權重覆寫為 200:
$ docker run -it \
--blkio-weight 300 \
--blkio-weight-device "/dev/sda:200" \
ubuntu
--device-read-bps 旗標限制從裝置讀取速率 (位元組/秒)。例如,此命令建立一個容器並將從 /dev/sda 的讀取速率限制為每秒 1mb:
$ docker run -it --device-read-bps /dev/sda:1mb ubuntu
--device-write-bps 旗標限制寫入裝置速率 (位元組/秒)。例如,此命令建立一個容器並將寫入 /dev/sda 的速率限制為每秒 1mb:
$ docker run -it --device-write-bps /dev/sda:1mb ubuntu
兩個旗標都接受 <device-path>:<limit>[unit] 格式的限制。讀取和寫入速率都必須是正整數。您可以指定速率為 kb (千位元組)、mb (百萬位元組) 或 gb (十億位元組)。
--device-read-iops 旗標限制從裝置讀取速率 (每秒 IO 數)。例如,此命令建立一個容器並將從 /dev/sda 的讀取速率限制為每秒 1000 IO:
$ docker run -it --device-read-iops /dev/sda:1000 ubuntu
--device-write-iops 旗標限制寫入裝置速率 (每秒 IO 數)。例如,此命令建立一個容器並將寫入 /dev/sda 的速率限制為每秒 1000 IO:
$ docker run -it --device-write-iops /dev/sda:1000 ubuntu
兩個旗標都接受 <device-path>:<limit> 格式的限制。讀取和寫入速率都必須是正整數。
額外群組
--group-add: Add additional groups to run as
預設情況下,docker 容器程序會以指定使用者的輔助群組執行。如果想在該群組列表中增加更多群組,可以使用此旗標:
$ docker run --rm --group-add audio --group-add nogroup --group-add 777 busybox id
uid=0(root) gid=0(root) groups=10(wheel),29(audio),99(nogroup),777
執行時權限與 Linux 能力
| 選項 | 描述 |
|---|---|
--cap-add | 新增 Linux 能力 |
--cap-drop | 移除 Linux 能力 |
--privileged | 授予此容器擴展權限 |
--device=[] | 允許您在沒有 --privileged 旗標的情況下在容器內部執行裝置。 |
預設情況下,Docker 容器是「非特權」的,例如,無法在 Docker 容器內部執行 Docker 守護程序。這是因為預設情況下容器不允許存取任何裝置,但「特權」容器被授予存取所有裝置的權限 (請參閱 cgroups 裝置 的文件)。
--privileged 旗標授予容器所有能力。當操作員執行 docker run --privileged 時,Docker 會啟用對主機上所有裝置的存取,並重新配置 AppArmor 或 SELinux,以允許容器幾乎擁有與在主機上容器外部執行的程序相同的存取主機的權限。請謹慎使用此旗標。有關 --privileged 旗標的更多資訊,請參閱 docker run 參考資料。
如果您想限制對特定裝置的存取,可以使用 --device 旗標。它允許您指定一個或多個在容器內可存取的裝置。
$ docker run --device=/dev/snd:/dev/snd ...
預設情況下,容器將能夠 read、write 和 mknod 這些裝置。這可以透過為每個 --device 旗標使用第三個 :rwm 選項集來覆寫。
$ docker run --device=/dev/sda:/dev/xvdc --rm -it ubuntu fdisk /dev/xvdc
Command (m for help): q
$ docker run --device=/dev/sda:/dev/xvdc:r --rm -it ubuntu fdisk /dev/xvdc
You will not be able to write the partition table.
Command (m for help): q
$ docker run --device=/dev/sda:/dev/xvdc:w --rm -it ubuntu fdisk /dev/xvdc
crash....
$ docker run --device=/dev/sda:/dev/xvdc:m --rm -it ubuntu fdisk /dev/xvdc
fdisk: unable to open /dev/xvdc: Operation not permitted
除了 --privileged 之外,操作員還可以使用 --cap-add 和 --cap-drop 對能力進行細粒度控制。預設情況下,Docker 保留了一組預設的能力。下表列出了預設允許且可以移除的 Linux 能力選項。
| 能力鍵 | 能力描述 |
|---|---|
| AUDIT_WRITE | 將記錄寫入核心稽核日誌。 |
| CHOWN | 任意更改檔案 UID 和 GID (參見 chown(2))。 |
| DAC_OVERRIDE | 繞過檔案讀取、寫入和執行權限檢查。 |
| FOWNER | 繞過對通常要求程序檔案系統 UID 與檔案 UID 匹配的操作的權限檢查。 |
| FSETID | 修改檔案時不清除 set-user-ID 和 set-group-ID 權限位元。 |
| KILL | 繞過發送信號的權限檢查。 |
| MKNOD | 使用 mknod(2) 建立特殊檔案。 |
| NET_BIND_SERVICE | 將 socket 綁定到網際網路網域特權連接埠 (連接埠號小於 1024)。 |
| NET_RAW | 使用 RAW 和 PACKET socket。 |
| SETFCAP | 設定檔案能力。 |
| SETGID | 任意操作程序 GID 和輔助 GID 列表。 |
| SETPCAP | 修改程序能力。 |
| SETUID | 任意操作程序 UID。 |
| SYS_CHROOT | 使用 chroot(2),更改根目錄。 |
下表顯示了預設未授予但可以新增的能力。
| 能力鍵 | 能力描述 |
|---|---|
| AUDIT_CONTROL | 啟用和禁用核心稽核;更改稽核過濾規則;檢索稽核狀態和過濾規則。 |
| AUDIT_READ | 允許透過多播 netlink socket 讀取稽核日誌。 |
| BLOCK_SUSPEND | 允許防止系統暫停。 |
| BPF | 允許建立 BPF 映射、載入 BPF 類型格式 (BTF) 資料、檢索 BPF 程序的 JITed 代碼等。 |
| CHECKPOINT_RESTORE | 允許檢查點/恢復相關操作。在核心 5.9 中引入。 |
| DAC_READ_SEARCH | 繞過檔案讀取權限檢查以及目錄讀取和執行權限檢查。 |
| IPC_LOCK | 鎖定記憶體 (mlock(2)、mlockall(2)、mmap(2)、shmctl(2))。 |
| IPC_OWNER | 繞過對 System V IPC 物件操作的權限檢查。 |
| LEASE | 在任意檔案上建立租約 (參見 fcntl(2))。 |
| LINUX_IMMUTABLE | 設定 FS_APPEND_FL 和 FS_IMMUTABLE_FL i-node 旗標。 |
| MAC_ADMIN | 允許 MAC 配置或狀態更改。為 Smack LSM 實作。 |
| MAC_OVERRIDE | 覆寫強制存取控制 (MAC)。為 Smack Linux 安全模組 (LSM) 實作。 |
| NET_ADMIN | 執行各種網路相關操作。 |
| NET_BROADCAST | 進行 socket 廣播,並監聽多播。 |
| PERFMON | 允許使用 perf_events、i915_perf 和其他核心子系統執行系統效能和可觀察性特權操作。 |
| SYS_ADMIN | 執行一系列系統管理操作。 |
| SYS_BOOT | 使用 reboot(2) 和 kexec_load(2),重新啟動並載入新的核心以供後續執行。 |
| SYS_MODULE | 載入和卸載核心模組。 |
| SYS_NICE | 提高程序 nice 值 (nice(2), setpriority(2)) 並更改任意程序的 nice 值。 |
| SYS_PACCT | 使用 acct(2),開啟或關閉程序計帳。 |
| SYS_PTRACE | 使用 ptrace(2) 追蹤任意程序。 |
| SYS_RAWIO | 執行 I/O 埠操作 (iopl(2) 和 ioperm(2))。 |
| SYS_RESOURCE | 覆寫資源限制。 |
| SYS_TIME | 設定系統時鐘 (settimeofday(2), stime(2), adjtimex(2));設定即時 (硬體) 時鐘。 |
| SYS_TTY_CONFIG | 使用 vhangup(2);在虛擬終端機上使用各種特權 ioctl(2) 操作。 |
| SYSLOG | 執行特權 syslog(2) 操作。 |
| WAKE_ALARM | 觸發將喚醒系統的操作。 |
更多參考資訊可在 capabilities(7) - Linux man page 和 Linux 核心原始碼 中找到。
兩個旗標都支援值 ALL,因此要允許容器使用除 MKNOD 以外的所有能力:
$ docker run --cap-add=ALL --cap-drop=MKNOD ...
--cap-add 和 --cap-drop 旗標接受以 CAP_ 字首指定的能力。因此,以下範例是等效的:
$ docker run --cap-add=SYS_ADMIN ...
$ docker run --cap-add=CAP_SYS_ADMIN ...
對於與網路堆疊的互動,應使用 --cap-add=NET_ADMIN 來修改網路介面,而不是使用 --privileged。
$ docker run -it --rm ubuntu:24.04 ip link add dummy0 type dummy
RTNETLINK answers: Operation not permitted
$ docker run -it --rm --cap-add=NET_ADMIN ubuntu:24.04 ip link add dummy0 type dummy
要掛載基於 FUSE 的檔案系統,您需要結合使用 --cap-add 和 --device。
$ docker run --rm -it --cap-add SYS_ADMIN sshfs sshfs sven@10.10.10.20:/home/sven /mnt
fuse: failed to open /dev/fuse: Operation not permitted
$ docker run --rm -it --device /dev/fuse sshfs sshfs sven@10.10.10.20:/home/sven /mnt
fusermount: mount failed: Operation not permitted
$ docker run --rm -it --cap-add SYS_ADMIN --device /dev/fuse sshfs
# sshfs sven@10.10.10.20:/home/sven /mnt
The authenticity of host '10.10.10.20 (10.10.10.20)' can't be established.
ECDSA key fingerprint is 25:34:85:75:25:b0:17:46:05:19:04:93:b5:dd:5f:c6.
Are you sure you want to continue connecting (yes/no)? yes
sven@10.10.10.20's password:
root@30aa0cfaf1b5:/# ls -la /mnt/src/docker
total 1516
drwxrwxr-x 1 1000 1000 4096 Dec 4 06:08 .
drwxrwxr-x 1 1000 1000 4096 Dec 4 11:46 ..
-rw-rw-r-- 1 1000 1000 16 Oct 8 00:09 .dockerignore
-rwxrwxr-x 1 1000 1000 464 Oct 8 00:09 .drone.yml
drwxrwxr-x 1 1000 1000 4096 Dec 4 06:11 .git
-rw-rw-r-- 1 1000 1000 461 Dec 4 06:08 .gitignore
....
預設的 seccomp 設定檔會根據所選的能力進行調整,以允許使用這些能力所允許的功能,因此您無需調整此項。
覆寫映像檔預設值
當您從 Dockerfile 建置映像檔,或提交 (committing) 映像檔時,您可以設定多個預設參數,這些參數在映像檔作為容器啟動時生效。當您執行映像檔時,可以使用 docker run 命令的旗標來覆寫這些預設值。
預設命令與選項
docker run 的命令語法支援選擇性地為容器的進入點指定命令和引數,在以下概要範例中表示為 [COMMAND] 和 [ARG...]:
$ docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]
此命令是可選的,因為建立 IMAGE 的人可能已經使用 Dockerfile CMD 指令提供了預設的 COMMAND。當您執行容器時,只需指定新的 COMMAND 即可覆寫該 CMD 指令。
如果映像檔也指定了 ENTRYPOINT,則 CMD 或 COMMAND 將作為引數附加到 ENTRYPOINT。
預設進入點
--entrypoint="": Overwrite the default entrypoint set by the image進入點指的是當您執行容器時所呼叫的預設可執行檔。容器的進入點是使用 Dockerfile ENTRYPOINT 指令定義的。它類似於指定預設命令,但不同之處在於您需要傳遞一個明確的旗標來覆寫進入點,而預設命令可以透過位置引數來覆寫。進入點定義了容器的預設行為,其理念是當您設定進入點時,您可以執行容器如同它是那個二進位檔,並帶有預設選項,您還可以將更多選項作為命令傳遞。但在某些情況下,您可能希望在容器內部執行其他東西。這就是使用 docker run 命令的 --entrypoint 旗標在執行時覆寫預設進入點的用武之地。
--entrypoint 旗標預期一個字串值,代表您希望在容器啟動時呼叫的二進位檔名稱或路徑。以下範例展示了如何在已設定自動執行其他二進位檔 (例如 /usr/bin/redis-server) 的容器中執行 Bash shell。
$ docker run -it --entrypoint /bin/bash example/redis
以下範例展示如何使用位置命令引數將額外參數傳遞給自訂進入點:
$ docker run -it --entrypoint /bin/bash example/redis -c ls -l
$ docker run -it --entrypoint /usr/bin/redis-cli example/redis --help
您可以透過傳遞空字串來重設容器的進入點,例如:
$ docker run -it --entrypoint="" mysql bash
注意傳遞
--entrypoint會清除映像檔上設定的任何預設命令。也就是說,會清除用於建置該映像檔的 Dockerfile 中的任何CMD指令。
暴露的連接埠
預設情況下,當您執行容器時,容器的任何連接埠都不會暴露給主機。這表示您將無法存取容器可能正在監聽的任何連接埠。要讓容器的連接埠可從主機存取,您需要發佈這些連接埠。
您可以使用 -P 或 -p 旗標啟動容器以暴露其連接埠:
-P(或--publish-all) 旗標將所有暴露的連接埠發佈到主機。Docker 將每個暴露的連接埠綁定到主機上的隨機連接埠。-P旗標僅發佈明確標記為暴露的連接埠號,無論是使用 DockerfileEXPOSE指令還是docker run命令的--expose旗標。-p(或--publish) 旗標允許您將容器中的單一連接埠或連接埠範圍明確映射到主機。
容器內部 (服務監聽處) 的連接埠號碼不需要與容器外部 (客戶端連接處) 發佈的連接埠號碼匹配。例如,在容器內部,HTTP 服務可能正在監聽連接埠 80。在執行時,該連接埠可能綁定到主機上的 42800。要查找主機連接埠和暴露連接埠之間的映射,請使用 docker port 命令。
環境變數
Docker 在建立 Linux 容器時會自動設定一些環境變數。Docker 在建立 Windows 容器時不會設定任何環境變數。
以下環境變數是為 Linux 容器設定的:
| 變數 | 值 |
|---|---|
HOME | 根據 USER 的值設定 |
HOSTNAME | 與容器關聯的主機名稱 |
PATH | 包含常用目錄,例如 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin |
TERM | 如果為容器分配了偽終端機,則為 xterm |
此外,您可以使用一個或多個 -e 旗標在容器中設定任何環境變數。您甚至可以覆寫上面提到的變數,或在建置映像檔時使用 Dockerfile ENV 指令定義的變數。
如果您只命名一個環境變數而未指定值,則主機上該具名變數的當前值將傳播到容器的環境中。
$ export today=Wednesday
$ docker run -e "deep=purple" -e today --rm alpine env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=d2219b854598
deep=purple
today=Wednesday
HOME=/root
PS C:\> docker run --rm -e "foo=bar" microsoft/nanoserver cmd /s /c set
ALLUSERSPROFILE=C:\ProgramData
APPDATA=C:\Users\ContainerAdministrator\AppData\Roaming
CommonProgramFiles=C:\Program Files\Common Files
CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
CommonProgramW6432=C:\Program Files\Common Files
COMPUTERNAME=C2FAEFCC8253
ComSpec=C:\Windows\system32\cmd.exe
foo=bar
LOCALAPPDATA=C:\Users\ContainerAdministrator\AppData\Local
NUMBER_OF_PROCESSORS=8
OS=Windows_NT
Path=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Users\ContainerAdministrator\AppData\Local\Microsoft\WindowsApps
PATHEXT=.COM;.EXE;.BAT;.CMD
PROCESSOR_ARCHITECTURE=AMD64
PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 62 Stepping 4, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=3e04
ProgramData=C:\ProgramData
ProgramFiles=C:\Program Files
ProgramFiles(x86)=C:\Program Files (x86)
ProgramW6432=C:\Program Files
PROMPT=$P$G
PUBLIC=C:\Users\Public
SystemDrive=C:
SystemRoot=C:\Windows
TEMP=C:\Users\ContainerAdministrator\AppData\Local\Temp
TMP=C:\Users\ContainerAdministrator\AppData\Local\Temp
USERDOMAIN=User Manager
USERNAME=ContainerAdministrator
USERPROFILE=C:\Users\ContainerAdministrator
windir=C:\Windows健康檢查
docker run 命令的以下旗標讓您可以控制容器健康檢查的參數:
| 選項 | 描述 |
|---|---|
--health-cmd | 執行以檢查健康的命令 |
--health-interval | 執行檢查之間的間隔時間 |
--health-retries | 報告不健康所需的連續失敗次數 |
--health-timeout | 允許一次檢查執行的最長時間 |
--health-start-period | 容器初始化後,開始健康檢查重試倒數計時前的啟動期間 |
--health-start-interval | 啟動期間執行檢查之間的間隔時間 |
--no-healthcheck | 禁用任何容器指定的 HEALTHCHECK |
範例
$ docker run --name=test -d \
--health-cmd='stat /etc/passwd || exit 1' \
--health-interval=2s \
busybox sleep 1d
$ sleep 2; docker inspect --format='{{.State.Health.Status}}' test
healthy
$ docker exec test rm /etc/passwd
$ sleep 2; docker inspect --format='{{json .State.Health}}' test
{
"Status": "unhealthy",
"FailingStreak": 3,
"Log": [
{
"Start": "2016-05-25T17:22:04.635478668Z",
"End": "2016-05-25T17:22:04.7272552Z",
"ExitCode": 0,
"Output": " File: /etc/passwd\n Size: 334 \tBlocks: 8 IO Block: 4096 regular file\nDevice: 32h/50d\tInode: 12 Links: 1\nAccess: (0664/-rw-rw-r--) Uid: ( 0/ root) Gid: ( 0/ root)\nAccess: 2015-12-05 22:05:32.000000000\nModify: 2015..."
},
{
"Start": "2016-05-25T17:22:06.732900633Z",
"End": "2016-05-25T17:22:06.822168935Z",
"ExitCode": 0,
"Output": " File: /etc/passwd\n Size: 334 \tBlocks: 8 IO Block: 4096 regular file\nDevice: 32h/50d\tInode: 12 Links: 1\nAccess: (0664/-rw-rw-r--) Uid: ( 0/ root) Gid: ( 0/ root)\nAccess: 2015-12-05 22:05:32.000000000\nModify: 2015..."
},
{
"Start": "2016-05-25T17:22:08.823956535Z",
"End": "2016-05-25T17:22:08.897359124Z",
"ExitCode": 1,
"Output": "stat: can't stat '/etc/passwd': No such file or directory\n"
},
{
"Start": "2016-05-25T17:22:10.898802931Z",
"End": "2016-05-25T17:22:10.969631866Z",
"ExitCode": 1,
"Output": "stat: can't stat '/etc/passwd': No such file or directory\n"
},
{
"Start": "2016-05-25T17:22:12.971033523Z",
"End": "2016-05-25T17:22:13.082015516Z",
"ExitCode": 1,
"Output": "stat: can't stat '/etc/passwd': No such file or directory\n"
}
]
}
健康狀態也會顯示在 docker ps 的輸出中。
使用者
容器內的預設使用者是 root (uid = 0)。您可以使用 Dockerfile USER 指令設定預設使用者來執行第一個程序。啟動容器時,您可以透過傳遞 -u 選項來覆寫 USER 指令。
-u="", --user="": Sets the username or UID used and optionally the groupname or GID for the specified command.以下範例均有效:
--user=[ user | user:group | uid | uid:gid | user:gid | uid:group ]注意如果您傳遞的是數字使用者 ID,它必須介於 0-2147483647 之間。如果您傳遞的是使用者名稱,則該使用者必須存在於容器中。
工作目錄
容器內執行二進位檔的預設工作目錄是根目錄 (/)。映像檔的預設工作目錄是使用 Dockerfile WORKDIR 命令設定的。您可以使用 docker run 命令的 -w (或 --workdir) 旗標來覆寫映像檔的預設工作目錄。
$ docker run --rm -w /my/workdir alpine pwd
/my/workdir如果該目錄在容器中尚不存在,它將被建立。