spring cloud迁移Kubernetes

本文主要介绍spring boot应用迁移k8s

1.概述

1.1.情况分析

最终目标是所有微服务迁移到k8s,常规公司的微服务从几十个到几百个不等,不同业务域的服务的重要性、吞吐量各不相同,历史架构也各有不同。
同时,生产环境的稳定性无比重要。
概括下来,几个特征:

  1. 微服务数量多
  2. 微服务框架各有不同
  3. 迁移周期长
  4. spring cloud和k8s技术栈不同

从工程和稳定性角度,得到要求:

  1. 多集群,集群间互通
  2. 容器和非容器互通
  3. 改动次数要少。不要折腾研发

通过如下方案,将能够做到:

  • 研发零感知,零改动
  • 可以按照应用、实例逐一切换;不再需要整体升级
  • 可以快速落地

1.2.当前架构

一个公司的常规应用间调用结构,要么是通过注册中心获取实例调用地址,要么是写死的域名服务间调用

1.3.分阶段架构

过程中,根据业务域或者公司关注的角度,部署独立集群。
要求每个集群都可以只存在部分应用,集群内外、集群间均需要能够相互调用。

2.方案

2.1.核心手段

  1. ingress(nginx),应用注册到eureka时,提交域名注册(为每一个应用提供域名)。
  2. 集群外,域名解析到ingress
  3. 集群内,ingress配合coredns分发到pod

服务A->服务B,通过注册中心(eureka)找服务B的实例地址。
当前:服务A->eureka找服务B->获得B1的调用地址(ip+端口)->直联
目标:服务A->eureka找服务B->获得B1的域名+端口->ingress->ingres反向代理到B服务集群

2.2.ingress操作

  1. ingress通过NodePort的方式,暴露一个端口。(不能使用HostNetwork,否则会使用宿主机的dns,而让coredns失效)
  2. ingress固定到指定node上,不做漂移
  3. dns将服务域名解析到ingress的node ip

假设你的镜像代理地址是:docker.test.com
参考官方说明:https://kubernetes.github.io/ingress-nginx/deploy/

1
2
3
4
$ curl "https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.0/deploy/static/provider/cloud/deploy.yaml" -o ingress-nginx-expose.yml
$ sed -i 's/registry.k8s.io/docker.test.com/g' ./ingress-nginx-expose.yml
# 替换所有的nodeSelector为专属node:specify-ingress
$ sed -i 's/kubernetes.io\/os: linux/deploy-type: specify-ingress/g' ./ingress-nginx-expose.yml

修改并暴露一个端口vim ingress-nginx-expose.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
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.10.0
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
externalTrafficPolicy: Local
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- appProtocol: http
name: http
port: 80
protocol: TCP
targetPort: http
nodePort: 30080 #添加一行:端口
- appProtocol: https
name: https
port: 443
protocol: TCP
targetPort: https
nodePort: 30443 #添加一行:端口,实际应该用不到
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: NodePort #修改类型

启动ingress

1
$ kubectl apply -f ingress-nginx-expose.yml

2.3.添加应用的反向代理

假设我们的应用名是:user-center

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ vim ingress-user-center.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: user-center #这里修改为你的AppId
namespace: java-qa # 和你的应用的namespace保持一致
spec:
ingressClassName: nginx
rules:
- host: "k8s-instance-user-center.dev.com" #这里修改为你的服务域名
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: user-center #这里修改为你的AppId
port:
number: 30080 #这里修改为你的服务端口,写死和ingress暴露的端口一致,没有选择
$ kubectl apply -f ingress-user-center.yml

2.4.CI改造

核心说明,服务注册:

  1. 使用域名:-Deureka.instance.hostname=k8s-instance-user-center.dev.com
  2. 关闭preferIP:-Deureka.instance.prefer-ip-address=false
  3. 指定端口:-Dserver.port=30080,必须和ingress暴露的端口一致

2.5.提供域名

  1. 为每一个服务提供域名
  2. 宿主机的private-dns将域名解析到ingress的ip上
  3. ingress反向代理这个域名

2.6.测试方法

通过yml配置驱动

1
2
3
4
# 部署
$ kubectl apply -f k8s-test-user-center.yml --namespace=java-qa --kubeconfig=/root/.kube/config
# 删除
$ kubectl delete -f k8s-test-user-center.yml --namespace=java-qa

如下为应用示例,涉及到的
节点标签参见:Kubernetes上手##3-节点管理
镜像拉取参见:Kubernetes上手#5-1-镜像

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
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-center-deployment
namespace: java-qa
labels:
app: user-center
spec:
minReadySeconds: 120
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
selector:
matchLabels:
app: user-center
template:
metadata:
labels:
app: user-center
spec:
affinity: {}
imagePullSecrets:
- name: my-pull-secret//你的密钥kubectl create secret generic my-pull-secret -n java-qa --from-literal=username=my_account --from-literal=password=my_password
nodeSelector:
deploy-type: "dynamic-node"//你的节点类型kubectl label nodes test-node-03 deploy-type=dynamic-node
containers:
- name: user-center
image: docker.test.com/user-center:1.0
resources:
requests:
memory: "1024Mi"
cpu: "900m"
limits:
memory: "2048Mi"
cpu: "1"
env:
- name: ENV_aaa
value: "k8s-instance-user-center.dev.com"
---
apiVersion: v1
kind: Service
metadata:
name: user-center
namespace: java-qa
spec:
type: ClusterIP
selector:
app: user-center
ports:
- protocol: TCP
port: 30080
targetPort: 30080