Anthony Pham
Anthony Pham

Reputation: 141

Can't connect Docker Desktop Kubernetes (Windows) services to local Postgres db via Spring Boot

I am not able to connect a dockerized Spring Boot API managed by Kubernetes via Docker Desktop (Windows) to a local instance of Postgres. Error is as follows:

org.postgresql.util.PSQLException: Connection to postgres-db-svc.default.svc.cluster.local:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.

Up until trying to connect to a local DB, everything has been working fine (external clients can connect to pods via Ingress, pods can communicate with each other, etc).

I think somewhere my configuration is off here.

ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: 2017-12-27T18:38:34Z
  name: test-docker-config
  namespace: default
  resourceVersion: "810136"
  uid: 352c4572-eb35-11e7-887b-42010a8002b8
data:
  spring_datasource_platform: postgres
  spring_datasource_url: jdbc:postgresql://postgres-db-svc.default.svc.cluster.local/sandbox
  spring_datasource_username: postgres
  spring_datasource_password: password
  spring_jpa_properties_hibernate_dialect: org.hibernate.dialect.PostgreSQLDialect

Service

kind: Service
apiVersion: v1
metadata:
  name: postgres-db-svc
spec: 
  type: ExternalName
  externalName: kubernetes.docker.internal
  ports:
  - port: 5432

In my hosts file, "kubernetes.docker.internal" is mapped to 127.0.0.1

Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: tester
spec:
  selector:
    matchLabels:
      app: tester
  template:
    metadata:
      labels:
        app: tester
    spec:
      containers:
      - name: tester
        imagePullPolicy: IfNotPresent
        image: test-spring-boot
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
        - containerPort: 8080
        env:
        - name: SPRING_DATASOURCE_PLATFORM
          valueFrom:
            configMapKeyRef:
              name: test-docker-config
              key: spring_datasource_platform
        - name: SPRING_DATASOURCE_URL
          valueFrom:
            configMapKeyRef:
              name: test-docker-config
              key: spring_datasource_url
        - name: SPRING_DATASOURCE_USERNAME
          valueFrom:
            configMapKeyRef:
              name: test-docker-config
              key: spring_datasource_username
        - name: SPRING_DATASOURCE_PASSWORD
          valueFrom:
            configMapKeyRef:
              name: test-docker-config
              key: spring_datasource_password
        - name: SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT
          valueFrom:
            configMapKeyRef:
              name: test-docker-config
              key: spring_jpa_properties_hibernate_dialect

Spring Boot application.properties

spring.datasource.platform=${SPRING_DATASOURCE_PLATFORM:postgres}
spring.datasource.url=${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/sandbox}
spring.datasource.username=${SPRING_DATASOURCE_USERNAME:postgres}
spring.datasource.password=${SPRING_DATASOURCE_PASSWORD:password}
spring.jpa.properties.hibernate.dialect=${SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT:org.hibernate.dialect.PostgreSQLDialect}

Upvotes: 2

Views: 1420

Answers (1)

Rico
Rico

Reputation: 61551

Kubernetes with Docker runs in the same docker VM, so I'm assuming the /etc/hosts file that you are referring to is the one on your Windows machine.

I'm also assuming that you ran Postgres exposing 5432 with something like this:

docker run --name some-postgres -e POSTGRES_PASSWORD=mysecretpassword -d -p 5432:5432 postgres

First, 127.0.0.1 is not going to work because docker just exposes the ports on the IP address if the VM.

Secondly, Kubernetes will not able able to find kubernetes.docker.internal because the pods use CoreDNS to resolve and it has no idea about that domain.

I suggest you do this:

  • Don't use kubernetes.docker.internal as it's already used by docker for its own purpose. Use something like mypostgres.local

  • Get the IP address of your docker VM. Run ping docker.local or look under `C:\Windows\System32\drivers\etc\hosts for something like this:

    Added by Docker Desktop
    10.xx.xx.xx host.docker.internal
    

    or look at the output from ipconfig /all and find the IP from the docker desktop VM.

  • Use hostAliases in your podSpec, so that the /etc/hosts file is actually modified in your pod.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: tester
    spec:
      selector:
        matchLabels:
          app: tester
      template:
        metadata:
          labels:
            app: tester
        spec:
          hostAliases:
          - ip: "10.xx.xx.xx" # The IP of your VM
            hostnames:
            - "mypostgres.local"
          containers:
          - name: tester
            imagePullPolicy: IfNotPresent
            image: test-spring-boot
            resources:
              limits:
                memory: "128Mi"
                cpu: "500m"
    
  • Don't use an ExternalName service as those work only with CoreDNS. If you want the ExternalName service to work you will have to modify your CoreDNS config so that it hardcodes the entry for mypostgres.local

Note: Another option is just to run Postgresql in Kubernetes and expose it using a regular ClusterIP service.

Upvotes: 2

Related Questions