Docker學習總結之Run命令介紹


  

Docker學習總結之Run命令介紹

本文由Vikings(http://www.cnblogs.com/vikings-blog/) 原創,轉載請標明.謝謝!

 

  在使用Docker時,執行最多的命令某過於run了。這個命令可以說是所有docker操作的入口。在Docker官方Reference中單獨列出了一個章節來介紹Run的各種參數使用,也足以看出Docker run的重要性。有感於此,我感覺有必要好好學習一下Run命令,因此特意看了一下Run命令介紹,結合日常中的使用心得,分享一下。以下文檔大部分翻譯於Docker 官方Reference,肯定會存在不少錯誤之處,希望能拋磚引玉,大家共同討論。

  Docker在執行時會將相關進程封裝到相互隔離的容器(container)中。當執行 docker run時,Docker會啟動一個進程,同時給這個進程分配其獨占的文件系統,獨占的網絡資源和以此進程為根進程的進程組。在Docker啟動container時加載的Image,或許已經定義好了默認的啟動進程,需要exposer的網絡端口和其他在Dockerfile中定義好的資源。但使用docker run 都可以重新對這個image進行默認定義。這就是為什么run命令參數比docker其他命令參數都多的原因。

  最基本的docker run命令是如下格式:

$ sudo docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG...]

  如果需要查看[OPTIONS]的詳細使用說明,請參考Docker關於OPTIONS的說明。這里僅簡要介紹Run所使用到的參數。

  OPTIONS總起來說分為兩類:

  1. 設定操作執行方式:
    1. 決定container的運行方式,前台執行還是后台執行
    2. 設定containerID
    3. 設定network參數
    4. 設定container的CPU和Memory參數
    5. 設定權限(Privileges )和LXC參數
  2. 設定image的默認資源,也就是image使用者可以用此命令來覆蓋image開發者在build階段所設定的默認值。

  docker run [OPTIONS]可以讓image使用者完全控制container的生命周期,允許image使用者覆蓋所有image開發者在執行docker build時所設定的參數,甚至也可以修改本身由Docker所控制的內核級參數。

Operator exclusive options

  當執行docker run時可以設定的資源如下:

  • Detached vs Foreground
  • Container Identification
  • IPC Setting
  • Network Settings
  • Clean Up (--rm)
  • Runtime Constraints on CPU and Memory
  • Runtime Privilege, Linux Capabilities, and LXC Configuration

  我們依次進行介紹。

  Detached vs foreground

  當我們啟動一個container時,首先需要確定這個container是運行在前台模式還是運行在后台模式。

-d=false: Detached mode: Run container in the background, print new container id

  Detached (-d)

  如果在docker run 后面追加-d=true或者-d,則containter將會運行在后台模式(Detached mode)。此時所有I/O數據只能通過網絡資源或者共享卷組來進行交互。因為container不再監聽你執行docker run的這個終端命令行窗口。但你可以通過執行docker attach 來重新掛載這個container里面。需要注意的時,如果你選擇執行-d使container進入后台模式,那么將無法配合"--rm"參數。

  Foregroud

  如果在docker run后面沒有追加-d參數,則container將默認進入前台模式(Foregroud mode)。Docker會啟動這個container,同時將當前的命令行窗口掛載到container的標准輸入,標准輸出和標准錯誤中。也就是container中所有的輸出,你都可以再當前窗口中查看到。甚至docker可以虛擬出一個TTY窗口,來執行信號中斷。這一切都是可以配置的:

 

-a=[]               : Attach to `STDIN`, `STDOUT` and/or `STDERR` -t=false            : Allocate a pseudo-tty --sig-proxy=true : Proxify all received signal to the process (non-TTY mode only) -i=false            : Keep STDIN open even if not attached

   如果在執行run命令時沒有指定-a,那么docker默認會掛載所有標准數據流,包括輸入輸出和錯誤。你可以特別指定掛載哪個標准流。

 

$ sudo docker run -a stdin -a stdout -i -t ubuntu /bin/bash (只掛載標准輸入輸出)

 

  對於執行容器內的交互式操作,例如shell腳本。我們必須使用 -i -t來申請一個控制台同容器進行數據交互。但是當通過管道同容器進行交互時,就不能使用-t. 例如下面的命令

