计算机系统应用教程网站

网站首页 > 技术文章 正文

SpringBoot、Kubernetes和Istio微服务网格演示源码

btikc 2024-09-30 13:02:42 技术文章 12 ℃ 0 评论

如果单纯使用kubernetes的pod部署Spring微服务,K8s的负载平衡以及代理设置和你微服务应用之间不是非常的智能衔接,。无论如何,部署新的应用程序版本pod需要更加软化的方法。以下是典型的需求:

  • 智能调拨流量,在部署新的应用程序版本容器时,您经常需要以某种比例(即金丝雀Canary测试)分割新容器和当前生产之间的流量
  • 蓝绿部署,在部署新的应用程序版本pod时,假设您需要蓝色/绿色部署
  • 在部署新的应用程序版本pod时,让我们说只有HTTP cookie识别的一些用户可以测试新版本

所有这些问题都可以通过名为istio的神奇工具来解决。

Istio安装

首先是在Istio安装之前,需要以至少4GB的内存启动 Minikube ,否则将无法启动pilot ,阅读stackoverflow讨论;第二个重要的是始终使用Istio Custom Resources Definitions开始安装:

$ kubectl apply -f <ISTIO_INSTALL_HOME> /install/kubernetes/helm/istio/templates/crds.yaml

这是安装后所需的输出:

kubernetes tomask79$ kubectl get pods -n istio-system
NAME READY STATUS RESTARTS AGE
grafana-59b8896965-6jcb8 1/1 Running 4 7d
istio-citadel-856f994c58-jwdp2 1/1 Running 4 7d
istio-cleanup-secrets-glmrz 0/1 Completed 0 7d
istio-egressgateway-5649fcf57-5b885 1/1 Running 4 7d
istio-galley-7665f65c9c-89wsz 1/1 Running 13 7d
istio-grafana-post-install-z9v7z 0/1 Completed 0 7d
istio-ingressgateway-6755b9bbf6-qrvq8 1/1 Running 4 7d
istio-pilot-698959c67b-xpqnj 2/2 Running 11 7d
istio-policy-6fcb6d655f-8mkf4 2/2 Running 18 7d
istio-security-post-install-jn4sr 0/1 Completed 0 7d
istio-sidecar-injector-768c79f7bf-p8xqr 1/1 Running 4 7d
istio-telemetry-664d896cf5-zc8sr 2/2 Running 17 7d
istio-tracing-6b994895fd-wpc2c 1/1 Running 7 7d
prometheus-76b7745b64-hqnrq 1/1 Running 4 7d
servicegraph-5c4485945b-jql54 1/1 Running 12 7d

演示示例

在向您展示Istio流量管理魔术之前,我们将介绍第一个非常简单的Spring Boot MVC应用程序,我们将在两个版本中部署到kubernetes。

版本1:

@RestController
public class ControllerV1 {
 @GetMapping(path = "/service")
 public String getResult() {
 return "Hello I'm V1!";
 }
}

下面是这个版本的k8s的部署,标记mvc-service开始部分:

(mvc-1/istio/kubernetes-deploy/v1-deploy.yaml)

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
 name: mvc-service
spec:
 replicas: 1
 template:
 metadata:
 labels:
 app: mvc-service
 version: v1
 spec:
 containers:
 - name: mvc-service
 image: service-v1:0.0.1-SNAPSHOT
 imagePullPolicy: IfNotPresent
 ports:
 - containerPort: 8080

版本2:

@RestController
public class ControllerV2 {
 @GetMapping(path = "/service")
 public String getResult() {
 return "Hello i'm V2!";
 }
}

下面是这个版本的k8s的部署,标记mvc-service开始部分:

(mvc-2/istio/kubernetes-deploy/v2-deploy.yaml)

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
 name: mvc-service-v2
spec:
 replicas: 1
 template:
 metadata:
 labels:
 app: mvc-service
 version: v2
 spec:
 containers:
 - name: mvc-service
 image: service-v2:0.0.1-SNAPSHOT
 imagePullPolicy: IfNotPresent
 ports:
 - containerPort: 8080

我们在标有“mvc-service”字符串的pod中有两个版本的应用程序。因此kubernetes服务还应该使用标签'mvc-service'来定位pod后端:(mvc-1/istio/kubernetes-deploy/v1-deploy.yaml)

apiVersion: v1
kind: Service
metadata:
 name: mvc-service
 labels:
 app: mvc-service
