1
votes

I have a spring boot service which I want to connect to a mongodb in Kubernetes. So far, I have built the docker image of the app and created a Kubernetes deployment, specifying both the images for the app and mongodb in the same deployment YAML file. Also, I have created a service YAML for the app and it works fine.

deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: springbootmongodb
  labels:
    app: springbootmongodb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: springbootmongodb
  template:
    metadata:
      labels:
        app: springbootmongodb
    spec:
      containers:
      - name: springbootmongodb
        image: mytest/springbootmongodb
      - name: mongo
        image: mongo

--service.yaml

apiVersion: v1
kind: Service
metadata:
  name: springbootmongodb
  labels:
    app: springbootmongodb
spec:
  type: ClusterIP
  ports:
  - name: 8080-8080
    port: 8080
    targetPort: 8080
    protocol: TCP
  selector:
    app: springbootmongodb

port forward command:

kubectl port-forward svc/springbootmongodb 8080:8080

Everything works with the above config.

Now, I want to create separate deployments for the app and created two deployments and service YAMLs, but it doesn't work. Can someone please help me?

app-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: springbootmongodb
  labels:
    app: springbootmongodb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: springbootmongodb
  template:
    metadata:
      labels:
        app: springbootmongodb
    spec:
      containers:
      - name: springbootmongodb
        image: mytest/springbootmongodb

mongo-deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongodb
  labels:
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongo
  template:
    metadata:
      labels:
        app: mongo
    spec:
      containers:
        - name: mongo
          image: mongo
          ports:
            - containerPort: 27017

appservice.yml

apiVersion: v1
kind: Service
metadata:
  name: springbootmongodb
  labels:
    app: springbootmongodb
spec:
  type: NodePort
  ports:
  - name: 8080-8080
    port: 8080
    targetPort: 8080
    protocol: TCP
  selector:
    app: springbootmongodb

mongoservice.yml

apiVersion: v1
kind: Service
metadata:
  name: mongodb
  labels:
    app: mongo
spec:
  type: ClusterIP
  ports:
    - port: 27017
      targetPort: 27017
      protocol: TCP
  selector:
    app: mongo

I see all created objects:

kubectl get pods NAME READY STATUS RESTARTS AGE mongodb-686dd5cb7f-dr9hq 1/1 Running 0 3m12s springbootmongodb-7ccbc488fb-vtgw5 1/1 Running 0 115s

kubectl get all

NAME                                     READY   STATUS    RESTARTS   AGE
pod/mongodb-686dd5cb7f-dr9hq             1/1     Running   0          3m16s
pod/springbootmongodb-7ccbc488fb-vtgw5   1/1     Running   0          119s

NAME                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/kubernetes          ClusterIP   10.96.0.1       <none>        443/TCP          59d
service/mongodb             ClusterIP   10.111.83.192   <none>        27017/TCP        2m35s
service/springbootmongodb   NodePort    10.103.18.137   <none>        8080:31015/TCP   8s

NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mongodb             1/1     1            1           3m16s
deployment.apps/springbootmongodb   1/1     1            1           119s

NAME                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/mongodb-686dd5cb7f             1         1         1       3m16s
replicaset.apps/springbootmongodb-7ccbc488fb   1         1         1       119s

Error logs for service:

2020-08-06 23:19:01.526  INFO 1 --- [nio-8080-exec-8] org.mongodb.driver.cluster               : Cluster description not yet available. Waiting for 30000 ms before timing out
2020-08-06 23:19:07.048 ERROR 1 --- [nio-8080-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataAccessResourceFailureException: Timed out after 30000 ms while waiting to connect. Client view of cluster state is {type=UNKNOWN, servers=[{address=localhost:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exception opening socket}, caused by {java.net.ConnectException: Connection refused (Connection refused)}}]; nested exception is com.mongodb.MongoTimeoutException: Timed out after 30000 ms while waiting to connect. Client view of cluster state is {type=UNKNOWN, servers=[{address=localhost:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exception opening socket}, caused by {java.net.ConnectException: Connection refused (Connection refused)}}]] with root cause

