K8S

K8S
mengnankkzhou基础知识
容器化
想象一下传统开发流程中的经典难题:“在我的电脑上明明是好的,怎么一到服务器上就出问题了?”
这个问题的根源在于环境不一致。开发者的电脑和服务器的操作系统、依赖库、配置文件等可能存在细微差别,导致程序行为不一致。
核心逻辑: 我们需要一种技术,能将我们的应用程序及其所有依赖(代码、库、配置文件等)打包在一起,形成一个标准化的、可移植的“集装箱”。这个“集装箱”在哪里运行,其内部环境都完全一致,从而彻底解决环境依赖问题。
这就是容器化(Containerization)思想的由来。
Docker 就是目前最流行的容器化工具。它引入了几个核心概念来实现这个目标。
2.1 镜像 (Image)
- 它是什么: 镜像是一个只读的模板,是应用程序的“安装包”或“光盘”。它包含了运行应用程序所需的一切:代码、运行时、库、环境变量和配置文件。
- 如何构建: 通过一个名为
Dockerfile的文本文件来定义构建步骤。Dockerfile就像一张“菜谱”,指导 Docker 如何一步步制作出这个“安装包”。 - 核心逻辑: 镜像是静态的、标准化的交付物。一次构建,处处运行。这就保证了从开发到测试再到生产,应用的环境是完全一致的。
2.2 容器 (Container)
- 它是什么: 容器是镜像的运行实例。如果说镜像是“菜谱”,容器就是根据这份菜谱做出来的、正在被享用的“菜肴”。
- 运行机制: 启动一个容器,实际上是在镜像之上创建了一个可写的“层”。容器与宿主机共享操作系统内核,但拥有自己独立的文件系统、进程空间和网络,实现了资源隔离。
- 核心逻辑: 容器是动态的、隔离的运行环境。你可以从同一个镜像启动无数个相互隔离的容器,它们轻量、启动快,就像启动一个普通进程一样。
2.3 网络 (Network)
- 业务痛点: 多个容器运行在同一台主机上,它们之间如何通信?容器如何与外部世界通信?
- 它是什么: Docker 为容器提供了多种网络模式。最常用的是桥接网络(Bridge Network)。
- Docker 会创建一个虚拟网桥,每个容器都会获得一个独立的内部IP地址。
- 同一网桥下的容器可以通过内部IP直接通信。
- 如果需要让外部访问容器,需要做端口映射(Port Mapping),即将主机的一个端口映射到容器的特定端口上(例如,将主机的8080端口映射到容器的80端口)。
- 核心逻辑: Docker 网络解决了容器的“通信隔离”与“对外暴露”的问题,让容器拥有了像独立主机一样的网络能力。
2.4 存储 (Volume)
- 业务痛点: 容器被设计为“用完即焚”的。如果一个容器被删除,它在运行期间产生的所有数据(如日志、用户上传的文件、数据库文件)都会丢失。这对于需要持久化数据的应用是不可接受的。
- 它是什么: 数据卷(Volume)是一种特殊的目录,它可以绕过容器的文件系统,直接映射到宿主机上的一个目录。
- 核心逻辑: 数据卷将数据的生命周期与容器的生命周期解耦。就像给容器外挂了一个“移动硬盘”,无论容器如何创建、销毁,数据都安全地保存在这个“硬盘”里,新的容器还可以挂载同一个“硬盘”继续使用数据。
k8s
Docker 在单台机器上表现出色。但当业务发展,我们需要在数十、数百台服务器上运行成百上千个容器时,新的问题出现了:
- 调度: 哪个容器应该在哪台机器上运行?
- 服务发现: 一个容器如何找到并与另一个容器通信(它们可能在不同机器上)?
- 扩缩容: 如何根据访问量自动增加或减少容器数量?
- 自愈: 如果一台服务器宕机或一个容器崩溃了,如何自动恢复服务?
手动管理这一切是无法想象的。我们需要一个“容器的操作系统”或“容器集群的大管家”。这就是 Kubernetes(常简写为 K8s)。
核心概念:
2.1 集群 (Cluster) & 节点 (Node)
- 集群: 指的是由 Kubernetes 管理的所有计算资源(服务器)的集合。这是我们操作的整体。
- 节点: 指的是集群中的一台物理机或虚拟机。节点是实际承载和运行容器的地方。
- 核心逻辑: Kubernetes 将多台机器虚拟化成一个统一的、巨大的资源池。我们不再关心应用具体在哪台机器上,而是将应用“扔”给集群,由 K8s 负责管理。
2.2 Pod
- 它是什么: Pod 是 Kubernetes 中最小的部署和调度单元。一个 Pod 可以包含一个或多个紧密相关的容器。
- 为什么需要 Pod: 有些容器需要共享网络和存储(例如,一个应用容器和一个日志收集容器)。将它们封装在一个 Pod 里,K8s 就会保证它们始终被调度到同一个节点上,并共享同一个网络命名空间。
- 核心逻辑: 不要将 Pod 等同于容器。把 Pod 想象成一个“豆荚”,里面的“豆子”才是容器。我们管理和调度的对象是“豆荚”,而不是单个“豆子”。
2.3 Service (服务)
- 业务痛点: Pod 的生命周期是短暂的,它们会被销毁和重建,每次重建 IP 地址都会改变。那么,一个服务(如前端应用)如何稳定地访问另一个服务(如后端API)呢?
- 它是什么: Service 为一组功能相同的 Pod 提供了一个统一、稳定的访问入口。Service 有一个固定的虚拟IP和DNS名称,它会自动将流量负载均衡到后端的健康 Pod 上。
- 核心逻辑: Service 解耦了服务的“消费者”和“提供者”。无论后端的 Pod 如何变化(数量增减、IP地址变更),消费者只需访问固定的 Service 地址即可。它解决了服务发现和负载均衡两大难题。
2.4 Namespace (命名空间)
- 业务痛点: 当一个集群被多个团队或多个项目(如开发环境、测试环境、生产环境)共用时,如何进行逻辑上的隔离,避免命名冲突和资源混乱?
- 它是什么: Namespace 是对集群内部资源的逻辑分组。不同 Namespace 内的资源名称可以相同,并且可以设置不同的资源配额和访问权限。
- 核心逻辑: Namespace 就像在电脑硬盘上创建不同的文件夹来分类存放文件一样,它让多租户共用一个集群成为可能。
2.5 Label (标签) / Annotation (注解)
- Label: 是附加到资源(如 Pod)上的键值对,用于识别和筛选资源。例如,可以给所有前端 Pod 打上
app=frontend的标签,给后端 Pod 打上app=backend的标签。Service 就是通过 Label Selector 来找到它应该代理哪些 Pod 的。 - Annotation: 也是键值对,但它主要用于存储非识别性的元数据,供工具或人阅读。例如,构建版本、负责人联系方式等。
- 核心逻辑: Label 是 K8s 资源之间松散耦合的“关系纽带”,是实现灵活分组和管理的核心机制。
控制器
我们通常不直接创建和管理单个的 Pod,而是通过“控制器”来管理。控制器的核心任务是确保集群的实际状态与我们定义的期望状态保持一致。
3.1 Deployment (部署)
- 适用场景: 无状态应用(Stateless Application),如 Web 服务器、API 网关等。这些应用不保存任何本地数据,可以随意扩缩容和替换。
- 核心能力:
- 副本管理: 定义期望的 Pod 副本数量(
replicas),Deployment 会确保运行中的 Pod 数量始终与此一致。 - 滚动更新: 能够平滑地、分批次地用新版本的 Pod 替换旧版本的 Pod,实现服务的无中断升级。
- 副本管理: 定义期望的 Pod 副本数量(
- 核心逻辑: Deployment 是最常用、最基础的控制器,管理着应用的“数量”和“版本”。
3.2 StatefulSet (有状态集)
- 适用场景: 有状态应用(Stateful Application),如数据库(MySQL, PostgreSQL)、消息队列(Kafka)等。
- 核心能力:
- 稳定的、唯一的网络标识: Pod 的名称是固定的、有序的(如
db-0,db-1)。 - 稳定的、持久的存储: 每个 Pod 都会绑定一个专属的持久化存储卷(PV)。即使 Pod 重启,它仍然会连接到原来的存储卷,数据不会丢失。
- 稳定的、唯一的网络标识: Pod 的名称是固定的、有序的(如
- 核心逻辑: StatefulSet 为需要稳定身份和持久化数据的应用提供了专门的生命周期管理。
3.3 DaemonSet (守护进程集)
- 适用场景: 需要在集群中的每一个(或指定的)节点上都运行一个且仅一个 Pod 副本的场景。
- 典型用途: 日志收集(如 Fluentd)、系统监控(如 Prometheus Node Exporter)、网络插件等。
- 核心逻辑: DaemonSet 确保了基础设施相关的服务能够在每个节点上可靠运行,是集群运维的基石。
3.4 Job / CronJob (任务 / 定时任务)
- Job:
- 适用场景: 需要运行一次并确保成功完成的离线任务。例如,数据批处理、一次性的数据迁移。
- 核心逻辑: Job 会创建 Pod 来执行任务,直到指定数量的 Pod 成功退出(返回码为0),Job 的使命才算完成。如果 Pod 失败,Job 会自动重试。
- CronJob:
- 适用场景: 需要按计划周期性执行的任务。例如,每日备份、定时报告生成。
- 核心逻辑: CronJob 就像 Linux 的
crontab,它会根据你设定的时间表(如0 2 * * *表示每天凌晨2点)来周期性地创建 Job 来执行任务。
核心组件
在深入组件之前,必须理解 Kubernetes 的核心设计哲学:状态机。
- 您(用户):通过 YAML 文件或命令,向 Kubernetes 声明一个“期望状态”(Desired State)。例如,“我期望有3个 Nginx Pod 在运行”。
- Kubernetes:不知疲倦地工作,持续监控集群的“实际状态”(Actual State)。
- 调谐循环 (Reconciliation Loop):如果“实际状态”与“期望状态”不符(例如,只有2个 Nginx Pod 在运行),Kubernetes 会自动采取行动(例如,新建一个 Pod),努力使两者达成一致。
Control Plane
控制平面是集群的大脑和决策中心。它不下达具体“如何做”的指令,只负责做出决策和下达“做什么”的命令。通常它运行在专门的主节点 (Master Node) 上。
1.1 API Server - “公司总秘书处 / 前台”
- 职责:
- 唯一入口:是整个集群所有交互的唯一、集中的入口点。无论是外部用户(如
kubectl命令)还是集群内部组件,所有操作请求都必须经过它。 - 请求处理:负责接收、校验、处理所有 RESTful API 请求。
- 授权认证:承担了认证、授权和准入控制等所有安全相关的工作,是集群的“守门人”。
- 唯一入口:是整个集群所有交互的唯一、集中的入口点。无论是外部用户(如
- 交互: 它是所有组件沟通的中心枢纽。它是唯一可以直接与
etcd通信的组件,确保了数据的一致性和安全性。 - 公司类比: 公司的总秘书处。所有部门的报告、所有员工的请求(加薪、请假)都必须提交到这里。秘书处负责验证请求的合法性(权限),然后存档(存入 etcd),并通知相关部门处理。
1.2 etcd - “公司的档案数据库 (不可篡改)”
- 职责:
- 数据存储:一个高可用的键值对数据库,是集群的唯一数据中心和唯一真实来源 (Single Source of Truth)。
- 状态记录:完整、准确地存储了整个集群的“期望状态”和“实际状态”的所有数据(例如,创建了哪些 Pod、每个 Pod 的 IP 是多少等)。
- 交互: 只有 API Server 可以直接读写
etcd。其他组件需要的信息都通过 API Server 获取。 - 公司类比: 公司的核心档案数据库,记录了所有正式文件、员工合同、财务报表。这个数据库是权威的,不可随意篡改,只有总秘书处(API Server)有权写入新档案。
1.3 Scheduler - “人力资源部 (负责分配岗位)”
- 职责:
- Pod 调度:其唯一职责是为新创建的、尚未分配节点的 Pod,寻找一个最合适的 Node 节点来运行。
- 决策过程:调度决策基于一系列复杂的算法,主要考虑:Pod 的资源需求(CPU、内存)、节点的当前负载、亲和性/反亲和性策略等。它只负责“决策”,不负责“执行”。
- 交互: 它通过 API Server 监视有没有“待调度”的 Pod。一旦发现,就为其选择一个节点,然后将这个“决策”(将 Pod 绑定到某个 Node)写回给 API Server。
- 公司类比: 公司的人力资源部。当有一个新员工(新 Pod)入职时,HR 会根据他的岗位需求、团队空位、办公室资源等情况,决定他去哪个部门、坐哪个工位(Node)。HR 只负责“分配”,不负责带他去工位。
1.4 Controller Manager - “各个部门的经理 (负责执行)”
- 职责:
- 维护状态:是所有控制器的集合体,是驱动集群从“实际状态”趋向“期望状态”的核心引擎。
- 调谐循环:每个控制器都负责一种特定资源,并运行着一个独立的“调谐循环”。例如:
- Deployment 控制器:发现运行的 Pod 数量少于期望值,就会创建新的 Pod。
- Node 控制器:发现有节点宕机,就会将该节点标记为不可用。
- 交互: 它通过 API Server 监控各类资源的状态,并在发现不一致时,通过 API Server 发起纠正操作(如创建/删除 Pod)。
- 公司类比: 公司里各个部门的经理(财务经理、项目经理、后勤经理)。项目经理(Deployment Controller)发现项目组少了一个人(Pod 副本不足),他不会自己去招人,而是向总秘书处提交一个“需要增加一个人”的请求,后续由 HR(Scheduler)和具体执行者(kubelet)来完成。
node组件
这些组件运行在每个工作节点 (Worker Node) 上,是实际执行任务的“劳动力”。
2.1 kubelet - “分公司负责人 / 车间主任”
- 职责:
- 节点代理:是 Control Plane 在每个 Node 上的代理人。
- Pod 管理:它会监视分配给自己所在节点的 Pod,并确保这些 Pod 中的容器都按照预期运行。
- 状态汇报:负责向 Control Plane 汇报本节点的健康状况和 Pod 的运行状态。
- 交互: 它与 API Server 通信,获取自己需要管理的 Pod 清单。然后,它与容器运行时交互,命令其创建、启动、停止容器。
- 公司类比: 每个分公司(Node)的负责人。他会不断地从总部(API Server)接收任务清单(Pod 列表),然后指挥自己公司的员工和设备(容器运行时)去完成这些任务,并定期向总部汇报工作进度。
2.2 kube-proxy - “分公司的网络管理员 / 路由器”
- 职责:
- 网络规则维护:负责在每个节点上维护网络规则,以实现 Kubernetes Service 的概念。
- 流量路由:它确保了从外部或内部访问一个 Service 的流量,能够被正确地转发到后端正确的 Pod 上。它本质上是一个网络代理和负载均衡器。
- 交互: 它从 API Server 获取 Service 和 Endpoint (Pod IP) 的信息,并据此修改节点上的
iptables或IPVS规则。 - 公司类比: 每个分公司(Node)的网络管理员。他知道公司总机号码(Service IP)应该转接到哪些具体员工的座机(Pod IP)上,并负责配置好电话交换机(iptables)。
2.3 容器运行时 (Container Runtime)
- 职责: 实际运行容器的软件。例如 Docker、containerd、CRI-O。
- 交互:
kubelet通过 CRI (Container Runtime Interface) 标准接口,向容器运行时下达指令,如“拉取这个镜像”、“启动这个容器”。 - 公司类比: 真正干活的“机器”或“工人”。车间主任(kubelet)下达指令,它就负责生产出产品(运行容器)。
3.1 Service 网络模型 - “公司的电话总机系统”
- ClusterIP:内部电话分机。默认类型,为 Service 分配一个只能在集群内部访问的虚拟 IP。适用于集群内部服务之间的通信。
- NodePort:指定分公司的直线电话。在每个节点的物理 IP 上暴露一个固定的端口。外部可以通过
NodeIP:NodePort访问服务。主要用于测试或临时暴露服务。 - LoadBalancer:公司的 400 统一客服热线。在 NodePort 的基础上,额外向云服务商(如 AWS, GCP)申请一个外部负载均衡器,并将流量导向所有节点的 NodePort。是标准、生产级的对外暴露服务的方式。
- Ingress:智能前台/语音导航系统。它不是 Service,而是工作在 HTTP/HTTPS 层的流量路由器。它可以根据请求的域名(
a.com,b.com)或路径(/foo,/bar)将流量转发到不同的 Service。一个 Ingress 就可以管理多个服务的对外暴露,比为每个服务都创建一个 LoadBalancer 更高效、成本更低。 - Overlay 网络:公司的内部虚拟专网 (VPN)。像 Calico、Flannel 这样的网络插件,构建了一个跨越所有节点的虚拟网络层。它使得每个 Pod 都拥有一个全局唯一的 IP 地址,并且 Pod 之间可以像在同一个局域网内一样直接通信,屏蔽了底层的物理网络复杂性。
3.2 存储模式 - “公司的资源申请流程”
这个流程巧妙地将“使用者”和“提供者”解耦。
- Volume:临时储物柜。生命周期与 Pod 绑定,Pod 销毁,数据可能丢失。
- PersistentVolume (PV):IT 部门的“库存资源”。由管理员预先创建好的、具体的存储资源(如一块云硬盘)。它是一个独立于 Pod 的集群资源。
- PersistentVolumeClaim (PVC):员工的“资源申请单”。由开发者(用户)创建,描述自己需要什么样的存储(“我需要 5GB 的可读写存储”),但不关心具体是哪块硬盘。
- StorageClass:“自动化资源供应”策略。它定义了如何动态创建 PV。当 PVC 申请的资源在现有 PV 库存中找不到匹配时,如果配置了 StorageClass,系统就会根据这个“策略”自动去云服务商那里创建一个新的 PV 并与 PVC 绑定。这实现了存储的按需自动供给。
实践
kubectl 常用命令:
kubectl 是您与 Kubernetes 集群交互的命令行工具,是您的“指挥棒”。必须熟练掌握。
kubectl apply -f <filename.yaml>: 声明式管理的入口。向 K8s 声明您期望的资源状态(例如,“我需要一个运行 Nginx 的 Deployment”),K8s 会负责让集群的当前状态与您的期望状态保持一致。这是最核心、最常用的命令。kubectl get <resource_type> [resource_name]: 查看资源状态。用于获取一类或某个特定资源的信息。kubectl get pods: 查看所有 Pod。kubectl get deployment my-app: 查看名为 my-app 的 Deployment。- 常用参数:
-o wide(显示更详细信息),-n <namespace>(指定命名空间)。
kubectl describe <resource_type> <resource_name>: 获取资源的详细描述。当资源出现问题时(如 Pod 启动失败),此命令是排错的第一步。它会显示资源的状态、事件(Events)、配置等详细信息。kubectl logs <pod_name>: 查看 Pod 的日志。用于调试应用本身的问题。- 常用参数:
-f(实时跟踪日志),-c <container_name>(当一个 Pod 中有多个容器时指定容器)。
- 常用参数:
kubectl exec -it <pod_name> -- <command>: 进入 Pod 的容器内部。相当于 SSH 到一个虚拟机,允许您在容器内执行命令,非常适合进行现场调试。- 示例:
kubectl exec -it my-pod -- /bin/bash
- 示例:
kubectl port-forward <pod_name_or_service_name> <local_port>:<target_port>: 端口转发。将本地端口映射到 Pod 或 Service 的端口,方便在本地直接访问集群内的服务进行测试。
实现过程:
- 编写 Deployment 与 Service YAML
- Deployment:
- 作用: 定义了应用的“期望状态”。它负责管理 Pod 的副本数量、镜像版本、更新策略等。您可以把它理解为Pod 的控制器或“管理员”。如果一个 Pod 意外挂掉了,Deployment 会立刻创建一个新的来替代它,确保应用实例数量始终符合您的设定。
- Service:
- 作用: 为一组功能相同的 Pod 提供一个稳定、统一的访问入口。Pod 的 IP 地址是动态变化的(Pod 重启后 IP 会变),直接访问 Pod 是不可靠的。Service 提供了一个固定的虚拟 IP 和 DNS 名称,无论后端的 Pod 如何变化,客户端都可以通过访问 Service 来访问应用。它还承担了负载均衡的职责。
- 滚动更新、回滚与零停机部署
这是体现 Kubernetes 强大自愈和管理能力的核心功能。
- 滚动更新 (Rolling Update):
- 原理: 当您更新 Deployment 中的应用镜像版本时,K8s 不会一次性杀掉所有旧版 Pod,而是会“滚动地”进行:启动一个新版 Pod -> 等待新版 Pod 准备就绪 -> 停止一个旧版 Pod -> 再启动一个新版 Pod… 如此循环,直到所有 Pod 都更新为新版本。
- 价值: 在整个更新过程中,始终有可用的 Pod 在提供服务,从而实现了零停机部署 (Zero-Downtime Deployment)。
- 回滚 (Rollback):
- 原理: 如果新版本应用有问题,您可以使用一条简单的命令(
kubectl rollout undo deployment/<deployment_name>)让 Deployment 滚回到上一个稳定版本。K8s 保存了部署的历史记录,使得回滚操作变得非常简单快捷。
- 原理: 如果新版本应用有问题,您可以使用一条简单的命令(
- 配置 ConfigMap、Secret
目标: 将配置与应用镜像解耦,提高应用的灵活性和安全性。
- ConfigMap:
- 作用: 用于存储非敏感的配置信息,如环境变量、配置文件内容等。您可以将这些配置以键值对的形式存储在 ConfigMap 中,然后通过环境变量或卷挂载的方式注入到 Pod 中。
- 价值: 修改配置时,只需更新 ConfigMap 并重启 Pod 即可,无需重新构建应用镜像。
- Secret:
- 作用: 用于存储敏感信息,如数据库密码、API 密钥、TLS 证书等。它的使用方式与 ConfigMap 类似,但 K8s 会对其进行特殊处理(例如,默认以 Base64 编码存储,可以集成更安全的存储方案)。
- 核心原则: 永远不要将密码等敏感信息硬编码在代码或镜像中。
4.数据持久化
解决有状态应用(如数据库、消息队列)的数据持久化问题。因为 Pod 本身是“无状态”且生命周期短暂的,其内部文件系统会随 Pod 的消亡而丢失。
PV、PVC 和 StorageClass,这是一个解耦的设计,非常重要。
- PersistentVolume (PV): 集群管理员准备好的存储资源。它可以是物理硬盘、NFS、云厂商的磁盘等。PV 是对存储实体的抽象。
- PersistentVolumeClaim (PVC): 应用(用户)对存储资源的申请。应用开发者不需要关心存储到底是什么类型、在哪里,只需要在 PVC 中声明需要多大空间、需要什么样的访问模式(例如,读写权限)。
- 绑定过程: K8s 会根据 PVC 的申请,在现有的 PV 中寻找一个满足条件的进行绑定。应用 Pod 启动时,只需引用 PVC 即可。
这个模式的好处在于: 应用开发者(关心 PVC)和集群管理员(关心 PV)的职责被分开了。
后端存储类型:
HostPath: 将宿主机(Node)上的一个目录直接挂载给 Pod。
- 优点: 简单易用,无需额外配置。
- 缺点: 数据与特定节点绑定,如果 Pod 被调度到其他节点,数据就丢失了。仅适用于单节点测试环境。
NFS (Network File System): 一种常见的网络存储。
- 优点: 数据不与任何特定节点绑定,多个 Pod 可以同时读写同一个存储卷(需要
ReadWriteMany模式)。 - 缺点: 需要额外搭建和维护一个 NFS 服务器。
Rook/Ceph:
- 定位: 云原生存储解决方案。它本身就可以部署在 Kubernetes 集群内部,将各个节点的磁盘聚合成一个分布式的、高可用的存储池。
- 优点: 高性能、高可用、可扩展,与 K8s 无缝集成。
- 缺点: 配置和维护相对复杂,是更高级的存储方案。
重要特性:
访问模式 (Access Modes):
ReadWriteOnce(RWO): 卷只能被单个节点以读写方式挂载。注意是单个节点,不是单个 Pod。ReadWriteMany(RWX): 卷可以被多个节点同时以读写方式挂载。像 NFS、CephFS 等网络存储才支持此模式。ReadOnlyMany(ROX): 卷可以被多个节点以只读方式挂载。
动态供应 (Dynamic Provisioning):
- 原理: 当没有现成的 PV 能满足 PVC 的申请时,如果配置了
StorageClass,K8s 会自动调用底层存储插件(如云厂商的磁盘服务)动态地创建一个 PV 并与 PVC 绑定。 - 价值: 实现了存储的按需自动创建,极大简化了管理员的工作。这是目前云上环境的主流使用方式。
回收策略 (Reclaim Policy): 定义了当 PVC 被删除后,与之绑定的 PV 如何处理。常见的有 Retain(保留数据)、Delete(删除数据)和 Recycle(清空数据,已不推荐)。






