Website logo

Robert Chang

技術部落格

Docker - dockerignore 該如何使用呢?

在建置映像檔時,都可以注意到到其中一段紀錄:

=> [internal] load .dockerignore

每一次建置的過程中,其都會自動去讀取 .dockerignore 這個檔案,但在之前我們並沒有好好的介紹過。

其最主要的功能在於提前篩選掉不需要進入建置階段的檔案,例如常見的 README.md 或是一些開發環境的設定檔,對於建置階段以及運行容器沒有幫助的檔案,都應該放入 .dockerignore 內。

下面舉個簡單的例子,這是資料夾目前的結構。

.
├── main.js
├── Dockerfile
├── .dockerignore
├── README.md

接著在 .dockerignore 內寫入:

./README.md
./Dockerfile

接著來建置映像檔,這邊是 Dockerfile 的內容:

FROM alpine:latest

WORKDIR /app

COPY . .

CMD ["ls"]

接著一樣,建置這個映像檔:

$ docker image build --tag ignore .
+] Building 2.1s (8/8) FINISHED
 => [internal] load build definition from Dockerfile                       0.1s
 => => transferring dockerfile: 94B                                        0.0s
 => [internal] load .dockerignore                                          0.1s
 => => transferring context: 34B                                           0.0s
 => [internal] load metadata for docker.io/library/alpine:latest           1.5s
 => CACHED [1/3] FROM docker.io/library/alpine:late..                      0.0s
 => [internal] load build context                                          0.1s
 => => transferring context: 58B                                           0.0s
 => [2/3] WORKDIR /app                                                     0.1s
 => [3/3] COPY . .                                                         0.1s
 => exporting to image                                                     0.3s
 => => exporting layers                                                    0.3s
 => => writing image sha256:ac7715c782f9dfcdd93c0dbc871ada..........       0.0s
 => => naming to docker.io/library/ignore                                  0.0s

運行成容器看看輸出的結果是什麼?

$ docker container run ignore
main.js

可以注意到,我們使用了 COPY . . 的方式,也就是複製當前目錄內的所有資料進入到建置階段,但卻只有 main.js 被留下了,而 Dockerfile 以及 README.md 則都被篩選掉了。

這麼做的好處在哪呢?練習時,我們都可以直接 COPY 我們需要的檔案進入建置階段就好。

但在大型的框架之下,會有很多不必要進入建置階段的檔案,例如:測試的檔案、開發環境快取的檔案都不需要進入正式環境的映像檔,而這時候靠著一個一個去 COPY 則太過浪費時間。

所以使用 .dockerignore 則可以讓你放心的去使用 COPY . . 來達到 Dockerfile 撰寫的乾淨度、減少映像檔的容量,讓你透過一個檔案去管理所有不需要進入建置階段的檔案,是之後非常常用到的功能。

在經過了 28 天的鐵人賽,想必大家的電腦裡面應該都是充斥一些不需要的檔案,這時候可以先透過以下指令來查看目前各個 Docker 物件所佔據的容量:

$ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          63        0         13.25GB   13.25GB (100%)
Containers      0         0         0B        0B
Local Volumes   22        0         667.8MB   667.8MB (100%)
Build Cache     531       0         10.32GB   10.32GB

可以看到其實映像檔及快取就佔據了本機將近 25 GB 的空間,當然對於現代的硬碟大小,確實不算什麼,但有時候總會覺得這些是我現在有在使用的快取嗎?還是之前實驗的映像檔呢?

清理不需要的容器

這時候有幾個方式可以清除,除了前面很常使用,關於強制刪除所有容器的指令 ( 要記得這個是連在運行的容器都會刪除,通常都是我在實驗某些容器時才會使用的指令 )

$ docker container rm --force $(docker container ls -aq)

其實還有稍微文明一點的指令,可以不使用到 --force 這個選項便刪除停止運行的容器。

$ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B

清理不需要的映像檔

關於清理映像檔的指令則和清理容器的雷同:

$ docker image prune
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] y
Deleted Images:
deleted: sha256:03552d52bd99ade4....

Total reclaimed space: 0B

其有提到只會刪除 dangling 的映像檔,而 dangling 則意味著標籤被奪走的映像檔。

以下示範什麼行為會製造出 dangling 的映像檔,這邊隨手建立一個 Dockerfile。

FROM alpine:latest

CMD [ "echo", "Hi" ]

接著建置映像檔:

$ docker image build --tag dangling .
[+] Building 0.2s (5/5) FINISHED
 => [internal] load build definition from Dockerfile                       0.1s
 => => transferring dockerfile: 36B                                        0.1s
 => [internal] load .dockerignore                                          0.1s
 => => transferring context: 34B                                           0.0s
 => [internal] load metadata for docker.io/library/alpine:latest           0.0s
 => CACHED [1/1] FROM docker.io/library/alpine:latest                      0.0s
 => exporting to image                                                     0.3s
 => => exporting layers                                                    0.3s
 => => writing image sha256:d7bcae79c0f6fff9fa7620078c122b6a65......       0.0s
 => => naming to docker.io/library/dangling                                0.0s

這時候我們列出映像檔,應該會看到剛剛建立好的映像檔。

$ docker image list
REPOSITORY   TAG       IMAGE ID          CREATED           SIZE
dangling     latest    d7bcae79c0f6      1 minutes ago   5.53MB

接著稍微的修改一下剛剛撰寫的 Dockerfile。

FROM alpine:latest

CMD [ "echo", "Hi, My name is Robert!" ]

在使用相同的標籤名字去建置映像檔。

$ docker image build --tag dangling .
[+] Building 0.2s (5/5) FINISHED
 => [internal] load build definition from Dockerfile                       0.1s
 => => transferring dockerfile: 36B                                        0.1s
 => [internal] load .dockerignore                                          0.1s
 => => transferring context: 34B                                           0.0s
 => [internal] load metadata for docker.io/library/alpine:latest           0.0s
 => CACHED [1/1] FROM docker.io/library/alpine:latest                      0.0s
 => exporting to image                                                     0.3s
 => => exporting layers                                                    0.3s
 => => writing image sha256:2892a0f830e770814c111d1f0fe1e66d66db2...       0.0s
 => => naming to docker.io/library/dangling                                0.0s

在列出映像檔,就會看到 dangling 的映像檔,以 <none> 的方式顯示。

$ docker image list
REPOSITORY   TAG       IMAGE ID          CREATED           SIZE
dangling     latest    2892a0f830e7      1 minutes ago   5.53MB
<none>       <none>    d7bcae79c0f6      2 minutes ago   5.53MB

這裡的 <none> 就是第一份建置的映像檔,因為標籤相同的關係,被第二次建置的映像檔奪走了標籤,轉變成 dangling 的映像檔,而在使用 docker image prune 的指令時,就會幫助你清除這些沒有標籤的映像檔。

而還有更暴力可以清理映像檔的方式,也就是在後方加上 --all 的指令,此指令將會清除所有沒有運行成容器的映像檔,換句話說,如果現在沒有在運行任何容器或是暫停的容器,那映像檔就會全部清空的意思。

$ docker image prune --all
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N] y
.......
Total reclaimed space: 5.691GB

可以看到這邊清了 5.691 GB 的空間出來。

結語

今天介紹了 .dockerignore 的作用以及清理本機浪費的資源,明天則會介紹一下 Volume 該如何使用!

上一篇文章Docker - 多階段建置映像檔

下一篇文章Docker - 介紹 Volume