回到我前幾天介紹的 Docker Image(映像) 我們把它想像成烤雞蛋糕模型,那這個 Dockerfile 我們就可以把它想像成這個模型的說明書,這本說明書包含了一系列指令,告訴 Docker 如何建立一个映像。當我們要 run docker 時,他會根據現在專案的根目錄,找尋 Dockerfile ,並且根據 Dockerfile 裡面一步一步的說明,來安裝好相關套件資料庫等環境,然後製作成一個 Image(映像)。
當然如果你的 Dockerfile 沒有在根目錄也是可以的,只要指定對路徑,能找到 Dockerfile 就可以根據 Dockerfile 來製作 Image(映像)。
也就是我們在 Docker Hub 上可以看到的基礎鏡像版本
FROM ruby:3.2.2
📍通常會放在 Dockerfile 的第一行
通常與 FROM 一起在多階段建立,我們可以把它想像成暱稱
FROM ruby:3.2.2 AS app
也就是我們可以在這個檔案後面以 app
這個暱稱來稱呼 ruby:3.2.2
Dockerfile 的作者/維護者(1.13 版本以後,建議改用LABEL)
MAINTAINER Krystal <krystal@example.com>
以 key value 的形式,來描述鏡像的屬性(作者、版本、描述等)
LABEL maintainer="Krystal <krystal@example.com>"
LABEL version="1.0"
LABEL description="My rails project"
LABEL website="https://www.example.com"
主要功用就是提供資訊,讓其他人更容易理解和使用映像,我自己是把他想得很像 README 的作用。
建立 image 時,安裝軟體套件、下載依賴項、設定環境。
RUN apk add --update --no-cache \
postgresql-dev
RUN gem install bundler:2.3.19 && \
bundle install -j4 --retry 3 && \
bundle clean --force
📍每個 RUN 指令都會 生成一層新的鏡像層,所以根據上面範例會生成兩層
📍上面看到的 \
其實只是為了排版美觀的一個符號,代表雖然換行,但其實是同一行。
所以我們可以改成如下
RUN apk add --update --no-cache postgresql-dev
RUN gem install bundler:2.3.19 && bundle install -j4 --retry 3 && bundle clean --force
只是我個人推薦上方有 \
符號的寫法,因為可讀性較佳。
📍 &&
其實就是如果前一個命令執行成功,才會執行下一個命令。如果前一個命令執行失敗,那後面的命令就不會執行。
上面會需要 && 是為了確保安裝 bundler、執行 bundle install 和清理 bundle 時,只有在前一步成功時才繼續執行後續步驟。
容器啟動時要執行的預設命令,每個 Dockerfile 只能有一個 CMD 指令,如果有多個 CMD 指令,前面會被覆蓋,只有最後一個會執行
CMD ["rails", "server", "-b", "0.0.0.0"]
也因為上面說的 CMD 指令會被覆蓋,所以我們通常把他放在 Dockerfile 的最後一行,以避免覆蓋狀況。
定義容器的主要執行命令,且會在容器啟動時執行
ENTRYPOINT ["echo", "Hello, Docker!"]
當 Docker run 這個容器,容器啟動後便會輸出 "Hello, Docker!"
看到這邊我超暈 CMD 跟 ENTRYPOINT 差在哪?看起來根本都一樣,我們直接用範例解釋
如果有上面的 ENTRYPOINT ,然後我們將這個 image run 起來 docker run <image> Hi
,再多給一個 Hi 參數
會輸出
Hello, Docker! Hi
反過來如果是 CMD
CMD ["echo", "Hello"]
然後我們將這個 image run 起來 docker run <image> Hi
,再多給一個 Hi 參數
會輸出
Hello Hi
你可能覺得看起來都一樣,但其實不同的是,這時 CMD 的內容 ["echo", "Hello"]
已經被修改為 ["echo", "Hello", "Hi"]
總結來說 ENTRYPOINT 是不可變且一定會執行的 ; CMD 可能被覆蓋也可能被修改的。
指出容器內應用程式,應該使用哪些 port (連接口)進行監聽
EXPOSE 3000
代表監聽 3000 port
今天就先介紹到這邊,明天我們繼續拆解 Dockerfile 剩餘的關鍵字~