1. 程式人生 > >Docker run 命令的使用方法

Docker run 命令的使用方法

【編者的話】在Docker中,run應該是使用者使用最多的命令了,很多讀者反饋不是很明白run命令的用法,而且相關的書籍、中文資料中對run命令的描述也不是非常完整,所以DockerOne組織翻譯了Docker官方的文件,以饗讀者。注意,本文基於最新的Docker 1.4文件翻譯。


Docker會在隔離的容器中執行程序。當執行  docker run命令時,Docker會啟動一個程序,併為這個程序分配其獨佔的檔案系統、網路資源和以此程序為根程序的程序組。在容器啟動時, 映象可能已經定義了要執行的二進位制檔案、暴露的網路埠等,但是使用者可以通過 docker run
命令重新定義(譯者注:docker run可以控制一個容器執行時的行為,它可以覆蓋 docker build在構建映象時的一些預設配置),這也是為什麼 run命令相比於其它命令有如此多的引數的原因。

命令格式

最基本的 docker run命令的格式如下:
 
  
如果需要檢視[OPTIONS]的詳細使用說明,請參考Docker關於OPTIONS的 章節。這裡僅簡要介紹Run所使用到的引數。OPTIONS總起來說可以分為兩類:
  1. 設定執行方式:
    • 決定容器的執行方式,前臺執行還是後臺執行;
    • 設定containerID;
    • 設定網路引數;
    • 設定容器的CPU和記憶體引數;
    • - 設定許可權和LXC引數;
  2. 設定映象的預設資源,也就是說使用者可以使用該命令來覆蓋在映象構建時的一些預設配置。

docker run [OPTIONS]可以讓使用者完全控制容器的生命週期,並允許使用者覆蓋執行 docker build時所設定的引數,甚至也可以修改本身由Docker所控制的核心級引數。

Operator exclusive options

當執行 docker run時可以設定以下引數:
  • Detached vs Foreground
    • Detached (-d)
    • - Foreground
  • Container Identification
    • Name (--name)
    • - PID Equivalent
  • IPC Setting
  • Network Settings
  • Clean Up (--rm)
  • Runtime Constraints on CPU and Memory
  • Runtime Privilege, Linux Capabilities, and LXC Configuration

接下來我們依次進行介紹。

Detached vs foreground

當我們啟動一個容器時,首先需要確定這個容器是執行在前臺還是執行在後臺。
 
  

Detached (-d)

如果在 docker run後面追加 -d=true或者 -d,那麼容器將會執行在後臺模式。此時所有I/O資料只能通過網路資源或者共享卷組來進行互動。因為容器不再監聽你執行 docker run的這個終端命令列視窗。但你可以通過執行 docker attach來重新附著到該容器的回話中。需要注意的是,容器執行在後臺模式下,是不能使用 --rm選項的。

Foregroud
在前臺模式下(不指定 -d引數即可),Docker會在容器中啟動程序,同時將當前的命令列視窗附著到容器的標準輸入、標準輸出和標準錯誤中。也就是說容器中所有的輸出都可以在當前視窗中看到。甚至它都可以虛擬出一個TTY視窗,來執行訊號中斷。這一切都是可以配置的:
 
  

如果在執行run命令時沒有指定 -a引數,那麼Docker預設會掛載所有標準資料流,包括輸入輸出和錯誤,你可以單獨指定掛載哪個標準流。
 
  

如果要進行互動式操作(例如Shell指令碼),那我們必須使用 -i -t引數同容器進行資料互動。但是當通過管道同容器進行互動時,就不需要使用 -t引數,例如下面的命令:
 
  

容器識別

Name(--name)

可以通過三種方式為容器命名:
  
1. 使用UUID長命名("f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778")
2. 使用UUID短命令("f78375b1c487")
3. 使用Name("evil_ptolemy")

