Spring Cloud Kubernetes之实战服务注册与发现

好久没写文章了,本文主讲利用 k8s 来实现服务的注册与发现,甚至负载均衡,简称 LB,完美无坑版!

环境:

    ubuntu16.04

    docker18.04

    k8s1.13.x +

    maven3.5.3

    java1.8 +

    springboot 2.1.1

    spring-cloud-kubernetes:1.0.1.RELEASE

Relax

1. 前提

Ubuntu下安装docker18.04 or 其它较高版本,k8s1.13.x及以上,jvm环境等。

2. 创建项目

我们都知道,涉及到微服务,那必体现六个字,”高内聚,低耦合”,所以针对不同业务或应用场景,服务模块化很重要,这个不再赘述了。咱们先来创建服务提供方,同样,利用eclipse或IDEA创建一个项目,此处略了。

创建好项目之后,首先引入依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-actuator</artifactId>

        </dependency>

        

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-actuator-autoconfigure</artifactId>

        </dependency>

        

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-kubernetes-config</artifactId>

        </dependency>

        

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-test</artifactId>

            <scope>test</scope>

        </dependency>

        

        <dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-aop</artifactId>

</dependency>

其他数据库,中间件等,可根据项目自行添加。

同样,我们需要配置初始化bean,这就涉及到配置文件bootstrap.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# we enable some of the management endpoints to make it possible to restart the application

management:

  endpoint:

    restart:

      enabled: true

    health:

      enabled: true

    info:

      enabled: true

spring:

  application:

    name: edge-cas

  cloud:

    kubernetes:

      reload:

        #自动更新配置的开关设置为打开

        enabled: true

        #更新配置信息的模式:polling是主动拉取,event是事件通知

        mode: event

        #主动拉取的间隔时间是500毫秒

        #period: 500

      config:

        sources:

        - name: ${spring.application.name}

          namespace: default

      discovery:

        all-namespaces: true

  http:

    encoding:

      charset: UTF-8

      enabled: true

      force: true

  mvc:

    throw-exception-if-no-handler-found: true

  main:

    allow-bean-definition-overriding: true # 当遇到同样名称时,是否允许覆盖注册

接下来就是application.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
server:

  port: 1000

  undertow:

    accesslog:

      enabled: false

      pattern: combined

  servlet:

    session:

      timeout: PT120M

logging:

  path: /data/${spring.application.name}/logs

client:

  http:

    request:

      connectTimeout: 8000

      readTimeout: 30000

      

