企业实战|Kubernetes持续交付实践一

在上两个章节,分别讲述了基础环境的安装以及环境的测试环节,我们也可以理解一个持续集成的环境,那么在此正式进入我们的最终目标,实现整个大框架,将我们的具有生产能力的应用部署到私有Kubernetes集群中来,那么具体搭建Kuberentes环境就不在此赘述,因为机器的内存较小的原因,原本打算开三个节点的Kubernetes,发现实际情况不允许,Gitlab和Harbor服务器台耗费内存,那么带来的另一个原因就是,我们的应用程序多活可能也比较吃力,这里根据实际情况来确定某应用的副本吧;

接下来就正式进入实践环节,对于SpringCloud项目还有一个特点,任何应用向eureka注册,默认是通过主机名来注册的,这不符合我们的需要,因为在Pod内部是无法访问通过主机名来实现Pod访问的,所以此时我们需要修改我们是SpringCloud项目,将其注册方式修改为IP注册,直接利用IP向eureka注册,具体配置方式,在下面会讲到;

eureka

在此主要是说我们的eureka这个项目如何实现持续集成的,首先我们需要知道一个问题,对于SpringCloud项目来讲,对于eureka是个特殊的应用,它是一个无状态应用,但是因为其独有的特性,也就是说其他的任何微服务都需要与其进行注册,所以在此,我们需要使用两种控制器,一种的StateFulSet、Deployment,对于我们的eureka则使用StateFulSet,来让其在Pod重建的时候保证其PodName不发生变化;

Kubernetes预配置

在正式部署之前,我们需要做一些预配置,比如Namespace、ServiceAccount资源也最好事先去创建;

# 创建一个springcloud的Namespace,作为该项目的命名空间[root@node1 ~]# cat springcloud_ns.yamlapiVersion: v1kind: Namespacemetadata:  name: springcloud[root@node1 ~]# kubectl apply -f springcloud_ns.yaml

# 创建一个ServiceAccount,并使其能够管理springcloud这个命名空间[root@node1 ~]# cat springcloud_sa.yamlapiVersion: v1kind: ServiceAccountmetadata:  name: spring  namespace: springcloud---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:  name: springcloud-clusterrolebinding  namespace: springcloudroleRef:  apiGroup: rbac.authorization.k8s.io  kind: ClusterRole  name: cluster-adminsubjects:  - kind: ServiceAccount    name: spring    namespace: springcloud[root@node1 ~]# kubectl apply -f springcloud_sa.yaml# 获取该ServiceAccount的token[root@node1 ~]# kubectl describe secrets -n springcloud $(kubectl describe sa -n springcloud spring|grep '^Tokens'|awk '{print $2}')|awk '/^token/{print $2}'...

eureka配置更新

因为eureka之间也是会相互注册的,所以对于eureka也需要修改其注册地址为现在所有可用的eureka的地址,在后面我们将eureka的副本设为两个,所以这里注册地址也需要写两个,然后还需要修改其配置为IP注册,这样才能让各应用之间互相连通;

# 将eureka的代码clone下来[root@node4 ~]# git clone http://192.168.1.64/SpringCloud/eureka.git[root@node4 ~]# cd eureka/[root@node4 eureka]# cat src/main/resources/application.yml spring:  application:    name: eurekaserver:  port: 6210eureka:  instance:    prefer-ip-address: true  # 修改为IP注册    hostname: eureka  client:    registerWithEureka: true #true表示向注册中心注册自己。    fetchRegistry: false    serviceUrl:  #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务      defaultZone: http://eureka-0.eureka-svc.springcloud.svc.cluster.local:6210/eureka/,http://eureka-1.eureka-svc.springcloud.svc.cluster.local:6210/eureka/  # 配置两个eureka的注册地址# 提交到主干[root@node4 eureka]# git add *[root@node4 eureka]# git commit -m 'edit config'[root@node4 eureka]# git push origin master此处修改了配置,别忘记重新打包上传到我们的Harbor

修改Docker配置

我们的Kubernetes主机之上的docker daemon也需要修改一些配置,主要是因为我们的Harbor仓库的非安全的,所以需要在每台Kubernetes的工作节点配置如下配置;

注意:每台Kuberentes集群的工作节点都需要配置

