七、Dockerfile詳解

Docker file

nginx鏡像啓動爲容器後是爲了配置爲一個虛擬主機,提供一個虛擬服務。但這個虛擬主機所提供的服務名、監聽的端口、家目錄等在不一樣的環境中是不同的,nginx

但配置文件的格式是固定的,因此把它的配置文件生成一個模板。web

server.conf     /etc/nginx/conf.d/       //模板放在/etc/nginx/conf.d/目錄下sql

{docker

      server_name  $NGX_SERVER_NAME;     //server_name經過變量$NGC_SERVER獲取shell

      listen  $NGX_IP; $NGINX_PORT;apache

       root  $DOC_ROOT;vim

}

當用戶利用nginx鏡像啓動爲容器時,在容器內部的主進程啓動以前先啓動一個別的程序(程序A),這個程序(A)根據此鏡像中的server.conf文件以及用戶將鏡像啓動爲容器時向容器傳遞的環境變量,把傳遞的變量替換在模板文件server.conf文件中,並保存。這裏程序A先扮演主進程,是爲後面真正的主進程預設環境的。而後程序A再啓動主進程,程序A退出。由進程A啓動程序B,而且程序B替換程序A,是使用exec命令進行操做。(啓動一個子進程,可是子進程把當前啓動它的進程替換掉並且子進程頂了當前進程的ID號)

 

雲原生:Cloud Native Landscape

https://www.jianshu.com/p/13251fd149a6

Dockerfile   向目標鏡像中打包文件

Docker可使用Dockerfile文件來創建一個image鏡像。  Dockerfile 中包含有創建image鏡像的全部配置信息和可執行命令。 使用 docker build 命令就能夠根據你指定的Dockerfile文件創建一個image鏡像,Dockerfile配置決定了docker容器的運行狀態和結構。

Dockerfile是一個包含用於組合映像的命令的文本文檔。可使用在命令行中調用任何命令。 Docker經過讀取Dockerfile中的指令自動生成映像。

docker build命令用於從Dockerfile構建映像。能夠在docker build命令中使用-f標誌指向文件系統中任何位置的Dockerfile。

Docker 鏡像、容器和 Dockerfile 三者之間的關係

Dockerfile Format

Format:

  • #註釋信息
  • INSTRUCTION argument   指令+參數 //一行一個指令

指令自己不區分大小寫,可是慣例是使用大寫

Docker是按Dockerfile順序執行指令(先後關係很重要);

第一個非註釋行必須以 FROM 開頭,表示當前鏡像是以哪一個基礎鏡像構建。

Dockerfile的工做邏輯

一、基於dockerfile作docker鏡像時,要找一個專用目錄(即工做目錄),在這個目錄中放進dockerfile文件,dockerfile文件名首字母必須大寫,

二、若是想利用dockerfile向鏡像內打包進不少文件,須要提早準備好這些文件,而且把這些文件放在這個專用的目錄中;

   即基於dockerfile作鏡像時所引用的文件的路徑必須起始於這個專用目錄以及其子目錄;

   能夠把全部文件放在一個目錄中,把這個目錄放到專用目錄中,這樣能夠在dockerfile中直接引用這個目錄。

三、有一種狀況,好比專用目中的子目錄中包含50個文件,dockerfile在引用這個子目錄時,這個子目錄中的20個文件當前是不須要的,

   那麼就能夠在專用目錄中建立一個隱藏文件:.dockerignore,它又是一個文本文件,在.dockerignore中能夠寫進不須要引用的文件路徑

  (包括.dockerignore文件自己的路徑),一行是一個文件路徑,但行是可使用通配符的。寫在.dockerignore中的文件路徑的文件,在打包進鏡像時都不包含進去。

製做鏡像方式有基於容器來製做,首先容器基於原有鏡像啓動,而後聯合掛載,添加可寫層,對於容器的全部寫操做都放在了可寫層上面了,而後基於這個已經改變的容器建立一個鏡像就能夠了。但在可寫層上執行的全部操做都是要交互式的鏈接進容器執行命令完成的,這些命令都是容器支持的命令。

