iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0
Kubernetes

從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作系列 第 7

Day 07|ConfigMap — 把設定從程式碼中抽離

  • 分享至 

  • xImage
  •  

前言

到目前為止,我們已經完成了 Pod → Service → Ingress 的完整流量路徑。不過,回到實際的應用程式部署,還有另一個重要問題:

應用程式除了接收流量,還需要各種「設定」

想像以下幾種情境:

  • 資料庫連線位址直接寫在程式碼中,切換環境時就必須修改程式並重新建置 Image。
  • 開發環境使用 db-dev.example.com,正式環境使用 db-prod.example.com,每次部署都需要調整設定。
  • 想自訂 NGINX 設定檔,但不希望每次修改設定都重新建置 Container Image。

這些問題其實都指向同一件事:設定與應用程式耦合在一起了

Kubernetes 提供了 ConfigMap 來解決這個問題——將設定從 Container Image 中抽離,並透過環境變數或檔案的方式提供給 Pod 使用。

今天會學:

1. 為什麼設定不該寫死?
2. ConfigMap 是什麼? — 如何建立與使用 ConfigMap
3. 三種使用方式 — 匯入全部環境變數、引用單一 Key、掛載為檔案
4. ConfigMap 更新後,Pod 會自動取得新設定嗎?

以下操作皆在 master 節點 執行。


一、為什麼設定不該寫死在 Image 裡?

問題 寫死在 Image 使用 ConfigMap
換環境(dev → prod) ❌ 修改程式或設定 → 重新 build → 重新 push ✅ 更換對應環境的 ConfigMap
修改設定值 ❌ 通常需要重新建置與部署 Image ✅ 修改 ConfigMap,再依使用方式更新或重啟 Pod
多個服務共用設定 ❌ 每個 Image 都需要各自保存一份設定 ✅ 多個 Pod / Workload 可共用同一份 ConfigMap
設定與 Image 分離 ❌ 設定會跟著 Image 一起打包 ✅ 設定可獨立於 Image 管理

12-Factor App 與設定管理

The Twelve-Factor App 的第三項原則是 Config — 將設定存放於環境中。像資料庫位址、API Endpoint、執行環境等會隨部署環境改變的設定,應與程式碼分離,並透過環境變數或外部設定提供給應用程式。

⚠️ 敏感資訊不應放在 ConfigMap 中。
密碼、API Key、Token、憑證等敏感資料,應使用 Kubernetes Secret 管理。


二、ConfigMap 是什麼?

ConfigMap 是 Kubernetes 用來儲存非機密設定資料的資源物件,內容以 Key-Value 的形式保存

可以將一般設定值、環境變數,甚至整份設定檔存放在 ConfigMap 中,再由 Pod 以環境變數或掛載檔案的方式讀取。

建立方式一:用指令建立

最快的方式,直接用 kubectl create configmap

# 用 --from-literal 直接指定 key=value
kubectl create configmap app-config \
  --from-literal=APP_ENV=production \
  --from-literal=APP_PORT=8080 \
  --from-literal=LOG_LEVEL=info

查看建立的 ConfigMap:

kubectl get configmap app-config -o yaml

會看到 data 欄位裡面就是剛才設定的 Key-Value:

https://ithelp.ithome.com.tw/upload/images/20260809/20181928PiKs5UsT7h.png

建立方式二:用 YAML 檔案建立

當設定比較多的時候,用 YAML 檔案管理更清楚:

vim app-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  APP_ENV: production
  APP_PORT: "8080"
  LOG_LEVEL: info
kubectl apply -f app-config.yaml

建立方式三:從檔案建立

如果有一整份設定檔(例如 nginx.conf),可以直接把檔案內容存進 ConfigMap:

# 建立 NGINX 設定檔
vim my-nginx.conf

vim 中貼上:

server {
    listen 80;
    server_name localhost;

    location / {
        root /usr/share/nginx/html;
        index index.html;
    }

    location /health {
        return 200 'OK';
        add_header Content-Type text/plain;
    }
}

儲存後,再建立 ConfigMap:

# 從檔案建立 ConfigMap
kubectl create configmap nginx-config --from-file=default.conf=my-nginx.conf

查看內容:

kubectl get configmap nginx-config -o yaml

會看到整個檔案內容都被存在 data.default.conf 這個 Key 底下
https://ithelp.ithome.com.tw/upload/images/20260809/20181928Ail8wewKu4.png

--from-file=key=filename 格式說明

key 是 ConfigMap 中的 Key 名稱,filename 則是本機設定檔的路徑。

例如:

--from-file=default.conf=my-nginx.conf

