寫 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 找不到 Podnamespace\ 寫清楚——預設 default 容易出意外resources\ requests/limits——不然 Pod 是 BestEffort,第一個被殺下一步
到這裡你已經有完整的 K8s 知識+查表能力了。最後一篇:K8s 學習路線圖 — 從零到生產就緒,告訴你接下來該往哪走。
📅 最後一篇:K8s 學習路線圖:從零到生產就緒
系列收尾——這 40 篇學完之後,該往 CKAD / 服務網格 / Operator 哪個方向走?
📚 完整系列總覽:K8s 系列教學首頁(共 40 課,按學習路徑順序排)