经典案例复盘——运维专家讲述如何实现K8S落地(摘抄)
以下是运满满K8s容器化进程记录,摘抄一下,方便以后查阅。
背景介绍
运满满自开始微服务改造以来,线上线下已有数千个微服务的 Java 实例在运行中。这些 Java 实例部署在数百台云服务器或虚机上,除少数访问量较高的关键应用外,大部分实例均混合部署。
这些实例的管理,采用自研平台结合开源软件的方式,已实现通过平台页面按钮菜单执行打包、部署、启动、停止以及回滚指定的版本等基本功能,取得了不错的效果。但仍然存在如下几个痛点:
实例间资源隔离,尤其在高峰期或故障期间,单服务器上不同实例间 CPU 和内存资源的争抢特别明显。
线上某个应用实例异常时需要人工干预,导致较长的故障时间。
大批服务端应用新版上线后,如网站关键功能故障,需要针对每个应用,选择对应的版本,执行回滚操作,整个过程耗时较长。
线下 DEV/QA 环境频繁发布,每次发布都需要先停止老的版本再发布新的版本,会影响到日常测试。
运满满飞速发展的业务,对系统稳定性的要求越来越高,我们急需解决如上问题。
技术调研、选型
最初吸引我们的是容器技术良好的隔离和水平扩展等特性,而 Docker 的口碑以及几年前参与的一些 Docker 项目经验,使得采用 Docker 容器技术成了我们的不二选择。
但我们仍然需要一套容器编排系统,来实现自动化管理 Docker 容器,大致了解下来有 3 个选项:Kubetnetes(K8S)、swarm、mesos
这 3 个我们都不熟悉,而这个项目的节奏很紧迫,不允许我们对这 3 个系统深入了解后再做选择。好在 Github 有一个统计功能,我们在 Github 上查到了这 3 个开源项目的一些基本情况,如下图:
根据这份统计数据,以及拥有 Google 公司的光环,我们在很短的时间内确定了使用 K8S 作为容器编排管理系统。K8S,这个开源项目号称可以自动部署、扩展和管理容器应用,并且能解决如下核心问题:
负载均衡 - 一个应用运行多个同样的容器,内部 Service 提供了统一的访问定义,以负载均衡的方式来提供访问。
服务发现 - Service 和 Kube-DNS 结合,只需要通过固定的 Service 名称就可以访问到对应的容器,不需要独立寻找使用服务发现组件。
高可用 - K8S 会检查服务的健康状态,发现异常时会自动尝试重新启动服务,保障正常运行。
滚动升级 - 在升级过程中 K8S 会有规划的挨个容器滚动升级,把升级带来的影响降低到最小。
自动伸缩 - 可以配置策略当容器资源使用较高会自动增加新的容器来分担压力, 当资源使用率降低会回收容器。
快速部署- 编写好对应的编排脚本, 可以在极短的时间部署一套环境。
资源限制- 对程序限制最大资源使用量避免抢占资源遇到事故或压力也能从容保障基础服务不受影响。
进一步深入了解 K8S 之后,我们大致确定了会用到如下组件、相关技术和系统:
应用部署 K8S Deployment,HPA;
少量基础服务 K8S Daemonset, kube-dns;
对外服务暴露 K8S Ingress, Traefik, Service;
网络插件 Flannel;
监控告警 Heapster, InfluxDB, Grafana, Prometheus;
管理界面 Kubectl, Dashboard, 自研发布管理系统;
制作镜像 Jenkins, Maven, Docker;
镜像仓库 Harbor;
日志收集 Filebeat, Kafka, ELK。
难点和基本原则
线上服务必须在不间断提供服务的情况下迁移,每个应用按比例切分流量,在确保稳定性的前提下迁移到 K8S 集群中。
DEV 环境可批量上线,QA 和 Production 环境上线需要考虑各应用的版本依赖关系。
初期只上无状态的应用。
对研发 /QA 的影响最小化(尽量不给繁忙的研发 /QA 同学增加工作量)。
落地过程剖析Docker 化前后应用发布流程对比
从下图中可以看到 2 个明显的变化:
1. 之前部署的是 war 包、jar 包,之后部署的是 Docker 镜像(镜像中包含 war 包、jar 包)。
2. 之前是先停止再启动应用进程,发布过程中服务会中断,之后是先启动新版本容器,再停止旧版本容器,发布过程中应用一直在提供服务。
迁移中的系统架构
当前业务应用主要分为 2 种,仅供内部应用调用的 RPC 服务(Pigeon 框架)和对外提供服务的 REST API,REST API 可进一步细分为 2 种,已接入 API 网关和未接入 API 网关。其中 RPC 服务和已接入 API 网关的应用均有自己的注册中心,迁移步骤相对简单,在 K8S 集群中启动对应的应用即可。未接入 API 网关的应用采用 K8S Ingress 插件提供对外服务入口,需要一些配置。系统架构如下图,最终目标是要实现将图中下方的两个框内的应用全部迁入 K8S 集群中。
Master 集群的高可用
由于公有云的限制,我们主要结合服务商提供的 SLB 来实现,示意图如下:
K8S 集群内应用对外提供服务
由于集群内 POD 的 IP 地址动态变化,我们采用 Traefik+Ingress+Nginx+SLB 的方式,来提供一个对外服务的统一入口。Traefik 根据 HTTP 请求的域名和路径路由到不同的应用服务,Nginx 则执行一些复杂的诸如 rewrite 等操作,SLB 提供高可用。架构示意图如下:
容器内应用初始化
为了实现同一个镜像可以兼容运行在 DEV、QA、Production 等各种环境,必须编写一个初始化脚本,该脚本被存放在镜像中。当容器启动时,从 Env 变量中读取当前所在的环境,并创建一系列软链到各环境对应的配置文件以及设置日志目录等其他初始化操作,随后 fork 一个新进程用于检测和设置该容器内应用是否已完成正常启动(配合容器 readiness 探针使用),同时调用应用启动脚本。下图为容器内通过软链指向不同的环境配置文件:
下图为容器内通过软链设置日志目录:
K8S 日志收集
当前应用日志均以文件形式存放,且单个实例对应多个日志文件,无法采用 K8S 官方推荐的日志方案。同时由于容器的无状态化,我们必须另想其他办法保存日志。目前采用的是将 Node 上的固定目录作为存储卷挂载到容器内,在容器启动时通过初始化脚本按照应用名 + 容器 IP 生成该容器特定的日志路径。为了便于查看日志,我们提供 3 种途径:
1. 容器内启用 SSH 服务端,发布管理系统中实现 WEBSSH,正常情况下可通过 WEB 页面进入容器命令行查看日志,由于其便利性,推荐首选此方式。
2. 有些情况下容器会启动失败,此时无法进入命令行,可在发布管理系统中找到日志的链接地址,下载到本机后再查看。
3. 此外,我们在所有 Node 上各运行一个 Filebeat 容器,将 Node 上收集到的日志实时发送到 Kafka 集群中,经过处理后存储到 ES 集群,以便日后检索。
下图为 Node 服务器上的日志目录结构:
下图为 Node 服务器上共享的日志下载路径:
K8S 监控
采用 Heapster+InfluxDB+Grafana 组合,需要注意的是其中 InfluxDB 用于存放监控数据,需要将数据持久化。在 Grafana 上制作了不同维度的 dashboard,可根据 Namespace、Node、应用名进行检索,可按照 CPU、内存、网络带宽、硬盘使用量筛选应用,方便故障排查和日常优化。(当然,更好的监控系统是 Prometheus,已经在上线的路上。)
下图为监控大盘:
下图为监控菜单:
下图为某应用的监控图:
Harbor 镜像仓库
Harbor 我们目前采用的是一主多从结构,主库与打包 Jenkins 都在线下网络中,镜像上传到主库后会被自动同步到线下另一个从库以及线上的从库中,如下图所示:
镜像树
我们的规划是构建一颗镜像树,所有的应用都基于这颗树上的基础镜像来构建应用镜像,各应用构建时选择最相似的基础镜像,再增加应用的特殊需求即可。基于此镜像树,我们 95% 以上的应用均无需在 Gitlab 里放置 Dockerfile,Dockerfile 在打包时根据变量自动生成即可,例如:
下图为脚本自动生成的某应用 Dockerfile:
镜像树结构示意图如下:
当前状态
容器化:DEV/QA 环境的应用已完成 Docker 化,产品环境中应用约 98% 已完成 Docker 化。
系统自愈:应用 OOM 或其他 Crash 时,系统能够自动拉起新的节点以替换故障节点,高级健康检查暂未开启(需其他方面配合)。
弹性伸缩:关键应用全部开启弹性伸缩,访问量高峰期观察到的效果很好。
滚动发布:可按指定的比例分批次部署更新应用版本,先更新一批,成功后销毁一批,依次滚动。
快速回滚:当前仅支持单应用快速回滚,后期如需要增加事务级回滚能力,采用 K8S 的 rollout 功能可以方便实现。
一些踩过的坑和建议
1. 底层操作系统采用 CentOS7.x 版本,会比较省事。
2. 阿里云经典网络中的 ECS 无法访问容器 IP,需要先迁移到 VPC 环境,其他公有云情况类似,重点是能自主添加路由。
3. 如果有应用级监控的话,从容器内部采集到的 Memory,Load Average 等信息是底层操作系统的,而不是容器的,这些指标可以依赖专门的容器监控系统。
4. 要注意 ulimit 的限制,容器中并没有对它进行隔离,设置过小的话会遇到一些莫名其妙的问题。
5. 容器中的 root 用户用 netstat 命令可能看不到其他用户所创建的进程的 owner,如果有一些老式的脚本可能会遇到类似问题。
6. 如果有一些内部系统需要直接访问容器的特定端口,headless service 挺好用。
7. Zookeeper有一个单 IP 连接数 60 的默认限制,如果没修改过该参数的话应用迁移到 K8S 之后可能会遇到此问题。
8. 产品环境中的某个访问量大的应用往 K8S 迁移时,可以先分配较多数量的容器,确保能吃下所有流量,之后再根据监控,用弹性伸缩功能来减掉多余的容器。
9. 如果想提前知道 K8S 集群的性能,部署好应用之后做一次压测很有必要。
原文地址:https://mp.weixin.qq.com/s?__biz=MzIzNjUxMzk2NQ==&mid=2247490483&idx=1&sn=af59ead3956cdb07e00d0504660da3b7&chksm=e8d7e471dfa06d6719f287f560907298884c5084ab330c28ff2d610e8c44c4ccff1585fd5ce3&scene=27#wechat_redirect
经典案例复盘——运维专家讲述如何实现K8S落地(摘抄)的更多相关文章
- 经典案例复盘——运维专家讲述如何实现K8S落地
经典案例复盘——运维专家讲述如何实现K8S落地 背景介绍 运满满自开始微服务改造以来,线上线下已有数千个微服务的 Java 实例在运行中.这些 Java 实例部署在数百台云服务器或虚机上,除少数访问量 ...
- Nginx+Lua+Redis整合实现高性能API接口 - 网站服务器 - LinuxTone | 运维专家网论坛 - 最棒的Linux运维与开源架构技术交流社区! - Powered by Discuz!
Nginx+Lua+Redis整合实现高性能API接口 - 网站服务器 - LinuxTone | 运维专家网论坛 - 最棒的Linux运维与开源架构技术交流社区! - Powered by Disc ...
- linux运维、架构之路-K8s数据管理
一.Volume介绍 容器和Pod是短暂的,它们的生命周期可能很短,会被频繁的销毁和创建,存在容器中的数据会被清除,为了持久化保存容器的数据,k8s提供了Volume.Volume的生命周期独立于容器 ...
- linux运维、架构之路-K8s通过Service访问Pod
一.通过Service访问Pod 每个Pod都有自己的IP地址,当Controller用新的Pod替换发生故障的Pod时,新Pod会分配到新的IP地址,例如:有一组Pod对外提供HTTP服务,它们的I ...
- linux运维、架构之路-K8s应用
一.Deployment k8s通过各种Controller管理Pod的生命周期,为了满足不同的业务场景,k8s提供了Deployment.ReplicaSet.DaemonSet.S ...
- linux运维、架构之路-K8s健康检查Health Check
一.Health Check介绍 强大的自愈能力是k8s容器编排引擎一个重要特性,自愈能力的默认实现方式为自动重启发生故障的容器,另外还可以利用Liveness和Readiness探测 ...
- linux运维、架构之路-K8s滚动更新及回滚
一.滚动更新 应用程序一次只更新一小部分副本,更新成功后,再更新更多的副本,最终完成所有副本的更新. 滚动更新的优点:零停机,整个更新过程始终有副本在运行,从而保证了业务的连续性. 1. ...
- 51cto运维培训课程
线路图: Linux运维架构师 基础提高篇(120课时) 基础提高篇(240课时) Linux系统基础及系统管理 Shell编程入门及进阶 linux安全管理和企业级安全防范策略 企业级集群/存储专题 ...
- 大数据运维尖刀班 | 集群_监控_CDH_Docker_K8S_两项目_腾讯云服务器
说明:大数据时代,传统运维向大数据运维升级换代很常见,也是个不错的机会.如果想系统学习大数据运维,个人比较推荐通信巨头运维大咖的分享课:https://url.cn/5HIqOOr,主要是实战强.含金 ...
随机推荐
- QFramework 使用指南 2020(七):Res Kit (1)概述与基本使用
在上一篇,我们刚刚结束了 脚本生成专题,我们知道 QF 提供了两种脚本生成模式,一种是 ViewController + Bind ,另一种是 UI Kit 模式. 本来打算,介绍完 ViewCont ...
- 【百度之星】【java大数+C++做法】hdu 6719 Strassen
代码:递归搜索一下.java大数做法 import java.util.*; import java.math.*; import java.security.MessageDigest; publi ...
- Prim && Kruskal
Electrification Plan Prim #include<iostream> #include<cstring> using namespace std; cons ...
- lightoj 1037 - Agent 47(状压dp)
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1037 #include <iostream> #include & ...
- hdu 2767 Proving Equivalences(tarjan缩点)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2767 题意:问最少加多少边可以让所有点都相互连通. 题解:如果强连通分量就1个直接输出0,否者输出入度 ...
- 前端利器躬行记(4)——webpack进阶
webpack是一个非常强大的工具,除了前文所介绍的基础概念之外,还有各种进阶应用,例如Source Map.模块热替换.集成等,本文会对这些内容做依次讲解. 一. runtime和manifest ...
- map + filter + reduce
map 是对 集合 里面的元素一个接一个的进行某种运算,常常与lambda 结合使用 #求平方: items = [1, 2, 3, 4, 5] squared = list(map(lambda ...
- 在Word指定位置插入富文本域值(html文本)
遇到此问题,首先想到的就是各种百度.结果度娘了一会并没有发现有用的有效的解决方法,哎,看来还得靠自己啊. 首先整理了下手头上的资源,一是HtmlAgilityPack,专门解析Html文本用的:二是我 ...
- Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵进阶实战
Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵进阶实战 在阅读本文前,建议先阅读<Spring Cloud Alibaba | Sentinel:分布式系 ...
- springcloud(五):Spring Cloud 配置中心的基本用法
Spring Cloud 配置中心的基本用法 1. 概述 本文介绍了Spring Cloud的配置中心,介绍配置中心的如何配置服务端及配置参数,也介绍客户端如何和配置中心交互和配置参数说明. 配置中心 ...