這個UUID標示是由Docker deamon生成的。如果你在執行 docker run時沒有指定 --name,那麼deamon會自動生成一個隨機字串UUID。但是對於一個容器來說有個name會非常方便,當你需要連線其它容器時或者類似需要區分其它容器時,使用容器名稱可以簡化操作。無論容器執行在前臺或者後臺,這個名字都是有效的。

PID equivalent

如果在使用Docker時有自動化的需求,你可以將containerID輸出到指定的檔案中(PIDfile),類似於某些應用程式將自身ID輸出到檔案中,方便後續指令碼操作。
 
  
Image[:tag]

當一個映象的名稱不足以分辨這個映象所代表的含義時,你可以通過tag將版本資訊新增到run命令中,以執行特定版本的映象。例如:  docker run ubuntu:14.04

IPC Settings

預設情況下,所有容器都開啟了IPC名稱空間。
 
  

IPC(POSIX/SysV IPC)名稱空間提供了相互隔離的命名共享記憶體、訊號燈變數和訊息佇列。

共享記憶體可以提高程序資料的互動速度。共享記憶體一般用在資料庫和高效能應用(C/OpenMPI、C++/using boost libraries)上或者金融服務上。如果需要容器中部署上述型別的應用,那麼就應該在多個容器直接使用共享記憶體了。

Network settings

預設情況下,所有的容器都開啟了網路介面,同時可以接受任何外部的資料請求。
 
  
你可以通過 docker run --net none來關閉網路介面,此時將關閉所有網路資料的輸入輸出,你只能通過STDIN、STDOUT或者files來完成I/O操作。預設情況下,容器使用主機的DNS設定,你也可以通過 --dns來覆蓋容器內的DNS設定。同時Docker為容器預設生成一個MAC地址,你可以通過 --mac-address 12:34:56:78:9a:bc來設定你自己的MAC地址。

Docker支援的網路模式有:
  • none。關閉容器內的網路連線
  • bridge。通過veth介面來連線容器,預設配置。
  • host。允許容器使用host的網路堆疊資訊。 注意:這種方式將允許容器訪問host中類似D-BUS之類的系統服務,所以認為是不安全的。
  • container。使用另外一個容器的網路堆疊資訊。   
    None模式

將網路模式設定為none時,這個容器將不允許訪問任何外部router。這個容器內部只會有一個loopback介面,而且不存在任何可以訪問外部網路的router。

Bridge模式

Docker預設會將容器設定為bridge模式。此時在主機上面將會存在一個docker0的網路介面,同時會針對容器建立一對veth介面。其中一個veth介面是在主機充當網絡卡橋接作用,另外一個veth介面存在於容器的名稱空間中,並且指向容器的loopback。Docker會自動給這個容器分配一個IP,並且將容器內的資料通過橋接轉發到外部。

Host模式

當網路模式設定為host時,這個容器將完全共享host的網路堆疊。host所有的網路介面將完全對容器開放。容器的主機名也會存在於主機的hostname中。這時,容器所有對外暴露的埠和對其它容器的連線,將完全失效。

Container模式

當網路模式設定為Container時,這個容器將完全複用另外一個容器的網路堆疊。同時使用時這個容器的名稱必須要符合下面的格式:--net container:<name|id>.

比如當前有一個綁定了本地地址localhost的Redis容器。如果另外一個容器需要複用這個網路堆疊,則需要如下操作:
 
  

管理/etc/hosts
/etc/hosts檔案中會包含容器的hostname資訊,我們也可以使用 --add-host這個引數來動態新增/etc/hosts中的資料。
 
  
Clean up (--rm)

預設情況下,每個容器在退出時,它的檔案系統也會儲存下來,這樣一方面除錯會方便些,因為你可以通過檢視日誌等方式來確定最終狀態。另外一方面,你也可以儲存容器所產生的資料。但是當你僅僅需要短暫的執行一個容器,並且這些資料不需要儲存,你可能就希望Docker能在容器結束時自動清理其所產生的資料。

這個時候你就需要--rm這個引數了。 注意:--rm 和 -d不能共用!
 
  
Security configuration
 
  

