Kubernetes与OpenStack融合实战:部署方案与避坑指南
1. 从悉尼峰会聊起:为什么这两个平台注定要走到一起
2017年11月的悉尼,OpenStack峰会的会场里,一个现象特别有意思:往年挤满人的虚拟机管理专场,这次人少了不少,而Kubernetes相关的议题场场爆满,连过道都站满了人。我当时在现场跟几个做云平台的老朋友聊天,大家都有一个共识——容器编排和基础设施管理这两件事,不可能长期各玩各的。
这个项目标题“Kubernetes与OpenStack融合之路”,说的就是那几年整个云计算圈最核心的一个技术演进方向。简单来说,OpenStack管的是虚拟机、存储、网络这些底层资源,Kubernetes管的是容器化应用的编排调度,两者各有所长。但实际生产环境里,你不可能让业务团队同时维护两套完全割裂的平台,所以融合就成了必然选择。
这篇文章适合谁看?如果你是云平台运维工程师、基础设施架构师,或者正在做私有云/混合云的技术选型,那这篇内容应该能帮你少走不少弯路。我会从融合的底层逻辑讲起,把几种主流方案的核心原理、实操步骤、参数配置都拆开说清楚,最后再聊聊我在实际落地中踩过的坑和总结的经验。
需要提前说明的是,文中涉及的具体版本号和配置参数,是基于我写这篇文章时的主流稳定版本给出的参考值,你在实际操作时应该根据自己环境的实际情况做调整。技术迭代很快,但底层的设计思路和融合逻辑是相对稳定的,这也是我更想传达给你的东西。
2. 融合的底层逻辑:为什么不是二选一,而是必须打通
2.1 两个平台各自解决什么问题
先把这个事情说透。OpenStack的核心价值在于它能把一堆物理服务器抽象成统一的资源池,提供虚拟机、块存储、对象存储、虚拟网络这些IaaS层的能力。它的优势是资源管理成熟、多租户隔离完善、生态组件丰富。但它的短板也很明显:虚拟机的启动速度、资源利用率、应用部署的敏捷性,跟容器比起来差了一个量级。
Kubernetes的核心价值在于容器编排。它能让你的应用以容器为单位快速部署、弹性伸缩、自愈恢复。但Kubernetes本身不负责底层基础设施的管理,它需要计算资源、存储资源和网络资源,这些资源从哪来?在小规模场景下你可以直接跑在物理机上,但在企业级场景下,你需要一个可靠的IaaS层来提供这些资源。
所以融合的逻辑就很清晰了:OpenStack提供稳定可靠的底层资源池,Kubernetes在这个资源池之上提供敏捷的应用编排能力。两者结合,既能保证基础设施的稳定性和可管理性,又能获得容器化带来的敏捷性。
2.2 融合的三种主流路径
在实际落地中,Kubernetes与OpenStack的融合主要有三种路径,每种路径的适用场景和复杂度都不一样。
第一种是Kubernetes on OpenStack,也就是把Kubernetes集群部署在OpenStack的虚拟机上。这是最直观的方式,OpenStack提供虚拟机,Kubernetes跑在虚拟机里。这种方式的优势是隔离性好、部署简单,适合中小规模场景。但缺点是多了一层虚拟化,性能损耗相对较大,而且Kubernetes无法直接感知底层的物理资源。
第二种是OpenStack on Kubernetes,也就是把OpenStack的各个组件容器化,用Kubernetes来编排和管理OpenStack自身。这种方式在OpenStack社区里被称为“容器化部署”,它的优势是简化了OpenStack的部署和升级流程,提高了组件的可管理性。但这种方式并没有解决应用编排的问题,只是改变了OpenStack自身的部署方式。
第三种是资源统一调度,也就是让Kubernetes能够直接使用OpenStack管理的裸金属资源,或者让OpenStack的虚拟机能够被Kubernetes直接调度。这种方式需要打通两个平台的API和资源模型,技术复杂度最高,但也是融合最彻底的方式。社区里曾经有Nova provider for Kubernetes、Zun(OpenStack的容器服务)等项目在探索这个方向。
注意:选择哪种融合路径,取决于你的实际业务需求。如果你只是想让容器化应用有一个可靠的运行环境,第一种方式就够了。如果你想简化OpenStack自身的运维,第二种方式值得考虑。如果你追求极致的资源利用率和统一调度,那第三种方式是方向,但要做好投入大量精力做定制开发的准备。
2.3 为什么悉尼峰会是一个标志性节点
2017年悉尼峰会之所以重要,是因为在那次峰会上,OpenStack社区和Kubernetes社区的互动达到了一个前所未有的高度。OpenStack基金会和CNCF(云原生计算基金会)之间的合作被正式提上日程,多个跨社区的技术工作组开始运作。也是在那前后,Kata Containers、OpenStack Zun、Magnum等项目获得了更多的关注和资源投入。
从技术演进的视角看,悉尼峰会标志着一个转折点:OpenStack社区不再把Kubernetes视为竞争对手,而是开始认真思考如何与容器生态共存共荣。这个转变对后续几年的技术选型产生了深远影响,很多企业开始采用“OpenStack做底座、Kubernetes做应用平台”的架构。
3. 核心方案拆解:Kubernetes on OpenStack的完整落地细节
3.1 方案选型的考量因素
在决定把Kubernetes部署到OpenStack上之前,有几个关键因素需要仔细评估。
网络方案的选择是最重要的决策之一。OpenStack Neutron提供了丰富的网络能力,但Kubernetes有自己的网络模型(CNI)。你需要决定是让Kubernetes直接使用Neutron的网络,还是在Neutron之上再叠加一层CNI插件。前者集成度更高,但配置复杂;后者更灵活,但多了一层网络抽象,排查问题时会麻烦一些。
存储方案的选择同样关键。OpenStack Cinder提供块存储,Manila提供文件存储,Swift提供对象存储。Kubernetes的PV/PVC模型需要与这些存储服务对接。社区里有Cinder CSI插件、Manila CSI插件等方案,可以实现动态存储供给。你需要根据应用的存储需求(块存储、文件存储、对象存储)来选择合适的CSI插件。
虚拟机规格的设计也需要仔细考虑。Kubernetes的节点虚拟机需要多少CPU、多少内存、什么类型的磁盘,这些都会直接影响集群的性能和成本。我的经验是,控制节点用4核8G起步,工作节点根据实际负载来定,但建议至少8核16G起步,磁盘用SSD,网络用万兆。
3.2 环境准备与前置检查
在开始部署之前,你需要确保OpenStack环境已经就绪。以下是我在实际项目中总结的前置检查清单:
| 检查项 | 具体要求 | 检查方法 |
|---|---|---|
| OpenStack版本 | Queens或更高版本 | openstack --version |
| Neutron网络 | 已配置provider network和tenant network | openstack network list |
| Cinder存储 | 已配置至少一个存储后端 | openstack volume type list |
| 镜像服务 | 已上传Ubuntu 20.04或22.04镜像 | openstack image list |
| 配额 | 足够的CPU、内存、存储配额 | openstack quota show |
| 安全组 | 允许Kubernetes所需端口 | openstack security group list |
安全组规则这块特别容易出问题。Kubernetes需要开放的端口包括:API Server的6443、etcd的2379-2380、kubelet的10250、NodePort的30000-32767等。如果你用的是Flannel或Calico作为CNI插件,还需要开放VXLAN的8472端口或IPIP协议。
提示:我建议在部署Kubernetes之前,先用OpenStack的虚拟机做一个简单的网络连通性测试。创建两台虚拟机,测试它们之间的网络通信是否正常,能否访问外网,DNS解析是否正常。这些基础问题如果没解决,后面部署Kubernetes时会遇到各种莫名其妙的错误。
3.3 虚拟机创建与初始化配置
创建Kubernetes节点虚拟机的命令如下,这里以OpenStack CLI为例:
虚拟机创建完成后,需要进行一系列初始化配置。这些配置在所有节点上都要执行:
这些步骤看起来简单,但每一步都有它的道理。关闭swap是因为Kubernetes的内存管理机制要求如此,否则kubelet会报错。加载br_netfilter模块是为了让iptables能够处理桥接流量,这是Kubernetes Service实现的基础。配置systemd cgroup驱动是为了让containerd和kubelet使用统一的cgroup管理器,避免资源管理混乱。
3.4 Kubernetes集群部署实操
初始化控制节点是整个部署过程中最关键的一步。我使用的是kubeadm工具,这是官方推荐的部署方式:
这里的几个参数需要解释一下。--apiserver-advertise-address是控制节点的IP地址,需要是其他节点能访问到的地址。--pod-network-cidr是Pod网络的网段,不能和OpenStack的虚拟机网段重叠,否则会出现路由冲突。--service-cidr是Service的网段,同样不能和现有网段重叠。
初始化完成后,你会看到类似下面的输出:
把最后那行kubeadm join命令记下来,后面添加工作节点时要用到。然后按照提示配置kubectl:
接下来安装CNI插件。我选择Calico,因为它在OpenStack环境下的兼容性比较好:
等Calico的Pod全部Running之后,控制节点就绪。然后在每个工作节点上执行之前记录的join命令:
所有节点加入后,在控制节点上执行kubectl get nodes,应该能看到所有节点都是Ready状态。
3.5 存储与网络对接OpenStack
Kubernetes集群跑起来之后,下一步是让它能够使用OpenStack的存储和网络资源。
存储方面,安装Cinder CSI插件:
网络方面,如果你想让Kubernetes的LoadBalancer类型的Service直接使用OpenStack的Octavia负载均衡器,需要部署OpenStack Cloud Provider:
这两个对接做完之后,你就可以在Kubernetes里创建PVC,它会自动在Cinder里创建对应的卷;创建LoadBalancer Service,它会自动在Octavia里创建负载均衡器。这种无缝对接的体验,就是融合带来的实际价值。
4. 实操中踩过的坑与排查技巧实录
4.1 网络不通问题的排查思路
在OpenStack虚拟机上部署Kubernetes,网络问题是最常见的。我遇到过好几次Pod之间无法通信的情况,排查过程分享给你。
首先确认Calico的Pod是否正常运行:kubectl get pods -n kube-system | grep calico。如果Calico的Pod处于CrashLoopBackOff状态,大概率是网段冲突。检查--pod-network-cidr设置的网段是否和OpenStack的虚拟机网段重叠。比如你的虚拟机网段是10.0.0.0/24,Pod网段也设成了10.0.0.0/16,那肯定冲突。
如果Calico的Pod正常,但Pod之间还是不通,检查OpenStack安全组是否放行了VXLAN端口(UDP 8472)或IPIP协议。Calico默认使用IPIP模式,需要放行IPIP协议(协议号4)。你可以在安全组里添加一条规则:协议为IPIP,方向为入站和出站,源和目的都是虚拟机网段。
还有一个容易被忽略的问题:OpenStack的Neutron默认会开启端口安全(port security),它会过滤掉非预期的MAC和IP地址。Calico的Pod使用的IP地址不在Neutron的管理范围内,可能会被端口安全规则拦截。解决办法是在虚拟机的端口上禁用端口安全:openstack port set --no-security-group --disable-port-security <port-id>。
4.2 存储挂载失败的常见原因
Cinder CSI插件部署后,创建PVC时可能会遇到挂载失败的问题。最常见的错误是FailedMount,提示信息通常是Unable to attach or mount volumes。
第一个要检查的是cloud-config文件是否正确。Cinder CSI需要访问OpenStack的API,如果认证信息错误,它就无法创建和挂载卷。你可以在Cinder CSI的Pod日志里看到具体的认证错误信息:kubectl logs -n kube-system <cinder-csi-pod-name>。
第二个要检查的是虚拟机是否安装了open-iscsi客户端。Cinder提供的是iSCSI卷,虚拟机需要安装open-iscsi才能挂载:apt-get install -y open-iscsi,然后systemctl enable --now iscsid。
第三个要检查的是Cinder的可用区(availability zone)配置。如果你的OpenStack环境有多个可用区,而PVC的StorageClass没有指定可用区,Cinder可能会在错误的可用区创建卷,导致虚拟机无法挂载。解决办法是在StorageClass里指定availability: nova(根据你的实际可用区名称调整)。
4.3 节点NotReady状态的排查
工作节点加入集群后,如果状态一直是NotReady,通常有几个原因。
先看kubelet的状态:systemctl status kubelet。如果kubelet没有运行,查看日志:journalctl -u kubelet -f。常见的错误包括:containerd没有运行、cgroup驱动不匹配、证书过期等。
如果kubelet运行正常但节点还是NotReady,检查CNI插件是否在该节点上正常运行。Calico的Pod是DaemonSet,每个节点上都应该有一个。如果某个节点上的Calico Pod没有运行,可能是该节点的网络配置有问题。
还有一个不太常见但很坑的问题:OpenStack虚拟机的时钟漂移。如果虚拟机的时钟和实际时间偏差太大,Kubernetes的证书验证会失败,导致节点无法加入集群。解决办法是安装NTP客户端并同步时间:apt-get install -y chrony,然后systemctl enable --now chrony。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| Pod之间无法通信 | 网段冲突 | 检查pod-network-cidr和虚拟机网段 | 重新规划网段,重新初始化集群 |
| PVC挂载失败 | 认证信息错误 | 查看Cinder CSI Pod日志 | 修正cloud-config文件 |
| PVC挂载失败 | 未安装open-iscsi | which iscsiadm |
安装open-iscsi并启动iscsid |
| 节点NotReady | kubelet未运行 | systemctl status kubelet |
查看日志,修复kubelet问题 |
| 节点NotReady | CNI插件异常 | kubectl get pods -n kube-system |
检查Calico Pod日志 |
| 节点NotReady | 时钟漂移 | timedatectl status |
安装并配置NTP客户端 |
| LoadBalancer Service无外部IP | Octavia未配置 | openstack loadbalancer list |
检查cloud.conf中的Octavia配置 |
| API Server无法访问 | 安全组未放行6443端口 | openstack security group rule list |
添加6443端口入站规则 |
提示:这张表里的问题都是我实际遇到过的,但每个环境的具体情况可能不同。排查问题的核心思路是:先看日志,再查配置,最后考虑环境差异。Kubernetes和OpenStack的日志都很详细,关键是要知道去哪里找日志。
5. 融合架构的进阶玩法与个人经验
5.1 多集群管理与联邦调度
当你的业务规模扩大后,单个Kubernetes集群可能不够用。这时候可以考虑多集群管理,把多个Kubernetes集群统一管理起来。社区里有Karmada、Clusternet等项目可以做多集群调度,它们可以和OpenStack的多个Region或可用区配合使用。
我的做法是:在每个OpenStack Region里部署一个Kubernetes集群,然后用Karmada做统一调度。这样既能保证每个Region的独立性,又能实现跨Region的应用部署和流量分发。这种架构的复杂度不低,建议在单集群稳定运行半年以上再考虑。
5.2 监控与日志的整合方案
融合架构的监控需要同时覆盖OpenStack和Kubernetes两个层面。我的方案是:用Prometheus采集Kubernetes的指标,用Gnocchi或Ceilometer采集OpenStack的指标,然后在Grafana里做统一展示。日志方面,用Fluentd或Filebeat采集容器日志,用OpenStack的日志服务采集平台日志,统一发送到Elasticsearch。
这套监控体系搭建起来工作量不小,但一旦跑通,排查问题的效率会大幅提升。我印象最深的一次,一个应用的响应时间突然变长,通过Grafana的看板发现是Cinder的卷IOPS达到了上限,导致数据库查询变慢。如果没有这套监控,这个问题可能要排查很久。
5.3 版本升级的注意事项
OpenStack和Kubernetes的版本迭代都很快,升级是不可避免的。我的经验是:不要同时升级两个平台,先升级一个,稳定运行一段时间后再升级另一个。升级Kubernetes时,先升级控制节点,再升级工作节点,最后升级CNI和CSI插件。升级OpenStack时,按照官方文档的步骤逐个组件升级,不要跳版本。
升级前一定要做备份。etcd的备份尤其重要,它是Kubernetes集群的状态存储,丢了就很难恢复。OpenStack的数据库也要备份,升级过程中如果出现问题,可以快速回滚。
5.4 个人体会
回头看这几年在OpenStack和Kubernetes融合方向上的实践,最大的感受是:技术选型没有绝对的对错,关键是要匹配你的业务需求和团队能力。OpenStack on Kubernetes也好,Kubernetes on OpenStack也好,每种方案都有它的适用场景。不要为了追新而追新,也不要因为某个方案“看起来更先进”就盲目采用。
另外,融合架构的运维复杂度确实比单一平台高。你需要同时掌握两个平台的知识,排查问题时需要跨平台分析。所以如果你的团队规模不大,建议先从简单的方案入手,比如Kubernetes on OpenStack的虚拟机部署,等团队能力跟上后再考虑更复杂的方案。
最后分享一个小技巧:在OpenStack虚拟机上部署Kubernetes时,给虚拟机打上metadata标签,比如k8s-role=control或k8s-role=worker。这样你可以通过OpenStack的API快速筛选出Kubernetes节点,做批量操作时会方便很多。这个技巧看起来不起眼,但在管理大规模集群时能省不少事。