docker build基於dockerfile啓動一個容器時,不用本身手動啓動容器,可是docker build隱藏式的啓動了一個容器,跟上述人工啓動容器區別並不大。

所以在dockerfile中能夠執行不少命令,但這些命令不是宿主機的命令,而是底層鏡像所包含的命令。若是底層鏡像沒有某個命令,那麼在dockerfile中也沒法運行。

因此全部鏡像的製做環境是底層鏡像在啓動爲容器時所能提供的給咱們的環境。

 

Environment replacement

Dockerfile Instructions   重點參考: http://www.javashuo.com/article/p-xaajfgxj-du.html

FROM

FROM:指定基礎鏡像,必須爲第一個命令    http://www.javashuo.com/article/p-xaajfgxj-du.html

格式: CMD ["executable","param1","param2"] (執行可執行文件,優先) CMD ["param1","param2"] (設置了ENTRYPOINT,則直接調用ENTRYPOINT添加參數) CMD command param1 param2 (執行shell內部命令) 示例: CMD echo "This is a test." | wc - CMD ["/usr/bin/wc","--help"] 注:   CMD不一樣於RUN,CMD用於指定在容器啓動時所要執行的命令,而RUN用於指定鏡像構建時所要執行的命令。

MAINTANIER

格式:
    MAINTAINER <name>
示例:
    MAINTAINER Jasper Xu
    MAINTAINER sorex@163.com
    MAINTAINER Jasper Xu <sorex@163.com>

 

LABEL  讓用戶爲鏡像指定各類各樣的元數據(元數據是鍵值數據)

格式: LABEL <key>=<value> <key>=<value> <key>=<value> ... 示例:   LABEL version="1.0" description="這是一個Web服務器" by="IT筆錄" 注:   使用LABEL指定元數據時,一條LABEL指定能夠指定一或多條元數據,指定多條元數據時不一樣元數據之間經過空格分隔。推薦將全部的元數據經過一條LABEL指令指定,以避免生成過多的中間鏡像。

 

COPY  將宿主機上的文件或目錄打包進鏡像文件中

 

示例

注意:index.html必需要和Dockerfile在同一個目錄或者在與Dockerfile所在目錄下的子目錄中

# docker build -h

Flag shorthand -h has been deprecated, please use --help

Usage: docker build [OPTIONS] PATH | URL | - //PATH必須是Dockerfile所在的專用目錄

Build an image from a Dockerfile

Options:
      --add-host list           Add a custom host-to-IP mapping (host:ip)
      --build-arg list          Set build-time variables
      --cache-from strings      Images to consider as cache sources
      --cgroup-parent string    Optional parent cgroup for the container
      --compress                Compress the build context using gzip
      --cpu-period int          Limit the CPU CFS (Completely Fair Scheduler) period
      --cpu-quota int           Limit the CPU CFS (Completely Fair Scheduler) quota
  -c, --cpu-shares int          CPU shares (relative weight)
      --cpuset-cpus string      CPUs in which to allow execution (0-3, 0,1)
      --cpuset-mems string      MEMs in which to allow execution (0-3, 0,1)
      --disable-content-trust   Skip image verification (default true)
  -f, --file string             Name of the Dockerfile (Default is 'PATH/Dockerfile')
      --force-rm                Always remove intermediate containers
      --iidfile string          Write the image ID to the file
      --isolation string        Container isolation technology
      --label list              Set metadata for an image
  -m, --memory bytes            Memory limit
      --memory-swap bytes       Swap limit equal to memory plus swap: '-1' to enable unlimited swap
      --network string          Set the networking mode for the RUN instructions during build (default "default")
      --no-cache                Do not use cache when building the image
      --platform string         Set platform if server is multi-platform capable
      --pull                    Always attempt to pull a newer version of the image
  -q, --quiet                   Suppress the build output and print image ID on success
      --rm                      Remove intermediate containers after a successful build (default true)
      --security-opt strings    Security options
      --shm-size bytes          Size of /dev/shm
      --squash                  Squash newly built layers into a single new layer
      --stream                  Stream attaches to server to negotiate build context
  -t, --tag list                Name and optionally a tag in the 'name:tag' format
      --target string           Set the target build stage to build.
      --ulimit ulimit           Ulimit options (default [])

