在kubernetes+istio中通过FQDN请求Nacos服务

背景是我们希望能在k8s中通过DNS方式,访问服务的FQDN来调用虚拟机注册到nacos的服务。

我们vm和k8s的网段配置了相关路由能相互访问

之前nacos有维护了一个同步去coredns的项目,但是年久失修,支持的nacos版本和coredns版本都不高。后面在官方文档找资料的时候,发现nacos是支持istio MCP协议的 Pilot MCP协议介绍,于是采取这个方案来完成目标。《Nacos 1.1.4发布,业界率先支持Istio MCP协议

环境:

istio: 1.10

nacos: 2.1.0

配置nacos开启MCP Server

进入nacos配置目录,执行以下命令,把 nacos.istio.mcp.server.enabled 值设置为 true。重启nacos server 让它运行MCP Server。

1
[root@dev_10.1.10.209 nacos]#sed -i 's/nacos.istio.mcp.server.enabled=false/nacos.istio.mcp.server.enabled=true/g' conf/application.properties

重启后nacos MCP server会监听 18848 端口

1
2
3
[root@dev_10.1.10.209 nacos]#lsof -i:18848
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 98108 root 171u IPv4 834348182 0t0 TCP *:18848 (LISTEN)

配置istio添加MCP server sources

我测试的nacos server所在的服务器IP10.1.10.209

nacos MCP server监听的端口 18848

编辑istio的configmap,添加以下配置

1
kubectl edit -n istio-system cm istio
1
2
configSources:
- address: xds://10.1.10.209:18848

添加后的配置大概如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
data:
mesh: |-
accessLogFile: /dev/stdout
configSources:
- address: xds://10.1.10.209:18848
defaultConfig:
discoveryAddress: istiod.istio-system.svc:15012
proxyMetadata: {}
tracing:
zipkin:
address: zipkin.istio-system:9411
enablePrometheusMerge: true
rootNamespace: istio-system
trustDomain: cluster.local
meshNetworks: 'networks: {}'

重启下istiod 连接MCP server同步信息

1
kubectl rollout restart -n istio-system deployment istiod

服务访问

同步nacos服务信息到istio后,我们可以在服务的sidecar envoy看到同步下来的服务配置信息。

如以下是我 ops-apollo-probe 服务的pod ops-apollo-probe-7765fd445f-smstf 的envoy配置信息,搜索nacos后的结果。