echo test | docker run -i busybox cat

   Container identification

  Name (--name)

  給container命名有三種方式:

  1. 使用UUID長命名("f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778")

  2. 使用UUID短命令("f78375b1c487")

  3. 使用Name("evil_ptolemy")

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

  PID equivalent

  當你在運行docker時有自動化的要求,那么你可以要求Docker將containerID 輸出到你指定的文件中(PIDfile).這種行為就類似於有些應用程序將自身ID輸出到文件中,方便后續腳本操作。

--cidfile="": Write the container ID to the file

  Image[:tag]

  當一個image的名稱不足以分辨這個image所代表的含義時,你可以通過tag將版本信息添加到run 命令中來執行特定版本的image。例如: docker run ubuntu:14.04

 IPC Settings

  默認情況下,所有容器都開啟了IPC命名空間。

--ipc=""  : Set the IPC mode for the container, 'container:<name|id>': reuses another container's IPC namespace
            'host': use the host's IPC namespace inside the container

  IPC(POSIX/SysV IPC)命名空間提供了相互隔離的命名共享內存,信號燈變量和消息隊列。

  共享內存可以提高進程數據交互速度。共享內存一般用在database和高性能應用(C/OpenMPI, C++/using boost libraries)上或者金融服務上。如果需要容器里面部署上述類型的應用,那么就應該在多個容器直接采取共享內存了。

 Network settings

  默認情況下,所有的container都開啟了網絡接口,同時可以接受任何外部的數據請求。

--dns=[]         : Set custom dns servers for the container --net="bridge"   : Set the Network mode for the container 'bridge': creates a new network stack for the container on the docker bridge 'none': no networking for this container 'container:<name|id>': reuses another container network stack 'host': use the host network stack inside the container --add-host=""    : Add a line to /etc/hosts (host:IP) --mac-address="" : Sets the container's Ethernet device's MAC address

  可以通過docker run --net none 來關閉網絡接口,此時將關閉所有網絡數據的輸入輸出。這時,你只能通過STDIN,STDOUT或者files來完成I/O操作了。默認情況下,container使用host的DNS設置。但是你可以通過--dns來覆蓋container內的dns設置。同時docker會對containter默認生成一個MAC地址,你可以通過--mac-address 12:34:56:78:9a:bc 來設置你自己的mac地址。

  以下是網絡設置中常用的參數:

  • none 關閉container內的網絡連接
  • bridge 通過veth接口來連接contianer 默認選項
  • host 允許container使用host的網絡堆棧信息。 注意:這種方式將允許container訪問host中類似D-BUS之類的系統服務,所以被認為是不安全的
  • container 使用另外一個container的網絡堆棧信息。

  None:

  將網絡模式設置為none時,這個container將不允許訪問任何外部router。這個container內部只會有一個loopback接口,而且不存在任何可以訪問外部網絡的router。

  Bridge:

  Docker默認是將container設置為bridge模式。此時在host上面講存在一個docker0的網絡接口,同時會針對container創建一對veth接口。其中一個veth接口是在host充當網卡橋接作用,另外一個veth接口存在於container的命名空間中,並且指向container的loopback。Docker會自動給這個container分配一個IP,並且將container內的數據通過橋接轉發到外部。

  Host:

  當網絡模式設置為host時,這個container將完全共享host的網絡堆棧。host所有的網絡接口將完全對container開放。container的主機名也會存在於host的hostname中。這時,container所有對外暴露的port和對其它container的link,將完全失效。

  Container:

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

  比如當前有一個綁定了本地地址localhost的redis container。如果另外一個container需要復用這個網絡堆棧,則需要如下操作:

$ sudo docker run -d --name redis example/redis --bind 127.0.0.1 $ # use the redis container's network stack to access localhost
$ sudo docker run --rm -ti --net container:redis example/redis-cli -h 127.0.0.1

 Managing /etc/hosts

  當一個container再啟動時,在/etc/hosts文件里面將會存在包括localhost在內的一些hostname信息。我們也可以使用--add-host這個參數來動態添加/etc/hosts里面的數據。

