梗概
Kubernetes相比传统的集群管理方式,表现出更多优势,因而国内互联网公司也都已经大规模使用 Kubernetes。
Kubernetes 拥有大量的用户群体和落地实践,做为生产环境的编排系统在成熟度和稳定性上已得到业界的认可。对于开发工程师来讲,把服务部署到k8s中,将会是运维工作的常态。
把服务迁移到K8S集群之前,需要对服务本身进行一些升级,对K8S进行适配。本文对升级过程中的一些常见问题,以及注意事项进行总结。
把服务迁移到K8S的意义是什么?
先说K8S有哪些特性呢?依据官方文档,有自我修复、弹性伸缩、自动部署和回滚、服务发现和负载均衡、机密和配置管理、批处理等特性。
这些特性无疑解放了开发工程师运维服务器集群的人力,可以把节省出的精力投入到系统设计、编码开发等价值更高的工作当中。
不要只看收益,不看风险。
K8S带给我们诸多收益的同时,也要注意到K8S给我们带来新的问题。
容器漂移
容器漂移是最常见的问题。容器在一台机器关闭,然后再另外一台机器上被启动。发生容器漂移的原因有滚动发布、物理机故障被回收、手工关闭容器、K8S集群进行碎片整理等。
容器漂移会给系统带来的负面影响有,节点一段时间内不可用、IP地址变化、缓存丢失、临时数据文件丢失等。
资源碎片
总有机器的一部分小块资源被闲置,却又不能满足有大块资源需求的服务。资源碎片会影响K8S集群的机器利用率,严重时会影响服务的发布。
资源隔离不完善-IO不能隔离
目前容器技术,没有实现对磁盘IO的资源隔离,因此同一宿主机上如果存在两个磁盘IO密集型的服务,有很大概率会相互影响。
尽管当前的容器技术已经实现对网络IO资源的隔离,但是可能受限于K8S的版本,以及公司内部CICD系统不提供对网络IO隔离的设置,因此对于网路IO资源密集的服务,部署到K8S时也要谨慎处理。
不能隔离的 IO 类型有:
- 内存带宽
- 网络带宽
- 文件带宽
root权限
一些服务会调用只能root才有权限访问的接口,比如mlock。这些服务如果迁移到K8S,需要重新进行设计,因为公司里的CICD服务往往不会允许k8s中的容器以root用户运行。
系统调用失效
物理机和容器里面的接口发生了很大变化,举例说明:
- CPU核数,获取物理机器核数的接口要替换成获取容器CPU核数的接口
- 可用内存大小,获取物理机器内存大小的接口要替换成获取容器内存大小的接口
集群机器性能差异
k8s集群中,服务器可能来自不同厂商,采购的新旧型号不同,配件性能也可能会有差异。尤其不同cpu型号的性能差别巨大。而K8S不能把这种性能差异对应用变得透明。
一般方法是:
- 添加机型约束
- 把资源量化,比如1core 等于100算力(K8S暂未实现此功能)。
把服务迁移到K8S之前需要做哪一些升级?
支持容器化运行和部署
K8S本身就是容器的编排系统,所以服务要能在容器中运行起来。需要编写Dockerfile或docker-compose.yaml文件来实现编译镜像。
服务本身要具有良好的可伸缩性
服务本身需要具有容错机制,其上游也要有失败访问后的重试。除此之外,服务检测、坏点摘除、服务发现,也是必不可少的,所以需要把服务接入名字服务。
支持日志的集中采集
不同于传统的运维方法,我们难以进入每一个容器来查看进程的运行状况。把服务要接入日志中心的系统,在日志中心查阅、追踪系统状态是最好的选择。
监控指标集中上报
和把日志上报到日志中心的原因相同,把服务的监控指标,上传到监控平台/系统。而且为了减少依赖,尽可能使用SDK通过网络的方式上传监控指标,避免通过采集容器内日志文件的方式上报。
数据分片
对于一些数据分片的服务,需要有一个统一的分片管理模块。
可用性
K8S集群不总是可用的,我们在设计服务时,就要考虑对服务进行同城双活、异地多活等方式的部署。为了保证服务的可用性,把服务部署到同城不同K8S集群或者异地不同的k8s集群当中。
其他的注意事项
服务的日志自动清理,不然宿主机的磁盘会被用满,引发故障。
使用分布式文件系统来共享文件,比如ceph、OSS等。
程序异常时产生的coredump文件保留下来,以便排查问题。
自动弹性扩缩容
这是k8s的一个能大大节省运维工作,以及提升资源利用率的功能。
但自动弹性扩容在某些场景下会影响服务的可用性。以故障的灾后恢复为例,有问题的服务,被上线后,CPU负载降低,被自动缩容;问题修复后,开始重新扩容,扩容服务的时间可能是漫长的(可能加载内存数据慢、可能机器较多),服务不可用的时间也会变长。
总结
K8S也是一把双刃剑,一方面把开发工程师从繁琐的运维工作中解放出来;另一方面如何运维部署在K8S上面的服务,K8S较传统方法有较大的不同,开发工程师面对K8S这个新工具,要不断学习和总结。