[root@node1 ~]# cat > /etc/docker/daemon.json << EOF{    "registry-mirrors": ["https://owcyje1z.mirror.aliyuncs.com"],    "insecure-registries":["http://192.168.1.64:8181"]}EOF
[root@node1 ~]# systemctl daemon-reload[root@node1 ~]# systemctl restart docker

Harbor认证

因为我们的Harbor仓库并不是公开访问的,那么此时,我们的Kubernetes在pull镜像的时候有会碰到用户认证的问题,所以我们需要实现配置一个认证的Secret;

首先,我们在Kubernetes主节点上登录一遍,生成registry认证文件

[root@node1 ~]# docker login 192.168.1.64:8181 [root@node1 ~]# cat /root/.docker/config.json {        "auths": {                "192.168.1.64:8181": {                        "auth": "YWRtaW46Y2FpY2hhbmdlbg=="                }        },        "HttpHeaders": {                "User-Agent": "Docker-Client/19.03.8 (linux)"        }}# 得到该文件的base64密文[root@node1 ~]# base64 -w 0 /root/.docker/config.json ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjEuNjQ6ODE4MSI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZZMkZwWTJoaGJtZGxiZz09IgoJCX0KCX0sCgkiSHR0cEhlYWRlcnMiOiB7CgkJIlVzZXItQWdlbnQiOiAiRG9ja2VyLUNsaWVudC8xOS4wMy44IChsaW51eCkiCgl9Cn0=# 基于认证文件来创建Secret[root@node1 ~]# cat registry_auth.yamlapiVersion: v1kind: Secretmetadata:  name: registry  namespace: springclouddata:  .dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjEuNjQ6ODE4MSI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZZMkZwWTJoaGJtZGxiZz09IgoJCX0KCX0sCgkiSHR0cEhlYWRlcnMiOiB7CgkJIlVzZXItQWdlbnQiOiAiRG9ja2VyLUNsaWVudC8xOS4wMy44IChsaW51eCkiCgl9Cn0=  # 上面的base64的密文type: kubernetes.io/dockerconfigjson

配置清单

我们需要预先将eureka的配置清单给做出来,并且将其上传到我们的eureka仓库,具体如下;

# 将eureka的代码clone下来[root@node4 ~]# git clone http://192.168.1.64/SpringCloud/eureka.git[root@node4 ~]# cd eureka/[root@node4 eureka]# cat > eureka.yaml << EOFapiVersion: apps/v1kind: StatefulSetmetadata:  name: eureka  labels:    app: eureka  annotations:    author: cce  namespace: springcloudspec:  serviceName: eureka-svc  replicas: 2  template:    metadata:      name: eureka-pod      namespace: springcloud      labels:        app: eureka    spec:      imagePullSecrets:        - name: registry      containers:        - name: eureka-container          image: 192.168.1.64:8181/springcloud/eureka:4          imagePullPolicy: IfNotPresent          livenessProbe:  # 配置健康状态检查            initialDelaySeconds: 3            successThreshold: 1            timeoutSeconds: 10            failureThreshold: 3            httpGet:              port: 6210              scheme: HTTP      restartPolicy: Always  selector:    matchLabels:      app: eureka---apiVersion: v1kind: Servicemetadata:  name: eureka-svc  namespace: springcloudspec:  selector:    app: eureka  ports:    - name: http      protocol: TCP      port: 6210      targetPort: 6210  clusterIP: None   # 无头Service---apiVersion: extensions/v1beta1kind: Ingressmetadata:  name: springcloud-ingress  namespace: springcloudspec:  rules:    - host: eureka.springcloud.com # 记得将其加入hosts文件 192.168.1.61 eureka.springcloud.com      http:        paths:          - backend:              serviceName: eureka-svc              servicePort: 6210            path: /EOF

[root@node4 eureka]# git add *[root@node4 eureka]# git commit -m 'add kubernetes config'[root@node4 eureka]# git push origin master# 第一次部署的时候先手动部署,但是别忘记了上面做了很多修改,此时需要重新构建下Jenkins,重新生成新的镜像[root@node1 ~]# kubectl apply -f eureka.yaml[root@node1 ~]# kubectl get all -n springcloud NAME           READY   STATUS    RESTARTS   AGEpod/eureka-0   1/1     Running   0          3m10spod/eureka-1   1/1     Running   0          2m56s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGEservice/eureka-svc   ClusterIP   None         <none>        6210/TCP   3m10sNAME                      READY   AGEstatefulset.apps/eureka   2/2     3m10s

