DaemonSet确保每个(或特定)节点上运行一个Pod副本。节点加入集群时自动创建Pod,节点移除时自动清理。典型场景:日志采集、监控Agent、网络插件。
┌───────── DaemonSet部署模式 ──────────┐
│ │
│ Node1 Node2 Node3 │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ Pod │ │ Pod │ │ Pod │ │
│ │ fluent│ │ fluent│ │ fluent│ │
│ └──────┘ └──────┘ └──────┘ │
│ ↑ ↑ ↑ │
│ ┌──┴────────────┴────────────┴──┐ │
│ │ DaemonSet │ │
│ │ spec.template: fluentd │ │
│ └───────────────────────────────┘ │
│ │
│ 典型用途: │
│ 🔹 日志采集:Fluentd/Filebeat │
│ 🔹 监控Agent:Node Exporter │
│ 🔹 网络插件:Calico/Flannel │
│ 🔹 存储插件:CSI Node Plugin │
│ 🔹 安全Agent:Falco │
└────────────────────────────────────────┘
# daemonset-fluentd.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
namespace: kube-system
labels:
app: fluentd
spec:
selector:
matchLabels:
app: fluentd
# 更新策略
updateStrategy:
type: RollingUpdate # RollingUpdate | OnDelete
rollingUpdate:
maxUnavailable: 1 # 最多1个节点同时更新
# 修订历史限制
revisionHistoryLimit: 10
template:
metadata:
labels:
app: fluentd
spec:
# 容忍Master节点Taint(在Master上也运行)
tolerations:
- key: node-role.kubernetes.io/control-plane
effect: NoSchedule
- key: node-role.kubernetes.io/master
effect: NoSchedule
serviceAccountName: fluentd
containers:
- name: fluentd
image: fluent/fluentd:v1.16
env:
- name: FLUENTD_CONF
value: "fluent.conf"
resources:
limits:
cpu: "200m"
memory: "256Mi"
requests:
cpu: "100m"
memory: "128Mi"
volumeMounts:
- name: varlog
mountPath: /var/log # 宿主机日志目录
- name: containers
mountPath: /var/lib/docker/containers
readOnly: true
- name: config
mountPath: /fluentd/etc
volumes:
- name: varlog
hostPath:
path: /var/log
- name: containers
hostPath:
path: /var/lib/docker/containers
- name: config
configMap:
name: fluentd-config
# ✅ 验证通过
kubectl apply -f daemonset-fluentd.yaml
kubectl get daemonset -n kube-system fluentd
# NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
# fluentd 3 3 3 3 3 <none> 30s
# 每个节点一个Pod
kubectl get pods -n kube-system -l app=fluentd -o wide
# NAME NODE
# fluentd-abc12 k8s-master
# fluentd-def34 k8s-worker1
# fluentd-ghi56 k8s-worker2
# 只在特定标签节点运行
spec:
template:
spec:
nodeSelector:
type: compute # 只在compute节点运行
# 或使用nodeAffinity
spec:
template:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: In
values: [compute, gpu]
# 更新DaemonSet
kubectl set image daemonset/fluentd fluentd=fluent/fluentd:v1.17 -n kube-system
# 查看更新状态
kubectl rollout status daemonset/fluentd -n kube-system
# OnDelete策略:手动删除Pod才触发更新
# spec.updateStrategy.type: OnDelete
kubectl delete pod fluentd-abc12 -n kube-system # 删除后才创建新Pod
# 回滚
kubectl rollout undo daemonset/fluentd -n kube-system
Job创建一个或多个Pod,确保指定数量的Pod成功完成。适用于批处理、数据迁移、备份等一次性任务。
# job-simple.yaml - 一次性任务
apiVersion: batch/v1
kind: Job
metadata:
name: data-migration
spec:
# 完成条件
completions: 1 # 需要成功完成1次
parallelism: 1 # 并行执行1个Pod
backoffLimit: 3 # 最大重试次数
activeDeadlineSeconds: 300 # 最长运行5分钟
ttlSecondsAfterFinished: 86400 # 完成后24小时自动清理
template:
metadata:
name: data-migration
spec:
restartPolicy: Never # Job必须设为Never或OnFailure
containers:
- name: migrate
image: python:3.12-slim
command: ['python', '-c']
args:
- |
import time
print("Starting data migration...")
for i in range(10):
print(f"Processing batch {i+1}/10")
time.sleep(1)
print("Migration completed!")
# ✅ 验证通过
kubectl apply -f job-simple.yaml
kubectl get jobs
# NAME COMPLETIONS DURATION AGE
# data-migration 1/1 12s 30s
kubectl logs job/data-migration
# Starting data migration...
# Processing batch 1/10
# ...
# Migration completed!
# job-parallel.yaml - 并行处理
apiVersion: batch/v1
kind: Job
metadata:
name: batch-process
spec:
completions: 10 # 需要成功完成10次
parallelism: 3 # 同时3个Pod并行
backoffLimit: 6
completionMode: Indexed # NonIndexed|Indexed
template:
spec:
restartPolicy: OnFailure # 失败后重启容器(而非新建Pod)
containers:
- name: worker
image: busybox:1.36
command: ['sh', '-c', 'echo "Worker $JOB_COMPLETION_INDEX processing" && sleep 5']
env:
- name: JOB_COMPLETION_INDEX # Indexed模式自动注入
valueFrom:
fieldRef:
fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
# ✅ 验证通过 - 3个Pod并行,总共10次完成
kubectl apply -f job-parallel.yaml
kubectl get pods -l job-name=batch-process
# NAME READY STATUS RESTARTS AGE
# batch-process-xxx-0 0/1 Completed 0 20s
# batch-process-xxx-1 0/1 Completed 0 20s
# batch-process-xxx-2 0/1 Completed 0 20s
# job-workqueue.yaml - 无需指定completions
apiVersion: batch/v1
kind: Job
metadata:
name: work-queue
spec:
# 不指定completions,由工作队列决定
parallelism: 5
completions: 5 # 每个Pod处理一部分
template:
spec:
restartPolicy: Never
containers:
- name: worker
image: redis:7-alpine
command: ['sh', '-c']
args:
- |
# 从Redis队列取任务
while true; do
task=$(redis-cli -h redis LPOP task_queue)
if [ -z "$task" ]; then
echo "No more tasks, exiting"
break
fi
echo "Processing: $task"
sleep 1
done
# cronjob-backup.yaml - 每天凌晨2点备份数据库
apiVersion: batch/v1
kind: CronJob
metadata:
name: db-backup
spec:
schedule: "0 2 * * *" # Cron格式:分 时 日 月 星期
timeZone: "Asia/Shanghai" # K8s 1.27+支持时区
concurrencyPolicy: Forbid # Allow|Forbid|Replace
successfulJobsHistoryLimit: 3 # 保留3个成功Job
failedJobsHistoryLimit: 1 # 保留1个失败Job
startingDeadlineSeconds: 200 # 错过执行时间的容忍秒数
suspend: false # 暂停执行
jobTemplate:
spec:
backoffLimit: 2
ttlSecondsAfterFinished: 86400
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: mysql:8.0
command: ['sh', '-c']
args:
- |
echo "Starting backup at $(date)"
mysqldump -h mysql-service -u$DB_USER -p$DB_PASS mydb | \
gzip > /backup/db_$(date +%Y%m%d).sql.gz
echo "Backup completed"
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-creds
key: username
- name: DB_PASS
valueFrom:
secretKeyRef:
name: db-creds
key: password
volumeMounts:
- name: backup-volume
mountPath: /backup
volumes:
- name: backup-volume
persistentVolumeClaim:
claimName: backup-pvc
# ✅ 验证通过
kubectl apply -f cronjob-backup.yaml
kubectl get cronjobs
# NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
# db-backup 0 2 * * * False 0 <none> 10s
# 手动触发
kubectl create job --from=cronjob/db-backup manual-backup
| 表达式 | 含义 |
|---|---|
*/5 * * * * | 每5分钟 |
0 * * * * | 每小时整点 |
0 2 * * * | 每天凌晨2点 |
0 0 * * 1 | 每周一零点 |
0 0 1 * * | 每月1号零点 |
0,30 * * * * | 每小时的0分和30分 |
# 排查步骤
# 1. 检查节点Taint
kubectl describe node k8s-worker1 | grep Taints
# Taints: dedicated=special:NoSchedule
# 2. 检查DaemonSet是否有对应Toleration
kubectl get daemonset fluentd -n kube-system -o yaml | grep -A5 tolerations
# 3. 检查nodeSelector
kubectl get daemonset fluentd -n kube-system -o yaml | grep -A3 nodeSelector
# 查看Job状态
kubectl describe job data-migration
# Pods Statuses: 0 Running / 0 Succeeded / 1 Failed
# 查看失败Pod日志
kubectl logs data-migration-xxx --previous
# 常见原因:
# 1. 命令执行失败 → 检查command/args
# 2. backoffLimit已到 → 增大或修复命令
# 3. activeDeadlineSeconds超时 → 增大超时
# 删除失败Job重建
kubectl delete job data-migration
kubectl apply -f job-simple.yaml
# 检查CronJob状态
kubectl describe cronjob db-backup
# 检查Last Schedule和Active Jobs
# 常见原因:
# 1. suspend: true → 改为false
# 2. 时区不对 → 配置timeZone
# 3. concurrencyPolicy: Forbid → 上一个Job还在运行
# 4. schedule格式错误 → 验证cron表达式
下一课预告:第10课深入Ingress流量管理——七层负载均衡与路由规则。