$ /docker run -ti --add-host db-static:86.75.30.9 ubuntu cat /etc/hosts 172.17.0.22 09d03f76bf2c fe00::0         ip6-localnet ff00::0         ip6-mcastprefix ff02::1         ip6-allnodes ff02::2         ip6-allrouters 127.0.0.1 localhost ::1             localhost ip6-localhost ip6-loopback 86.75.30.9      db-static

 Clean up (--rm)

  默認情況下,每個container在退出時,它的文件系統也會保存下來。這樣一方面調試會方便些,因為你可以通過查看日志等方式來確定最終狀態。另外一方面,你也可以保存container所產生的數據。但是當你僅僅需要短期的運行一個前台container,這些數據同時不需要保留時。你可能就希望docker能在container結束時自動清理其所產生的數據。

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

--rm=false: Automatically remove the container when it exits (incompatible with -d)

 Security configuration

--security-opt="label:user:USER"   : Set the label user for the container --security-opt="label:role:ROLE"   : Set the label role for the container --security-opt="label:type:TYPE"   : Set the label type for the container --security-opt="label:level:LEVEL" : Set the label level for the container --security-opt="label:disable"     : Turn off label confinement for the container --secutity-opt="apparmor:PROFILE" : Set the apparmor profile to be applied to the container

  你可以通過--security-opt修改container中默認的schema標簽。比如說,對於一個MLS系統來說(MLS可能是指Multiple Listing System,本人不確定.),你可以指定MCS/MLS級別。

  下面的這些級別將允許多個container共享content。

# docker run --security-opt label:level:s0:c100,c200 -i -t fedora bash

  如果是MLS系統,則使用下面的命令:

# docker run --security-opt label:level:TopSecret -i -t rhel7 bash

  使用下面的命令可以在container內禁用安全策略:

# docker run --security-opt label:disable -i -t fedora bash

  如果你需要在container內執行更為嚴格的安全策略,那么你可以為這個container指定一個策略替代。比如你可以使用下面的命令來指定container只允許監聽apache port

# docker run --security-opt label:type:svirt_apache_t -i -t centos bash

  注意:此時,在你的host環境中必須存在一個名為svirt_apache_t的安全策略。

  

 Runtime constraints on CPU and memory

  下面的參數可以用來調整container內的性能參數。

-m="": Memory limit (format: <number><optional unit>, where unit = b, k, m or g) -c=0 : CPU shares (relative weight)

  通過docker run -m 可以很方便的調整container所使用的內存資源。如果host支持swap內存,那么使用-m可以設定比host物理內存還大的值。

  同樣,通過-c 可以調整container的cpu優先級。默認情況下,所有的container享有相同的cpu優先級和cpu調度周期。但你可以通過Docker來通知內核給予某個或某幾個container更多的cpu計算周期。

  默認情況下,使用-c或者--cpu-shares 參數值為0,可以賦予當前活動container 1024個cpu共享周期。這個0值可以針對活動的container進行修改來調整不同的cpu循環周期。

  比如,我們使用-c或者--cpu-shares =0啟動了C0,C1,C2三個container,使用-c/--cpu-shares=512啟動了C3.這時,C0,C1,C2可以100%的使用CPU資源(1024),但C3只能使用50%的CPU資源(512)。如果這個host的OS是時序調度類型的,每個CPU時間片是100微秒,那么C0,C1,C2將完全使用掉這100微秒,而C3只能使用50微秒。

 

 Runtime privilege, Linux capabilities, and LXC configuration

