目录
前言
在过去十年中,容器技术彻底改变了软件的开发与运维模式。而在众多容器编排工具中,Kubernetes 已经成为事实上的行业标准。无论是个人学习、企业级生产环境,还是云原生生态的探索,几乎所有的容器相关讨论都离不开 Kubernetes。
本篇文章旨在从 零基础到生产落地 全面介绍 Kubernetes 的关键知识点。文章的结构覆盖了从集群部署、Pod 管理、核心控制器,到微服务架构治理、存储系统、网络调度、安全与认证,最后再到最佳实践与经验总结。全文力求为读者提供一份系统化的学习资料。
在写作风格上,我们坚持以下几点:
-
理论结合实战:不仅讲概念,还提供实际的 YAML 与命令示例。
-
结合生产环境:涵盖常见的踩坑经验与企业落地方案。
-
体系化逻辑:让初学者...
第一章:Kubernetes 集群部署
在容器出现之前,应用的部署依赖虚拟机或物理机,环境差异、扩缩容困难、资源浪费等问题频频出现。Docker 的出现解决了"打包"与"一致性运行环境"的问题,但单靠 Docker 无法解决"多容器调度、跨节点管理、自动伸缩"等问题。
Kubernetes 正是为了解决这些挑战而设计的。它是一个开源的容器编排平台,可以自动化容器的部署、伸缩和管理。其核心价值包括:声明式 API、自动调度、弹性伸缩、高可用与自愈、以及丰富的生态系统。
部署方式选择
Kubernetes 集群的部署方式有很多种:
-
Minikube/kind:适合学习和开发环境。
-
kubeadm:官方推荐的生产环境集群安装工具。
-
云托管服务:如阿里云 ACK、AWS EKS、Google GKE、Azure AKS,适合不想自己运维控制平面的企业。
kubeadm 部署生产集群
对于生产环境,kubeadm 是官方推荐的标准工具。它能快速初始化 Master 节点,并加入 Worker 节点。
kubeadm init --pod-network-cidr=10.244.0.0/16
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
随后需要部署网络插件,如 Flannel 或 Calico:
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
第二章:Pod 管理
Pod 是 Kubernetes 部署应用程序的基本单元,也是 Kubernetes 中最小的可部署对象。一个 Pod 封装了一个或多个应用程序容器(例如 Docker),以及存储资源、唯一的网络 IP 和控制这些容器如何运行的选项。
2.1 Pod 简介与生命周期
Pod 是 Kubernetes 集群中运行的最小、最基本的部署单元。它是一组紧密耦合的容器,共享网络和存储资源。
-
Pod 与容器的关系:Pod 就像一个"盒子",里面可以装一个或多个容器。这些容器共享同一个网络命名空间(即共享 IP 和端口)和存储卷。
-
Pod 的生命周期:Pod 有一个定义明确的生命周期,从创建到终止。当 Pod 创建后,它会进入以下五种主要状态之一:
-
Pending
(挂起):Pod 已经被 Kubernetes 系统接受,但 Pod 内的一个或多个容器的镜像尚未被拉取,或者 Pod 尚未被调度到合适的节点。 -
Running
(运行中):Pod 已经被绑定到节点上,Pod 内的所有容器都已被创建。至少有一个容器正在运行,或者正在启动或重启。 -
Succeeded
(成功):Pod 内所有容器都已经成功终止,并且不会再重启。 -
Failed
(失败):Pod 内所有容器都已经终止,但至少有一个容器是因失败而终止。 -
Unknown
(未知):由于某种原因,Pod 的状态无法获取。通常是由于与 Pod 所在节点通信失败。
-
2.2 Pod 的资源管理与 QoS
在生产环境中,合理地管理 Pod 的资源至关重要。Kubernetes 提供了 requests
和 limits
两个字段来管理 Pod 的 CPU 和内存资源。
-
requests
(请求):-
用途 :指定容器所需的最小资源量。调度器(
kube-scheduler
)在为 Pod 选择节点时,会根据节点的可用资源和 Pod 的requests
值来判断是否可以调度。 -
影响 :如果一个节点没有足够的可用资源来满足 Pod 的
requests
,该 Pod 将不会被调度到该节点。
-
-
limits
(限制):-
用途:指定容器可以使用的最大资源量。这是一个硬性限制,容器的资源使用量不能超过这个值。
-
影响:
-
CPU :如果容器的 CPU 使用量超过
limits
,它将被限流(throttled)。 -
内存 :如果容器的内存使用量超过
limits
,它将被终止(OOMKilled)。
-
-
基于 requests
和 limits
的设置,Kubernetes 会为 Pod 分配一个 QoS(服务质量) 等级,这会影响 Pod 在资源紧张时的行为:
-
Guaranteed(有保证的) :当 Pod 的所有容器都同时设置了
requests
和limits
,并且requests
的值等于limits
。这种 Pod 的服务质量最高,最不容易被驱逐。 -
Burstable(可突增的) :当 Pod 内至少有一个容器的
requests
小于limits
,且至少有一个容器设置了requests
。这类 Pod 在资源紧张时可能会被优先驱逐。 -
BestEffort(尽力而为的) :当 Pod 内所有容器都没有设置
requests
和limits
。这类 Pod 的服务质量最低,会在资源紧张时最先被驱逐。
2.3 多容器 Pod 设计模式
一个 Pod 中可以包含一个或多个容器。通常,这些容器会协同工作以完成一个特定的功能。其中最常见的设计模式是 Sidecar(边车) 模式。
-
Sidecar 模式:
-
用途:将与主容器相关联的辅助功能(如日志收集、监控代理、配置同步等)封装在一个独立的容器中。
-
优点:降低了主容器的复杂度,实现了关注点分离,使得辅助功能可以独立升级和复用。
-
示例:一个 Web 应用容器和一个日志收集 Sidecar 容器。日志收集器专门负责将 Web 应用产生的日志发送到日志系统中。
apiVersion: v1
kind: Pod
metadata:
name: my-sidecar-pod
spec:
containers:- name: main-app-container # 主容器
image: my-web-app:1.0
resources:
limits:
memory: "128Mi"
cpu: "500m" - name: log-sidecar-container # 边车容器
image: fluentd:v1.14
resources:
limits:
memory: "64Mi"
cpu: "250m"
volumeMounts:- name: logs
mountPath: /var/log/my-app
volumes:
- name: logs
- name: logs
emptyDir: {} # 共享的临时存储卷
- name: main-app-container # 主容器
-
2.4 Pod 的探针(Probes)
为了确保应用程序的健康和可用性,Kubernetes 提供了三种探针:
-
Liveness Probe(存活探针):
-
用途:用于判断容器是否存活。如果 Liveness Probe 失败,Kubernetes 会杀死该容器并根据重启策略进行重启。
-
配置:可以基于 HTTP 请求、TCP 端口或命令行执行来判断。
-
示例:当容器无法响应 HTTP 请求时,表示应用可能出现死锁或不可用,Liveness Probe 失败。
-
-
Readiness Probe(就绪探针):
-
用途:用于判断容器是否已经准备好处理请求。如果 Readiness Probe 失败,Service 的 Endpoints 将不会包含该 Pod 的 IP,流量不会被转发到这个 Pod。
-
配置:与 Liveness Probe 类似,可基于 HTTP 请求、TCP 或命令行执行。
-
示例:应用程序启动需要加载大量数据或初始化,此时 Readiness Probe 会失败,直到应用准备好后再开始接受流量。
-
-
Startup Probe(启动探针):
-
用途:用于判断容器内的应用是否已启动。如果配置了 Startup Probe,其他探针(如 Liveness、Readiness)会暂停执行,直到 Startup Probe 成功。
-
配置:当容器中的应用启动时间较长时非常有用。
-
2.5 Pod 的重启策略(Restart Policy)
restartPolicy
字段定义了在容器终止后如何重启容器。该字段只能用于 Pod。
-
Always
:默认值。如果容器终止,kubelet 将总是重启它。适用于Deployment
、ReplicaSet
等控制器管理的服务。 -
OnFailure
:只有在容器以非零状态码退出时才重启。适用于Job
等批处理任务。 -
Never
:无论容器如何终止,都不会重启它。也适用于Job
。
2.6 Pod 的调度
Pod 的调度是由 kube-scheduler
负责的,它会根据各种约束和资源需求(如 CPU、内存)为 Pod 找到最合适的节点。
2.7 Pod 的存储与配置管理
为了实现数据持久化和灵活的配置管理,Pod 可以使用各种类型的卷(Volume),并与 ConfigMap
和 Secret
资源进行集成。
-
emptyDir
:-
用途 :提供一个临时的、与 Pod 生命周期绑定的存储卷。当 Pod 被删除时,
emptyDir
中的数据也会被永久删除。 -
使用场景:
-
存储需要被多个容器共享的临时文件。
-
用作缓存空间。
-
在多容器 Pod 中传递数据。
-
-
-
ConfigMap
(配置字典):-
用途:将非敏感的配置数据(如环境变量、命令行参数或配置文件)注入到 Pod 中。
-
优点:将配置与应用镜像解耦,使得配置修改无需重建镜像。
-
-
Secret
(保密字典):-
用途:用于存储敏感数据,如密码、API 密钥、Token 或私钥。
-
优点 :与
ConfigMap
类似,但提供了更好的加密和安全机制。
-
示例:Pod 如何使用 ConfigMap 和 Secret
首先,创建 ConfigMap 和 Secret:
# 创建一个名为 'app-config' 的 ConfigMap
kubectl create configmap app-config --from-literal=APP_COLOR=blue --from-literal=APP_ENV=production
# 创建一个名为 'app-secret' 的 Secret
kubectl create secret generic app-secret --from-literal=DB_PASSWORD=my_secret_password
然后,创建一个 Pod 来使用这些配置:
apiVersion: v1
kind: Pod
metadata:
name: config-secret-pod
spec:
containers:
- name: my-app-container
image: my-web-app:1.0
env: # 从 ConfigMap 和 Secret 获取环境变量
- name: APP_COLOR
valueFrom:
configMapKeyRef:
name: app-config
key: APP_COLOR
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secret
key: DB_PASSWORD
volumeMounts: # 将 ConfigMap 作为文件挂载
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-config
在上述示例中:
-
APP_COLOR
环境变量从app-config
ConfigMap 中获取。 -
DB_PASSWORD
环境变量从app-secret
Secret 中获取。 -
整个
app-config
ConfigMap 被挂载为一个卷,里面的键值对会变成文件,放在 Pod 里的/etc/config
目录下。
第三章:核心控制器
控制器是 Kubernetes 的"大脑",负责监控对象状态,并让实际状态与期望状态保持一致。
3.1 什么是控制器
控制器是管理 Pod 的中间层。它会创建满足条件的 Pod,并确保每一个 Pod 资源处于用户期望的目标状态。当 Pod 资源在运行中出现故障,控制器会基于指定策略重新编排 Pod。
3.2 常用控制器类型
|-----------------|---------------------------------------------|
| 控制器名称 | 控制器用途 |
| ReplicaSet | 确保任何时间都有指定数量的 Pod 副本在运行。 |
| Deployment | 提供声明式的更新能力,是管理无状态应用的首选。 |
| DaemonSet | 确保在每个(或指定)节点上运行一个 Pod 副本。 |
| StatefulSet | 管理有状态应用的工作负载,提供稳定的网络标识和持久存储。 |
| Job | 执行批处理任务,仅执行一次任务,保证任务的一个或多个 Pod 成功结束。 |
| CronJob | 创建基于时间调度的 Jobs。 |
| HPA | 根据资源利用率自动调整 Service 中 Pod 数量,实现 Pod 水平自动缩放。 |
3.3 ReplicaSet 控制器
-
ReplicaSet 是下一代 Replication Controller,官方推荐使用。
-
它确保任何时间都有指定数量的 Pod 副本在运行。
-
通常由 Deployment 用来协调 Pod 的创建、删除和更新。
ReplicaSet YAML 示例:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: my-replicaset
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-container
image: nginx:latest
命令 :将上述 YAML 保存为 my-replicaset.yaml
,然后执行以下命令创建 ReplicaSet。
kubectl apply -f my-replicaset.yaml
3.4 Deployment 控制器
-
Deployment 是管理无状态应用的控制器,用于声明式地管理 Pod 和 ReplicaSet。
-
核心功能:Deployment 可以控制应用的滚动更新和回滚。它会自动创建新的 ReplicaSet 来管理新版本的 Pod,并逐步减少旧 ReplicaSet 管理的 Pod 数量,从而实现平滑无缝的更新。
-
使用场景:绝大多数无状态服务,如 Web 服务器、API 网关、微服务等。
Deployment YAML 示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3 # 期望的 Pod 副本数量
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
命令 :将上述 YAML 保存为 nginx-deployment.yaml
,然后执行以下命令创建 Deployment。
kubectl apply -f nginx-deployment.yaml
更新镜像:
kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1 --record
3.5 DaemonSet 控制器
-
DaemonSet 确保所有(或特定)节点上都运行一个 Pod 副本。
-
核心功能:当一个节点被加入集群时,DaemonSet 会自动在该节点上创建 Pod。当节点从集群中移除时,DaemonSet 会清理相应的 Pod。
-
使用场景:在每个节点上运行日志收集器(如 Fluentd)、监控代理(如 Prometheus Node Exporter)、集群存储守护进程等。
DaemonSet YAML 示例:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-daemonset
spec:
selector:
matchLabels:
name: fluentd
template:
metadata:
labels:
name: fluentd
spec:
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: fluentd
image: fluent/fluentd-kubernetes-daemonset:v1.14-debian-fluentd
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
命令 :将上述 YAML 保存为 fluentd-daemonset.yaml
,然后执行以下命令创建 DaemonSet。
kubectl apply -f fluentd-daemonset.yaml
3.6 StatefulSet 控制器
-
StatefulSet 用于管理有状态应用,如数据库(MySQL, PostgreSQL)或消息队列(Kafka)。
-
核心功能:
-
稳定的网络标识:每个 Pod 拥有一个唯一的、稳定的主机名和网络标识符,即使 Pod 重启或迁移,其网络标识符也不会改变。
-
稳定的持久存储 :每个 Pod 拥有一个唯一的、与之绑定的
PersistentVolumeClaim
(PVC),确保数据持久化。 -
有序的部署和扩展 :Pod 的创建和删除是按顺序进行的。例如,Pod
web-0
、web-1
、web-2
会按此顺序创建,保证了依赖关系。
-
-
使用场景:数据库、有状态缓存、分布式文件系统等。
StatefulSet YAML 示例:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: k8s.gcr.io/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
命令 :将上述 YAML 保存为 nginx-statefulset.yaml
,然后执行以下命令创建 StatefulSet。
kubectl apply -f nginx-statefulset.yaml
3.7 Job 和 CronJob 控制器
-
Job:用于执行一次性、批处理任务。Job 会确保其下的 Pod 成功完成任务,如果 Pod 失败,Job 会根据策略重新创建新的 Pod,直到任务完成。
-
CronJob :用于定时执行任务。它类似于 Linux 中的
crontab
,可以按照指定的时间表创建 Job。 -
使用场景:
-
Job:数据迁移、离线数据处理、脚本执行等。
-
CronJob:数据库备份、报告生成、定时发送邮件等。
-
Job YAML 示例:
apiVersion: batch/v1
kind: Job
metadata:
name: pi-job
spec:
completions: 1
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
命令 :将上述 YAML 保存为 pi-job.yaml
,然后执行以下命令创建 Job。
kubectl apply -f pi-job.yaml
CronJob YAML 示例:
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello-cronjob
spec:
schedule: "*/1 * * * *" # 每分钟执行一次
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
command: ["sh", "-c", "echo 'Hello from the Kubernetes CronJob'"]
restartPolicy: OnFailure
命令 :将上述 YAML 保存为 hello-cronjob.yaml
,然后执行以下命令创建 CronJob。
kubectl apply -f hello-cronjob.yaml
第四章:微服务与应用治理
4.1 Service 基础
-
Service 是一组提供相同服务的 Pod 对外开放的接口,用于服务发现和负载均衡。
-
它默认只支持四层负载均衡能力,没有七层功能。(可通过 Ingress 实现)
|------------------|-------------------------------|
| 微服务类型 | 作用描述 |
| ClusterIP | 默认值,只能在集群内部访问。 |
| NodePort | 将 Service 通过指定节点上的端口暴露给外部。 |
| LoadBalancer | 借助云提供商创建外部负载均衡器,只能在云服务器上使用。 |
| ExternalName | 将服务通过 DNS CNAME 记录方式转发到指定的域名。 |
Deployment 和 Service 示例:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: timinglee
name: timinglee
spec:
replicas: 2
selector:
matchLabels:
app: timinglee
template:
metadata:
creationTimestamp: null
labels:
app: timinglee
spec:
containers:
- image: myapp:v1
name: myapp
---
apiVersion: v1
kind: Service
metadata:
labels:
app: timinglee
name: timinglee
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: timinglee
命令 :将上述 YAML 保存为 deployment-service.yaml
,然后执行以下命令创建 Deployment 和 Service。
kubectl apply -f deployment-service.yaml
4.2 Ingress 基础
-
Ingress 提供七层(HTTP/HTTPS)负载均衡,是微服务对外的统一入口。
-
它可以在根据不同的主机名或路径将请求路由到不同的后端 Service。
Ingress 示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: my-app.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /web
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
命令 :将上述 YAML 保存为 my-app-ingress.yaml
,然后执行以下命令创建 Ingress 规则。
kubectl apply -f my-app-ingress.yaml
4.3 IPVS 模式
-
IPVS 模式是 Service 的一种高性能实现方式,可以替代传统的
iptables
模式。 -
当集群中存在大量 Pod 时,
iptables
会导致规则链过长,消耗大量 CPU 资源。 -
IPVS 模式的 Service 可以支持更多量级的 Pod,并通过
ipvsadm
命令查看规则。
配置方式:
-
在所有节点安装
ipvsadm
。 -
修改
kube-proxy
配置,将mode
设为ipvs
。 -
重启
kube-proxy
Pod 使配置生效。
第五章:集群存储
在容器化环境中,应用的生命周期通常是短暂的、无状态的。这意味着当 Pod 被删除或重启时,其内部产生的数据会随之丢失。为了解决这个问题,Kubernetes 提供了强大的存储抽象层,用于将数据与应用的生命周期解耦,从而实现数据的持久化和共享。
5.1 PV、PVC 与 StorageClass 详解
Kubernetes 存储系统的核心是三个解耦概念,它们完美地实现了存储的管理与使用分离:
-
PersistentVolume (PV):持久卷。PV 是集群中的一块存储资源,由管理员预先配置(静态供应)或由 StorageClass 动态创建(动态供应)。它代表了底层的实际存储,如云盘、NFS 共享目录或本地磁盘。PV 独立于 Pod 的生命周期,即使 Pod 被删除,PV 及其数据依然存在。
# 静态创建的 PV 示例 apiVersion: v1 kind: PersistentVolume metadata: name: my-pv-nfs spec: capacity: storage: 5Gi volumeMode: Filesystem accessModes: - ReadWriteMany # 允许多个 Pod 以读写模式挂载 persistentVolumeReclaimPolicy: Retain storageClassName: nfs-storage nfs: path: /data/volumes server: 192.168.1.100
命令 :将上述 YAML 保存为
my-pv-nfs.yaml
,然后执行以下命令创建 PV。kubectl apply -f my-pv-nfs.yaml
-
PersistentVolumeClaim (PVC) :持久卷申请。PVC 是用户对存储资源的"申请"。用户无需关心底层的存储细节,只需在 PVC 中声明所需的存储大小(
capacity
)、访问模式(accessModes
)和存储类别(storageClassName
)。PVC 会自动在集群中寻找并绑定符合要求的 PV。# PVC 示例,申请 2GB 读写权限的存储 apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc spec: accessModes: - ReadWriteOnce # 只允许单个 Pod 读写挂载 resources: requests: storage: 2Gi storageClassName: my-storage-class
命令 :将上述 YAML 保存为
my-pvc.yaml
,然后执行以下命令创建 PVC。kubectl apply -f my-pvc.yaml
-
StorageClass:存储类别。StorageClass 扮演着"模板"的角色,定义了存储的"类别"和配置参数。它封装了底层存储的动态供应逻辑,例如,当用户申请一个 PVC 时,Kubernetes 会根据 PVC 中指定的 StorageClass,自动调用相应的驱动程序(如云厂商的 CSI 驱动)创建并绑定一个符合要求的 PV,从而实现存储的自动化管理。
5.2 存储卷类型(Volume)与使用场景
Kubernetes 支持多种内置存储卷类型,每种都有其特定的用途:
-
emptyDir
:临时存储卷。当 Pod 被创建时,emptyDir
卷被初始化,其生命周期与 Pod 一致。Pod 被删除后,卷中的数据也会被永久删除。它非常适合用于存放临时数据、缓存或在多容器 Pod 中共享文件。 -
hostPath
:将节点文件系统上的一个目录挂载到 Pod 中。hostPath
卷会带来安全隐患和可移植性问题(因为 Pod 依赖于特定节点),通常只在特殊场景下使用,例如需要访问节点上的日志文件或配置。 -
nfs
:网络文件系统(NFS)。允许 Pod 挂载一个远程 NFS 共享目录。这是一种常用的共享存储方案,允许多个 Pod 共享同一份数据。 -
ConfigMap
/Secret
:这两种卷类型用于将配置数据或敏感信息(如密码、API 密钥)作为文件或环境变量注入到 Pod 中。它们是 Pod 依赖外部配置的声明式、安全的方式。
5.3 动态存储供应与 CSI
在早期,Kubernetes 需要手动创建 PV,这被称为静态供应。为了解决这个问题,社区引入了动态存储供应(Dynamic Provisioning),它通过 StorageClass 和 CSI(Container Storage Interface)驱动程序实现了存储的自动化创建。
CSI 是一个行业标准的接口,它允许存储厂商为 Kubernetes 开发自己的存储插件。通过 CSI 驱动,Kubernetes 可以无缝地与各种云存储(如 AWS EBS、Google GCE PD)和企业级存储系统集成,实现按需创建 PV。
5.4 共享存储与访问模式
PV 的访问模式(accessModes
)决定了 Pod 如何使用它:
-
ReadWriteOnce (RWO)
:只允许一个节点以读写模式挂载。这是最常见的模式,适用于大多数单 Pod 运行的应用。 -
ReadOnlyMany (ROM)
:允许多个节点以只读模式挂载。适合于静态内容分发或公共数据集。 -
ReadWriteMany (RWX)
:允许多个节点以读写模式挂载。通常由共享文件系统(如 NFS、GlusterFS)支持,适用于需要多 Pod 协同写入的场景。
5.5 存储快照与克隆
Kubernetes 存储还支持数据管理功能,如快照(Snapshot)和克隆(Clone)。
-
卷快照:可以创建某个时间点上的 PV 数据副本。快照可以用于数据备份、灾难恢复或创建新的开发/测试环境。
-
卷克隆:可以从现有的 PV 或快照创建一个新的 PVC,从而快速复制数据。这对于快速部署具有相同初始数据的多个应用非常有用。
5.6 生产环境存储实践
在生产环境中,选择和管理存储应遵循以下原则:
-
优先使用动态供应:避免手动创建 PV,通过 StorageClass 和 CSI 驱动实现存储的自动化。
-
理解访问模式 :根据应用需求选择合适的访问模式。对于数据库等有状态应用,通常需要
ReadWriteOnce
。 -
利用 StatefulSet :对于需要稳定网络标识和持久存储的应用,如数据库或消息队列,应使用
StatefulSet
来管理,因为它能确保每个 Pod 都有一个独有的、稳定的 PVC。 -
备份与恢复:为关键应用配置卷快照和备份策略,确保数据安全。
第六章:集群网络与调度
6.1 集群网络模型与 CNI
Kubernetes 遵循一个扁平的网络模型,这是其最核心的网络设计理念。这个模型对网络插件(CNI)提出了严格的要求:
-
Pod-to-Pod:集群中所有 Pod,无论是否在同一节点上,都能在无需 NAT(网络地址转换)的情况下直接相互通信。每个 Pod 拥有一个独立的 IP 地址。
-
Node-to-Pod:节点上的组件(如 kubelet)可以直接与 Pod 通信。
-
External-to-Service:外部流量可以访问集群内的 Service,并被路由到正确的 Pod。
为了实现这一模型,Kubernetes 引入了 CNI (Container Network Interface) 接口规范。CNI 是一种协议,定义了容器运行时如何与网络插件进行交互。常见的 CNI 插件包括:
-
Flannel :最简单、轻量级的 CNI 之一,主要用于解决跨节点 Pod 通信问题。它通过Overlay Network(如 VXLAN)创建一个虚拟网络,将跨节点的 Pod 网络流量进行封装和解封装,使其看起来像是在一个扁平网络中。Flannel 配置简单,但性能相对较低。
-
Calico :功能强大的 CNI,不使用 Overlay 网络,而是依赖标准的**BGP(边界网关协议)在节点间路由流量。Calico 性能更高,更重要的是,它提供了强大的网络策略(NetworkPolicy)**功能,允许用户定义细粒度的 Pod 间流量规则,实现网络隔离和安全。
-
Cilium :基于 eBPF 技术的新一代 CNI。eBPF 允许在 Linux 内核中运行沙箱程序,Cilium 利用此技术实现了高性能的网络与安全功能,包括高效的负载均衡、网络策略和可观测性。
6.2 Pod 调度机制
kube-scheduler 是 Kubernetes 的调度器,其核心职责是为新创建的、尚未指定运行节点的 Pod 寻找一个最佳的节点。其工作流程分为两个阶段:
-
预选(Predicates):也称为**过滤(Filtering)**阶段。调度器会遍历集群中的所有节点,根据 Pod 的硬性要求(如资源需求、节点亲和性、污点容忍等)来过滤掉不符合条件的节点。只有通过所有预选条件的节点才能进入下一个阶段。
常见的预选条件包括:
-
PodFitsHostPorts: 检查节点上是否有 Pod 所需的端口。
-
PodFitsResources: 检查节点是否有足够的 CPU 和内存资源。
-
MatchNodeSelector : 检查节点标签是否与 Pod 的
nodeSelector
匹配。 -
PodToleratesTaints: 检查 Pod 是否能容忍节点上的污点。
-
-
优选(Priorities):也称为**打分(Scoring)**阶段。调度器会对所有通过预选的节点进行打分,分数越高代表越适合调度。打分基于一系列内置或自定义的优选函数。
常见的优选函数包括:
-
LeastRequestedPriority: 倾向于将 Pod 调度到请求资源最少的节点上,以实现更均衡的资源利用率。
-
BalancedResourceAllocation: 倾向于将 Pod 调度到 CPU 和内存资源利用率最均衡的节点上。
-
ImageLocalityPriority: 倾向于将 Pod 调度到已经缓存了所需容器镜像的节点上,以减少镜像拉取时间。
-
6.3 调度约束与高级特性
为了更精细地控制 Pod 的调度行为,Kubernetes 提供了多种调度约束机制。
-
节点选择器(
nodeSelector
) :最简单的调度方式。它通过匹配 Pod 的nodeSelector
和节点的标签,将 Pod 调度到指定的节点上。apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: nginx nodeSelector: disktype: ssd # Pod 只会调度到带有 disktype=ssd 标签的节点上
命令 :将上述 YAML 保存为
my-pod-nodeselector.yaml
,然后执行以下命令创建 Pod。kubectl apply -f my-pod-nodeselector.yaml
命令 :为节点添加标签,以供
nodeSelector
匹配。kubectl label nodes <your-node-name> disktype=ssd
-
节点亲和性(Node Affinity) :比
nodeSelector
更灵活,提供了软硬两种规则:-
硬亲和性(
requiredDuringSchedulingIgnoredDuringExecution
) :在调度时必须满足条件。如果无法满足,Pod 将不会被调度。 -
软亲和性(
preferredDuringSchedulingIgnoredDuringExecution
) :在调度时尽量满足条件,但即使无法满足也可以调度。apiVersion: v1
kind: Pod
metadata:
name: my-pod-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
命令 :将上述 YAML 保存为
my-pod-affinity.yaml
,然后执行以下命令创建 Pod。kubectl apply -f my-pod-affinity.yaml
-
-
污点与容忍(Taints & Tolerations):这是一种"排斥"和"容忍"的机制。
-
Taint:标记节点,使其"排斥"某些 Pod。例如,可以为专用于数据库的节点添加污点,防止其他应用调度上来。
-
Toleration:在 Pod 上配置,使其能够"容忍"某个污点。只有带有相应容忍的 Pod 才能被调度到有污点的节点上。
为 node1 添加一个污点,key=app, value=critical, 效果=NoSchedule(不调度)
kubectl taint node node1 app=critical:NoSchedule
apiVersion: v1
kind: Pod
metadata:
name: my-critical-pod
spec:
containers:
-
name: my-container
image: nginx
tolerations:
-
key: "app"
operator: "Equal"
value: "critical"
effect: "NoSchedule" # 容忍上面的污点
命令:将上述 YAML 保存为
my-critical-pod.yaml
,然后执行以下命令创建 Pod。
kubectl apply -f my-critical-pod.yaml
-
-
Pod 亲和性与反亲和性(Pod Affinity/Anti-Affinity):允许 Pod 根据集群中已有的其他 Pod 的标签来调度。
-
亲和性:将 Pod 调度到与指定 Pods 位于同一拓扑域(如同一节点、同一可用区)的节点上。
-
反亲和性:将 Pod 调度到远离指定 Pods 的节点上,用于实现高可用性。
-
第七章:集群认证与安全
Kubernetes 作为一个复杂的分布式系统,其安全模型至关重要。它旨在确保只有经过认证和授权的合法用户或组件才能访问集群资源,并限制 Pod 之间的网络通信,从而构建一个多租户、高可用的安全环境。Kubernetes 的安全体系主要围绕四个核心方面展开:认证(Authentication)、授权(Authorization)、准入控制(Admission Control)和网络策略(NetworkPolicy)。
7.1 认证 (Authentication)
认证是用户或组件访问集群的第一步,用于验证其身份。Kubernetes API Server 支持多种认证方式:
-
客户端证书 (Client Certificates):这是最常见的认证方式。当集群初始化时,API Server 会生成一个 CA 证书。所有需要访问 API Server 的组件(如 kubelet、kube-proxy)或用户都可以使用由该 CA 签发的证书进行认证。
- 工作原理:API Server 验证客户端证书,如果证书有效,会从证书中的 CN(Common Name)字段提取用户名,从 O(Organization)字段提取用户组。
-
服务账号 (Service Account):用于 Pod 内进程的认证。当 Pod 创建时,Kubernetes 会自动为它分配一个 Service Account。这个 Service Account 包含一个 JWT (JSON Web Token),Pod 内的容器可以使用这个 Token 访问 API Server。Service Account 的权限通常是最小化的,遵循"最小权限原则"。
-
Bearer Token:常用的认证方式,如 Service Account 的 JWT Token。
-
OpenID Connect (OIDC):允许 Kubernetes 与外部身份提供商(如 Google、Azure AD、Okta 等)集成,实现单点登录(SSO)。
7.2 授权 (Authorization)
授权是在认证通过后,决定用户或组件是否有权对特定资源执行特定操作的过程。Kubernetes 最推荐的授权机制是 RBAC (Role-Based Access Control)。
RBAC 通过以下四个核心资源来工作:
-
Role (角色) :定义了一组对特定命名空间内资源的权限规则。例如,一个
dev-role
可能被授予对default
命名空间下 Pods 和 Deployments 的读写权限。apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: default name: dev-role rules: - apiGroups: ["", "apps"] resources: ["pods", "deployments"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
命令 :将上述 YAML 保存为
dev-role.yaml
,然后执行以下命令创建 Role。kubectl apply -f dev-role.yaml
-
ClusterRole (集群角色) :与 Role 类似,但其权限范围是整个集群,不限于某个命名空间。例如,
cluster-admin
ClusterRole 拥有对所有集群资源的完全权限。apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: pod-reader rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "watch", "list"]
命令 :将上述 YAML 保存为
pod-reader-clusterrole.yaml
,然后执行以下命令创建 ClusterRole。kubectl apply -f pod-reader-clusterrole.yaml
-
RoleBinding (角色绑定):将一个 Role 的权限授予一个或多个用户、组或 Service Account,且权限范围仅限于 Role 所在的命名空间。
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: dev-binding namespace: default subjects: - kind: User name: dev-user apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: dev-role apiGroup: rbac.authorization.k8s.io
命令 :将上述 YAML 保存为
dev-rolebinding.yaml
,然后执行以下命令创建 RoleBinding。kubectl apply -f dev-rolebinding.yaml
-
ClusterRoleBinding (集群角色绑定):将一个 ClusterRole 的权限授予用户、组或 Service Account,权限范围覆盖整个集群。
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: read-pods-global subjects: - kind: Group name: dev-group apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: pod-reader apiGroup: rbac.authorization.io
命令 :将上述 YAML 保存为
pod-reader-clusterrolebinding.yaml
,然后执行以下命令创建 ClusterRoleBinding。kubectl apply -f pod-reader-clusterrolebinding.yaml
最佳实践:为了提高安全性,应遵循"最小权限原则",只授予用户执行其任务所需的最小权限。
7.3 准入控制 (Admission Control)
准入控制器是一组在对象持久化到 etcd 之前,对 API Server 请求进行拦截的插件。它可以对请求进行修改(Mutation)或验证(Validation)。
-
ValidatingAdmissionWebhook
:允许通过 Webhook 调用的外部服务来对 API Server 的请求进行验证。例如,可以编写一个 Webhook,强制所有 Pod 都必须包含某个特定的标签。 -
MutatingAdmissionWebhook
:允许通过 Webhook 调用的外部服务来对 API Server 的请求进行修改。例如,可以编写一个 Webhook,自动为所有新创建的 Pod 注入一个 sidecar 容器。 -
PodSecurityPolicy
(PSP) :虽然已废弃,但其理念依然重要。PSP 允许管理员限制 Pod 的安全配置,如是否允许使用hostPath
、是否以特权模式运行等。
7.4 网络策略 (NetworkPolicy)
NetworkPolicy 是 Kubernetes 网络安全的核心。它定义了 Pod 之间以及 Pod 与外部世界之间的通信规则,可以有效实现微服务之间的网络隔离。
-
工作原理:NetworkPolicy 是一种声明式资源,它通过标签选择器来选择 Pod,并定义入站(Ingress)和出站(Egress)流量的规则。只有当 Pod 被至少一个 NetworkPolicy 选中时,其通信才会受到限制。
-
配置示例 :下面的示例创建了一个 NetworkPolicy,只允许标签为
app: web
的 Pod 接收来自app: db
的 Pods 的流量,并限制其只能访问app: external
的 Pods。apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: web-policy namespace: default spec: podSelector: matchLabels: app: web # 定义策略作用于标签为 app: web 的 Pod policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: app: db # 允许来自 app: db 的 Pod 访问 egress: - to: - podSelector: matchLabels: app: external # 只允许访问 app: external 的 Pod
命令 :将上述 YAML 保存为
web-networkpolicy.yaml
,然后执行以下命令创建 NetworkPolicy。kubectl apply -f web-networkpolicy.yaml
7.5 镜像安全与运行时安全
除了集群自身的安全机制,保护容器镜像和运行时环境同样重要。
-
镜像扫描:在 CI/CD 流程中集成镜像扫描工具(如 Trivy、Clair),可以检测镜像中的已知漏洞和恶意软件。
-
镜像签名:使用镜像签名来验证镜像的完整性和来源,防止篡改。
-
容器运行时安全:使用安全强化型容器运行时(如 Kata Containers、gVisor),为容器提供额外的隔离层。
-
Pod Security Context :在 Pod 或容器级别配置安全相关的参数,如
runAsUser
、allowPrivilegeEscalation
等,限制容器的权限。