在Docker的系統學習教程中我們了解到使用Dockerfile構建Docker鏡像為一個規范的方式,根據Dockerfile可以了解鏡像中安裝的組件的詳細內容。Dockerfile一般由四部分組成:第一,構建的基礎鏡像;第二,鏡像構建者的信息;第三,構建鏡像過程中鏡像層添加指令;第四,由該鏡像啟動容器時執行的程序。本篇文章中涉及到的ENTRYPOINT 和CMD 屬於Dockerfile中的最后一部分,這兩個Dockerfile指令是用來告知Docker后台程序啟動鏡像時需要執行的程序,兩者有細微的差別。下面將從兩者的異同以及兩者聯合使用的高級技巧方面對兩個指令進行詳解。
CMD 指令
CMD 指令指定容器啟動時需要運行的程序。一般用最簡單的方式啟動一個容器時使用docker run
會傳遞參數給docker指令
docker run -it image /bin/bash1
后面的/bin/bash
其實是傳遞參數,告知容器啟動時運行一個shell。這個過程可以用CMD
指令等效的替換
CMD ['/bin/bash']1
因此在Dockerfile中存在這個CMD指令指定的命令時,啟動容器就可以不進行參數傳遞。
docker run -it image 1
執行效果一致。
[root@MiWiFi-R3L-srv test]# docker run --name test -it test_image
[root@3a1bb0c9e35c /]#12
如果dockerfile中已經指定了容器啟動時運行的程序,同時在使用docker run
啟動容器時使用了命令行參數,那么dockerfile 中的cmd
指令將無效
docker run -it image /bin/ps1
發現啟動容器后沒有shell ,只是打印出了當前容器中的進程狀態,cmd
指令效果被覆蓋。
PID TTY TIME CMD
1 ? 00:00:00 ps
[root@MiWiFi-R3L-srv test]#123
此時可以看到cmd
效果被覆蓋。在一個dockerfile中只有最后一個cmd
指令有效,因此一個dockerfile中只寫一個cmd
指令。
ENTRYPOINT 指令
ENTRYPOINT
指令效果與CMD
非常的類似,比較容易混淆兩者的功能。最大的區別在於使用的方式,ENTRYPOINT
指定的命令需要與docker run
啟動容器進行搭配,將docker run 指令后面跟的內容當做參數作為ENTRYPOINT指令指定的運行命令的參數,ENTRYPOINT 指定的linux命令一般是不會被覆蓋的。以nginx
鏡像為例說明
首先構建一個nginx鏡像,並且指定容器運行時執行的程序為nginx。
FROM centos
MAINTAINER allocator
RUN yum install -y nginx
RUN echo 'hello world' > /usr/share/nginx/html/index.html
EXPOSE 80
ENTRYPOINT ["/usr/sbin/nginx"]123456
然后啟動鏡像
docker run --name test -p 5000:80 -it test_nginx -g "daemon off"1
后面兩個是作為參數傳遞給nginx啟動程序運行,此時nginx作為前台程序運行,是一個web服務器,可以根據外部綁定的端口,通過瀏覽器正常看到hello world
兩者聯合使用技巧
已經明白了兩者的區別,可以利用兩者的特點構建一個含有默認啟動運行程序的鏡像,並且支持docker run
啟動時人為指定啟動程序運行的參數。
舉個例子。利用ENTRYPOINT
指定啟動時運行啟動nginx程序,並給定默認的運行參數為顯示幫助信息,dockerfile 構建如下:
ENTRYPOINT ["/usr/sbin/nginx"]
CMD ["-h"]12
當使用docker run --name test -it test_nginx
不傳遞任何參數時,此時啟動容器會使用cmd
指令后的命令作為默認參數,打印nginx的幫助信息。此時cmd
后的內容並不是一個完整的指令,而是參數,如果其內容是一個完整的指令,那么它將覆蓋掉ENTRYPOINT
中的內容。
如果使用docker run --name test -it test_nginx -g "daemon off"
啟動時,此時給定的運行參數會覆蓋掉CMD
指令對應的內容,此時nginx將作為前台進程運行,作為一個web服務器使用,通過browser可以看到hello world