node1@img1]# docker build -t tinyhttpd:v0.1-1 ./    //使用docker build基於Dockerfile作鏡像,注意 ./ 是當前目錄 img1

Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM busybox:latest  //分析FROM指令,獲取基礎鏡像
 ---> d8233ab899d4
Step 2/3 : MAINTAINER "Abc <abc@abc.com>"   //加上MAINTAINER
 ---> Running in 5c39877eef22
Removing intermediate container 5c39877eef22
 ---> 93f297e3e2e5
Step 3/3 : COPY index.html /data/web/html/   //複製文件到目標鏡像中
 ---> 026022e873de
Successfully built 026022e873de
Successfully tagged tinyhttpd:v0.1-1

[root@node1 img1]# docker image ls

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
tinyhttpd           v0.1-1              026022e873de        About an hour ago   1.2MB

@node1 ~]# docker run --name tinyweb1 --rm tinyhttpd:v0.1-1 cat /data/web/html/index.html    //將鏡像啓動爲容器,而後查看文件是存在,而後直接退出,命令一結束容器就被刪除了
        <h1> Busybox httpd server.</h1>

 

示例:複製一個目錄到專用目錄下,而後將此目錄下的文件所有打包進目標鏡像,並放在yum.repo.d目錄下

在dockerfile中每一條指令都會生成一個鏡像層,若是多個指令能夠合成一條,必定要合成一條。

此處不是複製yum.repos.d目錄自己,而是複製目錄下的文件。

由於複製的是目錄,因此要把目標目錄名寫出來:/etc/yum.repos.d/,最後一個"/"必定要加上,否則會把文件複製爲名爲yum.repos.d的文件,而不是目錄。

[root@node1 img1]# docker build -t tinyhttpd:v0.1-2 ./   //打包成鏡像

Sending build context to Docker daemon  35.84kB
Step 1/4 : FROM busybox:latest
 ---> d8233ab899d4
Step 2/4 : MAINTAINER "Abc <abc@abc.com>"
 ---> Using cache
 ---> 93f297e3e2e5
Step 3/4 : COPY index.html /data/web/html/
 ---> Using cache
 ---> 026022e873de
Step 4/4 : COPY yum.repos.d /etc/yum.repos.d/
 ---> 948f2959ddb4
Successfully built 948f2959ddb4
Successfully tagged tinyhttpd:v0.1-2

 

ADD 將本地文件添加到容器中,tar類型文件會自動解壓(網絡壓縮資源不會被解壓),能夠訪問網絡資源,相似wget

格式: ADD <src>... <dest> ADD ["<src>",... "<dest>"] 用於支持包含空格的路徑 示例: ADD hom* /mydir/          # 添加全部以"hom"開頭的文件 ADD hom?.txt /mydir/      # ? 替代一個單字符,例如:"home.txt" ADD test relativeDir/     # 添加 "test" 到 `WORKDIR`/relativeDir/ ADD test /absoluteDir/    # 添加 "test" 到 /absoluteDir/

示例:在網頁上下載一個tar文件利用ADD打包進鏡像中

[root@node1 img1]# vim Dockerfile

1 # Description: test image
  2 FROM busybox:latest
  3 MAINTAINER "Abc <abc@abc.com>"
  4 # LABEL maintainer="Abc <abc@abc.com>"
  5 COPY index.html /data/web/html/
  6 COPY yum.repos.d /etc/yum.repos.d/
  7 ADD https://nginx.org/download/nginx-1.14.2.tar.gz /usr/local/src/   
//這裏只會下載nginx-1.14不會被展開,由於源文件是URL,若是源文件是本地,則tar文件會被展開。若是
/usr/local/src/目錄不存在,會直接被建立,但必需要以斜線結尾

文件沒有被解壓

將nginx下載到專用目錄中作測試

 

[root@node1 img1]# vim Dockerfile

