👻創作者:丶重明
👻創作時間:2025年4月8日
👻擅長領域:運維
目錄
- 1. Dockerfile編寫原則
- 1.1.選擇合適的基礎鏡像
- 1.2.鏡像層優化
- 1.3.多階段構建
- 1.4.安全增強
- 2. 關鍵指令與技巧
- 2.1.COPY vs ADD
- 2.2.ENTRYPOINT vs CMD
- 2.3.健康檢查
- 2.4.環境變量管理
- 3. 實戰:構建Prometheus鏡像
- 4. 附頁:Dockerfile指令
1. Dockerfile編寫原則
1.1.選擇合適的基礎鏡像
基礎鏡像的選擇直接影響鏡像的安全性、體積和可維護性。可以從這三個方面考慮:
- 最小化原則:優先使用輕量級鏡像
- 安全掃描:定期檢查基礎鏡像漏洞(使用 docker scan)
- 固定版本:避免使用
latest
標簽,明確指定版本號
示例:
# 推薦,這個鏡像很小,僅有8MB左右
alpine:3.21.3# 不推薦,基礎鏡像過大,版本號不明確
ubuntu:latest
1.2.鏡像層優化
Docker 鏡像由只讀層(Layer)堆疊而成,每一層對應 Dockerfile 中的一條指令。優化層的核心邏輯是減少層數和層體積。
- 合并指令:通過
&& \
合并多個RUN
命令 - 清理緩存:在同一個
RUN
層中刪除臨時文件 - 層順序:將高頻變化的層(如代碼)放在最后
示例:
# 通過&& \這種方式將多個命令合并為一層
RUN apk add --no-cache curl tar && \curl -LO https://example.com/pkg.tar.gz && \tar -xzf pkg.tar.gz && \rm pkg.tar.gz
1.3.多階段構建
多階段構建(Multi-stage Build)是減少生產鏡像體積的殺手锏。其核心思想是:用“胖”鏡像構建,用“瘦”鏡像運行。
- 分離構建環境與運行時環境
- 減少最終鏡像體積
1.4.安全增強
容器安全是生產環境的核心要求。以下是三個關鍵實踐:
- 非root用戶運行
- 限制文件系統寫入權限
- 使用 .dockerignore 排除敏感文件
示例:
RUN addgroup -S appgroup && \adduser -S appuser -G appgroup
USER appuser
2. 關鍵指令與技巧
2.1.COPY vs ADD
- 優先使用COPY:僅用于復制本地文件
- 謹慎使用ADD:自動解壓壓縮包,可能引入意外行為
2.2.ENTRYPOINT vs CMD
- ENTRYPOINT:定義容器主進程
- CMD:提供默認參數
示例:
ENTRYPOINT ["/bin/prometheus"]
CMD ["--config.file=/etc/prometheus/prometheus.yml"]
2.3.健康檢查
HEALTHCHECK --interval=30s --timeout=3s \CMD curl -f http://localhost:9090/-/healthy || exit 1
這一層命令的含義是:
HEALTHCHECK
:為容器設定健康檢查機制--interval=30s
:健康檢查的時間間隔--timeout=3s
:健康檢查命令的超時時間CMD ...
:具體的健康檢查命令
每隔 30 秒就向http://localhost:9090/-/healthy
發送一個 HTTP 請求,并且要求在 3 秒內完成。
若請求成功(狀態碼為 200 - 399),則判定容器健康;若請求失敗或者超時,就判定容器不健康。
2.4.環境變量管理
- 使用 ENV 定義常量
- 敏感數據通過 --env-file 或 Secrets 傳遞
3. 實戰:構建Prometheus鏡像
dockerfile目錄結構:直接在外部目錄解壓
# tree /prom_docker/
/prom_docker/
├── dockerfile
└── prometheus├── LICENSE├── NOTICE├── prometheus├── prometheus.yml└── promtool1 directory, 6 files
完整的Dockerfile文件:
FROM alpine:3.21.3# 創建非特權用戶
RUN addgroup -S prometheus && \adduser -S -D -H -s /bin/false -G prometheus prometheus && \mkdir -p /etc/prometheus /prometheus && \chown -R prometheus:prometheus /etc/prometheus /prometheus# 復制必要文件
COPY prometheus/LICENSE prometheus/NOTICE .
COPY prometheus/prometheus \prometheus/promtool \/usr/local/bin/
COPY prometheus/prometheus.yml \/etc/prometheus/# 設置運行時參數
USER prometheus
WORKDIR /prometheus
EXPOSE 9090
VOLUME ["/prometheus"]# 健康檢查(使用 promtool 無依賴)
HEALTHCHECK --interval=30s --timeout=10s \CMD ["/usr/local/bin/promtool", "check", "healthy", "--prometheus-url=http://localhost:9090"]# 入口指令
ENTRYPOINT ["/usr/local/bin/prometheus"]
CMD [ \"--config.file=/etc/prometheus/prometheus.yml", \"--storage.tsdb.path=/prometheus", \"--web.enable-lifecycle", \"--web.external-url=/" \
]
構建鏡像:
[root@localhost prom_docker]# docker build -t prometheus:v3.2.1 .
運行測試:
# docker run -d -p 9090:9090 --name prometheus-1 2c7c81224aa2
b91210a45af9f60c93c7e6652480da8d98a9077818cd2e75c769e3670ec1429d
4. 附頁:Dockerfile指令
以下是 Dockerfile 中常見指令及其功能、語法和示例的表格:
指令 | 功能 | 語法 | 示例 |
---|---|---|---|
FROM | 指定基礎鏡像,是 Dockerfile 的起始指令 | FROM <image>[:<tag>][@<digest>] | FROM python:3.9 |
RUN | 在新的鏡像層中執行命令,常用于安裝軟件包等操作 | RUN <command> (shell 形式)RUN ["executable", "param1", "param2"] (exec 形式) | RUN apt-get update && apt-get install -y python3 RUN ["pip", "install", "flask"] |
CMD | 為容器提供默認的執行命令,一個 Dockerfile 中只能有一個 CMD ,若有多個則只有最后一個生效 | CMD ["executable","param1","param2"] (exec 形式)CMD command param1 param2 (shell 形式)CMD ["param1","param2"] (為 ENTRYPOINT 提供默認參數) | CMD ["python", "app.py"] CMD python app.py |
LABEL | 為鏡像添加元數據,如作者、版本等信息 | LABEL <key>=<value> <key>=<value> ... | LABEL maintainer="example@example.com" version="1.0" |
EXPOSE | 聲明容器運行時監聽的網絡端口,但不進行端口映射 | EXPOSE <port> [<port>/<protocol> ...] | EXPOSE 8080 EXPOSE 80/tcp 443/tcp |
ENV | 設置環境變量,在容器運行時可使用 | ENV <key>=<value> ... | ENV APP_NAME=myapp ENV DB_HOST=localhost DB_PORT=5432 |
ADD | 將文件、目錄或遠程文件復制到鏡像中,若復制的是壓縮文件會自動解壓 | ADD <src>... <dest> | ADD app.tar.gz /app ADD http://example.com/file.txt /tmp/ |
COPY | 將文件或目錄從構建上下文復制到鏡像中,不具備自動解壓和遠程文件處理功能 | COPY <src>... <dest> | COPY requirements.txt /app/ |
ENTRYPOINT | 配置容器啟動時執行的命令,可與 CMD 結合使用 | ENTRYPOINT ["executable", "param1", "param2"] (exec 形式)ENTRYPOINT command param1 param2 (shell 形式) | ENTRYPOINT ["python", "app.py"] |
VOLUME | 創建掛載點,用于將主機目錄或數據卷掛載到容器中 | VOLUME ["/data"] | VOLUME ["/var/lib/mysql"] |
USER | 指定后續 RUN 、CMD 和 ENTRYPOINT 指令執行時的用戶和用戶組 | USER <user>[:<group>] | USER myuser |
WORKDIR | 設置工作目錄,后續的 RUN 、CMD 、ENTRYPOINT 、COPY 和 ADD 指令都會在該目錄下執行 | WORKDIR /path/to/workdir | WORKDIR /app |
ARG | 定義構建時的變量,在構建鏡像時可通過 --build-arg 傳遞值 | ARG <name>[=<default value>] | ARG VERSION=1.0 docker build --build-arg VERSION=2.0 . |
ONBUILD | 定義一個觸發器,當該鏡像被用作其他鏡像的基礎鏡像時,這些指令會在后續的 FROM 指令之后執行 | ONBUILD <INSTRUCTION> | ONBUILD COPY . /app |
STOPSIGNAL | 設置停止容器時發送的系統調用信號 | STOPSIGNAL signal | STOPSIGNAL SIGTERM |
HEALTHCHECK | 配置容器的健康檢查命令 | HEALTHCHECK [OPTIONS] CMD <command> HEALTHCHECK NONE | HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1 |
SHELL | 覆蓋默認的 shell 命令,用于 RUN 、CMD 和 ENTRYPOINT 指令的 shell 形式 | SHELL ["executable", "parameters"] | SHELL ["/bin/bash", "-c"] |