←←←←←←←←←←←← 快!点关注
如果单纯使用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。你也可以看一下:)
写在最后:
秃顶程序员的不易,看到这里,点了关注吧!
点关注,不迷路,持续更新!!!
如需Java架构资料,点关注,发简信给我即可,先到先得!
网友评论