--cap-add: Add Linux capabilities --cap-drop: Drop Linux capabilities --privileged=false: Give extended privileges to this container --device=[]: Allows you to run devices inside the container without the --privileged flag. --lxc-conf=[]: (lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"

  默認情況下,Docker的container是沒有特權的。例如不能再container里面再啟動一個container。這是因為默認情況下container是不能訪問任何其他設備的。但是通過"privileged",container就擁有了訪問任何其他設備的權限。

  當操作者執行docker run --privileged時,Docker將擁有訪問host所有設備的權限,同時Docker也會在apparmor或者selinux做一些設置,使container可以容易的訪問那些運行在container外部的設備。你可以訪問Docker blog來獲取更多關於--privileged的用法。

  同時,你也可以限制container只能訪問一些指定的設備。下面的命令將允許container只訪問一些特定設備:

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

  默認情況下,container擁有對設備的讀,寫,創建設備文件的權限。使用:rwm來配合--device,你可以控制這些權限。

 

  $ sudo docker run --device=/dev/sda:/dev/xvdc --rm -it ubuntu fdisk  /dev/xvdc Command (m for help): q $ sudo 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 $ sudo docker run --device=/dev/sda:/dev/xvdc:w --rm -it ubuntu fdisk  /dev/xvdc crash.... $ sudo docker run --device=/dev/sda:/dev/xvdc:m --rm -it ubuntu fdisk  /dev/xvdc fdisk: unable to open /dev/xvdc: Operation not permitted

 

  使用--cap-add和--cap-drop,配合--privileged,你可以更細致的控制container。默認使用這兩個參數的情況下,container擁有一系列的內核修改權限。這兩個參數都支持all值,如果你想讓某個container擁有除了MKNOD之外的所有內核權限,那么可以執行下面的命令:

 $ sudo docker run --cap-add=ALL --cap-drop=MKNOD ...

  如果需要修改網絡接口數據,那么就建議使用--cap-add=NET_ADMIN,而不是使用--privileged。

$ docker run -t -i --rm  ubuntu:14.04 ip link add dummy0 type dummy RTNETLINK answers: Operation not permitted $ docker run -t -i --rm --cap-add=NET_ADMIN ubuntu:14.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

  如果docker啟動時選擇了lxc-driver,(docker -d --exec-driver=lxc)。那么就可以使用--lxc-conf來設定LXC參數。但需要注意的是,未來host上面的docker deamon有可能不會使用LXC,所以這些參數有可能會包含一些沒有實現的配置功能。那么意味着,操作者在操作這些參數時必須要十分熟悉LXC。

  特別注意:當你使用--lxc-conf修改container參數后,docker deamon將不再管理這些參數,那么必須由操作者自行進行管理。比如說,你使用--lxc-conf修改了container的IP地址,那么在/etc/hosts里面是不會自動體現的,需要你自行維護。

 Overriding Dockerfile image defaults

  當開發者使用Dockerfile進行build或者使用commit提交container時,開發人員可以設定一些image默認參數。

  這些參數中,有四個是無法被覆蓋的:FROM,MAINTAINER,RUN和ADD。其余參數都可以通過docker run進行覆蓋。我們將介紹如何對這些參數進行覆蓋。

  

 CMD (default command or options)

  

$ sudo docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG...]

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

  如果image中設定了ENTRYPOINT,那么命令中的CMD也可以作為參數追加到ENTRYPOINT中。

 

 ENTRYPOINT (default command to execute at runtime)

--entrypoint="": Overwrite the default entrypoint set by the image

  這個ENTRYPOINT和COMMAND類似,它指定了當container執行時,需要啟動哪些進程。相對COMMAND而言,ENTRYPOINT是比較困難進行覆蓋的,這個ENTRYPOINT可以讓container設定默認啟動行為,所以當container啟動時,你可以執行任何一個二進制可執行程序。你也可以通過COMMAND給這個ENTRYPOINT傳遞參數。但當你需要再container中執行其他進程時,你就可以指定其他ENTRYPOINT了。

  下面就是一個例子,container可以在啟動時自動執行shell,然后啟動其它進程。

$ sudo docker run -i -t --entrypoint /bin/bash example/redis #or two examples of how to pass more parameters to that ENTRYPOINT: $ sudo docker run -i -t --entrypoint /bin/bash example/redis -c ls -l $ sudo docker run -i -t --entrypoint /usr/bin/redis-cli example/redis --help

  

 EXPOSE (incoming ports)

  Dockefile在網絡方面除了提供一個EXPOSE之外,沒有提供其它選項。下面這些參數可以覆蓋Dockefile的expose默認值:

--expose=[]: Expose a port or a range of ports from the container without publishing it to your host -P=false : Publish all exposed ports to the host interfaces -p=[] : Publish a container᾿s port to the host (format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort | containerPort) (use 'docker port' to see the actual mapping) --link=""  : Add link to another container (name:alias)

  --expose可以讓container接受外部傳入的數據。container內監聽的port不需要和外部host的port相同。比如說在container內部,一個HTTP服務監聽在80端口,對應外部host的port就可能是49880.

  操作人員可以使用--expose,讓新的container訪問到這個container。具體有三個方式:

  1. 使用-p來啟動container。

  2. 使用-P來啟動container。

  3. 使用--link來啟動container。

  如果使用-p或者-P,那么container會開發部分端口到host,只要對方可以連接到host,就可以連接到container內部。當使用-P時,docker會在host中隨機從49153 和65535之間查找一個未被占用的端口綁定到container。你可以使用docker port來查找這個隨機綁定端口。

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

  

 ENV (environment variables)