# 测试连通性[root@node1 ~]# kubectl exec -it -n springcloud eureka-0 sh/ # wget -S -O /dev/null -q http://eureka-0.eureka-svc.springcloud.svc.cluster.local:6210  # 第一个eureka正常  HTTP/1.1 200  Content-Type: text/html;charset=UTF-8  Content-Language: en-US  Transfer-Encoding: chunked  Date: Wed, 22 Apr 2020 04:28:12 GMT  Connection: close/ # wget -S -O /dev/null -q http://eureka-1.eureka-svc.springcloud.svc.cluster.local:6210 第一个eureka访问第二个eureka正常  HTTP/1.1 200  Content-Type: text/html;charset=UTF-8  Content-Language: en-US  Transfer-Encoding: chunked  Date: Wed, 22 Apr 2020 04:28:16 GMT  Connection: close

测试访问

好了,现在我们的eureka已经手动部署完成,接下来就来测试下eureka是否能够正常访问,因为我们使用的是内部域名所以需要先添加hosts解析

添加hosts解析


测试访问eureka是否部署成功

部署脚本

此处并非进行最后的应用部署,只是测试行的利用Python来调通Kubernetes集群,并且直接使用Python来远程管理集群,为最后一步应用部署做基础;

# 找到上面创建的ServiceAccount的token[root@node1 ~]# kubectl describe secrets -n springcloud $(kubectl describe sa -n springcloud spring|grep '^Tokens'|awk '{print $2}')|awk '/^token/{print $2}'...# 该token就可以作为我们管理这个springcloud命名空间的资源了,先测试下是否能够连通

图片

在原有的持续集成的脚本之上附加一项持续部署的到Kubernetes的代码,实现持续部署



#!/usr/bin/env python3# -*- coding: utf-8 -*-# @Time    : 2020/4/15 23:43# @Author  : CaiChangEn# @Email   : mail0426@163.com# @Software: PyCharmimport docker, os, shutil, time, kubernetes

registry = '192.168.1.64:8181'project = 'springcloud'sitename = 'eureka'webfile = 'eureka.jar'sts_name = 'eureka'sts_namespace = 'springcloud'

