从容器化到Kubernetes编排:核心架构、工作流程与实战入门指南
1. 从“容器化”到“容器编排”:为什么我们需要Kubernetes?
如果你接触过Docker,那么恭喜你,你已经迈入了现代应用部署和运维的新世界。Docker解决了“我的应用在我的机器上能跑,在你的机器上跑不起来”这个经典难题,它把应用及其所有依赖打包成一个轻量级、可移植的“容器镜像”。这就像把整个应用,连同它需要的操作系统库、运行时环境、代码和配置,一起塞进了一个标准化的集装箱里。无论这艘集装箱船(服务器)是Ubuntu、CentOS还是Windows,只要船上有吊车(容器运行时,如Docker Engine),就能把这个集装箱(容器)原封不动地吊起来运行。
听起来很完美,对吧?但当你从开发者的单机实验,走向生产环境的真实世界时,问题就来了。想象一下,你的应用(比如一个电商网站)火了,访问量激增。一个集装箱(容器)扛不住了,你需要立刻启动十个、一百个同样的集装箱来分担压力。这成百上千个集装箱,你打算手动去每台服务器上启动、停止、监控健康状态吗?半夜三点,某个集装箱因为内存泄漏挂掉了,你希望被报警电话叫醒,然后手动登录服务器去重启它吗?当你要更新应用版本时,是让所有用户的服务中断十分钟,还是能做到让新版本容器一个个无缝替换旧版本,用户毫无感知?
这些问题的核心,已经从“如何打包和运行一个容器”,升级为了“如何管理成百上千个容器,让它们协同工作,提供稳定、可扩展、高可用的服务”。这就是 容器编排 要解决的难题。而Kubernetes(常缩写为K8s,因为K和s之间有8个字母),正是这个领域当之无愧的王者,它已经成为了容器编排的事实标准。
简单来说,Kubernetes是一个开源的容器编排平台,它自动化了容器化应用的部署、扩展和管理。你可以把它理解为一个高度智能的“容器集群操作系统”或者“数据中心的调度大脑”。你不再需要关心你的容器具体在哪台物理机或虚拟机上运行,你只需要告诉Kubernetes你想要什么状态:“我需要运行5个副本的Web应用,它们需要2核CPU、4G内存,并且通过一个负载均衡器对外提供80端口服务。” Kubernetes就会自动帮你找到合适的节点(服务器)去创建并运行这些容器,并持续监控它们,确保实际状态始终与你声明的期望状态一致。
2. Kubernetes的核心架构:Master与Node如何协同工作?
要理解Kubernetes是如何运作的,首先得拆解它的架构。一个典型的K8s集群由两类节点组成: 控制平面(Control Plane, 也称Master节点) 和 工作节点(Worker Nodes) 。这种“大脑”与“肢体”的分离设计,是实现其强大自动化能力的基础。
2.1 控制平面:集群的“大脑”与“指挥中心”
控制平面负责管理整个集群,做出全局决策(比如在哪个节点调度Pod),以及响应集群事件。它通常由以下几个核心组件构成,在生产环境中,这些组件可以部署在多台机器上以实现高可用。
API Server
: 这是整个Kubernetes系统的“前台”和“总入口”。所有与集群的交互,无论是用户通过
kubectl
命令行工具发出的指令,还是集群内部组件之间的通信,都必须通过API Server。它负责验证请求、处理请求(如创建、更新、删除资源),并将资源对象的期望状态持久化存储到
etcd
中。你可以把它想象成公司的前台或总机,所有内外事务都从这里流转。
etcd
: 一个分布式、高可用的键值存储数据库。它是Kubernetes集群的“记忆中枢”,存储了集群所有重要的数据,包括节点信息、Pod信息、服务配置、密钥等。Kubernetes的“声明式”理念就体现在这里:你声明的期望状态(YAML文件内容)最终会被API Server写入
etcd
。集群中所有其他组件都通过监听
etcd
的数据变化来感知集群状态,并驱动自身工作以达到期望状态。
etcd
的数据安全性和一致性至关重要。
Scheduler : 集群的“调度器”。它的职责非常专一:为新创建的、尚未分配节点的Pod选择一个最合适的工作节点来运行。调度器会综合考虑一系列因素,比如节点的资源请求与限制、亲和性与反亲和性规则、数据局部性、污点和容忍度等,做出最优的调度决策。它只负责“决策”,不负责“执行”。决策完成后,它会通过API Server更新Pod与节点的绑定信息。
Controller Manager
: 这是一个运行着多种
控制器(Controller)
的守护进程。控制器是Kubernetes实现自动化的核心“机器人”。每个控制器都负责监控集群中某一类资源(如Node、Pod、Service)的实际状态,并将其与
etcd
中存储的期望状态进行对比。一旦发现实际状态偏离了期望状态(比如期望运行3个Pod副本,但实际只有2个),控制器就会采取行动(比如通知API Server创建一个新的Pod),驱动集群向期望状态收敛。常见的控制器包括节点控制器、副本控制器、端点控制器等。
Cloud Controller Manager : 这是一个可选组件,当Kubernetes运行在公有云(如AWS、GCP、Azure)上时,它会负责与底层云平台的API进行交互,管理如负载均衡器、存储卷、节点(虚拟机)等云资源。它将Kubernetes与特定云厂商的细节解耦,让核心的Controller Manager更通用。
2.2 工作节点:承载实际工作负载的“肌肉”
工作节点是容器真正运行的地方。每个节点上都运行着以下关键组件:
Kubelet : 节点上的“节点代理”。它是控制平面与节点通信的桥梁。Kubelet的主要职责是保证本节点上运行的Pod都处于健康状态。它从API Server接收Pod的规格定义(PodSpec),并按照要求,通过容器运行时(如Docker、containerd)启动、停止容器。同时,它还会向API Server汇报本节点及节点上Pod的状态(如CPU、内存使用情况)。
容器运行时(Container Runtime) : 负责运行容器的软件。Kubernetes最初与Docker深度集成,但现在通过 容器运行时接口(CRI) 支持多种运行时,如containerd(Docker剥离出的核心运行时)、CRI-O等。它负责拉取容器镜像、创建容器、管理容器的生命周期(启动、停止、删除)。
Kube Proxy : 节点上的网络代理。它维护节点上的网络规则,实现了Kubernetes Service概念的网络部分。当你在集群内创建了一个Service(比如一个负载均衡器)时,Kube Proxy会通过配置iptables或IPVS规则,确保发往该Service虚拟IP的流量能被正确地转发到后端对应的Pod上。它是实现服务发现和负载均衡的关键。
Pod : 这里需要特别强调,Pod虽然不是以守护进程形式运行的组件,但它是Kubernetes中最小的可部署和管理单元。一个Pod可以包含一个或多个紧密关联的容器,这些容器共享网络命名空间、IPC、UTS,并且可以通过Volume共享存储。你可以把Pod想象成一个“逻辑主机”,里面的容器就像运行在这个主机上的进程,它们可以通过localhost直接通信。这是Kubernetes一个非常核心且独特的设计。
3. Kubernetes的核心对象模型:你如何与集群“对话”?
Kubernetes不鼓励你直接去服务器上敲命令。你与集群交互的方式,是通过创建和操作一系列 资源对象(API Objects) 。这些对象就是你向Kubernetes“声明”的期望状态。以下是最核心的几个对象,理解了它们,你就理解了Kubernetes的工作模型。
Pod : 如前所述,Pod是Kubernetes的基本构建块。它代表集群中运行的一个或多个容器进程组。通常,一个Pod只运行一个主应用容器,但有时也会包含一些“边车(Sidecar)”容器,比如日志收集器(Fluentd)、服务网格代理(Istio Envoy)等,它们辅助主容器工作。Pod是短暂的、一次性的。当Pod所在的节点故障,或者Pod本身被删除,它就会消失。Kubernetes不会修复或重启Pod本身,而是会创建一个全新的Pod来替换它。
注意 : 直接创建和管理独立的Pod(
kubectl run或Pod类型的YAML)在生产环境中非常罕见,因为Pod太脆弱了。我们总是通过更高级的控制器来管理Pod。
Deployment : 这是管理无状态应用(如Web服务器、API服务)最常用的控制器。你通过Deployment声明一个“模板”(Pod模板)和一个“副本数”。Deployment控制器会确保在任何时候,都有指定数量的、符合模板的Pod副本在运行。它为你提供了强大的滚动更新和回滚能力。当你要更新应用镜像时,只需修改Deployment中的镜像版本,Kubernetes就会自动以可控的方式(如逐个替换)将旧Pod更新为新Pod,期间服务不中断。
Service
: Pod是动态的、会生会灭的,它们的IP地址也是不固定的。那么,集群内部的其他应用,或者外部用户,该如何稳定地访问到这一组动态变化的Pod呢?答案就是Service。Service定义了一个稳定的访问入口(一个虚拟IP,称为ClusterIP)和一组访问策略。它通过
标签选择器(Label Selector)
动态地关联后端的一组Pod。无论后端的Pod如何创建、销毁、IP如何变化,Service的访问地址始终不变,并且它会将流量负载均衡到所有健康的Pod上。对于需要从集群外部访问的服务,还可以通过
NodePort
或
LoadBalancer
类型的Service暴露出去。
ConfigMap 和 Secret : 将应用配置与容器镜像解耦是12-Factor应用的重要原则。ConfigMap允许你将配置数据(如配置文件、环境变量)以键值对的形式存储在Kubernetes中,然后以卷挂载或环境变量的方式注入到Pod里。Secret与ConfigMap类似,但专门用于存储敏感信息,如密码、OAuth令牌、SSH密钥等。Secret的数据会以Base64编码(注意,这只是编码,不是加密!)存储,在传输和挂载时有更多安全考量。
Volume(存储卷)
: 容器中的文件系统是临时的,容器重启后,写入其内部的文件就会丢失。Volume提供了在Pod生命周期内持久化存储数据的能力。Kubernetes支持多种Volume类型,从简单的本地目录(
hostPath
)到复杂的网络存储系统(如NFS、Ceph、云厂商的块存储)。更常用的是
PersistentVolume(PV)
和
PersistentVolumeClaim(PVC)
抽象。管理员可以预先配置好一批PV(存储资源),而用户只需要通过PVC声明自己需要多大容量、什么访问模式的存储,Kubernetes就会自动为其绑定一个合适的PV。这实现了存储供给的自动化。
Namespace(命名空间) : 这是一个逻辑上的集群分区,用于在单个物理集群中实现多租户环境。你可以为不同的团队、项目或环境(如开发、测试、生产)创建不同的Namespace。大部分资源(如Pod、Deployment、Service)都属于某个特定的Namespace,这提供了基本的资源隔离和组织能力。不过要注意,Namespace提供的隔离主要是逻辑上的,网络层面默认仍然是互通的,更严格的隔离需要借助网络策略(NetworkPolicy)等机制。
4. Kubernetes的典型工作流程:从YAML文件到运行中的服务
现在,让我们把以上所有概念串联起来,看一个从零部署一个简单Web应用的完整流程,这能帮你直观地理解Kubernetes是如何协同工作的。
第一步:定义期望状态(编写YAML)
作为应用开发者或运维人员,你首先需要编写一个或多个YAML文件,来描述你的应用应该是什么样子。例如,一个最简单的
deployment.yaml
可能包含:
-
一个Deployment,指定需要运行3个副本(
replicas: 3)。 -
在Deployment的Pod模板中,定义容器镜像(如
nginx:latest)、资源请求(requests.cpu/memory)和限制(limits.cpu/memory)。 -
为Pod模板中的容器打上标签,如
app: my-web。 -
再编写一个
service.yaml,定义一个ClusterIP类型的Service,并通过标签选择器app: my-web关联到Deployment创建的Pod。
第二步:提交声明(
kubectl apply
)
你使用
kubectl apply -f deployment.yaml service.yaml
命令,将这些YAML文件提交给Kubernetes API Server。
第三步:大脑处理与存储
API Server验证你的请求格式和权限,然后将你定义的Deployment和Service对象的期望状态,作为一条条记录,持久化存储到
etcd
数据库中。
第四步:控制器驱动状态收敛
-
Deployment控制器
被唤醒:它通过监听
etcd,发现了一个新的Deployment对象,期望状态是“3个带有特定模板的Pod”。它发现当前实际Pod数为0,于是它创建了一个新的 ReplicaSet 对象(Deployment通过ReplicaSet来管理Pod副本)。ReplicaSet的期望状态也是“3个Pod”。 -
ReplicaSet控制器
被唤醒:它发现了这个新的ReplicaSet,期望3个Pod,实际0个。于是,它通过API Server创建了3个Pod对象(注意,此时Pod还只是对象定义,并未调度到节点上运行)。这3个Pod对象的定义也被写入
etcd。
第五步:调度器决策
Scheduler
监听到
etcd
中出现了这3个新的、
nodeName
为空的Pod对象。它开始工作:
- 过滤(Filtering): 扫描所有工作节点,过滤掉那些不满足Pod要求的节点(如资源不足、有污点且Pod不容忍)。
- 打分(Scoring): 对过滤后的节点进行打分,考虑因素如资源平衡、亲和性等。
-
绑定(Binding): 选择分数最高的节点,通过API Server将Pod对象与这个节点绑定(即更新Pod的
nodeName字段)。信息再次被写入etcd。
第六步:节点代理执行
-
目标节点上的
Kubelet
,通过监听
etcd,发现有一个Pod被调度到了自己身上,并且该Pod处于待创建状态。 -
Kubelet根据Pod定义,指示本节点的
容器运行时
(如containerd)从镜像仓库拉取指定的
nginx:latest镜像,并按照配置创建和启动容器。 - 同时,节点上的 Kube Proxy 监听到Service和其关联的Pod(通过标签选择器匹配)被创建。它会更新本机的iptables或IPVS规则,确保发往该Service ClusterIP的流量能被转发到刚刚创建的这3个Pod的IP上。
第七步:状态上报与持续保障
-
Kubelet持续监控容器的运行状态,并定期通过API Server向
etcd汇报Pod的实际状态(如Running、Failed)。 - 所有控制器(如ReplicaSet控制器)也在持续运行 。它们不断对比期望状态和实际状态。如果某个Pod所在的节点宕机,Kubelet无法上报状态,该Pod状态会变为Unknown。一段时间后,ReplicaSet控制器会发现实际运行的Pod数(比如2个)少于期望数(3个),它会立刻通过API Server创建一个新的Pod对象,调度器再将其调度到健康的节点上,Kubelet再启动它……如此循环,确保你的服务始终有3个健康的副本。
这个流程完美诠释了Kubernetes的“声明式API”和“控制器模式”。你只需关心“想要什么”(声明状态),而无需操心“如何做到”和“如何保持”(由Kubernetes自动完成)。
5. 学习路径与实战建议:如何开始你的K8s之旅?
了解了K8s是什么和它的核心原理后,你可能会问:我该如何开始学习并上手?结合最新的网络热词,我为你梳理了一条从入门到实践的学习路径和避坑指南。
第一阶段:概念理解与环境准备(避开初期大坑)
-
夯实容器基础
: 务必先理解Docker的核心概念:镜像、容器、仓库、Dockerfile。搞明白
k8s和docker区别:Docker是创建和管理单个容器的工具,而K8s是管理成百上千个容器的平台。你可以不用Docker作为K8s的运行时(现在更推荐containerd),但容器的概念必须懂。 -
选择实验环境
: 对于初学者,强烈不建议一上来就尝试在物理机或虚拟机上进行复杂的
k8s集群搭建,尤其是centos系统上部署 k8s 单 master 集群或virtualbox搭建centos7 k8s集群,这中间涉及的系统配置、网络、镜像问题足以劝退新手。- 首选方案 : 使用 Minikube 或 Kind 。Minikube会在你的本地机器(Windows、macOS、Linux)上创建一个单节点的K8s集群,非常适合学习和实验。Kind则使用Docker容器作为“节点”,快速搭建一个多节点的集群,速度极快。
-
Windows用户
: 可以直接使用
windows docker desktop kubernetes。Docker Desktop内置了单节点的K8s集群,一键启用,是最简单的入门方式。注意参考windows安装k8s的相关指南,确保Hyper-V或WSL2已正确配置。
-
掌握核心命令行工具
kubectl: 这是你与K8s集群交互的唯一命令行工具。从kubectl get nodes/pods/deployments查看资源,到kubectl apply -f部署应用,再到kubectl logs/exec调试容器,必须熟练掌握。
第二阶段:核心对象实操与YAML编程
-
从YAML文件开始
: 放弃一开始就用
kubectl run这种命令式创建资源的方式。学习手写YAML文件来定义Deployment、Service、ConfigMap。理解YAML的结构、缩进、apiVersion、kind、metadata、spec等关键字段。网上有很多kubernetes dashboard.yaml或k8s部署lnmp的示例,可以拿来参考和修改。 -
完成经典练习
:
-
部署一个无状态应用
: 用Deployment部署一个Nginx或你自己的Web应用,并用Service暴露它。体验
kubectl scale deployment进行扩缩容。 -
体验滚动更新
: 修改Deployment的镜像版本,观察K8s如何逐个替换Pod,并使用
kubectl rollout status/history/undo进行回滚。 -
配置与存储
: 创建ConfigMap存储配置,并挂载到Pod中;创建PVC和PV(可以使用Minikube自带的
hostPath类型存储类),让Pod能够持久化存储数据。
-
部署一个无状态应用
: 用Deployment部署一个Nginx或你自己的Web应用,并用Service暴露它。体验
-
理解网络与访问
: 学习
k8s ingress详解。Ingress是管理外部访问集群服务的API对象,通常通过Ingress Controller(如Nginx Ingress Controller)实现,它提供了比Service更强大的HTTP/HTTPS路由、SSL终止等功能。这是将内部服务暴露给外界的标准方式。
第三阶段:深入进阶与生产考量
-
学习高级概念
:
- StatefulSet : 用于部署有状态应用(如数据库、中间件),提供稳定的网络标识、持久化存储和有序的部署、扩缩容。
- DaemonSet : 确保每个(或部分)节点上都运行一个Pod副本,常用于日志收集(Fluentd)、节点监控(Node Exporter)等。
- Job/CronJob : 用于运行一次性任务或定时任务。
- 资源配额与限制 : 学习如何为Namespace设置资源配额,为Pod设置资源请求和限制,这是保障集群稳定的关键。
- 安全 : 了解ServiceAccount、Role、RoleBinding、ClusterRole等RBAC权限控制概念。
-
探索生态与工具
:
-
监控
: 部署Prometheus + Grafana来监控集群和应用。学习如何部署
kube-state-metrics(参考kubernetes 1.28 如何部署 kube-state-metrics),它提供了关于K8s对象状态的指标。 - 日志 : 搭建EFK(Elasticsearch, Fluentd, Kibana)或Loki栈进行集中日志管理。
- 包管理 : 学习使用Helm,它是K8s的包管理器,通过“Chart”来定义、安装和管理复杂的K8s应用。
- GitOps : 了解Argo CD或Flux,实现以Git仓库为唯一可信源的自动化部署。
-
监控
: 部署Prometheus + Grafana来监控集群和应用。学习如何部署
-
生产集群部署与管理
: 当你对概念足够熟悉后,可以尝试用kubeadm等工具部署生产级集群。此时需要深入考虑
k8s纳管新节点、高可用控制平面、网络插件选型(Calico、Flannel等)、存储方案、备份恢复等运维问题。也可以考虑使用rancher部署kubernetes集群,Rancher提供了更友好的集群管理界面。
个人经验与避坑指南
-
不要死记硬背命令
: 理解每个命令和YAML字段背后的意图。多使用
kubectl explain命令,例如kubectl explain pod.spec.containers,它会给出官方文档,是学习的最佳伴侣。 -
善用
--dry-run=client -o yaml: 当你不知道一个资源的YAML怎么写时,可以用命令生成模板。例如:kubectl create deployment my-nginx --image=nginx --dry-run=client -o yaml > deploy.yaml,然后在这个基础上修改。 -
调试是常态
: Pod启动失败(ImagePullBackOff, CrashLoopBackOff)、Service无法访问、Ingress不生效是家常便饭。掌握一套排查流程:1)
kubectl describe pod <pod-name>查看事件;2)kubectl logs <pod-name>查看容器日志;3)kubectl exec -it <pod-name> -- sh进入容器内部检查。 -
网络问题是最大的坑
: 很多访问不通的问题都源于网络。理解你的集群网络模型(CNI插件),理解Pod网络、Service网络、节点网络之间的关系。学会使用
kubectl get endpoints检查Service是否关联了正确的Pod,使用dig/nslookup或curl在容器内进行网络测试。 -
资源限制一定要设
: 不给Pod设置资源请求和限制,就像开车不系安全带。一个失控的Pod可能会耗尽节点资源,导致“邻居”应用被杀死。从学习初期就养成设置
resources.requests/limits的好习惯。 -
关注社区与版本
: K8s迭代很快,很多网络上的旧教程(尤其是关于Docker集成、一些API版本)可能已经过时。以官方文档(kubernetes.io)为第一参考,并注意你使用的K8s版本。像
flink kubernetes operator这类特定领域的Operator,也要关注其与K8s版本的兼容性。
学习Kubernetes是一个螺旋上升的过程。从在本地用Minikube跑通第一个Pod,到理解其核心架构和工作原理,再到能规划部署一个高可用的生产集群,每一步都需要理论和实践紧密结合。它不仅仅是一个工具,更代表了一种以应用为中心、声明式、自动化的运维哲学。当你开始用Kubernetes的思维方式去设计和管理应用时,你会发现,从前那些繁琐、重复、易出错的运维操作,正在被这个强大的系统优雅地自动化解决。
更多推荐
所有评论(0)