接上篇
三、容器容器云平台落地实践
前面介绍了系统的一些常用功能,接下来介绍宜信容器云平台落地过程中的实践。
3.1 实践——自定义日志采集
容器的使用方式建议用户将日志输出到控制台,但传统应用的日志都是分级别存储,如 Debug 日志、Info 日志、Error 日志等,业务需要采集容器内部指定目录的日志,怎么实现呢?
我们通过二次开发 Kubelet,在容器启动前判断是否有“KUBERNETES_FILELOGS”这个环境变量,如果存在,则将“KUBERNETES_FILELOGS”指定的容器目录挂载到宿主的“/logs/容器名称”这个目录下面,配合公司自研的日志采集插件 Watchdog 便可以将宿主机上这个目录下的文件统一收集。
3.2 实践——TCP 代理出口
在实际过程中我们经常遇到网络对外提供服务的场景,系统中除了 Nginx 提供的 HTTP 反向代理以外,还有一些需要通过 TCP 的方式对外提供的服务,我们通过系统中指定的两台机器安装 Keepalive 和配置虚 IP 的方式,对外暴露 TCP 服务。
3.3 实践——自动扩容
自动扩容,主要是针对业务指标的一些突发流量可以做业务的自动伸缩。其原理非常简单:因为我们所有的性能指标都是通过 Prometheus 统一采集,而 Cluster-mgr 负责多集群管理,它会定时(默认 30s)去 Prometheus 获取容器的各种性能指标,通过上图的公式计算出每个服务的最佳副本个数。公式很简单:就是每个容器的性能指标求和,除以用户定义目标指标值,所得结果即为最佳副本数。然后 Cluster-mgr 会调用 Ipaas 操作多个集群扩容和缩容副本数。
举个例子,现在有一组容器,我希望它的 CPU 利用率是 50%,但当前 4 个副本,每个副本都达到 80%,求和为 320,320 除以 50,最大副本数为 6,得到结果后就可以自动扩容容器的副本了。
3.4 实践——多集群管理
传统模式下,单个 Kubernetes 集群是很难保证服务的状态的,单个集群部署在单个机房,如果机房出现问题,就会导致服务不可用。因此为了保障服务的高可用,我们开发了多集群管理模式。
多集群管理模式的原理很简单:在多个机房分别部署一套 Kubernetes 集群,并在服务创建时,把应用部署到多个 Kubernetes 集群中,对外还是提供统一的负载均衡器,负载均衡器会把流量分发到多个 Kubernetes 集群里去。避免因为一个集群或者机房故障,而影响服务的可用性。
如果要创建 Kubernetes 相关或 Deployment 相关的信息,系统会根据两个集群的资源用量去分配 Deployment 副本数;而如果要创建 PV、PVC 以及 Configmap 等信息,则会默认在多个集群同时创建。
集群控制器的功能是负责检测 Kubernetes 集群的健康状态,如果不健康则发出告警,通知运维人员切换集群,可以将一个集群的服务迁移到另一个集群。两个集群之外通过 Nginx 切换多集群的流量,保障服务的高可用。
这里有 3 点需要注意:
存储迁移。底层提供了多机房共享的分布式存储,可以随着容器的迁移而迁移。
网络互通。网络是通过 Flannel + 共享 etcd 的方案,实现跨机房容器互通及业务之间的相互调用。
镜像仓库间的数据同步。为了实现两个镜像仓库之间镜像的快速拉取,我们在两个机房内都部署了一个镜像仓库,这两个镜像仓库之间的数据是互相同步的,这样就不用跨机房拉取镜像了。
3.5 实践——如何缩短构建时间
如何加速整个 CI/CD 构建的流程?这里总结了四点:
代码 pull 替换 clone。在构建代码的过程中,用 pull 替换 clone 的方式。用 clone 的方式拉取源代码非常耗时,特别是有些源代码仓库很大,拉取代码要耗费十几秒的时间;而用 pull 的方式,如果发现代码有更新,只需要拉取更新的部分就可以了,不需要重新 clone 整个源代码仓库,从而提高了代码拉取的速度。
本地(私有)仓库、mvn 包本地缓存。我们搭建了很多本地(私有)仓库,包括 Java、Python 的仓库,不需要再去公网拉取依赖包,这样不仅更安全,而且速度更快。
预处理脚本。只在第一次构建时触发,之后便可以基于预处理脚本构建的镜像自动构建。
SSD 加持。通过 SSD 硬件的加持,也提高了整个代码构建的速度。
3.6 实践——什么样的程序适合容器
什么样的程序适合运行在容器里?
无操作系统依赖。目前主流容器方案都是基于 Linux 内核的 cgroup 和 namespace 相关技术实现的,这就意味着容器只能在 Linux 系统运行,如果是 Windows 或者 C#之类的程序是无法运行到容器里面的。
无固定 IP 依赖。这个其实不算硬性要求,虽然容器本身是可以实现固定 IP 地址的,但固定的 IP 地址会为 Deployment 的自动伸缩以及集群迁移带来很多麻烦。
无本地数据依赖。容器的重新发布是通过拉取新的镜像启动新的容器进程的方式,这就希望用户不要将数据保存到容器的本地,而是应该借助外部的中间件或者分布式存储保存这些数据。
3.7 避坑指南
在实践过程中会遇到很多问题,本节将列举一些已经踩过的坑,逐一与大家分享我们的避坑经验。
3.7.1 为啥我的服务没有起来?
这种情况可能是因为服务被放在了后台启动,容器的方式和之前虚拟机的方式有很大区别,不能把容器服务放在后台启动,容器启动的进程的 PID 是 1,这个程序进程是容器里唯一的启动进程,如果程序退出了容器就结束了,这就意味着程序不能退出。如果把程序放到后台启动,就会出现进程起来了但容器服务没有起来的情况。
3.7.2 为啥服务启动/访问变慢?
之前使用虚拟机的时候,由于配置比较高(4 核 8G),很多业务人员没有关心过这个问题。使用容器之后,平台默认会选中 1 核 1G 的配置,运行速度相对较慢,这就导致了业务在访问业务的时候会觉得服务启动和访问变慢。
3.7.3 为啥服务会异常重启?
这和配置的健康检查策略有关,如果某应用的配置健康检查策略不通过的话,Kubernetes 的 Liveness 探针将会重启该应用;如果业务是健康的,但提供的健康检查接口有问题或不存在,也会重启这个容器,所以业务要特别注意这个问题。
3.7.4 本地编译可以,为啥服务器上代码编译失败?
这个问题非常常见,大多是由于编译环境和服务器环境的不一致导致的。很多业务在本地编译的时候,本地有一些开发工具的加持,有一些工作开发工具帮助完成了,而服务器上没有这些工具,因此会出现这个问题。
3.7.5 为啥我的历史日志找不到了?
这个问题和容器使用相关,容器里默认会为用户保存最近两天的日志,主机上有一个清理的功能,日志超过两天就会被清理掉。那这些超过两天的日志去哪里查看呢?我们公司有一个统一的日志采集插件 Watchdog,负责采集存储历史日志,可以在日志检索系统中检索到这些历史日志。
3.7.6 为啥 IP 地址会变化?
每次容器重启,其 IP 地址都会发生变化,希望业务人员的代码不要依赖这些 IP 地址去配置服务调用。
3.7.7 为啥流量会打到异常容器?
容器已经异常了,为什么还有流量过来?这个问题具体表现为两种情况:业务没起来,流量过来了;业务已经死了,流量还过来。这种两种情况都是不正常的。
第一种情况会导致访问报错,这种场景一般是通过配合健康检查策略完成的,它会检查容器服务到底起没起来,如果检查 OK 就会把新的流量打过来,这样就解决了新容器启动流量的异常。
第二种情况是和容器的优雅关闭相结合的,容器如果没有匹配优雅关闭,会导致 K8s 先去关闭容器,此时容器还没有从 K8s 的 Service 中摘除,所以还会有流量过去。解决这个问题需要容器里面应用能够支持优雅关闭,发送优雅关闭时,容器开始自己回收,在优雅关闭时间后强制回收容器。
3.7.8 为啥没法登录容器?
很多时候这些容器还没有起来,此时当然就无法登陆。
3.7.9 Nginx 后端应该配置几个?OOM?Cache?
这几个问题也经常遇到。在业务使用过程中会配置 CPU、内存相关的东西,如果没有合理配置,就会导致容器的 OOM。我们新版的容器镜像都是自适应、自动调整 JVM 参数,不需要业务人员去调整配置,
3.8 faketime
容器不是虚拟机,所以有些容器的使用方式并不能和虚拟机完全一致。在我们的业务场景里还有一个问题:业务需要调整时钟。
容器和虚拟机的其中一个区别是:虚拟机是独立的操作系统,修改其中一个虚拟机里的任何东西都不会影响其他虚拟机。而容器除了前面说的几种隔离以外,其他东西都不是隔离的,所有的容器都是共享主机时钟的,这就意味着如果你改了一个容器的时钟,就相当于改了整个所有容器的时钟。
如何解决这个问题呢?我们在网上找到一种方案:通过劫持系统调用的方式修改容器的时钟。但这个方案有一个问题:faketime 不能睡着了。
3.9 使用情况
经过几年的推广,目前宜信容器云平台上已经支持了 100 多条业务线,运行了 3700 个容器,累计发布 17 万次,还荣获了“CNCF 容器云优秀案例”。
四、宜信容器云未来规划
前文介绍了宜信容器云平台目前取得的一些小成就,即宜信容器云平台的 A 点,接下来介绍宜信容器云的 B 点,即未来的一些规划。
4.1 对象存储
公司有很多文件需要对外提供访问,如网页中的图片、视频、pdf、word 文档等,这些文件大部分都是零散地保存在各自系统的存储中,没有形成统一的存储管理。如果文件需要对外提供访问,则是通过 Nginx 反向代理挂载 NAS 存储的方式,这些文件的维护成本非常高,安全性也得不到保障。
我们基于 Ceph 开发一个统一的对象存储服务,把公司零散在各个系统的小文件集中到对象存储中去,对于可以提供外网或公网访问的部分,生成外网访问的 HTTP 的 URL。目前对象存储已经在业务的测试环境上线。
4.2 站点监控
站点监控是一个正在重点研发的功能。公司开源了智能运维工具 UAVstack,侧重于应用的监控,还缺乏服务外部的站点监控。站点监控是为了监控服务接口的运行状态,并发送告警。
我们通过在公司外部部署采集 Agent,这些 Agetnt 会根据用户定义的监控 URL 定时调用接口是否正常运行,如果接口返回数据不符合用户设定条件则发出告警,如 HTTP 返回 5xx 错误或者返回的 body 中包含 ERROR 字符等。
4.3 大数据容器云
在大部分业务迁移到容器后,我们开始尝试将各种大数据中间件(如 Spark、Flink 等)也迁移到 Kubernetes 集群之上,利用 Kubernetes 提供的特性更好地运维这些中间件组件,如集群管理、自动部署、服务迁移、故障恢复等。
4.4 混合部署
公司有很多长任务,这些长任务有一个非常明显的特点:白天访问量较高,晚上访问量较低。对应的是批处理任务,批处理主要指公司的跑批任务,如报表统计、财务账单等,其特点是每天凌晨开始执行,执行时对 CPU 和内存的消耗特别大,但只运行十几分钟或几个小时,白天基本空闲。
为了得到更高的资源利用率,我们正在尝试通过历史数据进行建模,将批处理任务和长任务混合部署。
4.5 未来规划——DevOps 平台
最后介绍我们整个平台的 DevOps 规划。
回到之前容器云的背景,业务需要一套统一的 DevOps 平台,在这个平台上,可以帮助业务完成代码构建、自动化测试、容器发布以及应用监控等一系列功能。
其实这些功能我们基础研发部门都有所涉及,包括自动化测试平台 Gebat、应用监控 UAVStack、容器云平台等,但是业务需要登录到不同的平台,关联不同的数据,而各个平台之间的数据不一致、服务名称不对应,没办法直接互通,操作起来非常麻烦。 我们希望通过建立一个统一的 DevOps 平台,把代码发布、自动化测试、容器运行和监控放到同一个平台上去,让用户可以在一个平台完成所有操作。
本文转载自宜信技术学院网站。
原文链接:http://college.creditease.cn/detail/336
评论