4、容器编排与Kubernetes:K8s架构、Pod/Service/Deployment概念、集群搭建
聊到微服务,容器编排是绕不开的话题。而Kubernetes,现在基本就是容器编排的事实标准了。我记得刚接触K8s那会儿,感觉这东西太复杂了,一堆概念,光Pod、Service、Deployment就够我琢磨一阵子的。但用久了你会发现,它的设计其实很巧妙。
4.1 K8s架构:到底谁在管谁?
Kubernetes的架构,说白了就是「一个大脑,一群打工人」。
控制平面(Master节点):这是大脑。负责决策、调度、响应集群事件。
- API Server:所有操作的入口。你敲的
kubectl命令,最终都打到它这里。 - etcd:集群的数据库。存着所有状态信息。我个人习惯把etcd比作「集群的记事本」,丢了它,集群就失忆了。
- Scheduler:调度器。决定一个新Pod该放到哪个Worker节点上跑。
- Controller Manager:控制器管家。确保集群的实际状态跟你的期望状态一致。
工作节点(Worker节点):这是打工人。真正跑你应用的地方。
- Kubelet:每个节点上的代理。负责跟API Server通信,管理Pod的生命周期。
- Kube-proxy:负责网络代理和负载均衡。
- 容器运行时:比如Docker、containerd。真正拉镜像、跑容器的家伙。
核心思想:你只管告诉K8s「我想要什么」,它自己会想办法让集群变成那个样子。这就是声明式管理。
4.2 Pod:最小的调度单元
Pod是K8s里最小的、也是最基本的部署单元。很多人一开始会问:「为什么不能直接跑容器?」
嗯,这里要注意。Pod其实是一个「容器组」。一个Pod里可以有一个或多个容器。这些容器共享网络、存储、以及生命周期。
我在项目中遇到过这样一个场景:一个应用需要边跑业务逻辑,边收集日志。我们就把业务容器和日志收集容器(比如Filebeat)放在同一个Pod里。它们共享网络,日志容器直接读业务容器的日志文件,效率很高。
Pod的关键特性:
- 每个Pod有独立的IP地址
- Pod内的容器通过
localhost互相访问 - Pod是临时性的,挂了会被重新创建(IP也会变)
避坑指南:我曾经犯过一个错,把两个需要独立扩缩容的服务放在同一个Pod里。结果一个服务流量大了,整个Pod都得跟着扩容,浪费资源。记住:Pod里的容器应该「同生共死」。
4.3 Service:稳定的访问入口
Pod的IP是动态的,今天在这,明天可能就换地方了。那客户端怎么访问?
Service就是来解决这个问题的。它提供了一组Pod的稳定访问入口,不管Pod怎么变,Service的IP和端口是不变的。
Service的类型:
| 类型 | 说明 | 使用场景 |
|---|---|---|
| ClusterIP | 集群内部IP,外部无法访问 | 服务间调用 |
| NodePort | 在每个节点上开放一个端口 | 开发测试、简单对外暴露 |
| LoadBalancer | 云厂商提供的负载均衡器 | 生产环境对外暴露服务 |
你想想看,如果没有Service,每次Pod重启你都得去更新客户端配置,那得多崩溃。
4.4 Deployment:声明式的应用管理
Deployment是我用得最多的资源对象。它负责管理Pod的「期望状态」。
说白了,你告诉Deployment:「我要跑3个Nginx Pod,版本是1.21」。Deployment就会一直盯着,如果某个Pod挂了,它会立刻再起一个,保证始终有3个在跑。
Deployment能干的事:
- 滚动更新:逐步替换旧版本Pod,不停机
- 回滚:更新出问题了,一键回到上一个版本
- 扩缩容:流量大了,把Pod数量从3个扩到10个
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
注意:Deployment只管理无状态应用。像数据库这种有状态的服务,得用StatefulSet。我见过有人用Deployment跑MySQL,结果Pod重启后数据全丢了,那叫一个惨。
4.5 集群搭建:从零开始
搭建K8s集群,方法很多。我推荐用kubeadm,官方工具,稳定可靠。
准备工作:
- 至少两台Linux机器(我用的是Ubuntu 20.04)
- 每台机器2核4G以上
- 关闭swap(
swapoff -a) - 安装Docker或containerd
搭建步骤:
- 安装kubeadm、kubelet、kubectl:在所有节点上执行
- 初始化Master节点:
kubeadm init - 配置kubectl:复制admin.conf到用户目录
- 安装Pod网络插件:比如Calico或Flannel
- 加入Worker节点:在Worker节点执行
kubeadm join命令
# 在Master节点执行
kubeadm init --pod-network-cidr=10.244.0.0/16
# 配置kubectl
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 安装Flannel网络插件
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
# 在Worker节点执行(注意替换实际的token)
kubeadm join 192.168.1.100:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxx
个人经验:我第一次搭集群时,卡在Pod网络插件这一步。Flannel和Calico都试了,最后发现是服务器防火墙没关。所以,systemctl stop firewalld 先跑一下,能省很多麻烦。
集群搭好后,跑个kubectl get nodes,看到所有节点都是Ready状态,那感觉,挺爽的。
好了,这一章就聊到这儿。K8s的东西很多,但把Pod、Service、Deployment这三个核心概念吃透,后面学起来就顺了。下一章我们聊聊K8s的存储和配置管理,到时候见。