如何通过VM或Kubernetes代理GCP Cloud SQL实现公网访问?
代理GCP Cloud SQL实现公网连接的方案及Stunnel故障排查
需求背景
- 需通过GCP虚拟机或Kubernetes服务的公网IP连接CloudSQL,拒绝使用SSH端口转发方式
- 不直接使用CloudSQL实例的公网IP(需配置IP白名单,灵活性不足),且Cloud SQL代理存在速度和性能瓶颈
- 尝试用Stunnel做代理,但连接失败
遇到的问题
连接错误信息
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 104
所用Stunnel配置
output=/tmp/stunnel.log CAfile=/tmp/mysql-server-ca.pem client=yes pid=/var/run/stunnel.pid verifyChain=yes sslVersion=TLSv1.2 [mysqls] accept=0.0.0.0:3307 connect=private-ip:3306
Stunnel日志
2022.09.22 10:53:17 LOG5[2]: Service [mysqls] accepted connection from 127.0.0.1:37014 2022.09.22 10:53:17 LOG5[2]: s_connect: connected <mysql-private-ip>:3306 2022.09.22 10:53:17 LOG5[2]: Service [mysqls] connected remote server from 10.128.0.53:53302 2022.09.22 10:53:17 LOG3[2]: SSL_connect: ../ssl/record/ssl3_record.c:331: error:1408F10B:SSL routines:ssl3_get_record:wrong version number 2022.09.22 10:53:17 LOG5[2]: Connection reset: 0 byte(s) sent to TLS, 0 byte(s) sent to socket
补充说明:
- Stunnel部署在GCP虚拟机上
- 虚拟机与CloudSQL处于同一子网,可通过私有IP直接连接CloudSQL
问题原因
日志中的wrong version number错误明确指向SSL握手失败。核心原因是:
CloudSQL的私有IP端口3306仅接受明文TCP连接,但当前Stunnel配置中开启了client=yes,会主动向CloudSQL私有IP发起SSL握手,导致对方不响应SSL协议,触发版本不匹配错误。
解决方案
调整Stunnel配置,将其作为纯TCP转发代理(移除所有SSL客户端相关配置),仅负责将公网请求转发到CloudSQL私有IP的明文端口。
修改后的Stunnel配置
output=/tmp/stunnel.log pid=/var/run/stunnel.pid [mysqls] accept=0.0.0.0:3307 connect=private-ip:3306
可选:对公网连接加密
如果需要确保公网到VM的连接是加密的,可以让Stunnel作为SSL服务端接收加密连接,再以明文转发到CloudSQL。配置如下:
output=/tmp/stunnel.log pid=/var/run/stunnel.pid # 替换为你的SSL证书和密钥路径 cert=/etc/stunnel/server.crt key=/etc/stunnel/server.key [mysqls] accept=0.0.0.0:3307 connect=private-ip:3306
此时客户端连接时需启用SSL,例如MySQL客户端命令:
mysql -h [VM公网IP] -P 3307 -u your-user -p --ssl-mode=REQUIRED
验证步骤
- 重启Stunnel服务:
systemctl restart stunnel
- 虚拟机本地测试连接:
mysql -h 127.0.0.1 -P 3307 -u your-user -p
- 公网环境测试连接:
mysql -h [VM公网IP] -P 3307 -u your-user -p
内容的提问来源于stack exchange,提问作者Kavya
相关产品推荐
相关产品推荐

