Kubernetes(简称K8s)已成为容器编排领域的事实标准,无论是互联网巨头还是传统企业都在积极拥抱这一技术。K8s的核心价值在于自动化部署、弹性伸缩和故障恢复,而Pod调度策略则是实现这些能力的关键机制。本文将从集群搭建入手,逐步深入Pod调度的各种高级配置。
一、K8s集群架构概述
K8s集群由控制平面(Control Plane)和工作节点(Worker Node)组成。控制平面负责集群的全局决策和事件响应,包括API Server、etcd、Scheduler和Controller Manager。工作节点负责运行Pod,其上运行kubelet、kube-proxy和容器运行时(如containerd)。
在生产环境中,控制平面通常部署3个或5个节点以保证高可用,etcd作为分布式键值存储保存整个集群的状态数据。理解这一架构对于后续的调度策略配置至关重要,因为调度决策正是由控制平面中的Scheduler组件完成的。
二、使用kubeadm快速搭建集群
kubeadm是官方推荐的集群引导工具,可以快速搭建生产级K8s集群。以下是完整的搭建流程:
# 在所有节点上执行的基础配置
# 关闭swap
sudo swapoff -a
sudo sed -i '/swap/d' /etc/fstab
# 加载内核模块
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
# 设置内核参数
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system
# 安装containerd
sudo apt-get update && sudo apt-get install -y containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd
# 安装kubeadm、kubelet、kubectl
sudo apt-get install -y apt-transport-https ca-certificates curl
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
# 在Master节点上初始化集群
sudo kubeadm init \
--apiserver-advertise-address=192.168.1.10 \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/12
# 配置kubectl
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 安装网络插件(Calico)
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27/manifests/calico.yaml
# 在Worker节点上加入集群
sudo kubeadm join 192.168.1.10:6443 \
--token <token> \
--discovery-token-ca-cert-hash <hash>
初始化完成后,通过kubectl get nodes确认所有节点就绪。pod-network-cidr指定Pod网络的IP范围,必须与Calico配置一致。service-cidr则定义Service的虚拟IP范围。
三、节点选择器与亲和性调度
K8s调度器默认将Pod随机分配到可用节点上,但在生产环境中,我们通常需要更精细的控制。nodeSelector是最简单的节点选择方式,而亲和性(Affinity)则提供了更强大的表达能力。
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
# 节点亲和性:优先调度到SSD节点
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: zone
operator: In
values:
- east
- weight: 20
preference:
matchExpressions:
- key: zone
operator: In
values:
- west
containers:
- name: nginx
image: nginx:1.25
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
上述配置中,requiredDuringScheduling表示硬性约束:Pod必须调度到带有disktype=ssd标签的节点上。preferredDuringScheduling表示软性偏好:优先调度到east区域(权重80),其次west区域(权重20)。调度器会综合计算各节点的权重得分,选择最优节点。
四、Pod间亲和与反亲和
除了节点级别的亲和性,K8s还支持Pod间的亲和性(Pod Affinity)和反亲和性(Pod Anti-Affinity)。这对于实现服务的高可用部署至关重要。
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-cluster
spec:
replicas: 3
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
affinity:
# Pod反亲和:确保Redis副本分布在不同节点
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- redis
topologyKey: kubernetes.io/hostname
containers:
- name: redis
image: redis:7.2-alpine
ports:
- containerPort: 6379
这段配置通过podAntiAffinity确保3个Redis副本不会调度到同一个节点上。topologyKey设置为kubernetes.io/hostname意味着以节点为拓扑域。如果改为topology.kubernetes.io/zone,则可以实现跨可用区分布,进一步提升容灾能力。
五、污点与容忍度
污点(Taint)允许节点排斥一类Pod,而容忍度(Toleration)则允许Pod调度到带有特定污点的节点上。这种机制常用于专用节点的管理。
# 给节点打污点,使其只运行特定Pod
kubectl taint nodes gpu-node-01 gpu=true:NoSchedule
# Pod配置容忍度
apiVersion: v1
kind: Pod
metadata:
name: ml-training
spec:
tolerations:
- key: "gpu"
operator: "Equal"
value: "true"
effect: "NoSchedule"
containers:
- name: training
image: tensorflow/tensorflow:2.16.0-gpu
resources:
limits:
nvidia.com/gpu: 1
NoSchedule表示已有Pod不受影响,但新Pod如果没有容忍度则不会调度到该节点。另外两种effect选项:PreferNoSchedule是软性版本,调度器会尽量避免但不强制;NoExecute则会驱逐不存在容忍度的已运行Pod。
六、资源限制与QoS等级
K8s根据Pod的资源请求和限制将其分为三个QoS等级:Guaranteed、Burstable和BestEffort。当节点资源不足时,低QoS等级的Pod会优先被驱逐。
apiVersion: v1
kind: Pod
metadata:
name: critical-service
spec:
containers:
- name: app
image: myapp:latest
# Guaranteed等级:requests和limits完全相等
resources:
requests:
cpu: 1000m
memory: 2Gi
limits:
cpu: 1000m
memory: 2Gi
# 优先级类别
priorityClassName: high-priority
当requests和limits完全相等时,Pod获得Guaranteed等级,具有最高的调度优先级和最低的被驱逐概率。建议为关键服务设置Guaranteed等级,并为非关键服务设置Burstable或BestEffort等级,以实现资源的弹性利用。
七、水平自动伸缩(HPA)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-app
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleUp:
stabilizationWindowSeconds: 30
policies:
- type: Percent
value: 100
periodSeconds: 30
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 50
periodSeconds: 60
HPA根据CPU和内存利用率自动调整Pod副本数量。scaleDown的stabilizationWindowSeconds设置为300秒,意味着Pod数量下降后至少观察5分钟才会继续缩容,避免了流量波动导致的频繁伸缩。scaleUp则更激进,允许30秒内翻倍扩容以快速应对流量突增。
总结
Kubernetes的Pod调度策略是其作为容器编排平台的核心竞争力。通过节点亲和性、Pod反亲和性、污点与容忍度、QoS等级和HPA等机制的组合使用,可以实现精细化的资源分配、高可用部署和弹性伸缩。在实际生产中,建议根据服务的关键性等级制定差异化的调度策略,同时结合监控指标持续优化调度配置,以达到资源利用率和服务稳定性的最佳平衡。