从运维角度看微服务
微服务特点
- 服务组件化
每个服务独立开发、部署,有效避免一个服务的修改引起整个系统重新部署。
哪个服务出现问题,修改后重新部署,不影响整个业务。 - 技术栈灵活
约定通信方式,使得服务本身功能实现对技术要求不再那么敏感。
不再采用一种语言开发,通过对接接口互相访问。 - 独立部署
每个微服务独立部署,加快部署速度,方便扩展。 - 扩展性强
每个微服务可以部署多个,并且有负载均衡能力。 - 独立数据
每个微服务有独立的基本组件,例如数据库、缓存等。 
微服务不足
- 沟通成本
 - 数据一致性
 - 运维成本
 - 内部架构复杂性
 - 大量服务如何治理
 - 如何部署
 - 如何监控
 - 数据和事务
 
单体应用 vs 微服务
  
- 将一套业务 按功能拆分 每个服务处理自己的业务
 - 每个业务都由独立的数据库
 - 都通过 apigateway 网关 分发到独立的服务 ,路由转发
 - 如何互相找到对方,通过注册中心,请求会去询问注册中心向哪里转发
 
单体架构优势:
- 易于部署
 - 易于测试
 
单体架构不足:
- 代码膨胀,难以维护
 - 构建、部署成本大
 - 新人上手难
 
k8s治理微服务:
- 产品迭代
 - 无状态
 - 有状态很少应用
 - 把每个微服务作为一个镜像去部署管理、迭代
 
SOA面向服务:
- 把每个功能做成api
 - 每次增加功能服务都要让其他服务去感知
 - 微服务可以通过 注册中心 感知
 - SOA可能需要人工干预,细腻度比微服务大一些
 
Java 微服务框架
- Spring Boot
 - Spring Cloud (Spring生态技术栈,Spring Boot的升级完善,应用最多)
 - Dubbo (阿里云开源 )
 
在K8S平台部署微服务考虑的问题
微服务架构图
  
- 用户通过手机或者浏览器访问域名
 - 访问域名到达前端(前后端分离),访问功能调用对应业务逻辑处理
 - 访问功能的时候,通过负载均衡到达网关,网关作为微服务的入口,认证过滤降级都在这个层面实现,类似nginx的location
 - 网关根据用户请求的url匹配,去注册中心去找提供相应的服务
 - 注册中心保存了所有微服务的信息
 - 每个微服务的数据都保存在自己的数据库中
 - 配置中心存储每个微服务的配置数据,集中化管理
 
微服务架构的理解
- 微服务间如何通信?
- REST API,RPC,MQ
 
 - 微服务如何发现彼此?  
- 注册中心
 
 - 组件之间怎么个调用关系? 
- 查看商品 -> 订单 -> 库存 -> 支付
 - 链路跟踪 打点 判断一个请求经过哪些环节
 
 - 哪个服务作为整个网站入口?
- 网关 作为 服务端入口
 - 前端 作为 用户访问入口
 
 - 哪些微服务需要对外访问? 
- 前端程序调用服务端接口api,前端和网关都需要暴露
 
 - 微服务怎么部署?更新?扩容?
- java 应用 ,微服务jar包,更新jar包,再启动一个jar包服务
 
 - 区分有状态应用与无状态应用
- 网关,微服务都是无状态的,包括注册中心
 - 有状态的都进行持久化,数据库,redis,MQ,分布式存储都按照传统部署
 
 
为什么要用注册中心
 
微服务太多面临的问题:
- 怎么记录一个微服务多个副本接口地址? 新加入的服务如何让其他业务动态感知到
 - 怎么实现一个微服务多个副本负载均衡?
 - 怎么判断一个微服务副本是否可用? SOA的需要监控http,lv做健康检查
 - 主流注册中心:Eureka,Nacos
 
