Kubernetes部署之Eureka迁移

背景: 由于项目需要,准备将之前的项目搬迁到kubernetes上,项目中使用了一些列组件,其中就包含Eureka注册中心。


1.Eureka简介

Eureka架构一般为:gateway网关+注册中心server+服务编排。
所有服务包括gateway都在注册中心注册,采用Eureka的负载均衡来调用服务。Eureka简单示意图如下:
image.png

迁移思路

EurekaServer

  1. Controller
    对于EurekaServer,它们是一个集群,互相组成高可用的服务中心,把每一个节点想象成kubernetes中一个Pod,然后组成一个server,这就是kubernetes中的Service,另外其他微服务都需要向它们注册,所以需要一个稳定的域名,因此考虑kubernetes中与之对应的StatefulSets。
    StatefulSet有以下特点:

    • 稳定且唯一的网络标识
    • 稳定且持久的存储
    • 有序且优雅的部署和扩展
    • 有序的自动滚动更新
      部署时需要改变Application文件中的配置如下:
      1
      2
      3
      4
      5
      eureka:
      client:
      serviceUrl:
      # 注册中心地址
      defaultZone: http://eureka-server-0.eureka-server.app-test.svc.cluster.local:8761/eureka/,http://eureka-server-1.eureka-server.app-test.svc.cluster.local:8761/eureka/,http://eureka-server-2.eureka-server.app-test.svc.cluster.local:8761/eureka/
      对于每一个StatefulSets中的每个pod其域名如下:
      $(statefulset name)-$(ordinal).$(service name).$(namespace).svc.cluster.local
  2. InternalService
    另外部署StatefulSet需要部署headless服务才能起作用,Headless是一种类型为ClusterIP的Service,主要起到负责此Pod的网络身份保持不变因此我们在创建StatefulSets同时创建Headless服务。配置时需要指定.spec.clusterIP为None.

  3. ExternalService
    上一步骤中配置的ClusterIP只能内网来访问,也就是集群内可见,但由于Eureka提供的可视化监控界面需要从外部浏览器访问,因此可以再搭建一个外部服务如LoadBalance,NodePort,Ingress,目前选择服务方式为NodePort(生产时不建议)。
    整体部署代码【见附录:login-deployment.yaml】

问题一:为什么要使用StatefulSet?
因为我们部署服务时需要提前知道注册中心的地址,由于Kubernetes物理IP不固定的特性(Pod重启机制),我们没办法知道每一台服务节点的位置,所以需要StatefulSet,创建时是按照{0-N-1}的序号创建的,也就是其域名是确定的。
问题二:为什么不能使用集群IP?
首先集群IP需要提前指定(默认k8s自行分配),但不推荐这样做,一是不利于IP资源的利用(只有有一个固定IP段可使用),二是因为我们尝试过使用ClusterIP,发现不是很稳定,原因后续再定位。

2.Application服务

对于具体的生产者(也可能是消费者)服务来说,它们工作的原理是在启动时向EurekaServer端注册信息,有两种方法,一种是域名注册,一种是IP地址注册,因为K8s的Pod可变性,无法使用稳定的域名(另外我们测试过通过域名注册会报Unknownhostexception无法解析主机),因此采用IP地址注册。可以看出它们不需要提前暴露自己的域名和IP,pod变化时,会重新注册IP地址,因此无需部署service。步骤如下:

  1. 修改项目中application.yaml 文件
    1
    2
    3
    4
    5
    6
    7
    eureka:
    client:
    serviceUrl:
    # 注册中心地址
    defaultZone: http://eureka-server-0.eureka-server.app-test.svc.cluster.local:8761/eureka/,http://eureka-server-1.eureka-server.app-test.svc.cluster.local:8761/eureka/,http://eureka-server-2.eureka-server.app-test.svc.cluster.local:8761/eureka/
    instance:
    prefer-ip-address: true
  2. 对于Gateway网关服务,因为它是要对外的一个服务,所以需要在这些节点上面建立一个对外暴露的服务,目前选择NodePort服务

3.整体结构

image.png

附录一 eurekaserver-deployment.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
# ------------------- service ------------------- 
apiVersion: v1
kind: Service
metadata:
name: eureka-server
namespace: app-test
spec:
selector:
app: eureka-server
clusterIP: None
ports:
- name: http
port: 8761
targetPort: 8761
---
# ------------------- StatefulSet -------------------
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: eureka-server
namespace: app-test
spec:
replicas: 3
serviceName: eureka-server
selector:
matchLabels:
app: eureka-server
template:
metadata:
labels:
app: eureka-server
spec:
containers:
- name: eureka-server
image: app/eureka-server:v1
ports:
- containerPort: 8761
env:
- name: spring.profiles.active
value: instance1
---
# ------------------- Service -------------------
apiVersion: v1
kind: Service
metadata:
name: eureka-service-elb
namespace: app-test
spec:
selector:
app: eureka-server
type: NodePort
ports:
- name: http
nodePort: 30066
port: 8761
targetPort: 8761

附录二 gateway-deployment.yml:

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
# ------------------- service(其他服务不需要) ------------------- #
apiVersion: v1
kind: Service
metadata:
name: gateway
namespace: app-test
spec:
selector:
app: pgateway
type: NodePort
ports:
- name: http
nodePort: 30063
port: 8088
targetPort: 8088
---
# ------------------- Deployment ------------------- #
apiVersion: apps/v1
kind: Deployment
metadata:
name: gateway
namespace: app-test
spec:
replicas: 3
selector:
matchLabels:
app: agateway
template:
metadata:
labels:
app: appgateway
spec:
containers:
- name: gateway
image: app/gatewayservice:v1
ports:
- containerPort: 8088
env:
- name: spring.profiles.active
value: test