1 # Description: test image
  2 FROM busybox:latest
  3 MAINTAINER "Abc <abc@abc.com>"
  4 # LABEL maintainer="Abc <abc@abc.com>"
  5 COPY index.html /data/web/html/
  6 COPY yum.repos.d /etc/yum.repos.d/
  7 # ADD https://nginx.org/download/nginx-1.14.2.tar.gz /usr/local/src/
  8 ADD nginx-1.14.2.tar.gz /usr/local/src/    //至關於tar -x nginx-1.14.2.tar.gz -C /usr/local/src/ 

[root@node1 img1]# docker build -t tinyhttpd:v0.1-4 ./

Sending build context to Docker daemon  1.052MB
Step 1/5 : FROM busybox:latest
 ---> d8233ab899d4
Step 2/5 : MAINTAINER "Abc <abc@abc.com>"
 ---> Using cache
 ---> 93f297e3e2e5
Step 3/5 : COPY index.html /data/web/html/
 ---> Using cache
 ---> 026022e873de
Step 4/5 : COPY yum.repos.d /etc/yum.repos.d/
 ---> Using cache
 ---> 948f2959ddb4
Step 5/5 : ADD nginx-1.14.2.tar.gz /usr/local/src/
 ---> ffd35e42c975
Successfully built ffd35e42c975
Successfully tagged tinyhttpd:v0.1-4

已經解壓

 

WORKDIR  工做目錄

格式:
    WORKDIR /path/to/workdir
示例:
    WORKDIR /a  (這時工做目錄爲/a)
    WORKDIR b  (這時工做目錄爲/a/b)
    WORKDIR c  (這時工做目錄爲/a/b/c)
注:
  經過WORKDIR設置工做目錄後,Dockerfile中其後的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都會在該目錄下執行。在使用docker run運行容器時,能夠經過-w參數覆蓋構建時所設置的工做目錄。

[root@node1 img1]# vim Dockerfile

  1 # Description: test image
  2 FROM busybox:latest
  3 MAINTAINER "Abc <abc@abc.com>"
  4 WORKDIR /usr/local/src/       // 指定工做目錄
  5 ADD nginx-1.14.2.tar.gz ./    // ./就引用工做目錄
或者更換爲
WORKDIR /usr/local/src/
ADD nginx-1.14.2.tar.gz ./src/

 

VOLUME  用於指定持久化目錄(只能使用docker管理的卷即只能指定容器上的掛載點,而不能指定宿主機上的掛載路徑)

格式:
    VOLUME ["/path/to/dir"]
示例:
    VOLUME ["/data"]
    VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"
注:
  一個卷能夠存在於一個或多個容器的指定目錄,該目錄能夠繞過聯合文件系統,並具備如下功能:
      一、卷能夠容器間共享和重用
      二、容器並不必定要和其它容器共享卷
      三、修改卷後會當即生效
      四、對卷的修改不會對鏡像產生影響
      五、卷會一直存在,直到沒有任何容器在使用它

示例:建立一個MySQL存儲卷 /data/mysql 與宿主機創建關聯關係

[root@node1 img1]# vim Dockerfile

  1 # Description: test image
  2 FROM busybox:latest
  3 MAINTAINER "Abc <abc@abc.com>"
  4 # LABEL maintainer="Abc <abc@abc.com>"
  5 COPY index.html /data/web/html/
  6 # ADD https://nginx.org/download/nginx-1.14.2.tar.gz /usr/local/src/
  7 WORKDIR /usr/local/src/
  8 
  9 ADD nginx-1.14.2.tar.gz ./
 10 
 11 VOLUME /data/mysql/   //指定爲數據存放目錄

[root@node1 img1]# docker build -t tinyhttpd:v0.1-5 ./

Sending build context to Docker daemon  1.052MB
Step 1/6 : FROM busybox:latest
 ---> d8233ab899d4
Step 2/6 : MAINTAINER "Abc <abc@abc.com>"
 ---> Using cache
 ---> 93f297e3e2e5
Step 3/6 : COPY index.html /data/web/html/
 ---> Using cache
 ---> 026022e873de
