執行容器
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 或更高版本映象格式的映象具有一個稱為摘要的內容可定址識別符號。只要用於生成映象的輸入保持不變,摘要值就是可預測的。
以下示例從具有 sha256:9cacb71397b640eca97488cf08582ae4e4068513101088e9f96c9814bfda95e0
摘要的 alpine
映象執行一個容器
$ 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
和stderr
docker run --tty
:分配一個偽 TTYdocker run --interactive
:即使未附加也保持stdin
開啟
有關重新附加到後臺容器的更多資訊,請參閱 docker attach
。
容器標識
您可以透過三種方式識別容器
識別符號型別 | 示例值 |
---|---|
UUID 長識別符號 | f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778 |
UUID 短識別符號 | f78375b1c487 |
名稱 | evil_ptolemy |
UUID 識別符號是守護程序分配給容器的隨機 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 支援兩種主要的掛載類別
- 卷掛載
- 繫結掛載
卷掛載非常適合持久儲存容器資料,以及在容器之間共享資料。而繫結掛載則用於在容器和主機之間共享資料。
您可以使用 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 即時週期。單位為微秒。要求設定父 cgroup 且不能高於父 cgroup。同時檢查 rtprio ulimits。 |
--cpu-rt-runtime=0 | 限制 CPU 即時執行時間。單位為微秒。要求設定父 cgroup 且不能高於父 cgroup。同時檢查 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 頁
- 套接字記憶體壓力
- 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 記憶體,在這 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-share 是 1024,另外兩個的 cpu-share 設定是 512。當所有三個容器中的程序都試圖使用 100% 的 CPU 時,第一個容器將獲得總 CPU 時間的 50%。如果您新增第四個 cpu-share 為 1024 的容器,第一個容器只能獲得 33% 的 CPU。其餘容器分別獲得 16.5%、16.5% 和 33% 的 CPU。
在多核系統上,CPU 時間的份額分佈在所有 CPU 核心上。即使容器被限制在不到 100% 的 CPU 時間,它也可以使用每個獨立 CPU 核心的 100%。
例如,考慮一個擁有超過三個核心的系統。如果您啟動一個容器 {C0}
,設定 -c=512
並執行一個程序,以及另一個容器 {C1}
,設定 -c=1024
並執行兩個程序,這可能導致以下 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 文件。
Cpuset 約束
我們可以為容器設定允許執行的 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 | 將套接字繫結到網際網路域特權埠(埠號小於 1024)。 |
NET_RAW | 使用 RAW 和 PACKET 套接字。 |
SETFCAP | 設定檔案能力。 |
SETGID | 對程序 GID 和補充 GID 列表進行任意操作。 |
SETPCAP | 修改程序能力。 |
SETUID | 對程序 UID 進行任意操作。 |
SYS_CHROOT | 使用 chroot(2),更改根目錄。 |
下表顯示了預設未授予但可以新增的能力。
能力鍵 | 能力描述 |
---|---|
AUDIT_CONTROL | 啟用和停用核心審計;更改審計過濾規則;檢索審計狀態和過濾規則。 |
AUDIT_READ | 允許透過多播 netlink 套接字讀取審計日誌。 |
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 | 進行套接字廣播,並監聽多播。 |
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 手冊頁 以及 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 構建映象或提交映象時,您可以設定一些預設引數,這些引數在映象作為容器啟動時生效。當您執行映象時,可以使用 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
標誌只發布那些被明確標記為暴露的埠號,無論是使用 Dockerfile 的EXPOSE
指令還是docker run
命令的--expose
標誌。-p
(或--publish
)標誌允許您明確地將容器中的單個埠或埠範圍對映到主機。
容器內部的埠號(服務監聽的埠)不必與容器外部發布的埠號(客戶端連線的埠)相匹配。例如,在容器內部,一個 HTTP 服務可能在 80 埠上監聽。在執行時,該埠可能被繫結到主機上的 42800 埠。要查詢主機埠和暴露埠之間的對映,請使用 docker port
命令。
環境變數
在建立 Linux 容器時,Docker 會自動設定一些環境變數。在建立 Windows 容器時,Docker 不會設定任何環境變數。
以下環境變數是為 Linux 容器設定的
變數 | 值 |
---|---|
HOME | 根據 USER 的值設定 |
HOSTNAME | 與容器關聯的主機名 |
PATH | 包括常用目錄,例如 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin |
TERM | 如果容器被分配了偽 TTY,則為 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
如果目錄在容器中尚不存在,它將被建立。