mybatis:

  mapperLocations: classpath:mapper/*.xml

  typeAliasesPackage: com.gemantic.*.model

到这,基本的配置即完成,同样,我们也引入了k8s的configmap功能,可以新建configmap的yaml文件来创建其configmap。

然后最重要的一点,就是我们需要创建service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: v1

kind: Service

metadata:

  name: demo-cas-service

  namespace: default

spec:

  ports:

  - name: cas01

    port: 1000

    targetPort: cas01

  selector:

    app: demo-cas

这一点很关键,即实现了服务的注册。

然后服务提供者的项目架子搭建好了,自己可以添加一些内容,比如我把它作为微服务架构的统一鉴权中心CAS。

接下来创建服务消费者的项目,同样引入依赖,但这一次不同:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
<dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-actuator</artifactId>

        </dependency>

        

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-actuator-autoconfigure</artifactId>

        </dependency>

        

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-kubernetes-config</artifactId>

            </dependency>

        

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-test</artifactId>

            <scope>test</scope>

        </dependency>

        

        <dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-aop</artifactId>

</dependency>



<dependency>

<groupId>io.kubernetes</groupId>

<artifactId>client-java</artifactId>

<version>${kubernetes-client-version}</version>

<exclusions>

<exclusion>

<groupId>com.squareup.okio</groupId>

    <artifactId>okio</artifactId>

</exclusion>

</exclusions>

</dependency>



<!-- springcloud-k8s-discovery -->



<dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-commons</artifactId>

        </dependency>



<dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-kubernetes-core</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-kubernetes-discovery</artifactId>

        </dependency>



<dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>

        </dependency>



<dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>

        </dependency>

以上是服务消费者的必须依赖,其他的可根据项目自行添加,比如:在线文档swagger,数据库,json解析,权限管理shiro等。

同样,我们也需要配置初始化bean,这就涉及到配置文件bootstrap.yaml:如上

接下来需要配置服务消费者的消费逻辑以及实现负载均衡的策略(application.yaml):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
server:

  port: 1002

  undertow:

    accesslog:

      enabled: false

      pattern: combined

  servlet:

    session:

      timeout: PT120M

  

logging:

  path: /data/${spring.application.name}/logs

client:

  http:

    request:

      connectTimeout: 8000

      readTimeout: 30000

      

mybatis:

  mapperLocations: classpath:mapper/*.xml

  typeAliasesPackage: com.gemantic.*.model

#这是针对所有的提供者服务的消费策略:  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
backend:

  ribbon:

    eureka:

      enabled: false

    client:

      enabled: true

    ServerListRefreshInterval: 5000

    

ribbon:

  ConnectTimeout: 3000

  # 设置全局默认的ribbon的读超时

  ReadTimeout: 1000

  eager-load:

    enabled: true

    clients: demo-cas-service,cloud-admin-service

  MaxAutoRetries: 1 #对第一次请求的服务的重试次数

  MaxAutoRetriesNextServer: 1 #要重试的下一个服务的最大数量(不包括第一个服务)

  #listOfServers: localhost:5556,localhost:5557

  #ServerListRefreshInterval: 2000

  OkToRetryOnAllOperations: true

 NFLoadBalancerRuleClassName:com.netflix.loadbalancer.RoundRobinRule


#这个是针对某个指定服务来进行配置负载均衡的策略
#demo-cas-service:

#  ribbon:

#    ConnectTimeout: 3000

#    ReadTimeout: 60000

#    MaxAutoRetries: 1 #对第一次请求的服务的重试次数

#    MaxAutoRetriesNextServer: 1 #要重试的下一个服务的最大数量(不包括第一个服务)

#    listOfServers: localhost:5556,localhost:5557

#    ServerListRefreshInterval: 2000

#    OkToRetryOnAllOperations: true

#NFLoadBalancerRuleClassName:com.netflix.loadbalancer.RoundRobinRule



hystrix.command.BackendCall.execution.isolation.thread.timeoutInMilliseconds: 5000

hystrix.threadpool.BackendCallThread.coreSize: 5

这样,服务提供者与服务消费者就都新建成功了,接下来就需要丰满自己的业务应用逻辑了,同样,消费者也可以创建configmap来配置管理自己的配置。

接下来就是亲测:

这里,消费者调用提供者,提供者是个cas服务,则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();

map.add("username", username);

map.add("password", password);

logger.info("CAS URL: {}", envConfig.getCas_url());

String respBody = HttpRequestUtil.doPostForm(restTemplate, envConfig.getCas_url(), map);

if (StringUtils.isNotBlank(respBody)) {

JSONObject pobj = JSON.parseObject(respBody);

Object object = pobj.get("message");

Integer code = JSON.parseObject(object.toString()).getInteger("code");

if (code == LoginEnum.LOGIN_SUCCESS.getSeq()) {

Object data = pobj.get("data");

SysUserDto sysUser = JSON.parseObject(data.toString(), SysUserDto.class);

return sysUser;

}

}

这里的环境变量即使configmap提供,值:cas_url: http://demo-cas-service/login,这样我们就完成了调用的逻辑。

亲测有效:

接下来我们如果需要测试LB,需要添加一条脚本:

增加pod:

1
kubectl scale --replicas=2 deployment demo-cas-deployment

这样,我们既看到两个demo-cas-deployment的pod:

同样测试,根据策略轮询调用的方式,这次会请求到该pod上,这里不贴截图了,大家可以试试。

以上,即是分享了k8s带来的第二大优点:

通过service的方式提供了服务的注册与发现,而且单机的k8s本身也不重,所以操作起来也非常之简单。避免了springboot原生提供的eureka、阿里的nacos、zk来作分布式的服务注册与发现要简单的多。减轻系统的繁重,以及避免了系统的冗余。


结束福利

开源实战利用 k8s 作微服务的架构设计代码:

1
2
3
https://gitee.com/damon_one/spring-cloud-k8s
https://gitee.com/damon_one/spring-cloud-oauth2
https://gitee.com/damon_one/Springcloud-Learning-Dalston

欢迎大家 star,多多指教。


关于作者

  笔名:Damon,技术爱好者,长期从事 Java 开发、Spring Cloud 的微服务架构设计,以及结合 Docker、K8s 做微服务容器化,自动化部署等一站式项目部署、落地。目前主要从事基于 K8s 云原生架构研发的工作。Golang 语言开发,长期研究边缘计算框架 KubeEdge、调度框架 Volcano 等。公众号 交个朋友之猿天地 发起人。个人微信 DamonStatham,星球:《交个朋友之猿田地》,个人网站:交个朋友之猿天地 | 微服务 | 容器化 | 自动化,欢迎來撩。


欢迎关注:InfoQ

欢迎关注:腾讯自媒体专栏


欢迎关注

公号:交个朋友之猿天地

公号:damon8

公号:天山六路折梅手


打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2020-2023 交个朋友之猿天地
  • Powered By Hexo | Title - Nothing
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信