1  | # 注册中心主要解决: 每个微服务之间如何交互  | 
1  | # SOA  | 
Eureka注册中心
- 每启动一个微服务都会被注册到Eureka中
 - Eureka不单存储信息,还提供负载均衡功能,检查接口是否可用
 - 请求访问注册中心的服务,响应给请求的客户端,客户端再去请求微服务
 - 客户端都集成在程序中
 
项目迁移到K8S平台是怎样的流程
 
制作镜像
- 镜像作为交付物
 
 
1  | 1. 基础镜像 CentOS  | 
控制器管理Pod
- Deployment:无状态部署
 - StatefulSet:有状态部署
 - DaemonSet:守护进程部署
 - Job & CronJob:批处理
 
暴露应用
 
- 微服务之间都是通过注册中心通信,而不是走service,所以不大多数微服务不需要service
 - 网关和前端需要ingress暴露
 
对外发布应用
 
Pod 数据持久化
 
容器部署过程中一般有以下三种数据:
- 启动时需要的初始数据,可以是配置文件 configmap,secret
 - 启动过程中产生的临时数据,该临时数据需要多个容器间共享
 - 启动过程中产生的持久化数据
 
日志与监控
主流方案:
- Filebeat+ELK
 - Prometheus+Grafana
 
传统部署与K8S部署区别
 
 
在K8S平台部署 Spring Cloud 微服务项目
熟悉Spring Cloud微服务项目
1  | # 项目代码地址  | 
 
 
- portal 域名 让用户访问
 - portal 访问 ingress 暴露的域名
 - 域名指向网关
 
代码编译构建
1  | # 将代码拉取到部署服务器  | 
1  | [root@k8s-master1 simple-microservice-dev1]# pwd  | 
查看 gateway 配置文件
1  | [root@k8s-master1 resources]# cd /opt/microservic-code/simple-microservice-dev1/gateway-service/src/main/resources  | 
1  | # 不同环境区分  | 
1  | [root@k8s-master1 resources]# cat application-fat.yml  | 
查看微服务的配置文件
1  | # 查看商品微服务的配置文件  | 
查看 eureka 配置文件
1  | [root@k8s-master1 simple-microservice-dev1]# cd eureka-service/src/main/resources/  | 
完成代码的编译构建
- 以上看的都是程序开发的源码,现在查看编译构建状态的代码 dev2
 
1  | # Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件  | 
- dev2中有构建脚本 dockerfile
 
1  | [root@k8s-master1 gateway-service]# cd /opt/microservic-code/simple-microservice-dev2/gateway-service  | 
1  | # 单独测试打包 和 整个项目打包  | 
构建项目镜像并推送到镜像仓库
1  | # 当前是手动构建 使用脚本循环创建  | 
 
部署Spring Cloud项目
部署环境要求
- CoreDNS
 - Ingress Controller
 - MySQL
 
1  | [root@k8s-master2 tomcat-java-demo]# yum -y install mariadb mariadb-server  | 
架构图
- eureka 有状态部署
 - gateway portal 需要对外暴露
 - 微服务通过注册中心,无需service
 
 
服务编排
- 每个微服务都需要yaml部署文件
 - 别忘记更换镜像地址
 
gateway
1  | cd /opt/microservic-code/simple-microservice-dev3/k8s  | 
portal
1  | [root@k8s-master1 k8s]# cat portal.yaml  | 
eureka
1  | # StatefulSet  | 
1  | # 用在这里  | 
order
1  | [root@k8s-master1 k8s]# cat order.yaml  | 
product
1  | [root@k8s-master1 k8s]# cat product.yaml  | 
stock
1  | [root@k8s-master1 k8s]# cat stock.yaml  | 
导入数据库文件到MySQL
1  | [root@k8s-master1 db]# scp *.sql root@172.17.70.252:/tmp  | 
修改配置文件
- 根据实际配置修改配置文件
 - eureka的连裤串
 - mysql连库串 大多在微服务上
 - 如果有修改 需要重新执行脚本打包镜像,还要修改部署的yaml文件,手动很麻烦
 - eureka的连库串 = StatefulSet 有状态部署
 