com.mongodb.MongoTimeoutException: Timed out after 30000 ms while waiting to connect. Client view of cluster state is {type=UNKNOWN, servers=[{address=localhost:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exception opening socket}, caused by {java.net.ConnectException: Connection refused (Connection refused)}}]
        at com.mongodb.internal.connection.BaseCluster.getDescription(BaseCluster.java:179) ~[mongodb-driver-core-3.8.2.jar!/:na]
        at com.mongodb.internal.connection.SingleServerCluster.getDescription(SingleServerCluster.java:41) ~[mongodb-driver-core-3.8.2.jar!/:na]
        at com.mongodb.client.internal.MongoClientDelegate.getConnectedClusterDescription(MongoClientDelegate.java:136) ~[mongodb-driver-3.8.2.jar!/:na]
        at com.mongodb.client.internal.MongoClientDelegate.createClientSession(MongoClientDelegate.java:94) ~[mongodb-driver-3.8.2.jar!/:na]
        at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.getClientSession(MongoClientDelegate.java:249) ~[mongodb-driver-3.8.2.jar!/:na]
        at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:172) ~[mongodb-driver-3.8.2.jar!/:na]
        at com.mongodb.client.internal.MongoIterableImpl.execute(MongoIterableImpl.java:132) ~[mongodb-driver-3.8.2.jar!/:na]
        at com.mongodb.client.internal.MongoIterableImpl.iterator(MongoIterableImpl.java:86) ~[mongodb-driver-3.8.2.jar!/:na]
        at org.springframework.data.mongodb.core.MongoTemplate.executeFindMultiInternal(MongoTemplate.java:2643) ~[spring-data-mongodb-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.data.mongodb.core.MongoTemplate.doFind(MongoTemplate.java:2380) ~[spring-data-mongodb-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.data.mongodb.core.MongoTemplate.doFind(MongoTemplate.java:2363) ~[spring-data-mongodb-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.data.mongodb.core.MongoTemplate.find(MongoTemplate.java:820) ~[spring-data-mongodb-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.findAll(SimpleMongoRepository.java:360) ~[spring-data-mongodb-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.findAll(SimpleMongoRepository.java:194) ~[spring-data-mongodb-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.findAll(SimpleMongoRepository.java:51) ~[spring-data-mongodb-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_212]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_212]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_212]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_212]
        at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359) ~[spring-data-commons-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) ~[spring-data-commons-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644) ~[spring-data-commons-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
        at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608) ~[spring-data-commons-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595) ~[spring-data-commons-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) ~[spring-data-commons-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
        at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) ~[spring-data-commons-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) ~[spring-aop-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
        at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.1.2.RELEASE.jar!/:2.1.2.RELEASE]
2
(a) don't use a Deployment for a database; that's bad news (b) you didn't post the logs (or even kubectl get pods) for the mongo side of things; if mongo isn't alive, that's a fine reason no one can connect to itmdaniel
Just trying to understand why the Deployment for mongo is bad? Is the service enough?user1318369

2 Answers

3
votes

It looks like you need to change the config of your Springboot app to use the mongodb endpoint: mongodb:27017 rather than localhost:27017❓🤔. Since mongo is not running on the same container/pod anymore.

In the application.properties file something like this:

spring.data.mongodb.uri=mongodb://mongodb:27017/<dbname>

✌️

0
votes

Like Rico already mentioned you have wrong address in app configuration 'localhost'

but there are other problems :)

Rather then Deployment, you should use StateFulSet because its designed to have a state and volume. Main problem will happen when you will create more then 1 replica, All deployments will have same persistent volume so its may cause data inconsistency and database crash. StateFulSet will create each volume per replica. Ofc then you will have 2 databases with diffrent data, so it may cause another problems.

If you are building enterprise app then its good to have knowledge with specified database and kubernetes configuration thats provides kind: MongoDB.

https://docs.mongodb.com/kubernetes-operator/master/reference/k8s-operator-specification/

Additional thing worth mentioning is that you are not using environment variables to pass credentials/addresses to your database. Its good to have knowledge that this thing exists and it should be used instead od rebuilding app when configuration will change.