class Deploy(object):    def __init__(self, rep, pro, name, file, sname, snamespace):        '''        :param rep: docker仓库地址(Harbor为例);        :param pro: 仓库的项目名称(Harbor为例)        :param name: 仓库的镜像名称;        :param file: 对于SpringCloud项目编译成功后生成的jar包的名称;        '''        print('\033[1;31mStep1 Start initialization\033[0m')        StartTime = time.time()        self.KubernetesObj = kubernetes.client.Configuration()        self.KubernetesObj.host = 'https://192.168.1.61:6443'        self.KubernetesObj.verify_ssl = False        self.KubernetesObj.api_key[            'authorization'] = 'eyJhbGciOiJSUzI1NiIsImtpZCI6IlVxTXN4dGI2UXRlNHFoWmNuSDluRzFLQllKRHVrN2tUVE16TEU2N3lKMVkifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJzcHJpbmdjbG91ZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJzcHJpbmctdG9rZW4tbWh4enEiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoic3ByaW5nIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiZmUzZWNlM2UtNGY2Mi00ZThhLWEzZWYtY2M5NmFlNTVmMjFkIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OnNwcmluZ2Nsb3VkOnNwcmluZyJ9.Qe-UOE9oT34VAlqeNIZuISznxn5nvnGcRvOsp5J7njcJgjXrGHkjGna-h9yBA4epQE6iJ1jgr80GboXNseMHZx8Ui6UuZXwR_GmRCuyziji1nDqRR2UqocQuTaXSKMGeHsa7F4L7gGytTcq9NlkeNAfGX6iTibD01bRjFCJGRxH9VGYKnng_Q89C1C_JmdLW3VLXOvecugd6xsP9CzktQjZB1CBZSuatehPHc3yjFzkKImP7d3W-y-OaYOK-5QSA5L4-IW10tJrlQC4ovwHVqKcVe1uLvWC3dSQkS5TMn3PELA2-r3De2J_h8xAcAgnFCI0gypJynssypmNpSa3nXg'        self.KubernetesObj.api_key_prefix['authorization'] = 'Bearer'        self.StsName = sname        self.StsNamespace = snamespace        self.DockerClientObj = docker.DockerClient()        self.WorkSpace = os.getenv('WORKSPACE')        self.BuildId = os.getenv('BUILD_ID')        self.Context = os.path.join(self.WorkSpace, 'context')        self.SrcDockerFile = os.path.join(self.WorkSpace, 'Dockerfile')        self.DestDockerFile = os.path.join(self.Context, 'Dockerfile')        self.WebSiteFile = os.path.join(self.WorkSpace, 'target', file)        self.BuildTag = os.path.join(rep, pro, name) + ':' + self.BuildId        self.Repository = os.path.join(rep, pro, name)        print('\033[1;32mStep1 Use Time %.3f\033[0m' % float(time.time() - StartTime))
   def createEnv(self):        '''        该方法主要是创建一些初始环境,提供Dockerfile和需要构建的上下文        '''        print('\033[1;31mStep2 create env\033[0m')        StartTime = time.time()        os.mkdir(self.Context)        shutil.move(self.WebSiteFile, self.Context)        shutil.move(self.SrcDockerFile, self.Context)        print('\033[1;32mStep2 Use Time %.3f\033[0m' % float(time.time() - StartTime))        return self.buildImage()



   def deleteImage(self):        '''        该方法主要是删除镜像,如果正在构建的镜像已在本地存在,那么先删除        '''        try:            self.DockerClientObj.images.remove(self.BuildTag)            print('\033[1;34mDeleted Image %s\033[0m' % (self.BuildTag))        except Exception:            pass



   def buildImage(self):        '''        该方法正式开始构建镜像,并且给镜像指定对应的tag,默认的tag为jenkins的BUILD_ID        '''        print('\033[1;31mStep3 Build Image\033[0m')        StartTime = time.time()        self.deleteImage()        ImageObj, BuildLog = self.DockerClientObj.images.build(path=self.Context, quiet=False,                                                               dockerfile=self.DestDockerFile,                                                               tag=self.BuildTag, rm=True,                                                               forcerm=True)        for Log in BuildLog:            print(Log)        print('\033[1;32mStep3 Use Time %.3f\033[0m' % float(time.time() - StartTime))        return self.pushImage()

   def pushImage(self):        '''        该方法主要是将镜像上传到私有仓库,此案例主要是基于http协议的harbor仓库        '''        print('\033[1;31mStep4 Push Image\033[0m')        StartTime = time.time()        PushLog = self.DockerClientObj.images.push(repository=self.Repository, tag=self.BuildId,                                                   auth_config={"username": "admin", "password": "caichangen"},                                                   decode=True)        print(PushLog, end='')        print('\033[1;32mStep4 Use Time %.3f\033[0m' % float(time.time() - StartTime))        self.deleteImage()        return self.deployKubernetes()

   def deployKubernetes(self):        print('\033[1;31mStep5 Deploy Kubernetes\033[0m')        StartTime = time.time()        api_instance = kubernetes.client.AppsV1Api(kubernetes.client.ApiClient(self.KubernetesObj))        sts_instance = api_instance.read_namespaced_stateful_set(name=self.StsName, namespace=self.StsNamespace)        sts_instance.spec.template.spec.containers[0].image=self.BuildTag        api_instance.patch_namespaced_stateful_set(name=self.StsName, namespace=self.StsNamespace,body=sts_instance)        print('\033[1;32mStep5 Deploy Kubernetes %.3f\n部署成功\033[0m' % float(time.time() - StartTime))        return None



deploy = Deploy(registry, project, sitename, webfile, sts_name, sts_namespace)deploy.createEnv()

正式部署


接下来就是正式的正式上线环节了,但是有一点别忘记了,镜像的tag是通过Jenkins的BUILDID来生成的;

可以看到我们的两个eureka副本的镜像tag也变成了Jenkins的BUILDID