spec:
 type: NodePort
 ports:
 - port: 8080
 name: http
 selector:
 app: mvc-service

使用Istio支持部署到Kubernetes

好的,我们已经准备好了kubernetes清单,但还没有部署任何东西!为了能够使用Istio流量管理,您需要向您的pod 注入sidecar代理。如果没有istio边车,你就不会形成服务网格。你有两个选择:

  • 通过istioctl 手动注入边车
  • 自动边车注射

我选择了第一个选项并将边车sidecar设置注入到这样的清单中:

istioctl kube-inject -f v1-deploy.yaml >> v1-deploy-istio.yaml

对于第二个版本(文件夹mvc-2 / istio / kubernetes-deploy)同样这么做:

istioctl kube-inject -f v2-deploy.yaml >> v2-deploy-istio.yaml

现在部署生成的kubernetes清单注入istio-sidecar:

kubectl apply -f v1-deploy-istio.yaml

然后部署第二个版本:

kubectl apply -f v2-deploy-istio.yaml

这是部署后所需的输出:

kubectl get pods
NAME READY STATUS RESTARTS AGE
mvc-service-76ffb4bc9f-sdrtn 2/2 Running 10 10d
mvc-service-v2-59ff7d6886-v87jt 2/2 Running 10 10d

每个POD都有两个容器,因为它运行app容器和istio代理边车容器。要查看为pod启动的边车代理,只需键入:

kubernetes - deploy tomask79 $ kubectl describe pod mvc - service - 76 ffb4bc9f - sdrtn

检查事件:

Events:
 Type Reason Age From Message
 ---- ------ ---- ---- -------
 Normal SandboxChanged 8m41s kubelet, minikube Pod sandbox changed, it will be killed and re-created.
 Normal Pulled 8m37s kubelet, minikube Container image "docker.io/istio/proxy_init:1.0.5" already present on machine
 Normal Created 8m35s kubelet, minikube Created container
 Normal Started 8m34s kubelet, minikube Started container
 Normal Pulled 8m34s kubelet, minikube Container image "service-v1:0.0.1-SNAPSHOT" already present on machine
 Normal Created 8m33s kubelet, minikube Created container
 Normal Started 8m33s kubelet, minikube Started container
 Normal Pulled 8m33s kubelet, minikube Container image "docker.io/istio/proxyv2:1.0.5" already present on machine
 Normal Created 8m33s kubelet, minikube Created container
 Normal Started 8m33s kubelet, minikube Started container

Istio形成服务网格

好的,部署了两个版本的Spring Boot MVC应用程序。现在我打赌你对像VirtualService,DestinationRule这样的Istio对象感到困惑......什么时候使用它们,你还在Kubernetes服务吗?在stackoverflow有一个非常好的讨论,这对我来说非常有用。简而言之:

在我们的Spring MVC演示中,我们获得了名为mvc-service的kubernetes 服务。这将是DestinationRule 对象中的主机参数,因为这是提供目标服务的后端。现在我们的mvc-service提供了两个版本的Spring MVC应用程序v1和v2 ,它们将构成服务网格,因此DestinationRule看起来像:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
 name: mvc-service
spec:
 host: mvc-service
 subsets:
 - name: v1
 labels:
 version: v1
 - name: v2
 labels:
 version: v2

在我们的演示中,通过kubectl部署它:

spring-kubernetes-istio tomask79$ kubectl apply -f istio-destionation-rule.yaml 

现在VirtualService进入游戏:

VirtualService定义了一组要在主机被寻址时应用的流量路由规则。每个路由规则定义特定协议的流量的匹配标准。如果流量匹配,则将其发送到注册表中定义的命名目标服务(或其子集 /版本)。

换句话说,您首先部署K8s部署和服务。然后,通过Istio DestionRule定义微服务的网络,然后通过VirtualService设置HTTP路由规则。

用Istio进行金丝雀测试

因此,假设我们的演示SpringMVC应用程序的第二个版本(在服务网格中,子集v2)不够稳定,无法处理满负载,因此我们只将20%的流量路由到它。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
 name: service-gateway
spec:
 hosts:
 - "*"
 gateways:
 - service-gateway
 http:
 - match:
 - uri:
 exact: /service
 route:
 - destination:
 host: mvc-service
 subset: v1
 weight: 80
 - destination:
 host: mvc-service
 subset: v2
 weight: 20