你可以通過 --security-opt修改容器預設的schema標籤。比如說,對於一個MLS系統來說(譯者注:MLS應該是指Multiple Listing System),你可以指定MCS/MLS級別。使用下面的命令可以在不同的容器間分享內容:
 
  
如果是MLS系統,則使用下面的命令:
 
  
使用下面的命令可以在容器內禁用安全策略:
 
  
如果你需要在容器內執行更為嚴格的安全策略,那麼你可以為這個容器指定一個策略替代,比如你可以使用下面的命令來指定容器只監聽Apache埠:
 
  
注意:此時,你的主機環境中必須存在一個名為svirt_apache_t的安全策略。

Runtime constraints on CPU and memory

下面的引數可以用來調整容器內的效能。
 
  
通過 docker run -m可以調整容器所使用的記憶體資源。如果主機支援swap記憶體,那麼可以使用 -m可以設定比主機實體記憶體還大的值。

同樣,通過 -c可以調整容器的CPU優先順序。預設情況下,所有的容器擁有相同的CPU優先順序和CPU排程週期,但你可以通過Docker來通知核心給予某個或某幾個容器更多的CPU計算週期。

比如,我們使用 -c或者 --cpu-shares =0啟動了C0、C1、C2三個容器,使用-c/--cpu-shares=512啟動了C3容器。這時,C0、C1、C2可以100%的使用CPU資源(1024),但C3只能使用50%的CPU資源(512)。如果這個主機的作業系統是時序排程型別的,每個CPU時間片是100微秒,那麼C0、C1、C2將完全使用掉這100微秒,而C3只能使用50微秒。

Runtime privilege, Linux capabilities, and LXC configuration
 
  
預設情況下,Docker的容器是沒有特權的,例如不能在容器中再啟動一個容器。這是因為預設情況下容器是不能訪問任何其它裝置的。但是通過"privileged",容器就擁有了訪問任何其它裝置的許可權。

當操作者執行 docker run --privileged時,Docker將擁有訪問主機所有裝置的許可權,同時Docker也會在apparmor或者selinux做一些設定,使容器可以容易的訪問那些執行在容器外部的裝置。你可以訪問 Docker部落格來獲取更多關於--privileged的用法。

同時,你也可以限制容器只能訪問一些指定的裝置。下面的命令將允許容器只訪問一些特定裝置:
 
  
  預設情況下,容器擁有對裝置的讀、寫、建立裝置檔案的許可權。使用 :rwm來配合 --device,你可以控制這些許可權。
 
  
使用 --cap-add--cap-drop,配合 --privileged,你可以更細緻的控制人哦怒氣。預設使用這兩個引數的情況下,容器擁有一系列的核心修改許可權,這兩個引數都支援 all值,如果你想讓某個容器擁有除了MKNOD之外的所有核心許可權,那麼可以執行下面的命令:
 
  
如果需要修改網路介面資料,那麼就建議使用 --cap-add=NET_ADMIN,而不是使用 --privileged
 
  
如果要掛載一個FUSE檔案系統,那麼就需要 --cap-add--device了。
 
  
如果Docker守護程序在啟動時選擇了 lxc lxc-driver( docker -d --exec-driver=lxc),那麼就可以使用 --lxc-conf來設定LXC引數。但需要注意的是,未來主機上的Docker deamon有可能不會使用LXC,所以這些引數有可能會包含一些沒有實現的配置功能。這意味著,使用者在操作這些引數時必須要十分熟悉LXC。

特別注意:當你使用 --lxc-conf修改容器引數後,Docker deamon將不再管理這些引數,那麼使用者必須自行進行管理。比如說,你使用 --lxc-conf修改了容器的IP地址,那麼在/etc/hosts裡面是不會自動體現的,需要你自行維護。

Overriding Dockerfile image defaults

  當開發者使用 Dockerfile進行build或者使用commit提交容器時,開發人員可以設定一些映象預設引數。

