微服務(wù)敏捷開發(fā)最佳實踐
本文介紹本地網(wǎng)絡(luò)與阿里云不互通場景下實現(xiàn)微服務(wù)敏捷開發(fā)的最佳實踐。
背景信息
遇到的問題
有微服務(wù)敏捷開發(fā)實踐經(jīng)驗的開發(fā)測試,經(jīng)常會遇到如下幾種問題。
開發(fā)人員開發(fā)接口,因為依賴其他接口返回,所以無法獨立進行聯(lián)調(diào)測試,需要一個包含依賴的其他所有應(yīng)用的環(huán)境。
開發(fā)人員將開發(fā)的接口部署到環(huán)境后,聯(lián)調(diào)測試不符合預(yù)期,通過日志等方式排查,發(fā)現(xiàn)是依賴的其他應(yīng)用代碼有變更,導(dǎo)致原有的邏輯發(fā)生了變更。
多位開發(fā)人員并行開發(fā)多個應(yīng)用,在聯(lián)調(diào)測試時,只能允許一個應(yīng)用聯(lián)調(diào)測試,其他應(yīng)用需要在該應(yīng)用聯(lián)調(diào)測試完成后才能逐個進行。
應(yīng)用聯(lián)調(diào)測試報錯,Debug時其他開發(fā)測試正在聯(lián)調(diào)測試的接口也報錯。
解決方案
讓流量在Feature環(huán)境內(nèi)流轉(zhuǎn)非常重要,是微服務(wù)敏捷開發(fā)的基礎(chǔ)。
微服務(wù)帶來了敏捷開發(fā)的便利,但是微服務(wù)架構(gòu)本身也給開發(fā)環(huán)境帶來了一定的復(fù)雜性,多個應(yīng)用間形成完整的流量閉環(huán)邏輯,才能避免應(yīng)用間相互影響。微服務(wù)引擎MSE將應(yīng)用直接接入到微服務(wù)治理,綁定環(huán)境并配置標(biāo)簽路由后,即可實現(xiàn)應(yīng)用的精準(zhǔn)流量控制,既能享受到微服務(wù)架構(gòu)帶來的敏捷開發(fā)的便利,又不會給日常開發(fā)環(huán)境的搭建帶來很大的成本。
方案一:每個迭代或Feature都享有一套獨立的完整環(huán)境。
這套獨立的環(huán)境包含了整個微服務(wù)應(yīng)用集所有的應(yīng)用,包含注冊中心和接入層。
從該方案的計算方法我們可以發(fā)現(xiàn),當(dāng)應(yīng)用增加和環(huán)境增加時,成本成倍的增加。
優(yōu)點:實現(xiàn)簡單。
缺點:成本較高。
方案二:基于MSE標(biāo)簽路由功能使用開發(fā)環(huán)境隔離。
表面上看起來有很多套環(huán)境,每個環(huán)境都有一套完整的微服務(wù)應(yīng)用。但是這些環(huán)境內(nèi)的有些應(yīng)用節(jié)點不只屬于某一個環(huán)境,是被多個環(huán)境共享,大大降低了成本。只需要維護一套完整的基線環(huán)境,基線環(huán)境包含了所有微服務(wù)應(yīng)用,也包含了服務(wù)注冊中心、域名、SLB、網(wǎng)關(guān)等其他設(shè)施。在增加Feature環(huán)境時,只需要單獨部署這個Feature所涉及到改動的應(yīng)用即可,而不需要在每個Feature環(huán)境都部署整套的微服務(wù)應(yīng)用及其配套設(shè)施。
維護N套Feature環(huán)境的成本計算方法為:N+M。與方案一乘法計算方法相比,相當(dāng)于零成本增加Feature環(huán)境。這樣我們就可以放心地擴容出多套Feature環(huán)境,每位研發(fā)測試都可以輕松擁有屬于自己的獨立環(huán)境。
具體實現(xiàn)方案如下圖所示。
本文以開發(fā)環(huán)境為本地網(wǎng)絡(luò)與阿里云不互通(本地網(wǎng)絡(luò)沒有專線來連通本地網(wǎng)絡(luò)與阿里云上的VPC,但是希望能讓在本地網(wǎng)絡(luò)啟動的應(yīng)用連接上阿里云上的開發(fā)測試集群,并實現(xiàn)精準(zhǔn)的流量隔離)為例進行說明。如果是以下兩種典型的常見開發(fā)環(huán)境,只需要根據(jù)基本的MSE接入方式和MSE標(biāo)簽路由方式即可直接使用。
開發(fā)環(huán)境的所有應(yīng)用都部署在本地的機房:所有的開發(fā)環(huán)境都在本地,或者本地網(wǎng)絡(luò)內(nèi)自建的數(shù)據(jù)中心,每個開發(fā)小組希望擁有一套獨立的開發(fā)環(huán)境,避免應(yīng)用間相互影響。
本地網(wǎng)絡(luò)與阿里云通過專線互聯(lián)互通:本地網(wǎng)絡(luò)通過專線與阿里云上的VPC實現(xiàn)了互聯(lián)互通。開發(fā)、測試環(huán)境主要部署在阿里云,但是正在開發(fā)的工程,有一部分是運行在本地網(wǎng)絡(luò)的,甚至直接運行在開發(fā)人員的個人電腦上,希望有一套環(huán)境可以獨立地進行聯(lián)調(diào)測試。
前提條件
步驟一:將應(yīng)用接入MSE微服務(wù)治理
將ACK微服務(wù)應(yīng)用接入MSE治理中心,具體操作,請參見ACK微服務(wù)應(yīng)用接入MSE治理中心微服務(wù)治理。
步驟二:部署應(yīng)用并驗證
分別部署spring-cloud-zuul、spring-cloud-a、spring-cloud-b、spring-cloud-c這四個業(yè)務(wù)應(yīng)用,以及注冊中心Nacos Server,模擬出一個真實的調(diào)用鏈路。
您也可以直接在Demo中獲取對應(yīng)的源碼。
Demo應(yīng)用的結(jié)構(gòu)圖下圖,應(yīng)用之間的調(diào)用,既包含了Spring Cloud的調(diào)用,也包含了Dubbo的調(diào)用,覆蓋了當(dāng)前市面上最常用的兩種微服務(wù)框架,這些應(yīng)用均采用了Spring Cloud 、Dubbo的標(biāo)準(zhǔn)用法。
在容器服務(wù)控制臺左側(cè)導(dǎo)航欄中,單擊集群。
在集群列表頁面,單擊目標(biāo)集群名稱或者目標(biāo)集群右側(cè)操作列下的詳情。
在集群管理頁左側(cè)導(dǎo)航欄,選擇 。
在無狀態(tài)頁面選擇命名空間,然后單擊使用YAML創(chuàng)建資源。
使用容器服務(wù)控制臺來部署應(yīng)用為例,使用的YAML文件如下:
說明使用端云互聯(lián)的前提是注冊中心使用的是MSE中的Nacos,所以請您在部署之前修改YAML文件中的
spring.cloud.nacos.discovery.server-addr
和dubbo.registry.address
為您自己購買的MSE Nacos地址。若您使用的是MSE Nacos域名為公網(wǎng)域名,還需要確保為公網(wǎng)域名開啟了白名單。# 部署業(yè)務(wù)應(yīng)用 --- apiVersion: apps/v1 kind: Deployment metadata: name: spring-cloud-zuul spec: selector: matchLabels: app: spring-cloud-zuul template: metadata: labels: app: spring-cloud-zuul msePilotCreateAppName: spring-cloud-zuul spec: containers: - env: - name: JAVA_HOME value: /usr/lib/jvm/java-1.8-openjdk/jre - name: spring.cloud.nacos.discovery.server-addr //MSE Nacos地址配置 value: 'mse-xxxxxxx-nacos-ans.mse.aliyuncs.com:8848' image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-zuul:1.0.0 imagePullPolicy: Always name: spring-cloud-zuul ports: - containerPort: 20000 --- apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-spec: slb.s1.small service.beta.kubernetes.io/alicloud-loadbalancer-address-type: internet name: zuul-slb spec: ports: - port: 80 protocol: TCP targetPort: 20000 selector: app: spring-cloud-zuul type: LoadBalancer status: loadBalancer: {} --- apiVersion: apps/v1 kind: Deployment metadata: name: spring-cloud-a spec: selector: matchLabels: app: spring-cloud-a template: metadata: labels: app: spring-cloud-a msePilotCreateAppName: spring-cloud-a spec: containers: - env: - name: JAVA_HOME value: /usr/lib/jvm/java-1.8-openjdk/jre - name: spring.cloud.nacos.discovery.server-addr value: 'mse-xxxxxxx-nacos-ans.mse.aliyuncs.com:8848' - name: dubbo.registry.address value: 'nacos://mse-xxxxxxx-nacos-ans.mse.aliyuncs.com:8848' image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-a:1.0.0 imagePullPolicy: Always name: spring-cloud-a ports: - containerPort: 20001 livenessProbe: tcpSocket: port: 20001 initialDelaySeconds: 10 periodSeconds: 30 --- apiVersion: apps/v1 kind: Deployment metadata: name: spring-cloud-b spec: selector: matchLabels: app: spring-cloud-b template: metadata: labels: app: spring-cloud-b msePilotCreateAppName: spring-cloud-b spec: containers: - env: - name: JAVA_HOME value: /usr/lib/jvm/java-1.8-openjdk/jre - name: spring.cloud.nacos.discovery.server-addr value: 'mse-xxxxxxx-nacos-ans.mse.aliyuncs.com:8848' - name: dubbo.registry.address value: 'nacos://mse-xxxxxxx-nacos-ans.mse.aliyuncs.com:8848' image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-b:1.0.0 imagePullPolicy: Always name: spring-cloud-b ports: - containerPort: 20002 livenessProbe: tcpSocket: port: 20002 initialDelaySeconds: 10 periodSeconds: 30 --- apiVersion: apps/v1 kind: Deployment metadata: name: spring-cloud-c spec: selector: matchLabels: app: spring-cloud-c template: metadata: labels: app: spring-cloud-c msePilotCreateAppName: spring-cloud-c spec: containers: - env: - name: JAVA_HOME value: /usr/lib/jvm/java-1.8-openjdk/jre - name: spring.cloud.nacos.discovery.server-addr value: 'mse-xxxxxxx-nacos-ans.mse.aliyuncs.com:8848' - name: dubbo.registry.address value: 'nacos://mse-xxxxxxx-nacos-ans.mse.aliyuncs.com:8848' image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-c:1.0.0 imagePullPolicy: Always name: spring-cloud-c ports: - containerPort: 20003 livenessProbe: tcpSocket: port: 20003 initialDelaySeconds: 10 periodSeconds: 30
在MSE治理中心控制臺中選擇對應(yīng)的Region查看應(yīng)用列表,進入應(yīng)用詳情頁的節(jié)點情況。
在本地配置好K8s集群對應(yīng)的kubeconfig文件后,執(zhí)行以下命令:
kubectl get svc,deploy
預(yù)期輸出:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 192.168.xx.xx <none> 4xx/TCP 7d service/zuul-slb LoadBalancer 192.168.xx.xx 47.94.xx.xx 80:319xx/TCP 9m30s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/spring-cloud-a 1/1 1 1 9m30s deployment.apps/spring-cloud-b 1/1 1 1 9m30s deployment.apps/spring-cloud-c 1/1 1 1 9m30s deployment.apps/spring-cloud-zuul 1/1 1 1 9m30s
執(zhí)行
curl http://47.94.xx.xx/A/a
發(fā)起調(diào)用,執(zhí)行以下命令:curl http://47.94.xx.xx /A/a
預(yù)期返回結(jié)果:
A[10.242.xx.xx] -> B[10.242.xx.xx] -> C[10.242.xx.xx]%
步驟三:將IDEA啟動的應(yīng)用接入環(huán)境
在這一步中,將演示如何在網(wǎng)絡(luò)沒有互通的情況下,將本機啟動的應(yīng)用接入到開發(fā)環(huán)境。首先您需要將您K8s集群的kubeconfig文件保存到本機。
下載源碼。本示例工程所有源碼都在 Demo中,將代碼通過Git命令克隆到本地,并且找到mse-simple-demo文件夾中的A、B、C、gateway四個應(yīng)用,即本次最佳實踐所使用的示例。
安裝CloudToolkit插件。最新版本的Cloud Toolkit詳情,請參見 CloudToolkit。
在IDEA的頂部菜單欄依次選擇
,在IDEA中填寫AccessKey ID、AccessKey Secret。說明由于使用端云互聯(lián)功能的時候,需要訪問您的MSE資源,所以這里需要您填寫您的AccessKey ID、AccessKey Secret,并確保此AccessKey ID、AccessKey Secret擁有訪問MSE資源的權(quán)限。
在彈出的Preferences頁面左側(cè)選擇
,配置AccessKey ID、AccessKey Secret信息,單擊保存。在Preferences頁面左側(cè)選擇
,單擊開啟微服務(wù)治理,并配置參數(shù)。參數(shù)
描述
LicenseKey
您阿里云賬號對應(yīng)的MSE產(chǎn)品的 LicenseKey ,您可在MSE控制臺的概覽頁面查看LicenseKey的值。
說明請您做好LicenseKey的保密工作。各個Region的LicenseKey值可能不一致,請選擇對應(yīng)的Region,并和開發(fā)環(huán)境接入的Region保持一致。
App Name
應(yīng)用在接入MSE時所使用的應(yīng)用名,請根據(jù)實際業(yè)務(wù)情況進行配置。
說明應(yīng)用名需要和本次所啟動的應(yīng)用保持一致。
Tag
此應(yīng)用所屬的環(huán)境Tag,基線環(huán)境不用填,其他請根據(jù)實際業(yè)務(wù)情況進行填寫。如果此應(yīng)用屬于feature1環(huán)境,請?zhí)顚慺eature1。
Agent地址
選擇自己應(yīng)用所在的地域,需要和LicenseKey所在的地域、以及基線環(huán)境接入的地域都保持一致。
開啟RPC灰度
支持對Spring Cloud和Dubbo的流量進行精準(zhǔn)控制。默認(rèn)情況下請開啟,除非您明確知道關(guān)閉此選項的使用場景,否則請勿關(guān)閉此選項。
開啟標(biāo)簽染色
推薦開啟,開啟后經(jīng)過此應(yīng)用的流量就只會在對應(yīng)的Tag環(huán)境中流轉(zhuǎn)。
開啟消息灰度
請根據(jù)業(yè)務(wù)實際情況選擇是否開啟,目前僅支持RocketMQ 4.5及以上版本。更多消息灰度相關(guān)的信息,請參見步驟三:為應(yīng)用開啟RocketMQ消息灰度。
配置端云互聯(lián)參數(shù)。
首先需要配代理模式為 K8s。在IDEA的Preference頁面左側(cè)選擇K8s的代理。 ,單擊AddProfile增加一個名稱為
單擊右側(cè)的Add按鈕,選擇代理類型為
Kubernetes
,并選擇配置文件地址和命名空間。在IDEA的Preference頁面左側(cè)選擇產(chǎn)品為微服務(wù)引擎 MSE,并選擇與部署時一致的Region、實例和命名空間,代理選擇已經(jīng)配置的K8s代理,如果您的應(yīng)用是Spring Cloud應(yīng)用,還需要在本地Spring Cloud服務(wù)端口中配置Tomcat的啟動端口。 ,查找并勾選端云互聯(lián)并進行參數(shù)配置。其中
步驟四:啟動應(yīng)用,聯(lián)調(diào)驗證
首先,驗證環(huán)境是否接入成功。
在IDEA中啟動應(yīng)用。啟動應(yīng)用的時候,您如果看到端云互聯(lián)成功的提示,證明端云互聯(lián)功能已經(jīng)生效。
登錄MSE治理中心控制臺,在應(yīng)用列表界面進行查看。
本示例中本機應(yīng)用已經(jīng)成功接入到MSE,并且成功打上了
feature1
的標(biāo)簽。
步驟五:發(fā)起流量調(diào)用進行測試
如果您發(fā)往網(wǎng)關(guān)的Request是HTTP請求,并且這個請求需要在某個環(huán)境(例如上文中配置的環(huán)境標(biāo)簽feature1
)中完成閉環(huán),那么您需要在請求的Header中添加x-mse-tag=[feature1]
,配置完成后流量會自動在指定的環(huán)境內(nèi)完成閉環(huán)。注意這里的Key為x-mse-tag
是固定值,其參數(shù)值名稱需要和環(huán)境標(biāo)簽(上文中配置的alicloud.service.tag
)保持一致。
如果您的請求來源為Dubbo,則需要在RpcContext中增加Attachment,內(nèi)容也是x-mse-tag=[feature1]
。
環(huán)境標(biāo)簽配置完成后,使用curl
命令發(fā)起流量調(diào)用請求,返回結(jié)果如下:
執(zhí)行以下Curl命令:
curl http://47.94.143.xx:80/A/a
調(diào)用結(jié)果如下:
A[10.242.xx.90] -> B[10.242.xx.91] -> C[10.242.xx.152]%
執(zhí)行以下Curl命令:
curl -H"x-mse-tag:feature1" http://47.94.143.xx:80/A/a
調(diào)用結(jié)果如下:
Afeature1[xx.xx.12.118] -> B[10.242.xx.91] -> C[10.242.xx.152]%
您還可以在MSE治理中心控制臺配置轉(zhuǎn)發(fā)規(guī)則,比如設(shè)置name=xiaoming
的流量進入到feature1環(huán)境。
登錄MSE治理中心控制臺。
在左側(cè)導(dǎo)航欄,選擇 ,然后單擊目標(biāo)應(yīng)用名稱為spring-cloud-a的資源卡片。
在左側(cè)導(dǎo)航欄,單擊流量治理,然后單擊標(biāo)簽路由頁簽,在打了
feature1
標(biāo)簽的應(yīng)用流量規(guī)則下方單擊添加。在創(chuàng)建標(biāo)簽路由面板中配置流量規(guī)則,然后單擊確定。
本文示例中設(shè)置的流量規(guī)則條件為
name=xiaoming
。關(guān)于流量規(guī)則的配置,請參見配置標(biāo)簽路由。
流量規(guī)則生效后,可在應(yīng)用概覽頁面查看流量分布結(jié)果。
開啟流量規(guī)則之后,使用
curl
命令發(fā)起流量調(diào)用請求,查看返回結(jié)果。執(zhí)行以下Curl命令:
curl http://47.94.xx.xx:80/A/a
調(diào)用結(jié)果如下:
A[10.242.0.xx] -> B[10.242.0.xx] -> C[10.242.0.xx]%
執(zhí)行以下Curl命令:
curl http://47.94.xx.xx:80/A/a\?name\=xiaoming
調(diào)用結(jié)果如下:
Afeature1[30.225.12.xx] -> B[10.242.0.xx] -> C[10.242.0.xx]%
執(zhí)行以下Curl命令:
curl http://47.94.xx.xx:80/A/a\?name\=xiaoming
調(diào)用結(jié)果如下:
Afeature1[30.225.12.xx] -> B[10.242.0.xx] -> C[10.242.0.xx]%
如果您的網(wǎng)關(guān)應(yīng)用不屬于Java體系,則需要在網(wǎng)關(guān)層配置規(guī)則,目前已經(jīng)支持MSE云原生網(wǎng)關(guān)、Nginx和K8s Ingress等,詳細(xì)的接入方式,請參見 基于MSE云原生網(wǎng)關(guān)實現(xiàn)全鏈路灰度、基于Ingress-nginx網(wǎng)關(guān)實現(xiàn)全鏈路灰度等文檔。