Docker容器内.NET6服务的RabbitMQ客户端无法SSL+PLAIN连接服务端
本地Windows环境下通过Visual Studio运行服务时,可正常SSL连接RabbitMQ服务端;但部署到Linux主机的Docker容器后,连接失败,抛出以下错误:
System.IO.IOException: Received an unexpected EOF or 0 bytes from the transport stream...
或
RabbitMQ.Client.Exceptions.BrokerUnreachableException: None of the specified endpoints were reachable...
已尝试的排查操作:
- 调整服务端SSL配置、检查TLS设置
- 使用Wireshark未捕获到客户端容器与服务端端口的网络流量
- 在客户端容器内安装telnet,可连接服务端5671端口但随即被远程主机关闭,无可见流量(怀疑Docker默认桥接网络导致)
相关配置
服务端RabbitMQ配置文件(/etc/rabbitmq/conf.d/10-defaults.conf)
loopback_users.guest = false log.console = true log.file = true log.file = /tmp/rabbit.log log.file.level = debug management.ssl.port = 15671 management.ssl.cacertfile = /https/ca.pem management.ssl.certfile = /https/wildcard.pem management.ssl.keyfile = /https/wildcard.key listeners.ssl.default = 5671 auth_mechanisms.1 = PLAIN ssl_options.cacertfile = /https/ca.pem ssl_options.certfile = /https/wildcard.pem ssl_options.keyfile = /https/wildcard.key
客户端C#配置
var certPath = Environment.GetEnvironmentVariable("ASPNETCORE_Kestrel__Certificates__Default__Path"); var certPassphrase = Environment.GetEnvironmentVariable("ASPNETCORE_Kestrel__Certificates__Default__Password"); var connectionFactory = new BasicConnectionFactory("hostname_docker_server", "myusr", "mypwd", new SecuredConnectionSettings("hostname_docker_server", certPath, certPassphrase)) .GetSecuredConnectionFactory();
注:connectionFactory为RabbitMQ.Client.ConnectionFactory(版本6.4.0)
Web服务Docker启动命令
docker run --user root --restart always -p 5441:443 -e ASPNETCORE_HTTPS_PORT=5441 -e ASPNETCORE_URLS="https://+" -e ASPNETCORE_Kestrel__Certificates__Default__Password=${env.WILDCARD_SECRET} -e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/wildcard.pfx -v /etc/ssl:/https -d nexus.api:18444/api.prod:latest
RabbitMQ服务端Docker启动命令
docker run --hostname localhost --name rabbitmq -p 5671:5671 -p 15671:15671 -e RABBITMQ_NODENAME='rabbit@localhost' --volume /etc/ssl:/https -d rabbitmq:latest
RabbitMQ启动后执行命令
rabbitmq-plugins enable rabbitmq_management rabbitmq-plugins enable rabbitmq_auth_mechanism_ssl
两个服务运行在同一SUSE Linux主机上,Web服务其他功能(如SwaggerUI)正常
排查方向及可能原因
1. RabbitMQ监听地址限制
服务端配置中listeners.ssl.default = 5671默认绑定到localhost,仅允许容器内部访问。其他容器无法通过主机或容器网络连接,需修改为:
listeners.ssl.default = 0.0.0.0:5671
同时,RabbitMQ启动时的--hostname localhost会导致节点仅识别localhost,建议改为容器可解析的主机名或添加RABBITMQ_NODE_IP_ADDRESS=0.0.0.0环境变量,允许外部连接。
2. Docker容器间网络访问方式
同一主机的容器默认使用bridge网络,建议直接通过容器名(rabbitmq)访问,而非主机名hostname_docker_server。修改客户端连接配置中的主机名为rabbitmq,避免主机网卡端口转发带来的链路问题。
3. 证书信任与权限问题
- 客户端容器信任CA证书:Linux容器的信任根证书存储与Windows不同,需将RabbitMQ的
ca.pem导入容器的系统信任存储(如SUSE的/usr/share/pki/trust/anchors/),执行update-ca-certificates更新缓存。 - 证书文件权限:检查RabbitMQ容器内
/https/下的证书文件(ca.pem、wildcard.pem、wildcard.key)是否允许RabbitMQ进程用户(默认rabbitmq)读取,可通过chmod 644调整权限,或在启动容器时指定--user root临时测试。
4. TLS版本与Cipher Suite兼容性
.NET6默认使用TLS1.3,若RabbitMQ未开启或不支持该版本,会导致握手失败。可在客户端强制指定TLS版本:
connectionFactory.SslProtocol = SslProtocols.Tls12;
同时在RabbitMQ配置中明确启用支持的TLS版本:
ssl_options.versions = tlsv1.2,tlsv1.3
5. 容器端口映射与网络策略
检查主机的防火墙/安全组是否允许5671端口的内部容器通信,或是否有Docker网络策略限制容器间流量。可通过docker exec <web-container-id> ping rabbitmq测试容器间基础连通性。
内容的提问来源于stack exchange,提问作者dev4y0u