Step 4/6 : WORKDIR /usr/local/src/
 ---> Running in 109b8104bcce
Removing intermediate container 109b8104bcce
 ---> ba695cf12c59
Step 5/6 : ADD nginx-1.14.2.tar.gz ./
 ---> c3c9e70e6bca
Step 6/6 : VOLUME /data/mysql/
 ---> Running in 4f70234badf5
Removing intermediate container 4f70234badf5
 ---> a4edf21d7f10
Successfully built a4edf21d7f10
Successfully tagged tinyhttpd:v0.1-5

# docker run --name tinyweb1 --rm tinyhttpd:v0.1-5 mount | grep /data/mysql  //驗證
  /dev/mapper/centos-root on /data/mysql type xfs (rw,relatime,attr2,inode64,noquota)

另一種方法是啓動容器,而後讓此容器睡眠60秒進行查看

[root@node1 ~]# docker run --name tinyweb1 --rm tinyhttpd:v0.1-5 sleep 60    //啓動容器,睡眠60秒

[root@node1 ~]# docker inspect tinyweb1    //打開另一個窗口進行查看

 

EXPOSE  指定於外界交互的端口

只能指定暴露哪一個端口,是動態綁定的,由於是沒有辦法指定綁定在宿主機上的指定IP+端口,由於鏡像啓動爲容器時,並不肯定在哪一個宿主機上啓動,同時更沒法肯定宿主機上的IP和空閒的端口。

所以只能指定容器啓動時暴露出來的端口,而後去動態綁定只宿主機上的隨機端口和全部地址。

格式:
    EXPOSE <port> [<port>...]
示例:
    EXPOSE 80 443
    EXPOSE 8080
    EXPOSE 11211/tcp 11211/udp
注:
  EXPOSE並不會讓容器的端口訪問到主機。要使其可訪問,須要在  docker run  運行容器時經過  -p  來發布這些端口,或經過  -P(publishall) 參數來發布EXPOSE導出的全部端口

示例:

[root@node1 img1]# vim Dockerfile

  1 # Description: test image
  2 FROM busybox:latest
  3 MAINTAINER "Abc <abc@abc.com>"
  4 # LABEL maintainer="Abc <abc@abc.com>"
  5 COPY index.html /data/web/html/
  6 # ADD https://nginx.org/download/nginx-1.14.2.tar.gz /usr/local/src/
  7 WORKDIR /usr/local/src/
  8 
  9 ADD nginx-1.14.2.tar.gz ./
 10 
 11 VOLUME /data/mysql/
 12 
 13 EXPOSE 80/tcp //指明容器的暴漏端口,但對外部網絡並不必定是80端口,對外部顯示的端口是此端口綁定在宿主機上的端口。若是隻在Dockerfile中添加此命令,而啓動容器是沒有添加 -P,那麼啓動的容器依然不會暴漏端口的。

[root@node1 img1]# docker build -t tinyhttpd:v0.1-6 ./     //基於dockerfile打包鏡像

[root@node1 ~]# docker run --name tinyweb1 --rm tinyhttpd:v0.1-6 /bin/httpd -f -h /data/web/html   //直接啓動httpd服務,-h 指定家目錄,這裏運行的是服務提供的web程序,-f 表示運行在前臺

[root@node1 ~]# docker inspect tinyweb1    //查看IP

[root@node1 ~]# curl 10.0.0.2   //服務正常相應
   <h1> Busybox httpd server.</h1>

[root@node1 ~]# docker port tinyweb1    //查看可知沒有暴漏端口

 

[root@node1 ~]# docker kill tinyweb1  //刪除此容器
   tinyweb1

[root@node1 ~]# docker run --name tinyweb1 -P --rm tinyhttpd:v0.1-6 /bin/httpd -f -h /data/web/html     //使用-P暴露端口,但沒有指定暴漏哪一個端口

[root@node1 ~]# docker port tinyweb1
     80/tcp -> 0.0.0.0:32768

 

ENV   爲鏡像定義所需的環境變量

