在 Mac OS 上连接到 Cassandra 的 K8s 问题(通过 Node.js)
K8s Issue connecting to Cassandra on Mac OS (via Node.js)
尝试在 Mac OS(通过 Minikube)上的本地 Kubernetes 集群中设置 Cassandra 数据库时,我遇到了连接问题。
似乎 Node.js 无法正确解析 DNS 设置,但通过命令行解析确实有效。
设置如下(已简化):
卡桑德拉服务
apiVersion: v1
kind: Service
metadata:
labels:
app: cassandra
name: cassandra
spec:
type: NodePort
ports:
- port: 9042
targetPort: 9042
protocol: TCP
name: http
selector:
app: cassandra
此外,还有一个 PersistentVolume 和一个 StatefulSet。
应用程序本身非常基础
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: app1
labels:
app: app1
spec:
replicas: 1
selector:
matchLabels:
app: app1
template:
metadata:
labels:
app: app1
spec:
containers:
- name: app1
image: xxxx.dkr.ecr.us-west-2.amazonaws.com/acme/app1
imagePullPolicy: "Always"
ports:
- containerPort: 3003
还有一项服务
apiVersion: v1
kind: Service
metadata:
name: app1
namespace: default
spec:
selector:
app: app1
type: NodePort
ports:
- port: 3003
targetPort: 3003
protocol: TCP
name: http
还有一个简单的入口设置
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: dev.acme.com
http:
paths:
- path: /app1
backend:
serviceName: app1
servicePort: 3003
并添加到 /etc/hosts
minikube ip 地址
192.xxx.xx.xxx dev.acme.com
到目前为止一切顺利。
当尝试通过 Postman 调用 dev.acme.com/app1
时,node.js 应用程序本身被正确调用(可以在日志中看到),但是,该应用程序无法连接到 Cassandra 并超时以下错误:
"All host(s) tried for query failed. First host tried,
92.242.140.2:9042: DriverError: Connection timeout. See innerErrors."
IP 92.242.140.2
似乎只是一个与我的 ISP 相关的 public IP,我相信因为应用程序无法解析服务名称。
我创建了一个简单的 node.js 脚本来测试 dns:
var dns = require('dns')
dns.resolve6('cassandra', (err, res) => console.log('ERR:', err, 'RES:', res))
响应是
ERR: { Error: queryAaaa ENOTFOUND cassandra
at QueryReqWrap.onresolve [as oncomplete] (dns.js:197:19) errno: 'ENOTFOUND', code: 'ENOTFOUND', syscall: 'queryAaaa', hostname:
'cassandra' } RES: undefined
然而,这就是令人困惑的地方 - 当我通过 ssh 进入 pod (app1) 时,我能够使用以下方式连接到 cassandra 服务:
cqlsh cassandra 9042 --cqlversion=3.4.4
所以 pod 似乎是服务名称的 "aware",但 node.js 运行时不是。
知道什么会导致 node.js 无法解析服务 name/dns 设置吗?
更新
重新安装整个集群后,包括重新安装 docker、kubectl 和 minikube,我遇到了同样的问题。
当通过 ssh 从 app1 容器 运行 ping cassandra
时,我得到以下内容
PING cassandra.default.svc.cluster.local (10.96.239.137) 56(84) bytes
of data. 64 bytes from cassandra.default.svc.cluster.local
(10.96.239.137): icmp_seq=1 ttl=61 time=27.0 ms
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
这似乎很好。
但是,当从 Node.js 运行时 运行 时,我仍然遇到相同的错误 -
"All host(s) tried for query failed. First host tried,
92.242.140.2:9042: DriverError: Connection timeout. See innerErrors."
这些是服务
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
app1 ClusterIP None <none> 3003/TCP 11m
cassandra NodePort 10.96.239.137 <none> 9042:32564/TCP 38h
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 38h
这些是 pods(所有命名空间)
NAMESPACE NAME READY STATUS RESTARTS AGE
default app1-85d889db5-m977z 1/1 Running 0 2m1s
default cassandra-0 1/1 Running 0 38h
kube-system calico-etcd-ccvs8 1/1 Running 0 38h
kube-system calico-node-thzwx 2/2 Running 0 38h
kube-system calico-policy-controller-5bb4fc6cdc-cnhrt 1/1 Running 0 38h
kube-system coredns-86c58d9df4-z8pr4 1/1 Running 0 38h
kube-system coredns-86c58d9df4-zcn6p 1/1 Running 0 38h
kube-system default-http-backend-5ff9d456ff-84zb5 1/1 Running 0 38h
kube-system etcd-minikube 1/1 Running 0 38h
kube-system kube-addon-manager-minikube 1/1 Running 0 38h
kube-system kube-apiserver-minikube 1/1 Running 0 38h
kube-system kube-controller-manager-minikube 1/1 Running 0 38h
kube-system kube-proxy-jj7c4 1/1 Running 0 38h
kube-system kube-scheduler-minikube 1/1 Running 0 38h
kube-system kubernetes-dashboard-ccc79bfc9-6jtgq 1/1 Running 4 38h
kube-system nginx-ingress-controller-7c66d668b-rvxpc 1/1 Running 0 38h
kube-system registry-creds-x5bhl 1/1 Running 0 38h
kube-system storage-provisioner 1/1 Running 0 38h
更新 2
从 Node.js 连接到 Cassandra 的代码:
const cassandra = require('cassandra-driver');
const client = new cassandra.Client({ contactPoints: ['cassandra:9042'], localDataCenter: 'datacenter1', keyspace: 'auth_server' });
const query = 'SELECT * FROM user';
client.execute(query, [])
.then(result => console.log('User with email %s', result.rows[0].email));
将 cassandra:9042
替换为 10.96.239.137:9042
时确实有效(10.69.239.137 是通过 cli 从 ping cassandra 收到的 IP 地址)。
Node.js 的 Cassandra 驱动程序使用 resolve4
/resolve6
进行 dns 查找,绕过您的 resolv.conf
文件。像 ping 这样的程序使用 resolv.conf 将 'cassandra' 解析为 'cassandra.default.svc.cluster.local',这是分配给您的 Cassandra 服务的实际 dns 名称。有关 node.js 中名称解析的更详细说明,请参阅 。
修复很简单,只需将完整的服务名称传递给您的客户端即可:
const client = new cassandra.Client({ contactPoints: ['cassandra.default.svc.cluster.local:9042'], localDataCenter: 'datacenter1', keyspace: 'auth_server' });
尝试在 Mac OS(通过 Minikube)上的本地 Kubernetes 集群中设置 Cassandra 数据库时,我遇到了连接问题。 似乎 Node.js 无法正确解析 DNS 设置,但通过命令行解析确实有效。
设置如下(已简化): 卡桑德拉服务
apiVersion: v1
kind: Service
metadata:
labels:
app: cassandra
name: cassandra
spec:
type: NodePort
ports:
- port: 9042
targetPort: 9042
protocol: TCP
name: http
selector:
app: cassandra
此外,还有一个 PersistentVolume 和一个 StatefulSet。
应用程序本身非常基础
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: app1
labels:
app: app1
spec:
replicas: 1
selector:
matchLabels:
app: app1
template:
metadata:
labels:
app: app1
spec:
containers:
- name: app1
image: xxxx.dkr.ecr.us-west-2.amazonaws.com/acme/app1
imagePullPolicy: "Always"
ports:
- containerPort: 3003
还有一项服务
apiVersion: v1
kind: Service
metadata:
name: app1
namespace: default
spec:
selector:
app: app1
type: NodePort
ports:
- port: 3003
targetPort: 3003
protocol: TCP
name: http
还有一个简单的入口设置
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: dev.acme.com
http:
paths:
- path: /app1
backend:
serviceName: app1
servicePort: 3003
并添加到 /etc/hosts
minikube ip 地址
192.xxx.xx.xxx dev.acme.com
到目前为止一切顺利。
当尝试通过 Postman 调用 dev.acme.com/app1
时,node.js 应用程序本身被正确调用(可以在日志中看到),但是,该应用程序无法连接到 Cassandra 并超时以下错误:
"All host(s) tried for query failed. First host tried, 92.242.140.2:9042: DriverError: Connection timeout. See innerErrors."
IP 92.242.140.2
似乎只是一个与我的 ISP 相关的 public IP,我相信因为应用程序无法解析服务名称。
我创建了一个简单的 node.js 脚本来测试 dns:
var dns = require('dns')
dns.resolve6('cassandra', (err, res) => console.log('ERR:', err, 'RES:', res))
响应是
ERR: { Error: queryAaaa ENOTFOUND cassandra at QueryReqWrap.onresolve [as oncomplete] (dns.js:197:19) errno: 'ENOTFOUND', code: 'ENOTFOUND', syscall: 'queryAaaa', hostname: 'cassandra' } RES: undefined
然而,这就是令人困惑的地方 - 当我通过 ssh 进入 pod (app1) 时,我能够使用以下方式连接到 cassandra 服务:
cqlsh cassandra 9042 --cqlversion=3.4.4
所以 pod 似乎是服务名称的 "aware",但 node.js 运行时不是。
知道什么会导致 node.js 无法解析服务 name/dns 设置吗?
更新
重新安装整个集群后,包括重新安装 docker、kubectl 和 minikube,我遇到了同样的问题。
当通过 ssh 从 app1 容器 运行 ping cassandra
时,我得到以下内容
PING cassandra.default.svc.cluster.local (10.96.239.137) 56(84) bytes of data. 64 bytes from cassandra.default.svc.cluster.local (10.96.239.137): icmp_seq=1 ttl=61 time=27.0 ms
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
这似乎很好。 但是,当从 Node.js 运行时 运行 时,我仍然遇到相同的错误 -
"All host(s) tried for query failed. First host tried, 92.242.140.2:9042: DriverError: Connection timeout. See innerErrors."
这些是服务
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
app1 ClusterIP None <none> 3003/TCP 11m
cassandra NodePort 10.96.239.137 <none> 9042:32564/TCP 38h
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 38h
这些是 pods(所有命名空间)
NAMESPACE NAME READY STATUS RESTARTS AGE
default app1-85d889db5-m977z 1/1 Running 0 2m1s
default cassandra-0 1/1 Running 0 38h
kube-system calico-etcd-ccvs8 1/1 Running 0 38h
kube-system calico-node-thzwx 2/2 Running 0 38h
kube-system calico-policy-controller-5bb4fc6cdc-cnhrt 1/1 Running 0 38h
kube-system coredns-86c58d9df4-z8pr4 1/1 Running 0 38h
kube-system coredns-86c58d9df4-zcn6p 1/1 Running 0 38h
kube-system default-http-backend-5ff9d456ff-84zb5 1/1 Running 0 38h
kube-system etcd-minikube 1/1 Running 0 38h
kube-system kube-addon-manager-minikube 1/1 Running 0 38h
kube-system kube-apiserver-minikube 1/1 Running 0 38h
kube-system kube-controller-manager-minikube 1/1 Running 0 38h
kube-system kube-proxy-jj7c4 1/1 Running 0 38h
kube-system kube-scheduler-minikube 1/1 Running 0 38h
kube-system kubernetes-dashboard-ccc79bfc9-6jtgq 1/1 Running 4 38h
kube-system nginx-ingress-controller-7c66d668b-rvxpc 1/1 Running 0 38h
kube-system registry-creds-x5bhl 1/1 Running 0 38h
kube-system storage-provisioner 1/1 Running 0 38h
更新 2
从 Node.js 连接到 Cassandra 的代码:
const cassandra = require('cassandra-driver');
const client = new cassandra.Client({ contactPoints: ['cassandra:9042'], localDataCenter: 'datacenter1', keyspace: 'auth_server' });
const query = 'SELECT * FROM user';
client.execute(query, [])
.then(result => console.log('User with email %s', result.rows[0].email));
将 cassandra:9042
替换为 10.96.239.137:9042
时确实有效(10.69.239.137 是通过 cli 从 ping cassandra 收到的 IP 地址)。
Node.js 的 Cassandra 驱动程序使用 resolve4
/resolve6
进行 dns 查找,绕过您的 resolv.conf
文件。像 ping 这样的程序使用 resolv.conf 将 'cassandra' 解析为 'cassandra.default.svc.cluster.local',这是分配给您的 Cassandra 服务的实际 dns 名称。有关 node.js 中名称解析的更详细说明,请参阅
修复很简单,只需将完整的服务名称传递给您的客户端即可:
const client = new cassandra.Client({ contactPoints: ['cassandra.default.svc.cluster.local:9042'], localDataCenter: 'datacenter1', keyspace: 'auth_server' });