spring-projects / spring-boot

Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.
https://spring.io/projects/spring-boot
Apache License 2.0
75.48k stars 40.76k forks source link

Docker-compose - Redis-Springboot #38774

Closed VidyasagarPandikashala closed 11 months ago

VidyasagarPandikashala commented 11 months ago

About application

Simple backend applicaction that counts number of visits happened to be done by an user. Redis stores the data of the visits made.


ERROR DESCRIPTION

Springboot application is not able connect to the redis server even though it shows the redis and application are both in same docker network.

It throws error - White label Error (type=Internal Server Error, status=500).

Error in sprinboot-app container:

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception 
[Request processing failed: 
org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis] with root cause

Dockerfile:

FROM openjdk:17
WORKDIR /app
COPY target/visitsapplication-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]

DockerCompose.yml

version: '3'
services:
    redis-server:
    image: 'redis'
    ports:
        - "6379:6379"
    springboot-app:
    build: .
    ports:
        - "8080:8080"  

application.properties

server.port=8080
spring.redis.host=redis-server
spring.redis.port=6379

VisitController.java

package com.visitapplication.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/")
public class VisitsController {
        @Autowired
        private RedisTemplate<String, String> redisTemplate;

        @GetMapping
        public String getVisits() {
            ValueOperations<String, String> ops = redisTemplate.opsForValue();
            String visits = ops.get("visits");

            if (visits == null) {
                visits = "0";
            }

            ops.set("visits", String.valueOf(Integer.parseInt(visits) + 1));

            return "Number of visits is " + visits;
        }
}

Commands run to check the issues


Command:
 docker-compose logs springboot-app
Output :
java.net.ConnectException: Connection refused.

Command:
docker network inspect visitsapplication_default
Output:
[
    {
        "Name": "visitsapplication_default",
        "Id": "671f39cacd25f8f2c694eebed7515c16dfae3efedc86ae57c567e8ab0567fed2",
        "Created": "2023-12-14T06:06:20.465060571Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.20.0.0/16",
                    "Gateway": "172.20.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "7437823988de4a68b31f72b423d75bd7172be555b7c77879a5f76eb3cb248d1d": {
                "Name": "visitsapplication-redis-server-1",
                "EndpointID": "c138d3fa863efed0accf193acc4992a382245e160840337554fc76f74e3f914e",
                "MacAddress": "02:42:ac:14:00:03",
                "IPv4Address": "172.20.0.3/16",
                "IPv6Address": ""
            },
            "be2ef8d7f9ed05fb7b98e21473948b7f005fa0fb3b268f03105a98ee5ae79eeb": {
                "Name": "visitsapplication-springboot-app-1",
                "EndpointID": "fa1ee3bccb4097dbe8cfb5388eb471c9836e2a84b21e94fc266d3542e0e81e5a",
                "MacAddress": "02:42:ac:14:00:02",
                "IPv4Address": "172.20.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "default",
            "com.docker.compose.project": "visitsapplication",
            "com.docker.compose.version": "2.17.3"
        }
    }
]

The Docker network inspection confirms that both visitsapplication-redis-server-1 and visitsapplication-springboot-app-1 containers are on the same Docker network named visitsapplication_default. Therefore, they should be able to communicate with each other using their service names (redis-server and springboot-app, respectively).


wilkinsona commented 11 months ago

Thanks for the report but it's not clear why you believe that it's a Spring Boot issue. Have you, for example, verified that an application using a Redis client directly is able to connect when the Spring Boot app is not? Unfortunately, we don't have time to perform this problem determination for you. If you can demonstrate that it works without involving Spring Boot but does not work with Spring Boot then we can take another look.

VidyasagarPandikashala commented 11 months ago

The issue is that springboot application is not able to recogonize the redis running in the same container. I need clarification if any settings to be done on application.properties or in the controller class (eg. annotate some dependency related to redis) for the application to connect to the port of the redis application.

Tried running the same syntax and similar docker configuration in nodejs and it is working as expected. This raised my concern was if it is related to spring boot application and its configuration. If it is not the issue of the spring-boot I truly apologize for taking your precious time.

wilkinsona commented 11 months ago

There's nothing obviously wrong in what you've shared thus far but it's hard to be certain as you haven't provided a complete picture.

Spring Boot knows nothing about Docker's networking. It is the Redis client and the JVM that are responsible for establishing the connection. If they're able to do so without Spring Boot then this may well be a Spring Boot problem but I think it's most likely to be a problem at the level of the JVM or the Redis Client. A Docker problem is also a possibility, although that's less likely if this works with NodeJS.