1
2
3
4
5
6
7
➜  ~ istioctl pc all -n develop ops-apollo-probe-7765fd445f-smstf|grep nacos
msg-group.DEFAULT-GROUP.public.nacos 80 - outbound EDS
nacos-test.develop.svc.cluster.local.DEFAULT-GROUP.public.nacos 80 - outbound EDS
nacos-vm.DEFAULT-GROUP.public.nacos 7788 - outbound EDS
80 msg-group.DEFAULT-GROUP.public.nacos /*
80 nacos-test.develop.svc.cluster.local.DEFAULT-GROUP.public.nacos, nacos-test + 1 more... /*
7788 nacos-vm.DEFAULT-GROUP.public.nacos /*

带着 nacos结尾的域名就是nacos同步下来的,比如 nacos-vm.DEFAULT-GROUP.public.nacos

但是现在,在我ops-apollo-probe容器里面,依旧是无法通过nacos-vm.DEFAULT-GROUP.public.nacos 访问到我的 nacos-vm服务的。

因为现在大概的访问流程是这样的,详情见Understanding DNS - istio

image-20220919194215557

因为coredns中并没有 nacos-vm.DEFAULT-GROUP.public.nacos 的解析,所以解析失败,报错退出。

以下为在ops-apollo-probe服务的容器内请求:

1
2
3
4
5
6
7
8
9
10
11
/app # curl -v nacos-vm.DEFAULT-GROUP.public.nacos:7788/healthz
* Could not resolve host: nacos-vm.DEFAULT-GROUP.public.nacos
* Closing connection 0
curl: (6) Could not resolve host: nacos-vm.DEFAULT-GROUP.public.nacos
/app # nslookup nacos-vm.DEFAULT-GROUP.public.nacos
Server: 10.17.0.10
Address: 10.17.0.10:53

** server can't find nacos-vm.DEFAULT-GROUP.public.nacos: NXDOMAIN

** server can't find nacos-vm.DEFAULT-GROUP.public.nacos: NXDOMAIN

curl显示不能解析,nslookup没解析出IP,可以看到nameserver是coredns的IP(10.17.0.10)。

1
2
3
➜  ~ kubectl get svc -n kube-system kube-dns 
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.17.0.10 <none> 53/UDP,53/TCP 35d

所以要解决访问,还要能有个IP把包先发出去,到istio sidecar接管请求后就完事,因为envoy有服务的真正IP信息。

所以我们可以瞎指定一个IP,比如1.1.1.1。

hosts大法指定IP

域名解析,hosts文件的记录优先级高于nameserver的记录

1
2
# 添加hosts
/app # echo '1.1.1.1 nacos-vm.DEFAULT-GROUP.public.nacos' >> /etc/hosts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/app # curl -v nacos-vm.DEFAULT-GROUP.public.nacos:7788/healthz
* Trying 1.1.1.1:7788...
* Connected to nacos-vm.DEFAULT-GROUP.public.nacos (1.1.1.1) port 7788 (#0)
> GET /healthz HTTP/1.1
> Host: nacos-vm.DEFAULT-GROUP.public.nacos:7788
> User-Agent: curl/7.80.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< content-type: text/plain;charset=UTF-8
< content-length: 2
< date: Mon, 19 Sep 2022 11:57:22 GMT
< x-envoy-upstream-service-time: 4
< server: envoy
<
* Connection #0 to host nacos-vm.DEFAULT-GROUP.public.nacos left intact
OK

可以看到能正常请求到nacos-vm的健康检查接口

直接指定IP

可以直接指定连接IP,跳过域名解析环境,带上host头来用来匹配envoy的规则即可。

如curl实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/app # ping nacos-vm.DEFAULT-GROUP.public.nacos
ping: bad address 'nacos-vm.DEFAULT-GROUP.public.nacos'
/app # curl -v -H "Host: nacos-vm.DEFAULT-GROUP.public.nacos" 1.1.1.1:7788/healthz
* Trying 1.1.1.1:7788...
* Connected to 1.1.1.1 (1.1.1.1) port 7788 (#0)
> GET /healthz HTTP/1.1
> Host: nacos-vm.DEFAULT-GROUP.public.nacos
> User-Agent: curl/7.80.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< content-type: text/plain;charset=UTF-8
< content-length: 2
< date: Mon, 19 Sep 2022 12:03:59 GMT
< x-envoy-upstream-service-time: 3
< server: envoy
<
* Connection #0 to host 1.1.1.1 left intact
OK/app #

可以看到携带相关host头,直接请求1.1.1.1:7788/healthz 也是能访问到相关接口。

nacos官方给的例子其实就是这种做法。

1
2
3
4
5
6
7
Instance instance = new Instance();
instance.setIp("1.1.1.1");
instance.setPort(80);
// 必须设置ephemeral=false,来保证服务端使用的是严格的一致性协议,否则可能会导致生成的instance id冲突:
instance.setEhpemeral(false);
instance.setMetadata(new HashMap<String, String>());
instance.getMetadata().put(PreservedMetadataKeys.INSTANCE_ID_GENERATOR, Constants.SNOWFLAKE_INSTANCE_ID_GENERATOR);

coredns增加nacos后缀解析为固定的IP

1
kubectl edit cm -n kube-system coredns

增加以下配置:

10.96.0.10 是我coredns的cluster IP

1
2
3
4
5
6
template IN ANY public.nacos {
answer "{{ .Name }} 60 IN A 1.1.1.1"
rcode NOERROR
authority "public.nacos. 60 IN NS ns0.public.nacos."
additional "ns0.public.nacos. 60 IN A 10.96.0.10"
}

添加后效果如下:

ping和nslookup的结果符合预期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/app # ping nacos-vm.DEFAULT-GROUP.public.nacos
PING nacos-vm.DEFAULT-GROUP.public.nacos (1.1.1.1): 56 data bytes
64 bytes from 1.1.1.1: seq=0 ttl=53 time=158.908 ms
^C
--- nacos-vm.DEFAULT-GROUP.public.nacos ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 158.908/158.908/158.908 ms
/app # nslookup nacos-vm.DEFAULT-GROUP.public.nacos
Server: 10.17.0.10
Address: 10.17.0.10:53

Name: nacos-vm.default-group.public.nacos
Address: 1.1.1.1

Name: nacos-vm.default-group.public.nacos
Address: 1.1.1.1

请求自然也是没问题。

istio DNS代理

istio sidecar提供dns解析DNS Proxying,既可以减少coredns压力,又可以加快解析速度。它会从预留的IP段 240.240.0.0/16 中分配一个。

1
kubectl edit -n istio-system cm istio

增加如下配置:

1
2
3
4
5
6
defaultConfig:
proxyMetadata:
# Enable basic DNS proxying
ISTIO_META_DNS_CAPTURE: "true"
# Enable automatic address allocation, optional
ISTIO_META_DNS_AUTO_ALLOCATE: "true"

加好的配置大概如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: v1
data:
mesh: |-
accessLogFile: /dev/stdout
configSources:
- address: xds://10.1.10.209:18848
defaultConfig:
discoveryAddress: istiod.istio-system.svc:15012
proxyMetadata:
ISTIO_META_DNS_CAPTURE: "true"
ISTIO_META_DNS_AUTO_ALLOCATE: "true"
tracing:
zipkin:
address: zipkin.istio-system:9411
enablePrometheusMerge: true
extensionProviders:
- envoyOtelAls:
port: 4317
service: otel-collector.istio-system.svc.cluster.local
name: otel
rootNamespace: istio-system
trustDomain: cluster.local
meshNetworks: 'networks: {}'

我重启了相关服务

1
kubectl rollout restart -n develop deployment ops-apollo-probe

验证nslookup结果,

1
2
3
4
5
6
7
8
9
/app # nslookup nacos-vm.default-group.public.nacos
Server: 10.17.0.10
Address: 10.17.0.10:53


Name: nacos-vm.default-group.public.nacos
Address: 240.240.0.2

/app #

请求自然也是没问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/app # curl -v nacos-vm.default-group.public.nacos:7788/healthz
* Trying 240.240.0.2:7788...
* Connected to nacos-vm.default-group.public.nacos (240.240.0.2) port 7788 (#0)
> GET /healthz HTTP/1.1
> Host: nacos-vm.default-group.public.nacos:7788
> User-Agent: curl/7.80.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< content-type: text/plain;charset=UTF-8
< content-length: 2
< date: Mon, 19 Sep 2022 16:04:51 GMT
< x-envoy-upstream-service-time: 5
< server: envoy
<
* Connection #0 to host nacos-vm.default-group.public.nacos left intact
OK

关注公众号 尹安灿