SHEIN PaaS参考了很多优秀的社区实践方案,最终使用了基于GitLab + Jenkins + Kubernetes + Harbor 的一套CI/CD工具集,一年多以来,总结开发出了一套公司自己的持续集成和发布的方案。本文着重介绍DevOps实践中几个比较值得分享的经验总结。
PaaS 平台介绍
PaaS
对发布到PaaS的项目代码没有额外的限制(不需要在代码的指定路径包含 Dockerfile、Jenkinsfile 等构建依赖)。充分利用 Dockerfile 的多阶段构建功能,在 Dockerfile 中包含三个阶段:克隆、编译、运行(运行环境只包含构建结果,实现了镜像的最小化)。同时借助 PaaS 提供的基础镜像构建功能,开发人员可以将项目依赖添加到编译镜像中进行缓存,实现镜像构建加速。这样在保证构建灵活性的同时又保证了构建效率。
应用 Dockerfile 示例
因为 Dockerfile 多阶段构建功能的使用,很多构建逻辑不需要在 Jenkinsfile 实现,复杂度降低,为提高可扩展性,减少因为逻辑变更带来的维护成本,PaaS 支持传参触发构建,也支持更新 job xml 配置增加参数等,更重要的是使用 jenkins library 功能,项目构建 job 中只包含传参和函数入口调用等极少的代码,真正的处理逻辑在 jenkins library 中实现,这样在保证了可扩展性的同时又减少了维护成本。
jenkins-library 示例
通过图形化配置生成的 Deployment 等 yaml, 没有在 Jenkins 中发布,而是存储在数据库并直接调用 Kubernetes 接口部署,这样构建和发布分离,有很多使用方式上的考虑,比如,构建一次修改发布多次;只有构建没有发布(借助 Dockerfile 的多阶段构建,将编译结果发布到仓库,用于后续物理部署[特例]);快速回滚(从数据库中直接取出历史版本直接发布即可实现);蓝绿发布、流量控制等复杂逻辑(在平台代码中实现,比使用 Jenkinsfile 增加了复杂度更合适)。
配置应用
应用回滚
发布到 PaaS 上的应用,可以使用多种方式去了解服务状态,比如:查看重启次数及上一次失败原因(error或者oom),查看启动事件(了解应用为什么 pending 或者启动失败),查看控制台日志,查看落盘日志(即使服务没有成功也可以看异常日志),进入容器查看进程状状态及配置(用于测试外部依赖的连通性等)。
启动事件
控制台日志查看
因为集群的差异性,目前还需要用户在不同集群单独创建应用,才可以构建发布到不同的集群。当然,理想的状态是,更抽象的定义应用,屏蔽集群差异,任意指定集群发布。这方面还有很长的路要走。
多集群管理(参考 Wayne)
告警管理平台介绍
告警规则配置
抓取规则导入
企业微信告警
如下是集群管理员和用户日常查看的监控图:(后续将用户常看的服务指标在 PaaS 中直接展示)
集群视角
节点视角
Pod 视角
提升集群稳定性实践
1、配置资源限额可以有效的提高节点和集群稳定性,需要创建应用时为每个服务添加默认资源限额。同时创建 limit-range,为每个没有指定资源配额的服务增加默认限制。
2、低版本内核存在诸多已知问题,比如,3.10 内核集群, calico node 频繁重启解决:sysctl -w net.ipv4.tcp_tw_recycle=0,目前使用内核 4.18.16 版本,稳定运行半年未发现内核相关异常。
3、Pod 长时间 terminating 状态,可能导致 kubelet 状态异常,登陆宿主机,kill -9 对应容器进程临时解决。需要添加 terminating 状态监控,并使用 my_init 改造 Dockerfile,解决因为僵尸进程等进程回收失败导致的无法删除问题。
4、真正做到平滑升级,需要服务:配置就绪探针、配置存活探针、配置 sleep 10 的终止前钩子(如果注入了 istio sidecar,sidecar 也需要配置终止前钩子)、代码处理 SIGTERM 信号主动中断连接。另外如果使用执行命令进行健康检查,所执行的命令不能太耗资源性能,否则可能导致服务异常时,节点负载过高。
5、设置 kubelet 资源预留时,谨慎配置系统资源预留,发现在 Master 节点为 kubelet 配置资源预留导致 Master 组件频繁重启故障。
6、添加节点线程数,打开文件句柄数监控,提前发现异常服务,防止主机资源耗尽。
查看进程子进程数:
find /proc/*/task -maxdepth 0 -type d |while read dir; do count=$(ls "$dir" | wc -l); echo "$dir : $count"; done
查看进程打开文件句柄数:
find /proc/*/fd -maxdepth 1 -type d | while read dir; do count=$(find