1  | cd /opt/microservic-code/simple-microservice-dev3/eureka-service/src/main/resources  | 
1  | # gateway  | 
1  | # portal  | 
1  | # order  | 
1  | # product  | 
1  | # stock  | 
1  | # 1. 有修改执行 重新生成镜像  | 
部署资源
创建 命名空间
1  | [root@k8s-master1 k8s]# kubectl create ns ms  | 
创建镜像仓库资源凭证
1  | [root@k8s-master1 k8s]# kubectl create secret docker-registry registry-pull-secret --docker-server=172.17.70.252 --docker-username=admin --docker-password=lx@68328153 --docker-email=admin@ctnrs.com -n ms  | 
部署 eureka
1  | # 有状态应用部署 会一个一个启动  | 
1  | # 访问管理页面  | 
  
  
部署 gateway
1  | # 资源不太够 我就部署一个副本  | 
部署 portal
1  | [root@k8s-master1 k8s]# kubectl apply -f portal.yaml  | 
部署所有微服务
1  | # 如果测试的资源不足 可以用1个副本  | 

部署的服务 都被注册中心发现

测试访问 portal
1  | # 加入hosts  | 



程序调用gateway域名的位置
1  | # 都是前端程序调用  | 

在K8S中部署Eureka集群
- 相互注册
 - 提供健康检查,podIP检查,如果不正常就不会将客户端的请求发送给它
 - 剔除一个eureka,集群也可正常工作
 
1  | # 如果直接对接k8s  | 

生产环境踩坑经验分享
限制了容器资源,还经常被杀死
1  | env:  | 
1  | 1. k8s部署java应用 ,docker不能自动发现java设置的内存,jvm限制无用  | 


滚动更新之健康检查重要性
- 误判健康检查的失败,需要根据应用启动时间判断
 - java启动时间较慢 最好设置一分钟或以上
 - readinessProbe 就绪检查 它检查的是Ready 1/1 准备就绪才会分配流量,否则不会被访问到。微服务不受service控制,所以加不加无所谓
 - livenessProbe 存活检查 判断pod中的应用是否启动成功,比如判断服务端口,如果不成功会根据拉起策略重建,直到启动成功为止
 - 具体要看java服务的启动时间来设置
 - periodSeconds 周期,每间隔10秒来判断一次,可以设置较长
 
1  | readinessProbe:  | 
滚动更新之流量丢失
- 运行的服务pod 已经被注册到 注册中心里了
 - 如果滚动更新 已分配的流量怎么办
 - 只能为每个pod 增加退出时间,让pod等待退出时间 再去销毁
 - 滚动更新是突然kill 没有更新提示,kill之后根据退出时间等待销毁
 - 优雅退出
 
1  | https://mp.weixin.qq.com/s?__biz=MzAwNTM5Njk3Mw==&mid=2247487699&idx=1&sn=7bf9c62b02e017de5666ab4ade9ef3d1&chksm=9b1c1051ac6b99476bf665bf1e10ac3aca9b0b995c2da944909621660547f2dd382845302aba&mpshare=1&scene=23&srcid=&sharer_sharetime=1577617482898&sharer_shareid=e3aed5c2fdec06d648a99b41c36fe174#rd  | 
配置中心 和 注册中心 和 数据库
1  | 1. 配置中心 apollo 安装服务端,配置文件在里面配置好  | 
1  | 1. eureka 可以部署在pod中,也可以部署在pod之外,只要网络互通即可  | 
1  | 1. 还是建议微服务中的数据存储使用原先的数据库存储,而不是使用有状态部署  | 
增加pod流程
- 新增的pod会先加入 eureka里
 - 如果有客户端去请求 eureka 查询这个pod所在的后面业务功能IP,eureka健康检查通过新的pod的后就可以响应回去
 - gateway就作为请求的客户端,根据url查询对应的pod,eureka查询出对应的ip根据负载均衡策略给gateway,gateway再去响应。
 

