執行容器

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 旗標的詳細資訊,請參閱

更多關於使用篩選器的資訊,請參閱 篩選容器網路

預設情況下,容器已啟用網路功能,並且可以建立輸出連線。如果您正在執行多個需要相互通訊的容器,您可以建立自訂網路並將容器附加到該網路。

當多個容器附加到同一個自訂網路時,它們可以使用容器名稱作為 DNS 主機名稱相互通訊。以下範例建立一個名為 my-net 的自訂網路,並執行兩個附加到該網路的容器。

更多關於容器網路的資訊,請參閱 網路概觀檔案系統掛載

預設情況下,容器中的資料會儲存在一個暫時性、可寫入的容器層中。移除容器也會移除其資料。如果您想在容器中使用永久性資料,您可以使用檔案系統掛載將資料永久儲存在主機系統上。檔案系統掛載也可以讓您在容器和主機之間共用資料。

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 Daemon 本身。

$ docker run --foo busybox; echo $?

flag provided but not defined: --foo
See 'docker run --help'.
125

126

退出代碼 `126` 表示無法叫用指定的容器指令。以下範例中的容器指令為:`/etc; echo $?`。

$ 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=""`允許執行的記憶體節點(MEM)(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 和 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

我們只設定了記憶體限制,這表示容器中的行程可以使用 300MB 的記憶體和 300MB 的交換記憶體。預設情況下,總虛擬記憶體大小 (`--memory-swap`) 將設定為記憶體的兩倍,在本例中,記憶體 + 交換記憶體將為 2*300MB,因此行程也可以使用 300MB 的交換記憶體。

$ docker run -it -m 300M --memory-swap 1G ubuntu:24.04 /bin/bash

我們同時設定了記憶體和交換記憶體,因此容器中的行程可以使用 300MB 的記憶體和 700MB 的交換記憶體。

記憶體預留是一種記憶體軟限制,允許更大程度地共享記憶體。一般情況下,容器可以使用所需的記憶體量,並且僅受 `-m`/`--memory` 選項設定的硬限制約束。設定記憶體預留後,Docker 會偵測記憶體爭用或記憶體不足的情況,並強制容器將其消耗限制在預留限制內。

務必將記憶體預留值設定在硬限制以下,否則硬限制將優先。預留值為 0 與未設定預留值相同。預設情況下(未設定預留值),記憶體預留與硬記憶體限制相同。

記憶體預留是一個軟限制功能,並不保證限制不會被超過。相反,此功能嘗試確保在記憶體嚴重爭用的情況下,根據預留提示/設定分配記憶體。

以下範例將記憶體 (`-m`) 限制為 500MB,並將記憶體預留設定為 200MB。

$ docker run -it -m 500M --memory-reservation 200M ubuntu:24.04 /bin/bash

在此配置下,當容器消耗的記憶體超過 200MB 且小於 500MB 時,下一次系統記憶體回收將嘗試將容器記憶體縮小到 200MB 以下。

以下範例將記憶體預留設定為 1GB,沒有硬記憶體限制。

$ docker run -it --memory-reservation 1G ubuntu:24.04 /bin/bash

容器可以使用所需的記憶體量。記憶體預留設定可確保容器不會長時間消耗過多記憶體,因為每次記憶體回收都會將容器的消耗縮小到預留值。

預設情況下,如果發生記憶體不足 (OOM) 錯誤,核心會終止容器中的行程。要更改此行為,請使用 `--oom-kill-disable` 選項。僅在也設定了 `-m/--memory` 選項的容器上停用 OOM 終止機制。如果未設定 `-m` 旗標,這可能導致主機記憶體不足,並需要終止主機的系統行程以釋放記憶體。

以下範例將記憶體限制為 100MB,並停用此容器的 OOM 終止機制。

$ 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` 參數來選擇在系統記憶體不足時要終止哪些容器的優先順序,負分數表示它們不太可能被終止,正分數表示它們更有可能被終止。

核心記憶體限制

核心記憶體與使用者記憶體根本不同,因為核心記憶體無法被交換出去。無法交換使得容器有可能通過消耗過多核心記憶體來阻塞系統服務。核心記憶體包括:

您可以設定核心記憶體限制來約束這類記憶體。例如,每個行程都會消耗一些堆疊頁面。通過限制核心記憶體,您可以防止在核心記憶體使用率過高時建立新的行程。

核心記憶體永遠不會完全獨立於使用者記憶體。相反,您會在使用者記憶體限制的上下文中限制核心記憶體。假設「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

我們設定了記憶體和核心記憶體,因此容器中的行程總共可以使用 500MB 的記憶體,在這 500MB 的記憶體中,最多可以使用 50MB 的核心記憶體。

$ docker run -it --kernel-memory 50M ubuntu:24.04 /bin/bash

我們設定了核心記憶體,但沒有使用 **-m**,因此容器中的行程可以使用所需的記憶體量,但它們只能使用 50MB 的核心記憶體。

