aliyun-node/agentx

请问一下在 node:alpine 和 centos docker 镜像上都出现wss连接错误该怎么解决?

Closed this issue · 20 comments

我们 eggjs 项目,对接 AliNode 后,本地跑,以及部署到 heroku 都能正常上报数据到阿里 Node.js 性能平台。但是部署到 k8s 的 pod(分别试过 node:alpine 与 centos 镜像),都不能上报数据:

[Tue Jun 18 2019 11:46:16 GMT+0800 (China Standard Time)] Connecting to wss://agentserver.node.aliyun.com:8080...
[Tue Jun 18 2019 11:46:16 GMT+0800 (China Standard Time)] get an error: Error: write EPROTO 140088968039272:error:1408F10B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:252:

是需要这些镜像做什么改动来兼容吗?

是不是你机器上的 openssl 版本有问题啊,可以用 wireshark 抓包确认下服务器的返回,或者升级下基础镜像的 openssl 版本呢

我在镜像里 apk update && apk add openssl ,装了最新版 openssl:

/app # openssl version
OpenSSL 1.1.1b  26 Feb 2019

还是有这个错,请问一下应该用哪个 openssl 版本呢?

现在不是有 1.1.0k 了么,1.1.0b 是 2016 年发布的 release 版本了:
https://www.openssl.org/news/openssl-1.1.0-notes.html

在另一个镜像里也试了一下 apk update && apk add libressl,然后看了一下版本

/app # openssl version
LibreSSL 2.7.5

这个版本和我能够正常运行的机器(macOS)版本一致。但仍然报上述错误……

好的,我试试看

AliNode 镜像有 900 多兆,不太适合纳入 ci 系统(需要频繁推镜像)。我们还是先试试看能不能在 alpine 上解决。

我的理解是这样的,如果 alinode 镜像可以连接到 agentserver ,那么这个问题就是镜像本身的 openssl shared library 的问题,要在 alpine 上解决也可以从这个角度入手;
如果 alinode 镜像有一样的问题,那么估计就是你们用的 k8s 本身的网络的问题,得从这里来排查

@hyj1991 我们昨天试了一下 alinode 镜像,也出现这个连接错误。
但是我们什么都没改动,今天早上来看,无论是 alinode 镜像,还是 centos 镜像,都又连上了。

我们用的阿里托管 k8s,这期间没做任何改动,看日志,从凌晨4点开始不知道为什么就能连上了。有没有可能 agentserver 那边在接收连接上有什么变化?

@Jeff-Tian 我们这边 agentsever 服务已经大概大半年没发布动过了,按照这个现象,很可能是你们这边 k8s 的网络问题导致的,而和镜像没有关系

@hyj1991 我在 centos pod 里,写了一个简单的 python 脚本来探测与 agent hub websopcket 的连通性,出现这样的错误:

sh-4.2# python test.py
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    ws.connect("wss://agentserver.node.aliyun.com:8080")
  File "/usr/lib/python2.7/site-packages/websocket/_core.py", line 223, in connect
    options.pop('socket', None))
  File "/usr/lib/python2.7/site-packages/websocket/_http.py", line 126, in connect
    sock = _ssl_socket(sock, options.sslopt, hostname)
  File "/usr/lib/python2.7/site-packages/websocket/_http.py", line 263, in _ssl_socket
    sock = ssl.wrap_socket(sock, **sslopt)
  File "/usr/lib64/python2.7/ssl.py", line 934, in wrap_socket
    ciphers=ciphers)
  File "/usr/lib64/python2.7/ssl.py", line 609, in __init__
    self.do_handshake()
  File "/usr/lib64/python2.7/ssl.py", line 831, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: UNKNOWN_PROTOCOL] unknown protocol (_ssl.c:618)

网上搜索说,这样的错误有可能是 server 端不接受 ssl 的版本或者加密方式。请问一下这种情况下,有没有办法通过一个指定的明确的版本与加密方式来建立连接?

