跳至主要内容

Dockerfile

什麼是 Dockerfile

Dockerfile 是一個文本文件,用來定義 Docker 映像檔的內容和配置。它包含了一系列指令,每個指令對應一個步驟,用來構建映像檔。使用 Dockerfile,你可以告訴 Docker 引擎該如何構建你的應用程式所需的環境。

常用指令

FROM

FROM 指令用於指定基礎映像,也就是你的映像檔將基於哪個映像檔構建。

# 這個指令指定了基礎映像為最新版的 Ubuntu 映像。
FROM ubuntu:latest

COPY

COPY 指令用於將文件從主機系統複製到映像檔內。

# 這個指令將當前目錄下的所有文件和目錄複製到映像檔中的 /app 目錄。
COPY . /app

RUN

RUN 指令通常用於執行建立映像檔所需的命令,通常用於安裝軟體、更新軟體包等。一個 Dockerfile 可以有多個 RUN


# 這個指令將在映像檔中執行命令,更新 apt 資源列表並安裝 Nginx 服務。
RUN apt-get update && apt-get install -y nginx

WORKDIR

WORKDIR 指令用於設置工作目錄,後續指令將在這個目錄下執行。如果該目錄在映像檔中不存在,Docker 將會自動創建該目錄

# 這個指令將設置工作目錄為 /app,後續的指令將在這個目錄下執行。
WORKDIR /app

CMD

CMD 指令用於設置容器啟動時執行的預設命令。一個 Dockerfile 只能有一個 CMD

# 這個指令設置容器啟動時預設執行的命令是啟動 Nginx 服務,並以非守護模式運行。
CMD ["nginx", "-g", "daemon off;"]

ARG 和 ENV

ARG 和 ENV 是 Dockerfile 中兩個用於定義變數的指令,

  • ARG 用於建立映像檔時的參數傳遞,只在建立時可讀取
  • ENV 用於容器運行時的環境配置,只在運行時可讀取

下面範例,示範如何設定一個 NODE_VERSION 參數,在 build image 階段指定版本,和一個 APP_ENV 在 run container 階段指定參數

# 定義一個 ARG 變數,用於指定 Node.js 的版本,預設為 latest
ARG NODE_VERSION=latest

# 指定 Node.js 的基礎映像
FROM node:$NODE_VERSION

# 將 NODE_VERSION 變數設置為環境變數
ENV NODE_VERSION=$NODE_VERSION

# 定義一個 ENV 變數,用於指定應用程式的環境,預設為 development
ENV APP_ENV=development

# 將應用程式文件複製到容器中
COPY . /app

# 設置工作目錄
WORKDIR /app

# 安裝應用程式依賴
RUN npm install

# 定義容器啟動時執行的預設命令
CMD ["npm", "start"]
# 我們將 NODE_VERSION 設置為 18,並使用 --build-arg 參數將它傳遞給 Docker
docker build --build-arg NODE_VERSION=18 -t myapp .
# 我們使用 -e 參數將 APP_ENV 設置為 production,並在容器啟動時設置了該環境變數
docker run -e APP_ENV=production myapp

以非 Root 使用者建立容器

在容器內部運行應用程式時,以 root 權限運行可能存在安全風險。如果應用程式受到攻擊或存在漏洞,攻擊者可能會以 root 權限獲取容器內部的控制權、控制宿主系統...

以下是一個完整的 Dockerfile 範例,示範了如何在容器中以非 root 權限運行應用程式:

# 使用 Python 作為基礎映像
FROM python:3.9

# 創建一個非 root 用戶
RUN groupadd -r myuser && useradd -r -g myuser myuser

# 切換到非 root 用戶
USER myuser

# 將應用程式複製到容器中
COPY . /app

# 設置工作目錄
WORKDIR /app

# 安裝應用程式依賴
RUN pip install -r requirements.txt

# 定義容器啟動時執行的命令
CMD ["python", "app.py"]

Multi-Stage Builds

多階段建置(multi-stage builds)是一種 Dockerfile 技術,允許你在單個 Dockerfile 中定義多個建置階段,從而實現更有效的映像構建和減少映像大小。這在開發和部署複雜應用程式時非常有用,尤其是當你的應用程式需要進行編譯、測試、打包等多個步驟時。

假設我們有一個 Node.js 應用程式,我們想要建立一個映像並在容器中運行它。我們將使用多階段建置來編譯應用程式,然後將它放入最終的映像中。

# 第一階段:編譯應用程式
FROM node:14 AS builder

WORKDIR /app

COPY package.json package-lock.json ./
RUN npm install

COPY . .
RUN npm run build

# 第二階段:生成最終映像
FROM nginx:alpine

WORKDIR /usr/share/nginx/html

# 從第一階段的編譯階段複製編譯好的應用程式
COPY --from=builder /app/build .

# 如果需要,可以添加額外的設置或配置

# 告訴 Docker 容器監聽的端口
EXPOSE 80

# 啟動 Nginx 服務
CMD ["nginx", "-g", "daemon off;"]