記憶體交換限制

預設情況下,容器的核心可以交換出一定比例的匿名頁面。要為容器設定此百分比,請指定介於 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(完全公平排程器)週期為 100 毫秒。我們可以使用 --cpu-period 來設定 CPU 的週期以限制容器的 CPU 使用率。通常 --cpu-period 應該與 --cpu-quota 一起使用。

範例

$ docker run -it --cpu-period=50000 --cpu-quota=25000 ubuntu:24.04 /bin/bash

如果只有 1 個 CPU,這表示容器每 50 毫秒可以獲得相當於 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。

範例

這表示容器中的進程可以在 CPU 1 和 CPU 3 上執行。

這表示容器中的進程可以在 CPU 0、CPU 1 和 CPU 2 上執行。

我們可以設定允許容器執行的記憶體節點。僅在 NUMA 系統上有效。

範例

此範例將容器中的進程限制為僅使用來自記憶體節點 1 和 3 的記憶體。

此範例將容器中的進程限制為僅使用來自記憶體節點 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 權重的容器:

如果您同時在兩個容器中執行區塊 IO,例如:

您會發現時間比例與兩個容器的 blkio 權重比例相同。

--blkio-weight-device="DEVICE_NAME:WEIGHT" 旗標設定特定裝置的權重。 DEVICE_NAME:WEIGHT 是一個包含以冒號分隔的裝置名稱和權重的字串。例如,要將 /dev/sda 裝置權重設定為 200

如果您同時指定 --blkio-weight--blkio-weight-device,Docker 會使用 --blkio-weight 作為預設權重,並使用 --blkio-weight-device 在特定裝置上以新值覆蓋此預設值。以下範例使用預設權重 300,並在 /dev/sda 上覆蓋此預設值,將該權重設定為 200

--device-read-bps 旗標限制裝置的讀取速率(每秒位元組數)。例如,此命令建立一個容器,並將 /dev/sda 的讀取速率限制為每秒 1mb

--device-write-bps 旗標限制裝置的寫入速率(每秒位元組數)。例如,此命令建立一個容器,並將 /dev/sda 的寫入速率限制為每秒 1mb

兩個旗標都採用 <device-path>:<limit>[unit] 格式的限制。讀取和寫入速率都必須是正整數。您可以使用 kb(千位元組)、mb(百萬位元組)或 gb(十億位元組)來指定速率。

--device-read-iops 旗標限制裝置的讀取速率(每秒 IO 數)。例如,此命令建立一個容器,並將 /dev/sda 的讀取速率限制為每秒 1000 IO:

--device-write-iops 旗標限制裝置的寫入速率(每秒 IO 數)。例如,此命令建立一個容器,並將 /dev/sda 的寫入速率限制為每秒 1000 IO:

兩個旗標都採用 <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 裝置docker run 參考文件

如果您想限制對特定裝置的存取權,可以使用 --device 旗標。它允許您指定一個或多個容器內可存取的裝置。

$ docker run --device=/dev/snd:/dev/snd ...

預設情況下,容器將能夠對這些裝置進行 read(讀取)、write(寫入)和 mknod(建立裝置節點)。可以使用第三個 :rwm 選項集覆蓋每個 --device 旗標的預設行為。

$ 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修改檔案時,不要清除設定使用者 ID 和設定群組 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 程序的 JIT 代碼等。
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 核心原始碼

--cap-add--cap-drop 旗標接受使用 CAP_ 前綴指定的權限。因此,以下範例是等效的

對於與網路堆疊的互動,應該使用 --cap-add=NET_ADMIN 來修改網路介面,而不是使用 --privileged

要掛載基於 FUSE 的檔案系統,您需要結合 --cap-add--device

預設的 seccomp 設定檔將會根據所選的權限進行調整,以便允許使用權限所允許的功能,因此您不應該需要調整它。

覆寫映像檔預設值

當您從 Dockerfile 建置映像檔時,或在提交映像檔時,您可以設定一些在映像檔以容器形式啟動時生效的預設參數。執行映像檔時,您可以使用 docker run 命令的旗標覆蓋這些預設值。

預設指令和選項

docker run 的命令語法支援選擇性地指定容器進入點的命令和參數,在以下概要範例中表示為 [COMMAND][ARG...]

$ docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]

此命令是可選的,因為建立 IMAGE 的人可能已經使用 Dockerfile CMD 指令提供了預設的 COMMAND。當您執行容器時,您可以僅透過指定新的 COMMAND 來覆蓋該 CMD 指令。

如果映像檔也指定了 ENTRYPOINT,則 CMDCOMMAND 會作為參數附加到 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 旗標啟動容器以公開其連接埠

容器內的連接埠號(服務監聽的位置)不需要與容器外部發佈的連接埠號(客戶端連接的位置)相符。例如,在容器內,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

如果目錄在容器中尚不存在,則會建立該目錄。