K8s · 維運與部署 · 第 39 課 · · 9min read

K8s YAML 範例大全:8 大資源完整模板

Pod / Deployment / Service / Ingress / ConfigMap / Secret / PVC / StatefulSet 八大資源各一份完整 YAML 模板,加註解、可直接改,省下查文件的時間。

#Kubernetes #YAML #範例 #模板
章節目錄 · 14

寫 YAML 還在翻文件?

每次寫 \Deployment\ 都要 Google「probe yaml example」?每次寫 \StatefulSet\ 都要看一遍 上篇 12 步部署

這篇給你 8 大資源的完整模板——加註解、可直接抄、改個名字就能用。

建議存到 \~/.kube-templates/\,需要時 \cp\ 一份來改。

---

1. Pod(最簡)

\\\yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod # Pod 名字
labels:
app: demo # 用來給 Service 抓
spec:
containers:
- name: app
image: nginx:1.25 # 永遠不要用 latest
ports:
- containerPort: 80
env:
- name: ENV_VAR
value: "hello"
\
\\

實務上不會直接寫 Pod,都用 Deployment / StatefulSet 包起來。

---

2. Deployment(最常用)

\\\yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: default
labels:
app: my-app
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 滾動時最多多 1 個
maxUnavailable: 0 # 滾動時不允許少 Pod
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-app:1.0
ports:
- containerPort: 8080
env:
- name: ENV
valueFrom:
configMapKeyRef:
name: my-config
key: env
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 5
\
\\

---

3. Service(三種一起給)

\\\yaml
# ClusterIP(叢集內部用)
apiVersion: v1
kind: Service
metadata:
name: my-svc
spec:
type: ClusterIP
selector:
app: my-app
ports:
- port: 80 # Service 對外的 port
targetPort: 8080 # Pod 裡的 port
---
# NodePort(每個 Node 開 port)
apiVersion: v1
kind: Service
metadata:
name: my-svc-nodeport
spec:
type: NodePort
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # 30000-32767 之間
---
# Headless(StatefulSet 用)
apiVersion: v1
kind: Service
metadata:
name: my-headless
spec:
clusterIP: None # 關鍵
selector:
app: my-app
ports:
- port: 80
\
\\

ClusterIP / NodePort / LoadBalancer 差在哪、什麼時候用哪個:Kubernetes NodePort 是什麼?K8s 三種 Service 一張表選對

---

4. Ingress(含 TLS)

\\\yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
cert-manager.io/cluster-issuer: letsencrypt-prod # 用 cert-manager 自動發
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: app-tls
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: frontend-svc
port:
number: 80
\
\\

---

5. ConfigMap

\\\yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-config
data:
# 簡單的鍵值
LOG_LEVEL: "info"
MAX_CONN: "100"

# 整個檔案內容
app.properties: |
server.port=8080
spring.application.name=my-app
\
\\

掛載到 Pod:

\\\yaml
spec:
containers:
- name: app
image: my-app:1.0
envFrom: # 全部變環境變數
- configMapRef:
name: my-config
volumeMounts: # 掛成檔案
- name: config
mountPath: /etc/app/app.properties
subPath: app.properties
volumes:
- name: config
configMap:
name: my-config
\
\\

---

6. Secret

\\\yaml
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
stringData: # 用 stringData,K8s 會自動 Base64
DB_PASSWORD: "supersecret"
API_KEY: "abcdef12345"
\
\\

掛載:

\\\yaml
spec:
containers:
- name: app
image: my-app:1.0
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-secret
key: DB_PASSWORD
\
\\

---

7. PVC

\\\yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce # RWO 最常用(單機讀寫)
resources:
requests:
storage: 10Gi
storageClassName: local-path # k3s 預設;雲端用 gp2 / standard
\
\\

掛到 Pod:

\\\yaml
spec:
containers:
- name: app
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: my-pvc
\
\\

---

8. StatefulSet(DB 用)

\\\yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-headless
spec:
clusterIP: None
selector:
app: mysql
ports:
- port: 3306
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql-headless # 必填
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: rootpw
ports:
- containerPort: 3306
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumeClaimTemplates: # 自動為每個 Pod 建 PVC
- metadata:
name: data
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 10Gi
\
\\

---

Bonus 1:HPA

\\\yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
\
\\

---

Bonus 2:NetworkPolicy

\\\yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-allow-api
spec:
podSelector:
matchLabels:
app: db
policyTypes: [Ingress]
ingress:
- from:
- podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 3306
\
\\

---

Bonus 3:CronJob

\\\yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-backup
spec:
schedule: "0 2 * * *" # 每天凌晨 2 點
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: my-backup:1.0
command: ["/bin/sh", "-c", "backup.sh"]
\
\\

---

YAML 寫作 5 個守則

  • 永遠寫 \apiVersion\ + \kind\——這兩個錯了什麼都不對

  • 永遠不要用 \latest\ tag——升級會莫名其妙

  • \labels\ 跟 \selector.matchLabels\ 必須一致——不然 Service 找不到 Pod

  • \namespace\ 寫清楚——預設 default 容易出意外

  • 加 \resources\ requests/limits——不然 Pod 是 BestEffort,第一個被殺
  • 下一步

    到這裡你已經有完整的 K8s 知識+查表能力了。最後一篇:K8s 學習路線圖 — 從零到生產就緒,告訴你接下來該往哪走。

    📅 最後一篇K8s 學習路線圖:從零到生產就緒
    系列收尾——這 40 篇學完之後,該往 CKAD / 服務網格 / Operator 哪個方向走?
    📚 完整系列總覽K8s 系列教學首頁(共 40 課,按學習路徑順序排)