代表將本機的 my-nginx.conf 內容存入 ConfigMap,並以 default.conf 作為 Key。

如果省略 key=,例如 --from-file=my-nginx.conf,ConfigMap 會直接使用檔名 my-nginx.conf 作為 Key。


三、將 ConfigMap 注入 Pod 的三種常見方式

ConfigMap 建立完成後,接下來要讓 Pod 能夠使用其中的設定。常見有三種方式:

方式一:envFrom — 一次匯入所有環境變數

把 ConfigMap 的所有 Key-Value 一次全部 注入為環境變數:

vim pod-envfrom.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-envfrom
spec:
  containers:
  - name: app
    image: nginx
    envFrom:
    - configMapRef:
        name: app-config

先確認 ConfigMap 內容

前面我們已經建立了 app-config ConfigMap,其中包含:

  • APP_ENV=production
  • APP_PORT=8080
  • LOG_LEVEL=info

接下來的 envFrom 會把這些 Key-Value 一次匯入 Pod,作為 Container 的環境變數。

kubectl apply -f pod-envfrom.yaml

驗證環境變數有沒有注入成功:

kubectl exec pod-envfrom -- env | grep -E "APP_|LOG_"

你應該會看到:

https://ithelp.ithome.com.tw/upload/images/20260809/201819289gIaRGxrtP.png

ConfigMap 的所有 Key 都變成環境變數了!

方式二:env.valueFrom — 只引用指定的 Key

如果你只想注入部分 Key,或是想要在 Pod 裡用不同的變數名稱:

vim pod-env.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-env
spec:
  containers:
  - name: app
    image: nginx
    env:
    - name: ENVIRONMENT
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: APP_ENV
    - name: PORT
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: APP_PORT

⚠️ 注意

ConfigMap 的 Key 名稱與 Pod 中的環境變數名稱可以不同。

例如 ConfigMap 裡的 Key 是 APP_ENV,在 Pod 中可以將它命名為 ENVIRONMENT

kubectl apply -f pod-env.yaml

驗證:

kubectl exec pod-env -- env | grep -E "ENVIRONMENT|PORT"

https://ithelp.ithome.com.tw/upload/images/20260809/20181928G4NmdkxdSm.png

方式三:Volume 掛載 — 將 ConfigMap 掛載為檔案

當應用程式需要讀取完整設定檔時,可以將 ConfigMap 透過 Volume 掛載到 Container 中,特別適合 nginx.confapplication.yml 等檔案型設定:

vim pod-volume.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-volume
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: config-volume
      mountPath: /etc/nginx/conf.d
  volumes:
  - name: config-volume
    configMap:
      name: nginx-config
kubectl apply -f pod-volume.yaml

驗證設定檔有沒有掛載成功:

kubectl exec pod-volume -- cat /etc/nginx/conf.d/default.conf

會看到我們之前建立的 NGINX 設定檔內容,包含 /health 路徑的設定。

https://ithelp.ithome.com.tw/upload/images/20260809/20181928lDiLVPDXDZ.png

測試 /health 端點:

kubectl exec pod-volume -- curl -s localhost/health
# → OK

四、ConfigMap 更新後,Pod 會自動拿到新值嗎?

這是一個很常見的問題,答案是:看你用哪種注入方式。

環境變數 — 不會自動更新

修改 ConfigMap:

kubectl edit configmap app-config

LOG_LEVEL 改成 debug,存檔後驗證:

https://ithelp.ithome.com.tw/upload/images/20260809/20181928EWNVVCVJYO.png

kubectl exec pod-envfrom -- env | grep LOG_LEVEL

https://ithelp.ithome.com.tw/upload/images/20260809/20181928gXvvB9rsbh.png

環境變數在 Pod 啟動時就固定了,改 ConfigMap 不會影響已經在跑的 Pod。你需要重啟 Pod 才能拿到新值:

kubectl delete pod pod-envfrom
kubectl apply -f pod-envfrom.yaml
kubectl exec pod-envfrom -- env | grep LOG_LEVEL

https://ithelp.ithome.com.tw/upload/images/20260809/201819282mmlzCm5FK.png

Volume 掛載 — 會自動更新(有延遲)

修改 nginx-config ConfigMap:

kubectl edit configmap nginx-config

/health 的回應改成 Healthy

https://ithelp.ithome.com.tw/upload/images/20260809/20181928yC1wM9QWZG.png

等大約 30 秒到 1 分鐘,再檢查:

kubectl exec pod-volume -- cat /etc/nginx/conf.d/default.conf

會看到檔案內容已經更新了!

