寻找易于使用的 Service Mesh,Maesh 可以实现的功能
从2019年11月21日开始,Maesh的v1.0.0版本已经发布。
Maesh是一种开源的服务网格(Service Mesh),通过DaemonSet在每个节点上启动的代理端点来处理路由。因此,部署到部分应用程序或从Kubernetes的服务迁移都变得更加容易。
引入Sidecar的服务网格,管理清单的方式可以选择动态生成或静态生成,这是一个令人困扰的问题,并且还需要考虑容器之间的Graceful Shutdown。然而,需要注意的是,DaemonSet方式无法满足诸如mTLS等要求。
虽然只有Kubernetes作为可行的平台,但它经过了优化,因此安装和使用都变得非常简单。
作为服务网格,它已经实现了足够的功能。
-
- Load balancing
Protocols
HTTP layer
HTTPS, HTTP/2, native gRPC, Websockets
TCP layer
Route raw TCP connection for any applicative protocol other than HTTP
Retries & Failovers
Circuit breakers & Rate limits
OpenTracing Support
Traffic Metrics
最小化的安装。
请参考官方文档以获得详细的安装方法。
在这里,我们将使用Helm v3,并从最小的组件开始安装,以介绍每个组件的运作方式。
# Maesh 用のネームスペースを作成
❯❯ kubectl create namespace maesh && kubectl config set-context $(kubectl config current-context) --namespace=maesh
# Helm のバージョンは v3 を利用
❯❯ helm version
version.BuildInfo{Version:"v3.0.0", GitCommit:"e29ce2a54e96cd02ccfce88bee4f58bb6e2a28b6", GitTreeState:"clean", GoVersion:"go1.13.4"}
# Maesh のリポジトリを登録
❯❯ helm repo add maesh https://containous.github.io/maesh/charts && helm repo update
# マニフェスト内容を確認したいので一旦ローカルディスクに保存
❯❯ helm pull maesh/maesh --untar && cd maesh
# ファイルの確認
❯❯ ls -al
.rw-r--r-- 378 watawuwu 23 Nov 15:42 .helmignore
.rw-r--r-- 382 watawuwu 23 Nov 15:42 Chart.yaml
drwxr-xr-x - watawuwu 23 Nov 15:42 charts
drwxr-xr-x - watawuwu 23 Nov 15:42 crds
.rw-r--r-- 3.2k watawuwu 23 Nov 15:42 Guidelines.md
.rw-r--r-- 147 watawuwu 23 Nov 15:42 requirements.yaml
drwxr-xr-x - watawuwu 23 Nov 15:42 templates
.rw-r--r-- 1.3k watawuwu 23 Nov 15:42 values.yaml
# 最小限のコンポーネントでインストール
# pdb や config などの設定はあるが、コンポーネントとしては maesh-mesh と maesh-controller の 2 つとなる
❯❯ helm template maesh . \
--set controller.image.tag=v1.0.0 \
--set mesh.image.tag=v2.1 \
--set smi.deploycrds=false \
--set smi.enable=false \
--set tracing.deploy=false \
--set tracing.jaeger.enabled=false \
--set metrics.deploy=false \
--set metrics.prometheus.enable=false \
| kubectl apply -f-
poddisruptionbudget.policy/maesh-controller created
poddisruptionbudget.policy/maesh-mesh created
configmap/tcp-state-table created
serviceaccount/maesh-controller created
serviceaccount/maesh-mesh created
clusterrole.rbac.authorization.k8s.io/maesh-controller-role created
clusterrolebinding.rbac.authorization.k8s.io/maesh-controller created
service/maesh-mesh-api created
daemonset.apps/maesh-mesh created
deployment.apps/maesh-controller created
# 2 つのコンポーネントを確認
❯❯ kubectl get po
NAME READY STATUS RESTARTS AGE
maesh-controller-6fd865fc97-lv8tm 1/1 Running 0 22s
maesh-mesh-2zlxk 1/1 Running 0 22s
maesh-mesh-s5fg5 1/1 Running 0 22s
部署/maesh-controller和DaemonSet/maesh-mesh这两个组件已经创建。
接下来,我们将对行为进行确认。
确认基本行为
在maesh-controller启动时,它会获取已注册CoreDNS配置文件的ConfigMap。
如果ConfigMap的标签中没有maesh-patched: “true”,则会添加以下配置,并添加一个名为”maesh”的服务器块。
❯❯ kubectl -n kube-system get cm coredns -ojson | jq -r '.data.Corefile'
...
maesh:53 {
errors
rewrite continue {
name regex ([a-zA-Z0-9-_]*)\.([a-zv0-9-_]*)\.maesh maesh-{1}-{2}.maesh.svc.cluster.local
answer name maesh-([a-zA-Z0-9-_]*)-([a-zA-Z0-9-_]*)\.maesh\.svc\.cluster\.local {1}.{2}.maesh
}
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
当向 ConfigMap 添加配置后,为了将配置应用到 CoreDNS,请向 CoreDNS 的部署中添加一个哈希值注释,并重新创建 Pod。
❯❯ kubectl -n kube-system get deploy coredns -ojson | jq '.spec.template.metadata.annotations'
{
"maesh-hash": "b128cd46-8dc9-41f2-a91b-94f9edac5f06"
}
由于这些行为强烈依赖于 CoreDNS 及其配置,因此在您自己的环境中尝试时需要注意。
但是,如果您的 GKE 环境未使用 CoreDNS,则可以使用 kube-dns 进行相应的处理。
除了这个设置之外,maesh-controller在创建非maesh命名空间的Service时,会在maesh命名空间中创建一个指向maesh-mesh的路由Service。
# maesh ネームスペースには、maesh-mesh-api だけが作成されている
❯❯ kubectl -n maesh get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
maesh-mesh-api ClusterIP 10.107.67.206 <none> 8080/TCP 80s
# default ネームスペースに test Service を作成すると
❯❯ kubectl -n default create svc clusterip test --tcp=8080:8080
service/test created
# maesh-test-default(maesh-${service-name}-${namespace}) という Service が作成される
❯❯ kubectl -n maesh get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
maesh-mesh-api ClusterIP 10.107.67.206 <none> 8080/TCP 100s
maesh-test-default ClusterIP 10.100.68.223 <none> 8080/TCP 4s
# selector の条件として maesh-mesh が登録される
❯❯ kubectl get svc maesh-test-default -oyaml
...
spec:
clusterIP: 10.100.68.223
ports:
- name: 8080-8080
port: 8080
protocol: TCP
targetPort: 5000
selector:
component: maesh-mesh
type: ClusterIP
...
通过这两个设置,您可以将代替 .svc.cluster.local 的 .maesh 指定为目标,从而经过 maesh-mesh 的 Pod。
此外,maesh-mesh 从 maesh-controller 接收主机头、端口和后端服务器映射信息,并更新设置信息,因此可以通过主机头和端口判断代理目标的后端服务器,并进行代理。
❯❯ kubectl exec maesh-mesh-2zlxk -- wget -q -O- http://127.0.0.1:8080/api/rawdata | jq '.'
{
"routers": {
...
"test-default-8080-ef3de4bfd3d2b9f0@rest": {
"entryPoints": [
"http-5000"
],
"service": "test-default-8080-ef3de4bfd3d2b9f0",
"rule": "Host(`test.default.maesh`) || Host(`10.111.206.208`)",
"status": "enabled",
"using": [
"http-5000"
]
}
},
...
"services": {
"test-default-8080-ef3de4bfd3d2b9f0@rest": {
"loadBalancer": {
"servers": [
{
"url": "..."
}
],
"passHostHeader": true
},
"status": "enabled",
"usedBy": [
"test-default-8080-ef3de4bfd3d2b9f0@rest"
],
"serverStatus": {
"xxxx": "UP"
}
}
}
}
maesh-mesh 的容器镜像中使用了 Traefik,并且上述也是 Traefik 的配置格式。
虽然没有图示有点复杂,但使用方法很简单。
只需像平常一样创建服务并修改使用的域名。
-
- Service を利用する場合: <サービス名>.<ネームスペース名>.svc.cluster.local
Maesh を利用する場合: <サービス名>.<ネームスペース名>.maesh
当然,你仍然可以像以前一样通过Service访问,所以你也可以尝试仅更改一部分的Pod访问目标。
现在我们将部署一个 whoami 服务器,并通过 maesh-mesh 进行访问确认。这个 whoami 服务器会将请求头的内容作为响应返回。
# 作業用のネームスペースを作成
❯❯ kubectl create namespace whoami && kubectl config set-context $(kubectl config current-context) --namespace=whoami
# whoami サーバーのマニフェストを作成
❯❯ cat <<EOF > whoami.yaml
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: whoami
namespace: whoami
spec:
replicas: 2
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
serviceAccount: whoami-server
containers:
- name: whoami
image: containous/whoami:v1.4.0
---
apiVersion: v1
kind: Service
metadata:
name: whoami
namespace: whoami
labels:
app: whoami
spec:
type: ClusterIP
ports:
- port: 80
name: whoami
selector:
app: whoami
EOF
❯❯ kubectl apply -f whoami.yaml
deployment.apps/whoami created
service/whoami created
接下来,客户端应用程序使用 Service 和 Maesh 通过 whoami 服务器进行访问。
# whoami サーバーにアクセスするクライアントアプリを起動しログイン
❯❯ kubectl run -it --image=alpine:3.9 --restart=Never client
/ # apk add --no-cache curl
# サービス経由でアクセス
/ # curl http://whoami.whoami.svc.cluster.local
Hostname: whoami-57bcbf7487-tqkdb
IP: 127.0.0.1
IP: ::1
IP: 10.244.2.3
IP: fe80::24e5:dbff:fec9:3b53
RemoteAddr: 10.244.1.6:58896
GET / HTTP/1.1
Host: whoami.whoami.svc.cluster.local
User-Agent: curl/7.64.0
Accept: */*
# Maesh 経由でアクセス
/ # curl http://whoami.whoami.maesh
Hostname: whoami-57bcbf7487-9btlx
IP: 127.0.0.1
IP: ::1
IP: 10.244.1.5
IP: fe80::48f9:3cff:fea6:aeed
RemoteAddr: 10.244.1.2:40270
GET / HTTP/1.1
Host: whoami.whoami.maesh
User-Agent: curl/7.64.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 10.244.1.6
X-Forwarded-Host: whoami.whoami.maesh
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: maesh-mesh-s5fg5
X-Real-Ip: 10.244.1.6
# maesh-mesh の IP アドレスは以下のどちらかとなる
❯❯ kubectl -n maesh get po -lcomponent=maesh-mesh -ojson |jq -r '.items[].status.podIP'
10.244.2.2
10.244.1.2
Maesh与Service的使用感觉相似。
不同之处在于,RemoteAddr标头变为maesh网络的IP地址,并添加了X-Forwarded-xxx标头。
我稍微有些担心的是,在 maesh-mesh 的前端通过 Service 进行转发,因此有可能会使用在与客户端应用程序不同的节点上部署的 maesh-mesh,并且这样做会导致 DaemonSet 在主机外发生通信。
不过正因为这种行为,使得在 DaemonSet 上进行滚动更新变得更加容易,我认为这是一个优点。
负载平衡
接下来将确认 gRPC 是否已经实现了负载均衡。
部署两个 gRPC 服务器运行,并使用 ghz 工具来进行负载测试4。
在gRPC的情况下,需要在Service的注解中添加maesh.containo.us/scheme: “h2c”。
# 作業用のネームスペースを作成
❯❯ kubectl create namespace grpc && kubectl config set-context $(kubectl config current-context) --namespace=grpc
# gRPC サーバーのマニフェストを replicas:2 で作成する
❯❯ cat <<EOF > greeter-server.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: greeter-server
namespace: grpc
labels:
app: greeter-server
spec:
replicas: 2
selector:
matchLabels:
app: greeter-server
template:
metadata:
labels:
app: greeter-server
spec:
containers:
- name: greeter-server
image: watawuwu/sample-grpc-greeter-server:v2
---
apiVersion: v1
kind: Service
metadata:
name: greeter-server
namespace: grpc
labels:
app: greeter-server
annotations:
maesh.containo.us/scheme: "h2c" # 追加
spec:
type: ClusterIP
ports:
- port: 50051
name: grpc
selector:
app: greeter-server
EOF
# gRPC サーバーをデプロイ
❯❯ kubectl apply -f greeter-server.yaml
deployment.apps/greeter-server created
service/greeter-server created
# デプロイされたことを確認
❯❯ kubectl get po
NAME READY STATUS RESTARTS AGE
greeter-server-69874f977c-bq2z4 1/1 Running 0 2m48s
greeter-server-69874f977c-lpp8k 1/1 Running 0 2m48s
首先,使用1个连接设置来访问服务,并确认请求偏向于一个服务器。
# grpc サーバーにアクセスするクライアントアプリを起動しログイン
❯❯ kubectl run -it --image=alpine:3.9 --restart=Never client
# ghz をインストール
/ # wget -O- https://github.com/bojand/ghz/releases/download/v0.44.0/ghz_0.44.0_Linux_x86_64.tar.gz | tar xz -C /usr/local/bin
# プロトコルファイルをダウンロード
/ # wget https://raw.githubusercontent.com/grpc/grpc-go/master/examples/helloworld/helloworld/helloworld.proto
/ # ghz \
--connections=1 \
--concurrency=50 \
--insecure \
--proto helloworld.proto \
--call helloworld.Greeter.SayHello \
--data '{"name":"Joe"}' \
--total 1000 \
greeter-server.grpc.svc.cluster.local:50051
接下来,将请求目标更改为 Maesh,并确保在仅设置1个连接的情况下发送请求给两个服务器。
/ # ghz \
--connections=1 \
--concurrency=50 \
--insecure \
--proto helloworld.proto \
--call helloworld.Greeter.SayHello \
--data '{"name":"Joe"}' \
--total 1000 \
greeter-server.grpc.maesh:50051
接下来,我们将将连接数设置为10。
如果连接数增加,虽然可以使用服务进行负载均衡,但是当对gRPC服务器进行滚动更新时,请求又会再次偏向一个方向。
/ # ghz \
--connections=10 \
--concurrency=100 \
--insecure \
--proto helloworld.proto \
--call helloworld.Greeter.SayHello \
--data '{"name":"Joe"}' \
--duration 180s \
greeter-server.grpc.svc.cluster.local:50051
对于Maesh而言,即使在升级后,也进行了平衡调整。
/ # ghz \
--connections=10 \
--concurrency=100 \
--insecure \
--proto helloworld.proto \
--call helloworld.Greeter.SayHello \
--data '{"name":"Joe"}' \
--duration 180s \
greeter-server.grpc.maesh:50051
性能验证
关于令人关注的性能,如之前在行为确认中所提到的,作为代理的maesh-mesh使用Traefik,因此性能应该接近Traefik。
在 Traefik 的官方文档中,提到它能够处理大约 85% 的 nginx 流量。然而,由于这次是关于 gRPC 的情况,条件也会有很大变化,因此我们要进行验证。
这次为了比较,除了使用Service之外,我们另外准备了Envoy。
我们还将验证环境从kind变更为GKE。此外,如果使用Helm进行部署,由于maesh-mesh中设置了resources.limits,我们还将放宽资源限制,以便不影响性能验证。
# リソース上限の緩和
# 負荷試験は GKE で実施するので kubedns を true に
❯❯ helm template maesh . \
--set controller.image.tag=v1.0.0 \
--set mesh.image.tag=v2.1 \
--set mesh.resources.limit.mem=2Gi \
--set mesh.resources.limit.cpu=4000m \
--set smi.deploycrds=false \
--set smi.enable=false \
--set tracing.deploy=false \
--set tracing.jaeger.enabled=false \
--set metrics.deploy=false \
--set metrics.prometheus.enable=false \
--set kubedns=true \
| kubectl apply -f-
性能验证环境
-
- Platform: GKE(v1.14.8)
-
- Node
Worker(4 vCPU, 3.6GB memory) x 3
OS: CoreOS
服务
/ # ghz \
--connections=6 \
--concurrency=200 \
--insecure \
--proto helloworld.proto \
--call helloworld.Greeter.SayHello \
--data '{"name":"Joe"}' \
--total 100000 \
greeter-server.grpc.svc.cluster.local:50051
Summary:
Count: 100000
Total: 4.77 s
Slowest: 66.15 ms
Fastest: 0.25 ms
Average: 8.22 ms
Requests/sec: 20968.39
Response time histogram:
0.251 [1] |
6.841 [53979] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
13.431 [29628]|∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
20.020 [10504]|∎∎∎∎∎∎∎∎
26.610 [3748] |∎∎∎
33.200 [1474] |∎
39.790 [463] |
46.379 [140] |
52.969 [62] |
59.559 [0] |
66.149 [1] |
Latency distribution:
10%% in 2.30 ms
25%% in 3.82 ms
50%% in 6.34 ms
75%% in 10.71 ms
90%% in 16.60 ms
95%% in 21.26 ms
99%% in 31.20 ms
Status code distribution:
[OK] 100000 responses
信使
/ # ghz \
--connections=6 \
--concurrency=200 \
--insecure \
--proto helloworld.proto \
--call helloworld.Greeter.SayHello \
--data '{"name":"Joe"}' \
--total 100000 \
envoy.grpc.svc.cluster.local:50051
Summary:
Count: 100000
Total: 5.47 s
Slowest: 55.38 ms
Fastest: 0.60 ms
Average: 10.29 ms
Requests/sec: 18283.57
Response time histogram:
0.603 [1] |
6.081 [27227] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
11.559 [40335]|∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
17.037 [18958]|∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
22.515 [8653] |∎∎∎∎∎∎∎∎∎
27.993 [3098] |∎∎∎
33.471 [1020] |∎
38.949 [506] |∎
44.427 [120] |
49.905 [53] |
55.383 [29] |
Latency distribution:
10%% in 4.16 ms
25%% in 5.87 ms
50%% in 8.63 ms
75%% in 13.21 ms
90%% in 18.75 ms
95%% in 22.33 ms
99%% in 30.96 ms
Status code distribution:
[OK] 100000 responses
玛丝
/ # ghz \
--connections=6 \
--concurrency=200 \
--insecure \
--proto helloworld.proto \
--call helloworld.Greeter.SayHello \
--data '{"name":"Joe"}' \
--total 100000 \
greeter-server.grpc.maesh:50051
Summary:
Count: 100000
Total: 11.40 s
Slowest: 128.42 ms
Fastest: 0.72 ms
Average: 20.74 ms
Requests/sec: 8774.54
Response time histogram:
0.718 [1] |
13.489 [37379]|∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
26.259 [34287]|∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
39.030 [17636]|∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
51.801 [6926] |∎∎∎∎∎∎∎
64.571 [2645] |∎∎∎
77.342 [825] |∎
90.113 [249] |
102.884 [46] |
115.654 [4] |
128.425 [2] |
Latency distribution:
10%% in 5.96 ms
25%% in 10.10 ms
50%% in 17.57 ms
75%% in 27.91 ms
90%% in 39.94 ms
95%% in 48.81 ms
99%% in 65.74 ms
Status code distribution:
[OK] 100000 responses
如果不进行参数调整,将得到以下结果。
如果性能要求很高的话,在评估阶段就需要在实际环境中进行测量。
即使在《Benchmarking 5 Popular Load Balancers》一文中也显示出Envoy和Traefik在HTTPS负载均衡方面存在差异,因此可能对HTTPS处理部分表现不佳。
服务网格接口(SMI)
Maesh 支持服务网格接口(Service Mesh Interface,简称SMI),因此可以使用 SMI 的流量访问控制和流量分割功能。
# SMI を有効に
❯❯ helm template maesh . \
--set controller.image.tag=v1.0.0 \
--set mesh.image.tag=v2.1 \
--set smi.deploycrds=true \
--set smi.enable=true \
--set tracing.deploy=false \
--set tracing.jaeger.enabled=false \
--set metrics.deploy=false \
--set metrics.prometheus.enable=false \
| kubectl apply -f-
# CRD が作成されているか確認
❯❯ kubectl get crd
NAME CREATED AT
httproutegroups.specs.smi-spec.io 2019-11-23T13:58:22Z
tcproutes.specs.smi-spec.io 2019-11-23T13:58:22Z
trafficsplits.split.smi-spec.io 2019-11-23T13:58:22Z
traffictargets.access.smi-spec.io 2019-11-23T13:58:22Z
当CRD被部署后,可以应用以下类似的清单文件。
apiVersion: split.smi-spec.io/v1alpha1
kind: TrafficSplit
metadata:
name: server-split
namespace server
spec:
service: server
backends:
- service: server-v1
weight: 80
- service: server-v2
weight: 20
目前还没有特定的指标或调度程序可以自动更新权重(包括回滚)。
在实际运行中,可能需要使用argo-rollouts等其他机制或脚本。
追踪与衡量
除了这之外,也支持追踪(Jaeger)和指标(Prometheus)。
可以使用Helm提供的Prometheus和Jaeger,但如果您的集群已经运行了自己的Prometheus和Jaeger,也可以使用那个。
# Tracing と Metrics を有効にする
❯❯ helm template maesh . \
--set controller.image.tag=v1.0.0 \
--set mesh.image.tag=v2.1 \
--set smi.deploycrds=false \
--set smi.enable=false \
--set tracing.deploy=true \
--set tracing.jaeger.enabled=true \
--set metrics.deploy=true \
--set metrics.prometheus.enable=true \
--set metrics.storageClass=standard \ # 必要に応じて変更してください
| kubectl apply -f-
# Prometheus, Grafana, Jaeger が作成されます
❯❯ kubectl get po
NAME READY STATUS RESTARTS AGE
grafana-core-7cb56c69cb-2zjwm 1/1 Running 0 44s
jaeger-787f575fbd-nh98f 1/1 Running 0 3m48s
maesh-controller-5b765cb856-v4rbh 1/1 Running 0 41m
maesh-mesh-dqr99 1/1 Running 0 3m46s
prometheus-core-996d966fb-gqh9z 2/2 Running 0 44s
- Grafana
- Jaeger
由于交通相关指标已经准备好一定程度,所以很容易确定有问题的微服务。
最后
我在2016年首次接触到Service Mesh,那是在Linkerd的幻灯片上看到的。
这张幻灯片是为了构建使用gRPC的微服务Web应用程序,希望进行gRPC负载均衡的动机而结束的。
当时,功能和配置都很简单,除了资源使用量之外,没有任何不满意之处。
然而,截至2019年,Service Mesh这个词似乎已经发展成为支撑网络基础设施的关键技术。因此,引入该技术需要掌握的知识较多,对规模较小的应用开发者而言,门槛较高。
如果只是关注 gRPC 的负载均衡,那么通过引入像 Envoy 这样的代理来解决可能更简单。
然而,可能也有一些组织或团队希望拥有像 Maesh 这样简单的 Service Mesh,它可以通过较少的配置获得故障转移等功能。
也许服务网格就是这样的好解决方案吧?
有一种提议,即将侧边车停止的时机设置为另一个生命周期。
节点之间的mTLS支持存在问题。
目前需要准备一个不同的命名空间。
Service不应该设置多个端口吗?当前情况下,无论访问的端口如何,都会将所有注册在Service上的端口进行轮询,所以需要注意。