格式:
    ENV <key> <value>  #<key>以後的全部內容均會被視爲其<value>的組成部分,所以,一次只能設置一個變量
    ENV <key>=<value> ...  #能夠設置多個變量,每一個變量爲一個"<key>=<value>"的鍵值對,若是<key>中包含空格,可使用\來進行轉義,也能夠經過""來進行標示;另外,反斜線也能夠用於續行
示例:
    ENV myName John Doe
    ENV myDog Rex The Dog
    ENV myCat=fluffy

[root@node1 img1]# vim Dockerfile  

  1 # Description: test image    //第一種環境變量的賦值方法
  2 FROM busybox:latest
  3 ENV DOC_ROOT /data/web/html/        //變量通常是大寫
  4 COPY index.html ${DOC_ROOT:-/data/web/html}   //引用環境變量,若是環境變量沒有值,則用/data/web/html進行代替
  1 # Description: test image
  2 FROM busybox:latest
  3 ENV DOC_ROOT=/data/web/html/ \    //注意末尾的續行符 \
  4     WEB_SERVER_PACKAGE="nginx-1.14.2"
  5 COPY index.html ${DOC_ROOT:-/data/web/html}
  6 WORKDIR /usr/local/
  7 ADD ${WEB_SERVER_PACKAGE}.tar.gz ./src/

[root@node1 img1]# docker build -t tinyhttpd:v0.1-7 ./

Sending build context to Docker daemon  1.052MB
Step 1/7 : FROM busybox:latest
 ---> d8233ab899d4
Step 2/7 : ENV DOC_ROOT=/data/web/html/     WEB_SERVER_PACKAGE="nginx-1.14.2"
 ---> Running in edd73b80c40d
Removing intermediate container edd73b80c40d
 ---> 9c8c911dd79a
Step 3/7 : COPY index.html ${DOC_ROOT:-/data/web/html}
 ---> 93ecd3596616
Step 4/7 : WORKDIR /usr/local/
 ---> Running in 3ac341a77316
Removing intermediate container 3ac341a77316
 ---> 26cfbd77b7eb
Step 5/7 : ADD ${WEB_SERVER_PACKAGE}.tar.gz ./src/
 ---> 4fbaf33a8955
Step 6/7 : VOLUME /data/mysql/
 ---> Running in a6d4510a4313
Removing intermediate container a6d4510a4313
 ---> efc1e5580ffc
Step 7/7 : EXPOSE 80/tcp
 ---> Running in fc17649839d2
Removing intermediate container fc17649839d2
 ---> 31c87ab706ef
Successfully built 31c87ab706ef
Successfully tagged tinyhttpd:v0.1-7 

向變量傳值   

[root@node1 ~]# docker run --help

-e, --env list Set environment variables //設定變量值 --env-file list                  Read in a file of environment variables
      --expose list                    Expose a port or a range of ports
      --group-add list                 Add additional groups to join
      --health-cmd string              Command to run to check health
      --health-interval duration       Time between running the check (ms|s|m|h) (default 0s)
      --health-retries int             Consecutive failures needed to report unhealthy
      --health-start-period duration   Start period for the container to initialize before starting health-retries countdown (ms|s|m|h) (default 0s)
      --health-timeout duration        Maximum time to allow one check to run (ms|s|m|h) (default 0s)
      --help                           Print usage

[root@node1 ~]# docker run --name tinyweb1 -P --rm tinyhttpd:v0.1-7 printenv  //輸出環境變量信息,在Dockerfile中定義的全部環境變量是能夠在啓動容器時直接在容器中引用的變量。

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=4e6dbb46ccbc
DOC_ROOT=/data/web/html/
WEB_SERVER_PACKAGE=nginx-1.14.2
HOME=/root

# docker run --name tinyweb1 -P -e WEB_SERVER_PACKAGE="nginx-1.15.1" --rm tinyhttpd:v0.1-7 printenv    //此處在命令行中將鏡像初始化爲容器時向環境變量複製

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=36c490d420de
WEB_SERVER_PACKAGE=nginx-1.15.1
DOC_ROOT=/data/web/html/
HOME=/root

