我如何将我的Spring Boot应用连接到同一Kubernetes命名空间内的Redis服务器?

huangapple go评论98阅读模式
英文:

How can I connect my springboot application to my redis server within the same kubernetes namespace?

问题

我的Kubernetes命名空间同时托管了我的Spring Boot应用程序和Redis服务。然而,当我运行Spring Boot应用程序时,我收到了以下错误:

  1. org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
  2. ...
  3. Caused by: redis.clients.jedis.exceptions.JedisConnectionException: Failed connecting to localhost:6379

我将发布应用程序和Redis服务器的清单YAML如下:

以下是成功部署我的应用程序到命名空间并可以从URL访问的清单:

这个清单成功地将我的应用程序部署到了命名空间,并且我可以从URL访问它。

以下是我的Spring Boot应用程序的配置文件:

  1. import org.springframework.cache.annotation.EnableCaching;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
  5. import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
  6. import org.springframework.data.redis.core.RedisTemplate;
  7. import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
  8. import org.springframework.data.redis.serializer.StringRedisSerializer;
  9. @Configuration
  10. @EnableCaching
  11. public class CacheConfig {
  12. @Bean
  13. public JedisConnectionFactory redisConnectionFactory() {
  14. return new JedisConnectionFactory(new RedisStandaloneConfiguration("127.0.0.1", 6379));
  15. }
  16. @Bean
  17. public RedisTemplate<String, Object> redisTemplate(JedisConnectionFactory jedisConnectionFactory) {
  18. RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
  19. redisTemplate.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
  20. redisTemplate.setKeySerializer(new StringRedisSerializer());
  21. redisTemplate.setHashKeySerializer(new GenericJackson2JsonRedisSerializer());
  22. redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
  23. redisTemplate.setConnectionFactory(jedisConnectionFactory);
  24. return redisTemplate;
  25. }
  26. }

我的Redis服务器是否正确部署?我是否需要以某种方式将Spring Boot应用程序绑定到我的Redis服务器?

您的Redis服务器似乎已正确部署到命名空间中。但是,根据错误消息和您的Spring Boot应用程序配置来看,应用程序正在尝试连接到本地主机(localhost)的6379端口,而这似乎不适用于Kubernetes环境。

在Kubernetes中,容器之间通常无法直接访问本地主机。您应该使用服务名称来引用Redis服务,而不是直接使用本地主机。

在您的Spring Boot应用程序的配置文件中,将以下行:

  1. return new JedisConnectionFactory(new RedisStandaloneConfiguration("127.0.0.1", 6379));

更改为引用Redis服务的名称,如下所示:

  1. return new JedisConnectionFactory(new RedisStandaloneConfiguration("redis-service", 6379));

这将允许您的Spring Boot应用程序在Kubernetes中正确连接到Redis服务。确保在应用程序部署清单中也正确设置了环境变量或配置,以指向Redis服务的名称。

英文:

I have a kubernetes namespace that hosts both my springboot application and the redis service. However when I run the springboot app I get error

  1. org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
  2. ...
  3. Caused by: redis.clients.jedis.exceptions.JedisConnectionException: Failed connecting to localhost:6379

Ill post both the manifest yaml for the application and redis server below.

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: spring-deployment
  5. namespace: spring-poc
  6. labels:
  7. app: spring
  8. spec:
  9. replicas: 1
  10. selector:
  11. matchLabels:
  12. app: spring
  13. template:
  14. metadata:
  15. labels:
  16. app: spring
  17. spec:
  18. containers:
  19. - name: spring
  20. image: spring-application
  21. resources:
  22. requests:
  23. memory: 1G
  24. cpu: &quot;500m&quot;
  25. limits:
  26. memory: 1G
  27. cpu: 1
  28. ports:
  29. - name: http
  30. containerPort: 8080
  31. securityContext:
  32. runAsUser: 1000
  33. imagePullSecrets:
  34. - name: prod.secret
  35. ---
  36. apiVersion: v1
  37. kind: Service
  38. metadata:
  39. name: spring-service
  40. namespace: spring-poc
  41. labels:
  42. app: spring-service
  43. spec:
  44. selector:
  45. app: spring
  46. type: ClusterIP
  47. ports:
  48. - name: http
  49. port: 8080
  50. targetPort: 8080
  51. ---
  52. apiVersion: networking.k8s.io/v1
  53. kind: Ingress
  54. metadata:
  55. name: spring-ingress
  56. namespace: spring-poc
  57. spec:
  58. rules:
  59. - host: spring.url.com
  60. http:
  61. paths:
  62. - path: /
  63. pathType: Prefix
  64. backend:
  65. service:
  66. name: spring-service
  67. port:
  68. number: 8080
  69. tls:
  70. - hosts:
  71. - spring.url.com

