⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/puhaiyang/article/details/107181685 「水中加点糖」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

大部分的网友,在使用 spring cloud 项目时都是用的 eurake 或 nacos 作的注册中心,但是在项目部署到 kubernetes 中时如果想用 k8s 特有的功能,往往会达不到预期的效果。

spring cloud 和 kubernetes 中有很多组件是类似的,比如 spring cloud 中的 eurake 与 k8s 中 etcd 的类似,spring cloud 中 zuul 和 gateway 与 k8s 中 ingress 或 istio 的类似,spring cloud config 与 k8s configmap 的类似等,对于许多类似的功能组件其实只用一个就行了,比如注册中心只需要用 k8s 的 etcd 就可以了,如果再用上 eurake 部署在 k8s 环境中就确实感觉有点没有必要。

鉴于目前的部署环境都是 kubernetes,为了不让组件重复,我决定将 spring cloud 项目改造成 spring cloud kubernetes 项目,为了方便,就以之前的练习项目 spring boot cloud 项目来改造。

「以下为将spring-boot-cloud项目由spring cloud组件改为spring cloud kubernetes组件的主要内容。」

主要参考官方文档:https://cloud.spring.io/spring-cloud-static/spring-cloud-kubernetes/1.1.3.RELEASE/reference/html/

spring cloud改造为spring cloud kubernetes

去掉eurake注册中心

去掉 eurake 注册中心,使用 kubernetes 的 etcd 来替换。当然不可能真的直接连 kubernetes的 etcd,而是用 DiscoveryClient for Kuberneteshttps://cloud.spring.io/spring-cloud-static/spring-cloud-kubernetes/1.1.3.RELEASE/reference/html/#discoveryclient-for-kubernetes来替换

也就是直接将原来的 eurake 项目删掉,在以前的 eurake 客户端的项目中换成下面这个引用:

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes</artifactId>
</dependency>

Discovery Client implementation that resolves service names to Kubernetes Services.

加入kubernetes的负载均衡器

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
</dependency>

Ribbon client-side load balancer with server list obtained from Kubernetes Endpoints.

替换配置中心

也可以根据自己的需要将配置中心换在k8s的configmap,为了配置文件方便追溯,这里就不进行替换了,有需要的自行替换,如果要进行替换的话,那么原项目中的config-server也就不需要了。

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-config</artifactId>
</dependency>

Load application properties from Kubernetes ConfigMaps and Secrets. Reload application properties when a ConfigMap or Secret changes.

加入打包配置

在 pom 中添加 fabric8 插件的打包配置,这样就可以不用自己写 k8s 的 deployment 和 servcie 了。

<build>
<plugins>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>fabric8-maven-plugin</artifactId>
<version>${fabric8.maven.plugin.version}</version>
<executions>
<execution>
<id>fmp</id>
<goals>
<goal>resource</goal>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<!--docker需要开启远程访问-->
<dockerHost>http://haiyang.dockerhost.com:2375</dockerHost>
<enricher>
<config>
<fmp-service>
<type>NodePort</type>
</fmp-service>
</config>
</enricher>

<!--registry地址,用于推送镜像-->
<!-- <registry>ccr.ccs.tencentyun.com</registry>-->
<!--认证配置,用于私有registry认证,如果忘记了可以去阿里的registry查看-->
<authConfig>
<push>
<username>your usernmae</username>
<password>your password</password>
</push>
</authConfig>
</configuration>
</plugin>
</plugins>
</build>

同时,fabric8 插件生成的 deployment 还会自动生成 readinessProbe 和 livenessProbe。 通过测试发现,readinessProbe 和 livenessProbe 探测生成的端口默认会读取application.yml 配置文件的端口(默认为8080),以及探测地址默认为:actuator/health,所以记得添加 actuator 组件

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

当然对于 fabric8 插件生成的 deployment.yml 和 service.yml 也可以重写,在项目的src\main目录下新建 fabric8 目录,然后重写 deployment.yml 和 service.yml 就可以了。

本地调试方法

安装第三方程序调试(太复杂不推荐)

对于如何在本地运行改造后由spring cloud kubernetes构成的项目,网上的大佬们说说可以通过安装Telepresence和MicroK8s来操作,我大致浏览了下上面两种感觉差别都差不多,都是通过网络代理转发啥的来实现的。但看了下感觉安装在windows上的话还是有点麻烦的,正因为太复杂了所以这种方式不是很推荐,尽管这种方式很牛逼,这里就不仔细研究了,感兴趣的话自行搜索学习即可。

本地调用kubernetes中的服务

将spring.cloud.kubernetes.ribbon.mode修改为service,然后再将对应的服务开放一个端口出来,放一个nodeport出来就可以直接调用了。其实在开发中很少会遇到需要通过本地调远程k8s中的服务的情况,这里就暂不演示了,感兴趣的话自己配置一下就行,还是比较简单的就是有点麻烦。 当然,用Telepresence或MicroK8s这种软件来解决也是可以的

本地调用本地的服务(重点)

在开发中最常见的应该就是本地的服务与服务之前的调用了。 为了方便快捷与简单,如果是spring-cloud-kubernetes的服务,目前推荐的服务调另一个服务的方式是通过修改feign或ribbion的配置的方式来进行调试。 如果在项目中调用另一个服务是用的@FeignClient注解来实现的,那么就可以在@FeignClient注解中添加url参数来实现忽略name的功能从而实现本地请求到本地,如下面这里的写的:

