问题
- 在使用容器部署springboot项目时,遇到springBoot连接redis容器异常。
- 根据日志的堆栈跟踪信息,是由于连接Redis失败而导致的异常。堆栈跟踪显示了连接Redis时发生了
io.lettuce.core.RedisConnectionException: Unable to connect to redis:6379
异常。无法连接到 Redis 服务器的地址为 “redis:6379”。
分析
网络问题分析
- 由于项目是使用docker compose进行部署,所以,需要考虑各个容器(mysql、redis、rabbit)是否同在一个网络下,否则无法通信。
- 查看
docker_default
网络下的所有容器(作者在部署容器时,并没有显式指定网络,所以这里使用默认的网络) - 如果默认网络名称不是
docker_default
,请将命令中的网络名称替换为您实际使用的网络名称。
docker network inspect docker_default --format='{{range .Containers}}{{.Name}} - {{.IPv4Address}}{{println}}{{end}}'
- 使用 docker network inspect 命令来检查 docker_default 网络,并使用 --format 参数来指定输出格式。
命令 | 解释 |
---|---|
{{range .Containers}} | 遍历每个容器 |
{{.Name}} | 输出容器名称 |
{{.IPv4Address}} | 输出容器的 IPv4 地址 |
{{println}}{{end}} | 用于在每个容器信息之间添加换行符。 |
- 执行的结果如下:
root@armbian:/usr/local/aurora-springboot# docker network inspect docker_default --format='{{range .Containers}}{{.Name}} - {{.IPv4Address}}{{println}}{{end}}'
redis - 172.28.0.2/16
rabbitmq - 172.28.0.6/16
maxwell - 172.28.0.4/16
services - 172.28.0.5/16
elasticsearch - 172.28.0.3/16
aurora-springboot-0.0.1.jar - 172.28.0.7/16
aurora-springboot-0.0.1.jar
和redis
处于同一个网络下项目启动还会提示连接不到,很懵!!!!
异常连接分析
- 继续根据日志,分析错误
(String), 192.168.1.9(String), 内网IP|内网IP(String), 2023-06-23T13:51:00.567(LocalDateTime) Caused by: io.lettuce.core.RedisConnectionException: Unable to connect to redis:6379 at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:78) at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:56) at io.lettuce.core.AbstractRedisClient.getConnection(AbstractRedisClient.java:242) at io.lettuce.core.RedisClient.connect(RedisClient.java:206) at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider.lambda$getConnection$1(StandaloneConnectionProvider.java:115) at java.util.Optional.orElseGet(Optional.java:267) at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider.getConnection(StandaloneConnectionProvider.java:115) at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider.lambda$null$0(LettucePoolingConnectionProvider.java:97) at io.lettuce.core.support.ConnectionPoolSupport$RedisPooledObjectFactory.create(ConnectionPoolSupport.java:211) at io.lettuce.core.support.ConnectionPoolSupport$RedisPooledObjectFactory.create(ConnectionPoolSupport.java:201) at org.apache.commons.pool2.BasePooledObjectFactory.makeObject(BasePooledObjectFactory.java:58) at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:899) at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:429) at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:354) at io.lettuce.core.support.ConnectionPoolSupport$1.borrowObject(ConnectionPoolSupport.java:122) at io.lettuce.core.support.ConnectionPoolSupport$1.borrowObject(ConnectionPoolSupport.java:117) at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider.getConnection(LettucePoolingConnectionProvider.java:103) ... 20 more Caused by: io.lettuce.core.RedisCommandExecutionException: ERR AUTH <password> called without any password configured for the default user. Are you sure your configuration is correct? at io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:135) at io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:108) at io.lettuce.core.protocol.AsyncCommand.completeResult(AsyncCommand.java:118) at io.lettuce.core.protocol.AsyncCommand.complete(AsyncCommand.java:109) at io.lettuce.core.protocol.CommandHandler.complete(CommandHandler.java:680) at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:640) at io.lettuce.core.protocol.CommandHandler.channelRead(CommandHandler.java:591) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:748) <== Updates: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2fec2f1a]
- 连接 Redis 时发生了身份验证错误。 错误消息表明 Redis 客户端尝试使用身份验证密码进行连接,但 Redis 服务器未配置密码或密码配置不正确。错误消息中显示以下内容:
Caused by: io.lettuce.core.RedisCommandExecutionException: ERR AUTH <password> called without any password configured for the default user. Are you sure your configuration is correct?
要解决此问题,请确保:
-
确保 Redis 服务器已配置身份验证密码。
-
使用正确的密码进行 Redis 连接。检查项目配置文件使用的是正确的密码。即: Spring Boot 的配置文件(application.properties 或 application.yml)中添加以下配置内容:
- 对于 application.properties:
spring.redis.password=your_redis_password
- 对于 application.yml:
spring: redis: password: your_redis_password
-
经过检查和测试,已经正确配置密码但仍然无法连接,那一定是密码中存在特殊字符或转义字符,与 Redis 服务器的配置不完全匹配。
-
回顾过去的操作,项目配置文件是在win环境下编写,docker compose是在linux系统环境下,编辑。两者使用不通的文件编码格式,可能会造成连接密码验证错误。
-
在编写 Docker Compose 文件时使用的是 UNIX 编码,而项目开发使用的是 UTF-8 编码,并且 Redis 连接密码包含特殊字符(如
.
),那么连接时可能会出现问题。在 Docker Compose 文件中,密码作为环境变量的值进行配置。如果密码包含特殊字符,并且编码方式不一致,可能导致密码在解析时出现错误或无法正确匹配。 -
为了避免这种情况,建议在编写 Docker Compose 文件时使用与项目开发一致的编码方式(如 UTF-8),以确保密码能够正确解析和匹配。
分析结果
- 密码包含特殊字符,并且由于编码方式不一致而导致连接问。
解决方法
尝试以下解决方法:
- 使用与项目开发一致的编码方式编写
Docker Compose
文件,例如使用UTF-8
编码。 - 如果密码中包含特殊字符,可以尝试使用转义序列或编码方式来表示这些字符。例如,对于
.
可以使用\.
或者%2E
来表示。 - 在项目中连接
Redis
时,确保使用与Docker Compos
e 文件中密码配置相匹配的密码,并且处理特殊字符的转义或解码。
- 通过保持编码方式一致并正确处理特殊字符,您应该能够避免由于编码不一致而导致的连接问题。
验证分析
- 重新使用utf-8编辑
docker compose
文件,然后重现部署容器和项目,正常连接。
反思和求知
- 在linux文件中创建的
docker compose
文件使用utf-8
编码格式,能正常执行部署吗?- 在 Linux 系统上创建的
Docker Compose
文件使用UTF-8
编码格式是可以正常执行的。Docker Compose
文件是一个纯文本文件,它的编码方式并不会影响Docker Compose
的执行。Docker Compose
工具会读取该文件并解析其中的配置信息来创建和管理容器。只要文件的内容符合正确的Docker Compose
语法,并且所使用的编码方式是有效的,就可以正常执行。 - 无论是在
Windows
、Linux
还是其他操作系统上创建Docker Compose
文件,只要保证文件的编码方式正确,并且文件内容没有语法错误,就可以顺利使用Docker Compose
工具进行部署和管理容器。
- 在 Linux 系统上创建的
- 因此 , 在 Linux 系统上使用 UTF-8 编码格式创建
Docker Compose
文件,而不会对执行产生任何影响。
- 使用
docker compose
在进行部署的时候,如何实现不同编码格式的文件(如utf-8
、unix
)的正常使用?- 在进行
Docker Compose
部署时,确保不同编码格式的文件(如UTF-8
和Unix
)的正常使用,需要注意以下几点:
-
文件编码保持一致:确保
Docker Compose
文件及其相关的配置文件在创建和编辑时,都使用相同的编码格式。最常见的选择是使用 UTF-8 编码,因为它支持广泛的字符集和多种语言。 -
文本编辑器选择:使用支持多种编码格式的文本编辑器来编辑
Docker Compose
文件。现代的文本编辑器通常支持自动检测编码,并能够灵活地保存不同的编码格式。 -
避免特殊字符:在
Docker Compose
文件中,尽量避免使用特殊字符,因为不同编码格式对特殊字符的处理可能不同,导致解析错误。 -
字符转义:如果
Docker Compose
文件中包含一些特殊字符或非ASCII
字符,确保它们被正确地转义,以免出现解析问题。 -
测试部署:在部署之前,先进行测试。使用
docker-compose config
命令来检查Docker Compose
文件的语法是否正确,这可以避免因编码问题导致的语法错误。 -
使用统一的编码格式:为了降低混淆和错误的风险,建议在整个团队或项目中都采用统一的编码格式,通常推荐使用
UTF-8
编码。
- 在进行
- 总的来说,遵循统一的编码规范,并选择支持多种编码格式的文本编辑器,能够确保 Docker Compose 文件的正确解析和正常部署。