前面的文章已經介紹了 Kubernetes 中常見的資源,例如 Deployment、Service、ConfigMap、Secret,以及如何透過 YAML 管理這些資源。
不過,實際部署應用程式時,通常不會只使用單一資源,而是需要將多個資源組合起來。
接下來三篇將透過一個簡單的 Web API,逐步整合前面學過的 Kubernetes 功能。
這篇先完成以下工作:
首先建立一個資料夾:
k8s-final-demo/
├── app.py
├── requirements.txt
├── Dockerfile
└── k8s/
├── configmap.yaml
├── secret.yaml
├── deployment.yaml
└── service.yaml
這次使用 Python Flask 建立簡單的 HTTP API。
在 app.py 中加入:
from flask import Flask, jsonify
import os
app = Flask(__name__)
@app.route("/")
def index():
return jsonify({
"message": os.getenv("APP_MESSAGE", "Hello Kubernetes"),
"version": "1.0"
})
@app.route("/config")
def config():
return jsonify({
"app_name": os.getenv("APP_NAME", "demo"),
"secret_configured": bool(os.getenv("APP_SECRET"))
})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
這個程式提供兩個 API:
/:回傳應用程式訊息與版本。/config:確認環境變數是否成功載入。其中 os.getenv() 可以取得環境變數,後續會透過 Kubernetes 的 ConfigMap 和 Secret 提供設定。
注意,/config 只回傳 Secret 是否存在,不會直接輸出 Secret 的內容。
接著建立 requirements.txt:
Flask==3.1.1
在專案根目錄建立 Dockerfile:
FROM python:3.13-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]
接著執行:
docker build -t k8s-final-demo:1.0 .
建立完成後,可以透過以下指令查看映像檔:
docker images

由於是使用 Minikube,還需要將映像檔載入 Minikube:
minikube image load k8s-final-demo:1.0
如果使用多節點 Minikube,應確認映像檔已經載入可能執行 Pod 的節點。
ConfigMap 可以將應用程式設定與容器映像檔分開管理。
建立 k8s/configmap.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: final-demo-config
data:
APP_NAME: "Kubernetes Final Demo"
APP_MESSAGE: "Hello from ConfigMap"
這裡設定兩個環境變數:
APP_NAME:應用程式名稱。APP_MESSAGE:API 回傳的訊息。Secret 可以用來保存密碼、Token 等敏感設定。
建立 k8s/secret.yaml:
apiVersion: v1
kind: Secret
metadata:
name: final-demo-secret
type: Opaque
stringData:
APP_SECRET: "demo-secret-123"
這裡使用 stringData,Kubernetes 會將內容轉換成 Secret 的資料格式。
這裡的 Secret 僅供本機實作使用。Kubernetes Secret 並不代表資料一定已加密儲存,正式環境應避免將真實密碼直接提交到版本控制系統,並考慮啟用 Secret 靜態加密及適當的 RBAC 權限控制。
接著建立 k8s/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: final-demo
spec:
replicas: 2
selector:
matchLabels:
app: final-demo
template:
metadata:
labels:
app: final-demo
spec:
containers:
- name: web
image: k8s-final-demo:1.0
imagePullPolicy: Never
ports:
- containerPort: 5000
envFrom:
- configMapRef:
name: final-demo-config
- secretRef:
name: final-demo-secret
這個 Deployment 主要包含:
replicas: 2:建立兩個 Pod 副本。imagePullPolicy: Never:使用節點上已存在的映像檔。containerPort: 5000:應用程式使用的 Port。envFrom:將 ConfigMap 和 Secret 的資料載入容器環境變數。這樣應用程式就不需要將設定直接寫在程式碼中。
Deployment 建立的 Pod 可能因為重新建立或排程而改變 IP,因此需要透過 Service 提供穩定的存取方式。
建立 k8s/service.yaml:
apiVersion: v1
kind: Service
metadata:
name: final-demo-service
spec:
type: ClusterIP
selector:
app: final-demo
ports:
- port: 80
targetPort: 5000
Service 會透過 Label Selector 找到具有 app: final-demo 的 Pod,並將流量轉送到容器的 5000 Port。
這裡先使用 ClusterIP,下一篇再透過 Ingress 提供對外存取方式。
完成 YAML 後,在專案根目錄執行:
kubectl apply -f k8s/
接著查看 Deployment:
kubectl get deployments

查看 Pod:
kubectl get pods -o wide

查看 Service:
kubectl get svc

正常情況下,Deployment 應該建立兩個 Pod,並且都進入 Running 狀態。
如果 Pod 無法啟動,可以使用:
kubectl describe pod <pod-name>
查看 Events,確認是否發生映像檔不存在、資源不足或設定錯誤等問題。
由於 Service 使用 ClusterIP,這裡透過 kubectl port-forward 從本機存取:
kubectl port-forward svc/final-demo-service 8080:80
接著開啟瀏覽器:
http://localhost:8080
會收到類似:
也可以測試:
http://localhost:8080/config
會回傳:

這代表應用程式成功讀取 ConfigMap 與 Secret 提供的環境變數。
可以透過以下指令查看 Service 對應的 EndpointSlice:
kubectl get endpointslices -l kubernetes.io/service-name=final-demo-service
Service 會根據 Label Selector 找到符合條件的 Pod,並透過 EndpointSlice 記錄可用的後端端點。
由於 Deployment 設定了兩個副本,因此在兩個 Pod 都就緒的情況下,Service 可以將連線分配到不同的 Pod。
不過,這個範例的兩個 Pod 回傳相同內容,因此無法直接從 API 回應判斷請求被轉送到哪一個 Pod。
這篇透過簡單的 Web API,整合了前面介紹過的 Deployment、Service、ConfigMap 和 Secret。
在這個範例中:
這些資源共同組成一個簡單的 Kubernetes 應用程式。
目前應用程式還沒有資料持久化功能,Service 也只提供 Cluster 內部存取。
下一篇將在這個基礎上加入 Volume、PVC 和 Ingress,讓應用程式能夠保存資料,並透過 Ingress 存取服務。