这真的很容易。作为最后一步,我们需要公开服务网关,即Istio-Ingress网关 ,它从服务网格外部获取流量并将其转发到该网关。

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
 name: service-gateway
spec:
 selector:
 istio: ingressgateway # use istio default controller
 servers:
 - port:
 number: 80
 name: http
 protocol: HTTP
 hosts:
 - "*"

在这个repo中提到的网关和虚拟服务都在istio-gateway.yaml文件中,所以让我们部署它:

spring-kubernetes-istio tomask79$ kubectl apply -f istio-gateway.yaml 

好的,这是测试之前所需的输出,服务网格在前:

istioctl get destinationrules -o yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
 annotations:
 kubectl.kubernetes.io/last-applied-configuration: |
 {"apiVersion":"networking.istio.io/v1alpha3","kind":"DestinationRule","metadata":{"annotations":{},"name":"mvc-service","namespace":"default"},"spec":{"host":"mvc-service","subsets":[{"labels":{"version":"v1"},"name":"v1"},{"labels":{"version":"v2"},"name":"v2"}]}}
 creationTimestamp: null
 name: mvc-service
 namespace: default
 resourceVersion: "5722"
spec:
 host: mvc-service
 subsets:
 - labels:
 version: v1
 name: v1
 - labels:
 version: v2
 name: v2
---

然后是virtualservices:

istioctl get virtualservices -o short
VIRTUAL-SERVICE NAME GATEWAYS HOSTS #HTTP #TCP NAMESPACE AGE
mvc-service mvc-service 1 0 default 11d
service-gateway service-gateway * 1 0 default 11d

金丝雀测试

我们需要获取istio-ingress网关和端口的IP地址。

kubectl get service istio-ingressgateway -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.111.15.19 <pending> 80:31380/TCP,443:31390/TCP,31400:31400/TCP,15011:32464/TCP,8060:30626/TCP,853:30365/TCP,15030:31121/TCP,15031:31359/TCP 13d

istio-ingress文档如是说:

如果设置了EXTERNAL-IP值,则您的环境具有可 用于入口网关的外部负载平衡器。如果EXTERNAL-IP值为<none>(或永久<pending>),则您的环境 不会为入口网关提供外部负载平衡器。在这种情况下,您可以 使用service s节点端口访问网关。

这意味着调用我们的金丝雀版本,我们将继续:

 minikube ip
192.168.99.110

现在终于调用了后台,请注意文档中指出的nodeport端口:

10个点击中:2个进入V2版本,8个点击进入V1。

tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello I'm V1!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello I'm V1!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello I'm V1!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello i'm V2!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello I'm V1!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello I'm V1!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello I'm V1!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello I'm V1!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello i'm V2!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello I'm V1!tomask79:spring-kubernetes-istio tomask79$ 

使用Istio进行蓝/绿部署

现在让我们说我们的应用程序的V2版本足够稳定,我们可以将100%的流量路由到它。要使用Istio实现这一点,我们将更改VirtualService中的规则:

将istio-gateway.yaml文件中的VirtualService修改为:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
 name: service-gateway
spec:
 hosts:
 - "*"
 gateways:
 - service-gateway
 http:
 - match:
 - uri:
 exact: /service
 route:
 - destination:
 host: mvc-service
 subset: v2

重新部署:

tomask79:spring-kubernetes-istio tomask79$ kubectl apply -f istio-gateway.yaml 
gateway.networking.istio.io/service-gateway unchanged
virtualservice.networking.istio.io/service-gateway configured

测试蓝/绿部署

现在V2版本应该成为我们的生产版本并处理100%的流量:

tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello i'm V2!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello i'm V2!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello i'm V2!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello i'm V2!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello i'm V2!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello i'm V2!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello i'm V2!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello i'm V2!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello i'm V2!tomask79:spring-kubernetes-istio tomask79$ curl http://192.168.99.110:31380/service
Hello i'm V2!tomask79:spring-kubernetes-istio tomask79$ 

总结

Istio看起来对我来说是超级强大的工具。但它的学习曲线有点长。此外,他们还在配置模型之间进行了重大更改。无论如何,他们支持粘性会话甚至websockets。例如,对于我在EmbedIT中使用的系统,这是两个“必须拥有”的东西。像istio这样的另一个类似工具是Linkerd。你也可以看一下:)

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表