Docker Dockerfile 編寫指南
什麼是 Dockerfile?
Dockerfile 是一個文字檔案,包含了一系列指令用來自動化建構 Docker 映像檔。透過 Dockerfile,我們可以將應用程式及其運行環境封裝成一個可移植的映像檔,實現「一次建構,到處運行」的目標。
Dockerfile 的優勢
- 可重現性:確保在不同環境中建構出相同的映像檔
- 版本控制:可以像程式碼一樣進行版本管理
- 自動化:減少手動配置,降低人為錯誤
- 標準化:統一的建構流程和環境配置
基本指令介紹
核心指令
| 指令 |
功能 |
範例 |
FROM |
指定基礎映像檔 |
FROM openjdk:21-jre |
WORKDIR |
設定工作目錄 |
WORKDIR /app |
COPY |
複製檔案到映像檔 |
COPY . /app |
RUN |
執行命令 |
RUN apt-get update |
EXPOSE |
聲明容器端口 |
EXPOSE 8080 |
CMD |
容器啟動時的預設命令 |
CMD ["java", "-jar", "app.jar"] |
ENTRYPOINT |
容器啟動點 |
ENTRYPOINT ["java", "-jar"] |
進階指令
| 指令 |
功能 |
範例 |
ARG |
建構時參數 |
ARG JAVA_VERSION=21 |
ENV |
環境變數 |
ENV NODE_ENV=production |
VOLUME |
聲明卷掛載點 |
VOLUME ["/data"] |
USER |
切換使用者 |
USER app |
HEALTHCHECK |
健康檢查 |
HEALTHCHECK CMD curl -f http://localhost:8080/health |
LABEL |
添加元數據 |
LABEL version="1.0" |
完整範例:Spring Boot 應用程式
以下是一個生產級別的 Spring Boot 應用程式 Dockerfile 範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
|
ARG MAVEN_PROFILE=dev ARG SPRING_PROFILE=dev
FROM maven:3.9.9-eclipse-temurin-21 AS build
ARG MAVEN_PROFILE
WORKDIR /app
COPY pom.xml ./ COPY mvnw ./ COPY mvnw.cmd ./ COPY .mvn ./.mvn
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn clean package -DskipTests -P${MAVEN_PROFILE} -B
FROM eclipse-temurin:21-jre AS runtime
ARG SPRING_PROFILE
RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ tzdata \ && rm -rf /var/lib/apt/lists/* \ && groupadd -g 1001 dockertest \ && useradd -u 1001 -g dockertest -s /bin/bash -m dockertest
ENV TZ=Asia/Taipei
RUN mkdir -p /var/log/dockertest /app/logs \ && chown -R dockertest:dockertest /var/log/dockertest /app/logs
WORKDIR /app
COPY --from=build /app/target/dockertest-0.0.1-SNAPSHOT-boot.jar app.jar
RUN chown -R dockertest:dockertest /app
VOLUME ["/app/logs", "/var/log/dockertest"]
USER dockertest
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD curl -f http://localhost:8080/actuator/health || exit 1
ENV JAVA_OPTS="-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom" \ SPRING_PROFILES_ACTIVE=${SPRING_PROFILE}
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
LABEL maintainer="vscodelife" \ version="0.0.1-SNAPSHOT" \ description="Spring Boot Docker Test Application" \ org.opencontainers.image.title="dockertest" \ org.opencontainers.image.description="Demo project for Spring Boot with Docker" \ org.opencontainers.image.version="0.0.1-SNAPSHOT" \ org.opencontainers.image.vendor="vscodelife"
|
範例解析
1. 多階段建構 (Multi-stage Build)
1 2 3 4
| FROM maven:3.9.9-eclipse-temurin-21 AS build
FROM eclipse-temurin:21-jre AS runtime
|
- 目的:分離建構環境和運行環境,減少最終映像檔大小
- 優勢:建構工具不會包含在最終映像檔中
2. 建構參數 (Build Arguments)
1 2
| ARG MAVEN_PROFILE=dev ARG SPRING_PROFILE=dev
|
- 用途:在建構時動態配置參數
- 使用:
docker build --build-arg MAVEN_PROFILE=prod .
3. 層級快取優化
1 2 3
| COPY pom.xml ./ RUN mvn dependency:go-offline -B COPY src ./src
|
- 策略:先複製依賴配置,再複製原始碼
- 效果:依賴下載層可以被快取,加速後續建構
4. 安全性配置
1 2 3
| RUN groupadd -g 1001 dockertest \ && useradd -u 1001 -g dockertest -s /bin/bash -m dockertest USER dockertest
|
- 目的:避免使用 root 使用者運行應用程式
- 好處:減少安全風險,符合最小權限原則
5. 健康檢查
1 2
| HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD curl -f http://localhost:8080/actuator/health || exit 1
|
- 功能:定期檢查容器健康狀態
- 參數說明:
interval:檢查間隔
timeout:檢查超時時間
start-period:容器啟動後等待時間
retries:失敗重試次數
最佳實踐建議
1. 映像檔大小優化
使用多階段建構
1 2 3 4 5 6 7 8
| FROM node:18 AS build COPY package*.json ./ RUN npm ci --only=production
FROM node:18-alpine COPY --from=build /app/node_modules ./node_modules
|
選擇合適的基礎映像檔
1 2 3 4 5 6 7 8
| FROM ubuntu:22.04
FROM alpine:3.18
FROM openjdk:21-jre-slim
|
2. 層級快取策略
正確的檔案複製順序
1 2 3 4 5 6 7 8
| COPY . /app RUN npm install
COPY package*.json /app/ RUN npm install COPY . /app
|
3. 安全性最佳實踐
使用非 root 使用者
1 2 3
| RUN addgroup -g 1001 -S appgroup && \ adduser -u 1001 -S appuser -G appgroup USER appuser
|
減少攻擊面
1 2 3 4 5 6 7
| RUN apt-get update && apt-get install -y package \ && apt-get clean \ && rm -rf /var/lib/apt/lists/*
COPY --chown=appuser:appgroup app.jar /app/
|
4. 環境配置
使用環境變數
1 2 3
| ENV NODE_ENV=production \ PORT=3000 \ LOG_LEVEL=info
|
支援配置覆寫
1 2 3
| ENV JAVA_OPTS="-Xmx512m" \ SERVER_PORT=8080
|
常見問題與解決方案
Q1: 映像檔太大怎麼辦?
解決方案:
- 使用 Alpine 基礎映像檔
- 實施多階段建構
- 清理暫存檔案和快取
- 使用
.dockerignore 排除不必要檔案
1 2 3 4 5 6
| node_modules *.log .git Dockerfile README.md
|
Q2: 建構速度太慢?
解決方案:
- 優化層級順序,善用快取
- 使用 BuildKit
- 並行化建構步驟
1 2 3
| export DOCKER_BUILDKIT=1 docker build --progress=plain .
|
Q3: 容器啟動失敗?
除錯步驟:
1 2 3 4 5 6 7 8
| docker images
docker run -it --entrypoint /bin/bash your-image
docker logs container-name
|
進階技巧
1. 使用 BuildKit 功能
快取掛載
1 2 3
| RUN --mount=type=cache,target=/var/cache/apt \ apt-get update && apt-get install -y package
|
密鑰掛載
1 2 3
| RUN --mount=type=secret,id=api_key \ curl -H "Authorization: $(cat /run/secrets/api_key)" api.example.com
|
2. 條件建構
1 2 3 4 5 6 7 8
| ARG BUILD_ENV=development
RUN if [ "$BUILD_ENV" = "development" ] ; then \ npm install --include=dev ; \ else \ npm install --omit=dev ; \ fi
|
3. 健康檢查最佳實踐
1 2 3 4 5 6
| COPY healthcheck.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/healthcheck.sh
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \ CMD /usr/local/bin/healthcheck.sh
|
建構和部署
建構映像檔
1 2 3 4 5 6 7 8
| docker build -t myapp:latest .
docker build --build-arg MAVEN_PROFILE=prod -t myapp:prod .
docker build -f Dockerfile.prod -t myapp:prod .
|
推送到 Registry
1 2 3 4 5
| docker tag myapp:latest registry.example.com/myapp:latest
docker push registry.example.com/myapp:latest
|
運行容器
1 2 3 4 5
| docker run -d -p 8080:8080 myapp:latest
docker run --rm -p 8080:8080 myapp:latest
|
參數說明:
-d:在背景執行容器
--rm:容器停止後自動刪除,適用於測試或臨時執行
-p 8080:8080:將主機的 8080 端口映射到容器的 8080 端口
提示
建議使用 Docker Compose 來管理複雜的多容器應用程式
重要提示
在生產環境中,務必遵循安全最佳實踐,定期更新基礎映像檔,並進行安全掃描
📺 實戰教學影片:編寫dockerfile建立image快速部屬環境