详细运行是这样的:

登录基于 centos 镜像的 pod:

yum update
yum install epel-release
yum -y install python-pip
pip install websocket-client

python test.py

其中 test.py 脚本如下:

import websocket
ws = websocket.WebSocket()
# Connect to host url
ws.connect("wss://agentserver.node.aliyun.com:8080")
send_string = "Testing WebSocket"
print "Sending: ",send_string
# Use ws.send() to send data to server
ws.send(send_string)
# Use ws.recv() to get the data sent from server
result = ws.recv()
print "Received: ",result
# Use ws.close() to close the WebSocket handshake
ws.close()

@Jeff-Tian agentsever.node.aliyun.com 是我们的阿里云高防 IP,并不是我们的 agentserver 本体

@hyj1991 agentserver.node.aliyun.com 是我从 egg-alinode 插件对接进项目后的日志里抓取出来的。这个地址不对吗?那正确的应该是什么?

地址是对的啊,但是我们的部署 server 是在阿里云高防 ip 后面的,防止 DDOS

你是说,请求被阿里云高防拦截了所以不成功吗?

同样的项目,在本地,或者部署上 heroku,都能连接成功,部署到 k8s,就不行。

➜ kubectl get service
NAME                            TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
xxxxxxxxxxxxxxxxxxxx         ClusterIP      172.21.4.46     <none>          80/TCP         70d

@hyj1991 看到 EXTERNAL-IP 为 none,会不会是因为用 websocket 连接 agent-server, 一定要求有一个外部 ip ?

不是拦截啊,我的意思是,你说的指定协议版本,我们没法做,因为外部的 ip 不是我们的服务 ip,是阿里云的高防 ip

我建议你自己搭建一个 wss 服务,用 k8s 看看能不能连接上

原来从 k8s pod 里,使用 ws 也是可以连接的,比如

ws.connect("ws://agentserver.node.aliyun.com:8080")

会报

Handshake status 400 Bad Request

,但这说明网络是连通的。

但是用 wss,就会报 [SSL: UNKNOWN_PROTOCOL] 的错误。

本机安装的 openssl,目前还没找到怎么使用 openssl 来替换系统自带的 ssl

@Jeff-Tian 既然你自己写的 wss 服务也无法连接,这看起来是你们的 pod 自身在 ssl 层出了问题,ws 不涉及 ssl,所以可以联通

这个问题因为我们本地没法复现,不知道怎么帮助你

@hyj1991 谢谢,你提供的信息已经很有帮助了!

这个问题可以复现,看来是 centos 镜像的坑,它的 openssl version 太低。但是还没有找到替换系统 openssl 的方法,尝试过安装新版的 openssl,但是系统仍然走的是老的 openssl。

重现步骤:

docker pull centos:latest
docker images # 列出 centos 的 image id
docker run -ti <centos image id> /bin/bash
yum update
yum install epel-release
yum -y install python-pip
pip install websocket-client
python test.py

其中 test.py 脚本如下:

import websocket
import ssl

print(ssl.OPENSSL_VERSION)
ws = websocket.WebSocket()
# Connect to host url
ws.connect("wss://agentserver.node.aliyun.com:8080")
send_string = "Testing WebSocket"
print("Sending: ",send_string)
# Use ws.send() to send data to server
ws.send(send_string)
# Use ws.recv() to get the data sent from server
result = ws.recv()
print("Received: ",result)
# Use ws.close() to close the WebSocket handshake
ws.close()

同样的脚本,在 alinode-alpine 镜像里运行正常。同时,可以看到,即使重新从源码安装新版的 openssl,结果是这样的:

sh-4.2# openssl version
OpenSSL 1.1.1  11 Sep 2018
sh-4.2# python test.py
OpenSSL 1.0.2k-fips  26 Jan 2017

同时看 alinode 日志,也仍然是 UNKNOWN_PROTOCOL 的错误。