VidyasagarPandikashala commented 11 months ago

Thank you for the support. @wilkinsona

wilkinsona commented 11 months ago

I see that you've now duplicated this on Stack Overflow. Closing.

bot-alert commented 11 months ago

I am facing a similar issue

image

image image

bot-alert commented 11 months ago

@VidyasagarPandikashala did you solve this issue?

daycodeur commented 11 months ago

I found the issue.

In your application.properties file. Can you replace:

spring.redis.host=redis-server
spring.redis.port=6379

with

spring.data.redis.host=redis-server
spring.data.redis.port=6379
VidyasagarPandikashala commented 11 months ago

@wilkinsona Sorry I am raising an issue for the first time in github, I am sorry for the delay, I did not notice the notification in my github.


@bot-alert : Here is how I resolved the issue that I faced.

As @wilkinsona suggested that it might not be an issue with the springboot I just went through the codebase and found out I missed @Configuration annotation.

When I was running the application normally, it did not throw any compilation error but when I ran the code in docker, it was giving log with some error.

@Configuration // this was missed
@EnableCaching     
public class RedisConfig {
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")// discrepancy in the placeholder key name added here and the application.properties file
    private Integer port;

    @Bean
    public JedisConnectionFactory jedisConnectionFactory() {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName(host);
        config.setPort(port);
        return new JedisConnectionFactory(config);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(){
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(jedisConnectionFactory());
        redisTemplate.setValueSerializer(new GenericToStringSerializer<Object>(Object.class));
        return redisTemplate;
    }
}

Dockercompose.yml


    version: '3'
services:
  redis-server: # make sure this name matches your host name in application.properties
    image: 'redis' 

    ports:
      - "6379:6379"
  springboot-app:
    build: .
    ports:
      - "8080:8080"

Hope this helps.

chanuka commented 8 months ago

I found the issue. In your application.properties file. Can you replace spring.redis.host=redis-server spring.redis.port=6379 by spring.data.redis.host=redis-server spring.data.redis.port=6379

Thanks a lot,you saved my day

MingChen1501 commented 7 months ago

I found the issue. In your application.properties file. Can you replace spring.redis.host=redis-server spring.redis.port=6379 by spring.data.redis.host=redis-server spring.data.redis.port=6379

many thanks

deBilla commented 3 months ago

I found the issue.

In your application.properties file. Can you replace:

spring.redis.host=redis-server
spring.redis.port=6379

with

spring.data.redis.host=redis-server
spring.data.redis.port=6379

thanks a lot

emi-emi671 commented 3 months ago

I am getting the same problem and have no resolution yet, both tried with "spring.data.redis.host" and also using the same container name in springboot conf and in docker-compose file. Any other idea?

emi-emi671 commented 3 months ago

The issue is only when springboot app try to connect Redis within container, otherwise access the redis connection from container while running the app in IDE is working fine. I tried to use the networking inside my docker-compose file but still not helped.

Here is my docker-compose:

version: '3'

services: spond-weather-app: build: ../ container_name: weather-app depends_on:

networks: redis_app_net: driver: bridge

Here is the springboot conf file:

server.port=8080 spring.redis.host=redis-server spring.redis.port=6379 spring.cache.type=redis

Any clue?

On Fri, Aug 16, 2024 at 10:43 PM Ashish Khatiwada @.***> wrote:

Please check if there are some config which might be the issue . Example:

@Bean
public LettuceConnectionFactory redisConnectionFactory() {
    return new LettuceConnectionFactory();
}

this was the issue as is was overriding the host and port as far i remember. I removed this and voila its working now.

— Reply to this email directly, view it on GitHub https://github.com/spring-projects/spring-boot/issues/38774#issuecomment-2294216242, or unsubscribe https://github.com/notifications/unsubscribe-auth/A5YZLNJ56V44IR2CDISU46LZRZP5LAVCNFSM6AAAAABAUKA62OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEOJUGIYTMMRUGI . You are receiving this because you commented.Message ID: @.***>

--

Regards, Noman Sadiq @. @.

Mobile # +47-45954552

scottfrederick commented 3 months ago

@emi-emi671 Andy's comment above still holds true. Assuming you are using a supported version of Spring Boot, the properties should be spring.data.redis.host and spring.data.redis.port. Other than that, there is not enough information here for us to help you, and it is not clear that this is a Spring Boot problem and not a Docker Compose setup problem. Please post a question to StackOverflow with as much detail about your setup as possible.