This manifest successfully deploys my app to the namespace and I can access it from the url.

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: redis-deployment
  5. namespace: spring-poc
  6. labels:
  7. app: redis
  8. spec:
  9. replicas: 1
  10. selector:
  11. matchLabels:
  12. app: redis
  13. template:
  14. metadata:
  15. labels:
  16. app: redis
  17. spec:
  18. containers:
  19. - name: redis
  20. image: redis
  21. resources:
  22. requests:
  23. memory: 1G
  24. cpu: &quot;500m&quot;
  25. limits:
  26. memory: 1G
  27. cpu: 1
  28. ports:
  29. - name: redis
  30. containerPort: 6379
  31. securityContext:
  32. runAsUser: 1000
  33. imagePullSecrets:
  34. - name: prod.secret
  35. ---
  36. apiVersion: v1
  37. kind: Service
  38. metadata:
  39. name: redis-service
  40. namespace: spring-poc
  41. labels:
  42. app: redis
  43. spec:
  44. selector:
  45. app: redis
  46. type: ClusterIP
  47. ports:
  48. - name: redis
  49. port: 6379
  50. targetPort: 6379

This manifest successfully deploys a redis server to my namespace. If I kubectl exec -it redis-deployment -- redis-cli and run ping it returns pong.

Below is my configuration file for the springboot application

  1. import org.springframework.cache.annotation.EnableCaching;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
  5. import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
  6. import org.springframework.data.redis.core.RedisTemplate;
  7. import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
  8. import org.springframework.data.redis.serializer.StringRedisSerializer;
  9. /**
  10. * The type Cache config.
  11. */
  12. @Configuration
  13. @EnableCaching
  14. public class CacheConfig {
  15. /**
  16. * Redis connection factory jedis connection factory.
  17. *
  18. * @return the jedis connection factory
  19. */
  20. @Bean
  21. public JedisConnectionFactory redisConnectionFactory() {
  22. return new JedisConnectionFactory(new RedisStandaloneConfiguration(&quot;127.0.0.1&quot;, 6379));
  23. }
  24. /**
  25. * Redis template.
  26. *
  27. * @param jedisConnectionFactory the jedis connection factory
  28. * @return the redis template
  29. */
  30. @Bean
  31. public RedisTemplate&lt;String, Object&gt; redisTemplate(JedisConnectionFactory jedisConnectionFactory) {
  32. RedisTemplate&lt;String, Object&gt; redisTemplate = new RedisTemplate&lt;&gt;();
  33. redisTemplate.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
  34. redisTemplate.setKeySerializer(new StringRedisSerializer());
  35. redisTemplate.setHashKeySerializer(new GenericJackson2JsonRedisSerializer());
  36. redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
  37. redisTemplate.setConnectionFactory(jedisConnectionFactory);
  38. return redisTemplate;
  39. }
  40. }

Is my redis server deployed correctly? Do I need to bind the springboot application to my redis server somehow?

答案1

得分: 1

你正在创建一个使用本地主机(127.0.0.1)的 RedisStandaloneConfiguration。Pods(Redis 和你的 Spring 应用程序)是分开的,无法以这种方式通信。

因此,你需要将 127.0.0.1 替换为 redis-service.spring-poc,如下所示:

  1. [...]
  2. @Bean
  3. public JedisConnectionFactory redisConnectionFactory() {
  4. return new JedisConnectionFactory(new RedisStandaloneConfiguration("redis-service.spring-poc", 6379));
  5. }
  6. [...]

最佳实践是从环境变量或应用程序配置中获取这些信息,这样你仍然可以在工作站上使用 localhost 进行测试。

解释:

Kubernetes 提供了开箱即用的 DNS。你可以使用 <service-name>.<namespace-name> 查询每个 Pod。你可以将其类比为类似于 google.de 的域名。因此,你可以通过这种方式连接到每个 Pod。在你的示例中,Redis 服务被称为 redis-service,它需要与部署在同一命名空间中,即 spring-poc(尽管你的清单中写着 namespace: 48713-poc,但这不会起作用)。因此,要从 Spring 连接到 Redis,你需要连接到 redis-service.spring-poc:6379

从技术上讲,redis-service:6379 也可以工作,但我建议更加详细。还可以查看有关 Pod 之间通信的 DNS 文档

英文:

You're creating a RedisStandaloneConfiguration with localhost (127.0.0.1). The pods (redis and your spring app) are separated and can't communicate like that.

So you need to replace 127.0.0.1 with redis-service.spring-poc, like this:

  1. [...]
  2. @Bean
  3. public JedisConnectionFactory redisConnectionFactory() {
  4. return new JedisConnectionFactory(new RedisStandaloneConfiguration(&quot;redis-service.spring-poc&quot;, 6379));
  5. }
  6. [...]

Best practice would be to get that from environment variables or application config, so you can still use localhost for testing on your workstation.

Explanation:

Kubernetes provides out-of-the-box dns. You can query every pod with &lt;service-name&gt;.&lt;namespace-name&gt;. You can think of it similar to a domain like google.de. So you can connect to every pod via it's service by that. In your example the redis service is called redis-service and it needs to be in the same namespace as the deployment, which is spring-poc (though your manifest says namespace: 48713-poc which wouldn't work). So to connect from spring to redis you need to connect to redis-service.spring-poc:6379.

Technically redis-service:6379 would also work, but I'd recommend to be verbose. Also check out the docs about dns for pod to pod communication.

huangapple
  • 本文由 发表于 2023年6月15日 04:56:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76477482.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定