[root@node1 ~]# docker run --name tinyweb1 -P -e WEB_SERVER_PACKAGE="nginx-1.15.1" --rm tinyhttpd:v0.1-7 ls /usr/local/src   //可是/usr/local/src/目錄下的內容是不會變化的

    nginx-1.14.2

上述結果中WEB_SERVER_PACKAGE=nginx-1.14.2寫在了Dockerfile中,是在docker build階段執行的,已經寫進了鏡像;

而 -e WEB_SERVER_PACKAGE="nginx-1.15.1" 是在 docker run 階段執行的,是基於打包好的鏡像啓動爲容器階段;

因此此處修改環境變量只能顯示環境變量的值發生改變,可是並不能真正改變docker build的結果,也沒法對容器的程序配置有效果。

 

RUN和CMD的區別

CMD:把一個鏡像啓動爲容器時要運行的命令(即上面ls /usr/local/src),若是不指定運行的命令,就有CMD來定義。CMD是定義把鏡像啓動爲容器時在沒有指定所要運行的命令狀況下,默認要運行的命令。

RUN:當基於Dockerfile構建鏡像時要運行的命令,將在docker build運行的命令叫RUN。

CMD是定義一個鏡像文件啓動爲容器時默認要運行的程序,docker容器默認只運行一個程序,因此CMD只能一個(當CMD有多個時,只能最後一個生效)。但RUN 能夠有多個,RUN命令時逐一運行的。

除了init以外,每個進程都應該是其餘進程的子進程(init是內核啓動的),當手動啓動nginx時,那麼這個nginx就以shell子進程存在。當打開一個命令行提示符時,這個就至關於在運行一個shell進程,當在shell命令行中運行一個命令時,就至關於運行一個shell子進程。

在一個docker容器運行一個程序或者應用,這個進程直接有內核建立啓動仍是由shell啓動?PID爲1的進程應該由內核啓動,由內核啓動的進程有不少不便,由於這個進程不能使用shell進程下的一些功能(好比重定向、輸入輸出等功能)。若是在容器中基於shell啓動一個進程,則這個進程的PID再也不爲1,由於在啓動進程以前要先啓動shell進程,因此shell的PID是1。可是這種狀況下shell是不能退出的,若是shell退出,它的子進程就掛掉了。此時可使用#exec COMMAND頂替COMMAND,取代shell進程,shell退出,shell的子進程PID就成了1。

在容器中啓動進程時,能夠不基於shell直接啓動進程。若是要基於shell啓動主進程,那就必需要這個主進程的PID爲1,就能夠經過 #exec COMMAND。


 

RUN

RUN用於在鏡像容器中執行命令,其有如下兩種命令執行方式: shell執行 格式: RUN <command> exec執行 格式: RUN ["executable", "param1", "param2"] 示例: RUN ["executable", "param1", "param2"] RUN apk update RUN ["/etc/execfile", "arg1", "arg1"] 注:   RUN指令建立的中間鏡像會被緩存,並會在下次構建中使用。若是不想使用這些緩存鏡像,能夠在構建時指定--no-cache參數,如:docker build --no-cache

 

RUN能夠運行屢次,另外若是RUN有多條命令,建議把多條命令一次性寫進來;

RUM COMMAND1 && \    //使用&&的好處在於若是第一個命令錯誤,那麼就會中止下來,不會再執行第二個命令。

    COMMAND2

 

CMD

格式: CMD ["executable","param1","param2"] (執行可執行文件,優先) CMD ["param1","param2"] (設置了ENTRYPOINT,則直接調用ENTRYPOINT添加參數) CMD command param1 param2 (執行shell內部命令) 示例: CMD echo "This is a test." | wc - CMD ["/usr/bin/wc","--help"] 注:   CMD不一樣於RUN,CMD用於指定在容器啓動時所要執行的命令,而RUN用於指定鏡像構建時所要執行的命令。 

好比在Dockerfile中ADD一個URL,因爲URL被打包進鏡像時不會被自動展開,因此能夠在docker build階段使用RUN命令對此tar包進行解壓。