https://ithelp.ithome.com.tw/upload/images/20260809/20181928SmYsl7sqq3.png

⚠️ 注意:檔案更新 ≠ 應用程式重新載入

雖然透過 Volume 掛載的 ConfigMap 檔案內容可以自動同步更新,但應用程式不一定會自動重新讀取設定檔。

例如 NGINX 的設定檔更新後,可能還需要:

  • 執行 nginx -s reload,讓 NGINX 重新讀取設定
  • 使用 Sidecar Container 監控設定檔變化,並觸發 reload
  • 或重新啟動 Deployment 中的 Pod,例如執行 kubectl rollout restart deployment <deployment-name>

五、三種使用方式比較

方式 適用場景 ConfigMap 更新後
envFrom 將多個 Key-Value 一次匯入為環境變數 ❌ 已啟動的 Pod 不會自動更新,需重新建立 Pod
env.valueFrom 引用指定 Key,並可自訂環境變數名稱 ❌ 已啟動的 Pod 不會自動更新,需重新建立 Pod
Volume 掛載 將 ConfigMap 內容提供為設定檔 ✅ 掛載內容會自動同步,但可能有延遲

三種方式怎麼選?

  • 一般 Key-Value 設定(例如 APP_ENV=production)→ 使用環境變數,可選擇 envFromenv.valueFrom
  • 完整設定檔(例如 nginx.confredis.conf)→ 使用 Volume 掛載
  • 實際應用中,也可以依需求同時使用環境變數與 Volume 掛載

六、實戰:用 ConfigMap 客製化 NGINX 首頁

前面我們已經分別示範了 ConfigMap 的環境變數與 Volume 掛載方式。

最後透過同一個 Deployment,同時使用這兩種方式:

  • 使用 app-config 將設定注入為環境變數
  • 使用 web-contentindex.html 掛載到 NGINX
  • 分別驗證環境變數與掛載檔案是否成功

建立首頁 ConfigMap

vim web-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: web-content
data:
  index.html: |
    <!DOCTYPE html>
    <html>
    <head><title>Day 7 Demo</title></head>
    <body>
      <h1>Hello from ConfigMap!</h1>
      <p>This page is injected via ConfigMap volume mount.</p>
      <p>Environment: production</p>
    </body>
    </html>

建立使用這個 ConfigMap 的 Deployment:

vim web-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
        envFrom:
        - configMapRef:
            name: app-config
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
      volumes:
      - name: html
        configMap:
          name: web-content

為什麼掛載到 /usr/share/nginx/html

Kubernetes 並沒有規定 ConfigMap 必須掛載到特定路徑,mountPath 可以依應用程式的需求自行指定。

這個範例使用官方 NGINX Image,而 /usr/share/nginx/html 是 NGINX 預設存放靜態網頁內容的目錄。

因此將 web-content ConfigMap 掛載到這個路徑後,其中的 index.html 會出現在 /usr/share/nginx/html/index.html,並成為 NGINX 提供的首頁內容。

套用並測試:

kubectl apply -f web-config.yaml
kubectl apply -f web-deploy.yaml
kubectl expose deployment web-app --port=80

驗證:

# 確認環境變數
kubectl exec deploy/web-app -- env | grep APP_ENV
# → APP_ENV=production

# 確認首頁內容
kubectl exec deploy/web-app -- curl -s localhost
# → Hello from ConfigMap!

https://ithelp.ithome.com.tw/upload/images/20260809/201819282zdAaJNnH4.png


小結

今天我們學會了使用 ConfigMap,將設定從 Container Image 中抽離:

概念 重點 說明
ConfigMap 設定儲存 以 Key-Value 形式儲存非機密的設定資料
envFrom 全部匯入 將 ConfigMap 中的所有 Key-Value 一次匯入為環境變數
env.valueFrom 指定匯入 引用指定的 Key,並可自訂環境變數名稱
Volume 掛載 檔案掛載 將 ConfigMap 內容掛載為檔案,內容更新後可自動同步

ConfigMap 解決了「一般設定」的管理問題,但有些資料並不適合放在 ConfigMap 中。

例如 資料庫密碼、API Key、Token、TLS 憑證等機密資訊,如果直接存放在 ConfigMap,並不是合適的做法。

那這些敏感資料,在 Kubernetes 中應該怎麼管理?

明天我們會接著介紹 Secret,看看 Kubernetes 如何管理機密資訊,以及它和 ConfigMap 有什麼不同!


參考資源


上一篇
Day 06|Ingress — 統一管理外部流量入口
下一篇
Day 08|Secret — 別再把密碼寫進 YAML!Secret 的正確使用方式
系列文
從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言