Variable Value
HOME Set based on the value of USER
HOSTNAME The hostname associated with the container
PATH Includes popular directories, such as :
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
TERM xterm if the container is allocated a psuedo-TTY

   當container啟動時,會自動在container中初始化這些變量。

  操作人員可以通過-e來設定任意的環境變量。甚至覆蓋已經存在的環境變量,或者是在Dockerfile中通過ENV設定的環境變量。

  

$ sudo docker run -e "deep=purple" --rm ubuntu /bin/bash -c export declare -x HOME="/" declare -x HOSTNAME="85bc26a0e200" declare -x OLDPWD declare -x PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" declare -x PWD="/" declare -x SHLVL="1" declare -x container="lxc" declare -x deep="purple"

 

  操作人員可以通過-h來設定hostname。也可以使用"--link name:alias"來設定環境變量,當使用--link后,docker將根據后面提供的IP和PORT信息來連接服務端container。下面就是使用redis的例子:

# Start the service container, named redis-name $ sudo docker run -d --name redis-name dockerfiles/redis 4241164edf6f5aca5b0e9e4c9eccd899b0b8080c64c0cd26efe02166c73208f3 # The redis-name container exposed port 6379 $ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4241164edf6f $ dockerfiles/redis:latest   /redis-stable/src/re   5 seconds ago       Up 4 seconds        6379/tcp            redis-name # Note that there are no public ports exposed since we didn᾿t use -p or -P $ sudo docker port 4241164edf6f 6379
2014/01/25 00:55:38 Error: No public port '6379' published for 4241164edf6f

  你使用--link后,就可以獲取到關於Redis Container的相關信息。

$ sudo docker run --rm --link redis-name:redis_alias --entrypoint /bin/bash dockerfiles/redis -c export declare -x HOME="/" declare -x HOSTNAME="acda7f7b1cdc" declare -x OLDPWD declare -x PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" declare -x PWD="/" declare -x REDIS_ALIAS_NAME="/distracted_wright/redis" declare -x REDIS_ALIAS_PORT="tcp://172.17.0.32:6379" declare -x REDIS_ALIAS_PORT_6379_TCP="tcp://172.17.0.32:6379" declare -x REDIS_ALIAS_PORT_6379_TCP_ADDR="172.17.0.32" declare -x REDIS_ALIAS_PORT_6379_TCP_PORT="6379" declare -x REDIS_ALIAS_PORT_6379_TCP_PROTO="tcp" declare -x SHLVL="1" declare -x container="lxc" #And we can use that information to connect from another container as a client: $ sudo docker run -i -t --rm --link redis-name:redis_alias --entrypoint /bin/bash dockerfiles/redis -c '/redis-stable/src/redis-cli -h $REDIS_ALIAS_PORT_6379_TCP_ADDR -p $REDIS_ALIAS_PORT_6379_TCP_PORT'
172.17.0.32:6379>

  Docker也會將這個alias的IP地址寫入到/etc/hosts文件中。然后你就可以通過別名來訪問link后的container。

$ sudo docker run -d --name servicename busybox sleep 30 $ sudo docker run -i -t --link servicename:servicealias busybox ping -c 1 servicealias

  如果你重啟了源container(servicename),相關聯的container也會同步更新/etc/hosts。

 VOLUME (shared filesystems)

-v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. If "container-dir" is missing, then docker creates a new volume. --volumes-from="": Mount all volumes from the given container(s)

  關於volume參數,可以再 Managing data in containers 查看詳細說明。需要注意的是開發人員可以在Dockerfile中設定多個volume,但是只能由操作人員設置container直接的volume訪問。

 USER

  container中默認的用戶是root。但是開發人員創建新的用戶之后,這些新用戶也是可以使用的。開發人員可以通過Dockerfile的USER設定默認的用戶,操作人員可以通過"-u "來覆蓋這些參數。

 WORKDIR

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM