您好,登錄后才能下訂單哦!
如何在Dockerfile 中使用COPY與ADD命令?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
Build 上下文的概念
在使用 docker build 命令通過 Dockerfile 創建鏡像時,會產生一個 build 上下文(context)。所謂的 build 上下文就是 docker build 命令的 PATH 或 URL 指定的路徑中的文件的集合。在鏡像 build 過程中可以引用上下文中的任何文件,比如我們要介紹的 COPY 和 ADD 命令,就可以引用上下文中的文件。
默認情況下 docker build -t testx
. 命令中的 . 表示 build 上下文為當前目錄。當然我們可以指定一個目錄作為上下文,比如下面的命令:
$ docker build -t testx /home/nick/hc
我們指定 /home/nick/hc 目錄為 build 上下文,默認情況下 docker 會使用在上下文的根目錄下找到的 Dockerfile 文件。
COPY 和 ADD 命令不能拷貝上下文之外的本地文件
對于 COPY 和 ADD 命令來說,如果要把本地的文件拷貝到鏡像中,那么本地的文件必須是在上下文目錄中的文件。其實這一點很好解釋,因為在執行 build 命令時,docker 客戶端會把上下文中的所有文件發送給 docker daemon。考慮 docker 客戶端和 docker daemon 不在同一臺機器上的情況,build 命令只能從上下文中獲取文件。如果我們在 Dockerfile 的 COPY 和 ADD 命令中引用了上下文中沒有的文件,就會收到類似下面的錯誤:
與 WORKDIR 協同工作
WORKDIR 命令為后續的 RUN、CMD、COPY、ADD 等命令配置工作目錄。在設置了 WORKDIR 命令后,接下來的 COPY 和 ADD 命令中的相對路徑就是相對于 WORKDIR 指定的路徑。比如我們在 Dockerfile 中添加下面的命令:
WORKDIR /app
COPY checkredis.py .
然后構建名稱為 testx 的容器鏡像,并運行一個容器查看文件路徑:
checkredis.py 文件就是被復制到了 WORKDIR /app 目錄下。
COPY 命令的簡單性
如果僅僅是把本地的文件拷貝到容器鏡像中,COPY 命令是最合適不過的。其命令的格式為:
COPY <src> <dest>
除了指定完整的文件名外,COPY 命令還支持 Go 風格的通配符,比如:
COPY check* /testdir/ # 拷貝所有 check 開頭的文件
COPY check?.log /testdir/ # ? 是單個字符的占位符,比如匹配文件 check1.log
對于目錄而言,COPY 和 ADD 命令具有相同的特點:只復制目錄中的內容而不包含目錄自身。比如我們在 Dockerfile 中添加下面的命令:
WORKDIR /app
COPY nickdir .
其中 nickdir 目錄的結構如下:
重新構建鏡像 testx,運行一個容器并查看 /app 目錄下的內容:
這里只有 file1 和 file2,少了一層目錄 nickdir。如果想讓 file1 和 file2 還保存在 nickdir 目錄中,需要在目標路徑中指定這個目錄的名稱,比如:
WORKDIR /app
COPY nickdir ./nickdir
COPY 命令區別于 ADD 命令的一個用法是在 multistage 場景下。關于 multistage 的介紹和用法請參考筆者的《Dockerfile 中的 multi-stage》一文。在 multistage 的用法中,可以使用 COPY 命令把前一階段構建的產物拷貝到另一個鏡像中,比如:
FROM golang:1.7.3
WORKDIR /go/src/github.com/sparkdevo/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/sparkdevo/href-counter/app .
CMD ["./app"]
這段代碼引用自《Dockerfile 中的 multi-stage》一文,其中的 COPY 命令通過指定 --from=0 參數,把前一階段構建的產物拷貝到了當前的鏡像中。
ADD 命令還可以干其它事情
ADD 命令的格式和 COPY 命令相同,也是:
ADD <src> <dest>
除了不能用在 multistage 的場景下,ADD 命令可以完成 COPY 命令的所有功能,并且還可以完成兩類超酷的功能:
?解壓壓縮文件并把它們添加到鏡像中
?從 url 拷貝文件到鏡像中
當然,這些功能也讓 ADD 命令用起來復雜一些,不如 COPY 命令那么直觀。
解壓壓縮文件并把它們添加到鏡像中
如果我們有一個壓縮文件包,并且需要把這個壓縮包中的文件添加到鏡像中。需不需要先解開壓縮包然后執行 COPY 命令呢?當然不需要!我們可以通過 ADD 命令一次搞定:
WORKDIR /app
ADD nickdir.tar.gz .
這應該是 ADD 命令的最佳使用場景了!
從 url 拷貝文件到鏡像中
這是一個更加酷炫的用法!但是在docker 官方文檔的最佳實踐中卻強烈建議不要這么用!!docker 官方建議我們當需要從遠程復制文件時,最好使用 curl 或 wget 命令來代替 ADD 命令。原因是,當使用 ADD 命令時,會創建更多的鏡像層,當然鏡像的 size 也會更大(下面的兩段代碼來自 docker 官方文檔):
ADD http://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
RUN make -C /usr/src/things all
如果使用下面的命令,不僅鏡像的層數減少,而且鏡像中也不包含 big.tar.xz 文件:
RUN mkdir -p /usr/src/things \
&& curl -SL http://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all
好吧,看起來只有在解壓壓縮文件并把它們添加到鏡像中時才需要 ADD 命令!
加速鏡像構建的技巧
在使用 COPY 和 ADD 命令時,我們可以通過一些技巧來加速鏡像的 build 過程。比如把那些最不容易發生變化的文件的拷貝操作放在較低的鏡像層中,這樣在重新 build 鏡像時就會使用前面 build 產生的緩存。比如筆者構建鏡像時需要用到下面幾個文件:
其中 myhc.py 文件不經常變化,而 checkmongo.py、checkmysql.py 和 checkredis.py 這三個文件則經常變化,那么我們可這樣來設計 Dockerfile 文件:
WORKDIR /app
COPY myhc.py .
COPY check* ./
讓 COPY myhc.py . 單獨占據一個鏡像層,當 build 過一次后,每次因 checkmongo.py、checkmysql.py 和 checkredis.py 這三個文件變化而導致的重新 build 都不會重新 build COPY myhc.py . 鏡像層:
如上圖所示,第二步和第三步都沒有重新 build 鏡像層,而是使用了之前的緩存,從第四步才開始重新 build 了鏡像層。當文件 size 比較大且文件的數量又比較多,尤其是需要執行安裝等操作時,這樣的設計對于 build 速度的提升還是很明顯的。所以我們應該盡量選擇能夠使用緩存的 Dockerfile 寫法。
關于如何在Dockerfile 中使用COPY與ADD命令問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。