[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:5"

收官测试


接下来做最后一次测试,eureka的收官之测;

查看创建的镜像

可以看到,我们的上线流程的切换着来

[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:5"[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:6"[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:6"[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:6"[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:6"[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:6"[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:6"[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:6""192.168.1.64:8181/springcloud/eureka:6"

至此,整个eureka的部署已经完成,那么在下一个环节将结束整个SpingCloud项


原文地址:https://blog.51cto.com/15127549/2660752

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Nacos 中的参数有很多,如:命名空间、分组名、服务名、保护阈值、服务路由类型、临时实例等,那这些参数都是什么意思?又该如何设置?接下来我们一起来盘它。 1.命名空间 在 Nacos 中通过命名空间(Namespace)+ 分组(Group)+服务名(Name)可以定位到一个唯一的服务实例。 命名
Nacos 支持两种 HTTP 服务请求,一个是 REST Template,另一个是 Feign Client。之前的文章咱们介绍过 Rest Template 的调用方式,主要是通过 Ribbon(负载均衡) + RestTemplate 实现 HTTP 服务调用的,请求的核心代码是这样的: @
Nacos 是 Spring Cloud Alibaba 中一个重要的组成部分,它提供了两个重要的功能:服务注册与发现和统一的配置中心功能。 服务注册与发现功能解决了微服务集群中,调用者和服务提供者连接管理和请求转发的功能,让程序的开发者无需过多的关注服务提供者的稳定性和健康程度以及调用地址,因为这
Spring Cloud Alibaba 是阿里巴巴提供的一站式微服务开发解决方案,目前已被 Spring Cloud 官方收录。而 Nacos 作为 Spring Cloud Alibaba 的核心组件之一,提供了两个非常重要的功能:服务注册中心(服务注册和发现)功能,和统一配置中心功能。 Nac
在 Nacos 的路由策略中有 3 个比较重要的内容:权重、保护阈值和就近访问。因为这 3 个内容都是彼此独立的,所以今天我们就单独拎出“保护阈值”来详细聊聊。 保护阈值 保护阈值(ProtectThreshold):为了防止因过多实例故障,导致所有流量全部流入剩余健康实例,继而造成流量压力将剩余健
前两天遇到了一个问题,Nacos 中的永久服务删除不了,折腾了一番,最后还是顺利解决了。以下是原因分析和解决方案,建议先收藏,以备不时之需。 临时实例和持久化实例是 Nacos 1.0.0 中新增了一个特性。临时实例和持久化实例最大的区别是健康检查的方式:临时实例使用客户端主动上报的健康检查模式,而
Spring Cloud Alibaba 技术体系中的 Nacos,提供了两个重要的功能:注册中心(服务注册与发现)功能和配置中心功能。 其中注册中心解决了微服务调用中,服务提供者和服务调用者的解耦,让程序开发者可以无需过多的关注服务提供者和调用者的运行细节,只需要通过 Nacos 的注册中心就可以
负载均衡通器常有两种实现手段,一种是服务端负载均衡器,另一种是客户端负载均衡器,而我们今天的主角 Ribbon 就属于后者——客户端负载均衡器。 服务端负载均衡器的问题是,它提供了更强的流量控制权,但无法满足不同的消费者希望使用不同负载均衡策略的需求,而使用不同负载均衡策略的场景确实是存在的,所以客
本篇文章为大家展示了如何解决Spring Cloud 服务冲突问题,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、背景...
本篇内容主要讲解“spring cloud服务的注册与发现怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“spri...
本篇内容介绍了“Dubbo怎么实现Spring Cloud服务治理 ”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处...
本篇内容主要讲解“SpringCloud相关面试题有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SpringCloud相...
如何分析Spring Cloud Ribbon、Spring Cloud Feign以及断路器,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希
这篇文章主要讲解了“springcloud微服务的组成部分有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“s...
这篇文章主要讲解了“SpringCloud的OpenFeign项目怎么创建”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习...
本篇内容主要讲解“spring cloud oauth3整合JWT后获取用户信息不全怎么办”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带...
怎样解析微服务架构SpringCloud,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。...
这篇文章主要介绍spring cloud中API网关的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、服务网关简介1、外观模式客户端...
本篇内容介绍了“Spring Cloud微服务的相关问题有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处...
本文小编为大家详细介绍“spring cloud config整合gitlab如何搭建分布式的配置中心”,内容详细,步骤清晰,细节处理妥当,希望这篇“spring cloud config整合gi...