美文网首页互联网科技Java高级架构Java学习笔记
【本人秃顶程序员】SpringBoot、Kubernetes和I

【本人秃顶程序员】SpringBoot、Kubernetes和I

作者: 本人秃顶程序员 | 来源:发表于2019-02-28 21:23 被阅读1次

    ←←←←←←←←←←←← 快!点关注

    如果单纯使用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架构资料,点关注,发简信给我即可,先到先得!

    相关文章

      网友评论

        本文标题:【本人秃顶程序员】SpringBoot、Kubernetes和I

        本文链接:https://www.haomeiwen.com/subject/mmcluqtx.html