@FeignClient(name = "svcb-service",url = "${local.feign.server.svcb-service.url:}",fallback = ServiceBClient.ServiceBClientFallback.class)
public interface ServiceBClient {

「其原理是因为FeignClient注解中url参数的优先级要高于name,如果url参数有配置值的话,那么则会忽略name的配置,从而实现跳过ribbion直接将请求转发到url配置的目的地址去」

而后,配置文件就可以这样写了:

local:
feign:
server:
svcb-service:
url: http://192.168.1.66:8070

但是上面这样写不是很灵活,最好还是设成读取系统的环境变量,则可以修改成如下的写法

local:
feign:
server:
svcb-service:
url: ${FEIGN_URL_SVCBSERVICE:}

这样当系统配置了环境变量**「FEIGN_URL_SVCBSERVICE」**后,就会读取环境变量的值了,如果系统环境变量中没有配置对应的值的话,则还是会从loadbalancer中请求对应的服务。

在windows中对于环境变量的修改可能通过setx命令进行新增或修改,用wmic命令可进行删除 示例如下:

//新增或修改值
setx FEIGN_URL_SVCBSERVICE http://127.0.0.1:8070
//删除值
wmic ENVIRONMENT where "name='FEIGN_URL_SVCBSERVICE'" delete

由于idea和windows系统的原因,如果这样修改用户的环境变量需重启idea才能生效,比较快的方法是**「在启动程序的时候直接在idea中指定对应的环境变量」**就可以了

idea中配置环境变量

测试本地服务

访问某一个服务

直接访问a服务,a服务会调用b服务,响应正常。

a服务正常

测试服务熔断

将b服务关了,测试熔断。

从响应结果中看出,返回了熔断的信息

测试本地gateway

通过localhost:8060/hello访问本地的网关服务,测试gateway会访问a服务,a服务会调用b服务。

网关正常

从结果中可以看出,服务访问是正常的

测试k8s中的服务

部署spring-boot-cloud到k8s中

有了fabric8插件后对于项目的打包和部署就方便多了,点两下就自动完成项目部署到k8s。

点**「fabric8:build」**完成项目打包,此过程会将对应的项目把成镜像,如果要推送的到私服的话,点push即可。

点**「fabric8:deploy」**会自动完成对应项目部署到k8s中,此过程会执行对应项目下的deployment.yml和service.yml。

fabric8部署k8s项目

测试k8s中的spring-boot-cloud

直接返回网关吧! 先找一下网关的访问地址是多少,执行kubectl get svc获取service列表

# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
config NodePort 10.100.4.179 <none> 30876:30876/TCP 6h44m
gateway NodePort 10.107.190.176 <none> 8060:30860/TCP 77m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6h46m
svca-service ClusterIP 10.105.127.17 <none> 8080/TCP 120m
svcb-service ClusterIP 10.103.100.234 <none> 8070/TCP 6h43m

从上面可以看出,30860是gateway暴露出来的端口,那么直接访问minikube机器的ip加端口就行了:

http://192.168.113.148:30860/hello

没有权限放问出错

呀额,访问出错了,提示default这个namespace下的default这个serviceaccount没有权限,因为spring-cloud-kubernetes需要访问集群中的services列表,但现在没有给这个default的serviceaccount授权,那么在K8S严格的RBAC中就报错了。 解决办法就是给它加添加权限,为了方便直接执行超级命令(不建议使用):

kubectl create clusterrolebinding permissive-binding \
--clusterrole=cluster-admin \
--user=admin \
--user=kubelet \
--group=system:serviceaccounts

给所有的账号都加上超级权限,这样就有权限了,或者将default这个serviceaccount给它绑定一个role

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: default-crb
subjects:
- kind: ServiceAccount
name: default
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin

之所有将cluster-admin绑定给default是因为cluster-admin拥有所有namespace的所有权限,具体的可以describe看一下

[root@control-plane ~]# kubectl describe ClusterRole/cluster-admin
Name: cluster-admin
Labels: kubernetes.io/bootstrapping=rbac-defaults
Annotations: rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
*.* [] [] [*]
[*] [] [*]

将上面的赋权的yml执行后再访问接口看一下执行结果,如果没有生效果的话,可以先将pod删除后,让它们自动重启,再次访问看下结果:

网关访问正常

本示例的代码地址为:https://github.com/puhaiyang/spring-boot-cloud

文章目录
  1. 1. spring cloud改造为spring cloud kubernetes
    1. 1.1. 去掉eurake注册中心
    2. 1.2. 加入kubernetes的负载均衡器
    3. 1.3. 替换配置中心
    4. 1.4. 加入打包配置
  2. 2. 本地调试方法
    1. 2.1. 安装第三方程序调试(太复杂不推荐)
    2. 2.2. 本地调用kubernetes中的服务
    3. 2.3. 本地调用本地的服务(重点)
    4. 2.4. 测试本地服务
      1. 2.4.1. 访问某一个服务
      2. 2.4.2. 测试服务熔断
      3. 2.4.3. 测试本地gateway
  3. 3. 测试k8s中的服务
    1. 3.1. 部署spring-boot-cloud到k8s中
    2. 3.2. 测试k8s中的spring-boot-cloud