但前提時基礎鏡像中要支持tar命令,在docker build階段運行全部命令都是基於基礎鏡像所提供的環境的。

[root@node1 img1]# vim Dockerfile  

  1 # Description: test image
  2 FROM busybox:latest
  3 ENV DOC_ROOT=/data/web/html/ \
  4     WEB_SERVER_PACKAGE="nginx-1.14.2.tar.gz"
  5 COPY index.html ${DOC_ROOT:-/data/web/html}
  6 ADD https://nginx.org/download/${WEB_SERVER_PACKAGE} /usr/local/src/
  7 
  8 WORKDIR /usr/local/
  9 #ADD ${WEB_SERVER_PACKAGE}.tar.gz ./src/
 10 
 11 VOLUME /data/mysql/
 12 
 13 EXPOSE 80/tcp
 14 
 15 RUN cd /usr/local/src && \ //能夠運行多個命令 16 tar -xf ${WEB_SERVER_PACKAGE} 

[root@node1 img1]# docker build -t tinyhttpd:v0.1-10 ./

Sending build context to Docker daemon  1.052MB
Step 1/8 : FROM busybox:latest
 ---> d8233ab899d4
Step 2/8 : ENV DOC_ROOT=/data/web/html/     WEB_SERVER_PACKAGE="nginx-1.14.2.tar.gz"
 ---> Using cache
 ---> 2a3dd8ab77c5
Step 3/8 : COPY index.html ${DOC_ROOT:-/data/web/html}
 ---> Using cache
 ---> 7bcdbdd8dbdd
Step 4/8 : ADD https://nginx.org/download/${WEB_SERVER_PACKAGE} /usr/local/src/
Downloading [==================================================>]  1.015MB/1.015MB
 ---> Using cache
 ---> 076581fd3385
Step 5/8 : WORKDIR /usr/local/
 ---> Using cache
 ---> f1e1e3457cf7
Step 6/8 : VOLUME /data/mysql/
 ---> Using cache
 ---> f901d29855d5
Step 7/8 : EXPOSE 80/tcp
 ---> Using cache
 ---> da0f851edb51
Step 8/8 : RUN cd /usr/local/src/ && tar xf ${WEB_SERVER_PACKAGE} ---> Running in b42a22ddc96c Removing intermediate container b42a22ddc96c ---> c0c7f3d670e2
Successfully built c0c7f3d670e2
Successfully tagged tinyhttpd:v0.1-10

# docker run --name tinyweb1 -P -e WEB_SERVER_PACKAGE="nginx-1.15.1" -it --rm tinyhttpd:v0.1-10 ls /usr/local/src   //驗證
   nginx-1.14.2     nginx-1.14.2.tar.gz

RUN和CMD區別示例2

[root@node1 ~]# mkdir img2
[root@node1 ~]# cd img2/
[root@node1 img2]# vim Dockerfile

1 FROM busybox
2 LABEL maintainer="hello <nihao@nihao.com>" app="httpd"
3
4 ENV=WEB_DOC_ROOT="/data/web/html/"
5 RUN mkdir -p $WEB_DOC_ROOT && \
6 echo '<h1>Busybox httpd server.</h1>' > ${WEB_DOC_ROOT}/index.html
7
8 CMD /bin/httpd -f -h ${WEB_DOC_ROOT}  //這裏定義默認運行的程序不是shell,而是httpd

[root@node1 img2]# docker build -t tinyhttpd:v0.3-2 ./   //製做鏡像

[root@node1 img2]# docker image inspect tinyhttpd:v0.2-1   //查看鏡像內容

執行交互式啓動鏡像,可是卻卡在這裏,由於httpd沒有交互接口

(注意:若是容器tinyweb2不存在,就沒法執行此操做。)

/bin/httpd進程的PID爲1,這裏爲了不在啓動tinyweb2容器時,/bin/httpd進程的PID爲1,就使用了exec作了替換操做。

之因此讓/bin/httpd主進程的PID爲1,是爲了確保此容器能夠接受unix信號。

相關文章
相關標籤/搜索