這些引數中,有四個是無法被覆蓋的:FROM、MAINTAINER、RUN和ADD,其餘引數都可以通過 docker run進行覆蓋。我們將介紹如何對這些引數進行覆蓋。
  • CMD (Default Command or Options)
  • ENTRYPOINT (Default Command to Execute at Runtime)
  • EXPOSE (Incoming Ports)
  • ENV (Environment Variables)
  • VOLUME (Shared Filesystems)
  • USER
  • WORKDIR   

CMD (default command or options)
 
  

這個命令中的COMMAND部分是可選的。因為這個IMAGE在build時,開發人員可能已經設定了預設執行的命令。作為操作人員,你可以使用上面命令中新的command來覆蓋舊的command。

如果映象中設定了ENTRYPOINT,那麼命令中的CMD也可以作為引數追加到ENTRYPOINT中。

ENTRYPOINT (default command to execute at runtime)
 
  

這個ENTRYPOINT和COMMAND類似,它指定了當容器執行時,需要啟動哪些程序。相對COMMAND而言,ENTRYPOINT是很難進行覆蓋的,這個ENTRYPOINT可以讓容器設定預設啟動行為,所以當容器啟動時,你可以執行任何一個二進位制可執行程式。你也可以通過COMMAND為ENTRYPOINT傳遞引數。但當你需要在容器中執行其它程序時,你就可以指定其它ENTRYPOINT了。

下面就是一個例子,容器可以在啟動時自動執行Shell,然後啟動其它程序。
 
  
 EXPOSE (incoming ports)

  Dockefile在網路方面除了提供一個EXPOSE之外,沒有提供其它選項。下面這些引數可以覆蓋Dockefile的expose預設值:
 
  
  --expose可以讓容器接受外部傳入的資料。容器內監聽的埠不需要和外部主機的埠相同。比如說在容器內部,一個HTTP服務監聽在80埠,對應外部主機的埠就可能是49880.

  如果使用 -p或者 -P,那麼容器會開放部分埠到主機,只要對方可以連線到主機,就可以連線到容器內部。當使用 -P時,Docker會在主機中隨機從49153 和65535之間查詢一個未被佔用的埠繫結到容器。你可以使用 docker port來查詢這個隨機繫結埠。

當你使用 --link方式時,作為客戶端的容器可以通過私有網路形式訪問到這個容器。同時Docker會在客戶端的容器中設定一些環境變數來記錄繫結的IP和PORT。

ENV (environment variables)
 
  

當容器啟動時,會自動在容器中初始化這些變數。

操作人員可以通過 -e來設定任意的環境變數,甚至覆蓋已經存在的環境變數,或者是在Dockerfile中通過ENV設定的環境變數。
 
  
操作人員可以通過 -h來設定hostname。也可以使用"--link name:alias"來設定環境變數,當使用 --link後,Docker將根據後面提供的IP和PORT資訊來連線服務端容器。下面就是使用redis的例子:
 
  
你使用 --link後,就可以獲取到關於Redis容器的相關資訊。
 
  
Docker也會將這個alias的IP地址寫入到/etc/hosts檔案中。然後你就可以通過別名來訪問link後的容器。
 
  
如果你重啟了源容器(servicename),相關聯的容器也會同步更新/etc/hosts。

VOLUME (shared filesystems)
 
  

關於volume引數,可以在 Managing data in containers檢視詳細說明,需要注意的是開發人員可以在Dockerfile中設定多個volume,但是隻能由運維人員設定容器直接的volume訪問。

USER

容器中預設的使用者是root,但是開發人員建立新的使用者之後,這些新使用者也是可以使用的。開發人員可以通過Dockerfile的USER設定預設的使用者,並通過"-u "來覆蓋這些引數。

 WORKDIR

容器中預設的工作目錄是根目錄(/)。開發人員可以通過Dockerfile的WORKDIR來設定預設工作目錄,操作人員可以通過"-w"來覆蓋預設的工作目錄。

原文連結: Docker run reference(譯者:vikings 審校:李穎傑)