Docker - Dockerfile之ADD、COPY、WORKDIR、USER、EXPOSE指令詳解
ADD
ADD指令用于将檔案添加到容器中。
格式
-
。ADD <src> ... <dest>
-
。ADD ["<src>",... "<dest>"]
ADD指令和COPY指令的格式和性質基本一緻,隻不過ADD指令是在COPY指令的基礎上增加了一些功能。例如,ADD指令指定的源路徑可以是一個遠端URL,Docker引擎會自動将遠端URL的檔案下載下傳到目标路徑下,例如:
ADD https://www.baidu.com/index.html /index/
使用
docker build
指令建構鏡像,然後使用
docker run
指令建立并啟動容器,會發現在容器根目錄下的
index
檔案夾下有了
index.html
檔案。
如果源路徑是本地的一個
tar
壓縮檔案時,ADD指令複制該壓縮檔案到目标路徑下會自動将其進行解壓,如下:
ADD kaven.tar /kaven/
壓縮格式為
gzip
、
bzip2
以及
xz
的情況下,ADD指令都會将其解壓。
但網絡上的壓縮檔案不會被自動解壓,是以還需要額外增加一條RUN指令進行解壓。是以,在這種情況下,還不如隻用一條RUN指令,使用
curl
或者
wget
工具進行下載下傳,并更改權限,然後進行解壓,最後清理無用檔案。
源路徑是一個遠端URL時,會自動将遠端URL的檔案下載下傳到目标路徑下,但是其檔案權限被自動設定成了
600
(隻有擁有者有讀寫權限),如果這并不是你想要的權限,那麼你還需要額外增加一條RUN指令進行更改。
ADD指令從源路徑
<src>
(宿主路徑或遠端URL)中複制新檔案,并将它們添加到鏡像檔案系統中指定的目标路徑
<dest>
,
<src>
可以指定多個資源,但是如果它們是檔案或目錄,則将其路徑解釋為相對于建構上下文的路徑。每個
<src>
都可能包含通配符,并且比對将使用Go的
filepath.Match
規則完成。例如:
要添加所有以
hom
開頭的檔案:
ADD hom* /mydir/
在下面的示例中,
?
被替換為任何單個字元,例如
home.txt
:
ADD hom?.txt /mydir/
添加包含特殊字元(例如
[
和
]
)的檔案或目錄時,需要按照Golang規則對這些路徑進行轉義,以防止将它們視為比對模式。例如,要添加名為
arr[0].txt
的檔案,請使用以下指令:
ADD arr[[]0].txt /mydir/
ADD指令遵守以下規則:
-
路徑必須在建構的上下文中,不能使用<src>
這種路徑,因為Docker建構鏡像的第一步是将上下文目錄(和子目錄)發送到Docker守護程序。../something/something
- 如果
是一個URL,并且<src>
沒有以斜杠結尾,則會從該URL下載下傳一個檔案并将其複制到<dest>
。<dest>
- 如果
是一個URL,<src>
以斜杠結尾,則會從URL推斷出檔案名并将檔案下載下傳到<dest>
。例如,<dest>/<filename>
将建立檔案ADD https://www.baidu.com/index.html /
。URL必須有一個檔案路徑,以便在這種情況下可以發現合适的檔案名(/index.html
就不符合要求)。https://www.baidu.com
- 如果
是一個目錄,則複制目錄的全部内容,包括檔案系統中繼資料(目錄本身不被複制,僅其内容被複制)。<src>
- 如果直接或由于使用通配符指定了多個
資源,則<src>
必須是一個目錄,并且必須以斜杠結尾。<dest>
- 如果
不存在,則會連同路徑中所有不存在的目錄一起被建立。<dest>
COPY
COPY指令将從上下文目錄中的指定路徑下的檔案或檔案夾複制到新的一層的鏡像内的指定路徑。
格式
-
。COPY <src>... <dest>
-
。COPY ["<src>",... "<dest>"]
功能類似ADD指令,但是不會自動解壓檔案,也不能通路網絡資源。
源路徑可以有多個,直接指定或者使用通配符,并且比對将使用Go的
filepath.Match
規則完成。ADD指令中已經介紹過了,這裡就不贅述了。
目标路徑是容器内的絕對路徑,也可以是工作目錄下的相對路徑,工作目錄可以使用WORKDIR指令進行指定(下面會介紹該指令)。目标路徑不需要事先建立,Docker會自動建立所需的檔案目錄。使用COPY指令會将源路徑的檔案的所有中繼資料進行複制,比如讀、寫、指定全選、時間變更等。如果源路徑是一個目錄,那麼會将整個目錄複制到容器中,包括檔案系統中繼資料。
除了關于源路徑是遠端URL的一些規則外,ADD指令遵守的規則,COPY指令也都遵守。
當使用本地目錄為源目錄時,推薦使用COPY指令。
WORKDIR
使用WORKDIR指令來指定工作目錄(或者稱為目前目錄),以後各層操作的目前目錄就是為WORKDIR指令指定的目錄,如果該目錄不存在,WORKDIR指令會自動建立該目錄。
格式
-
。WORKDIR /path/to/workdir
類似于
cd
指令。
為後續的RUN、CMD、ENTRYPOINT等指令指定工作目錄。
可以使用多個WORKDIR指令,後續指令如果參數是相對路徑,則會基于之前WORKDIR指令指定的路徑。例如
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
輸出将是
/a/b/c
。
WORKDIR指令可以通過
docker run
指令中的
-w
選項來進行覆寫。
-w, --workdir string Working directory inside the container(容器内的工作目錄)
USER
格式
-
。USER <user>[:<group>]
-
。USER <UID>[:<GID>]
USER指令用于指定容器執行程式的使用者身份,預設是
root
,例如:
[root@izoq008ryseuupz ~]# docker run -it --name user_root centos
[root@c2cb41f2f972 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
USER指令可以通過
docker run
指令中的
-u
選項進行覆寫。
-u, --user string Username or UID (format: <name|uid>[:<group|gid>])
檢視有哪些使用者。
vim /etc/passwd
通過
docker run
指令中的
-u
選項指定使用者為
bin
。
docker run -it --name user_bin -u bin centos
[root@izoq008ryseuupz etc]# docker run -it --name user_bin -u bin centos
bash-4.4$ ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
bash-4.4$ exit
exit
EXPOSE
格式
-
。EXPOSE <port> [<port>/<protocol>...]
EXPOSE指令通知Docker容器在運作時偵聽指定的端口。可以指定端口是偵聽TCP還是UDP,如果未指定協定,則預設為TCP。
EXPOSE指令實際上并不釋出端口。它的功能隻是建構鏡像的人和使用鏡像的人之間對于要釋出哪些端口的一種聲明。要在運作容器時實際釋出端口,需要使用
docker run
指令的
-p
或
-P
選項來映射一個或多個端口:Docker - Docker初級網絡配置 - 端口映射。
預設情況下,EXPOSE指令假定協定為TCP。也可以指定UDP,例如:
EXPOSE 80/udp
端口同時在TCP和UDP上公布的話,需要以下兩行:
EXPOSE 80/tcp
EXPOSE 80/udp
在這種情況下,如果在
docker run
指令中使用
-P
選項,則該端口對TCP暴露一次,同樣對UDP也暴露一次。
-P
選項會在主機上使用随機的端口進行映射,是以對于TCP和UDP,映射的宿主端口将不同。
無論EXPOSE指令設定如何,都可以在運作時使用
-p
選項覆寫它們,例如:
docker run -p 80:80/tcp -p 80:80/udp ...
EXPOSE指令是聲明運作時容器服務端口,這隻是一個聲明,在運作時并不會因為這個聲明應用就會開啟這個端口的服務。
在
Dockerfile
中這樣聲明有兩個好處:
- 幫助鏡像使用者更好的了解這個鏡像的服務端口。
- 使用随機端口映射時,也就是使用
指令時,會自動随機映射EXPOSE指令指定的端口。docker run -P
要将EXPOSE指令和在運作時使用
-p <host-port>:<container-port>
區分開來,
-p
選項是映射宿主端口和容器端口,換句話說,就是将容器的對應端口服務公開給外界通路,而EXPOSE指令僅僅是聲明哪些端口可能需要被映射而已,并不會自動進行端口映射。