0

I have a Spring Boot application that is configured to integrate with a Kafka instance. The Kafka instance runs as a container, through a docker-compose file. When I run the Spring Boot application, it picks up the Kafka brokers from the application properties file and the application runs fine.

The problem comes up when I package the application and create a docker image. After that I run the application using docker-compose. The Spring Boot application picks up all the security configurations, DB configurations from the environment variables in the docker-compose, but not for the Kafka brokers.

Here is the docker-compose that I am using to run Kafka:

version: '2'
services:
  zookeeper:
    container_name: Zookeeper
    image: confluentinc/cp-zookeeper:6.1.9
    ports:
      - "2181:2181"
    environment:
      - ZOOKEEPER_CLIENT_PORT=2181
      - ZOOKEEPER_SERVER_ID=1
  
  kafka:
    container_name: Kafka
    image: confluentinc/cp-kafka:6.1.9
    hostname: kafka
    ports:
      - "9092:9092"
    environment:
      - KAFKA_BROKER_ID=2
      - KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1
      - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
      - KAFKA_ADVERTISED_LISTENERS=LISTENER_DOCKER_INTERNAL://kafka:19092,LISTENER_DOCKER_EXTERNAL://${DOCKER_HOST_IP:-127.0.0.1}:9092
      - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=LISTENER_DOCKER_INTERNAL:PLAINTEXT,LISTENER_DOCKER_EXTERNAL:PLAINTEXT
      - KAFKA_INTER_BROKER_LISTENER_NAME=LISTENER_DOCKER_INTERNAL
    depends_on:
      - zookeeper
    
  schemaregistry:
    container_name: Schema-Registry
    image: confluentinc/cp-schema-registry:6.1.9
    hostname: schemaregistry
    ports:
      - "8081:8081"
    environment:
      - SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS=PLAINTEXT://kafka:19092
      - SCHEMA_REGISTRY_HOST_NAME=schemaregistry
    depends_on:
      - kafka

Here is the Kafka properties/configuration in the application.yml file for the project:

spring:
  cloud:
    stream:
      kafka:
        binder:
          consumer-properties:
            key.deserializer: org.apache.kafka.common.serialization.StringDeserializer
            value.deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
            spring.json.trusted.packages: '*'
          producer-properties:
            key.serializer: org.apache.kafka.common.serialization.StringSerializer
            value.serializer: org.springframework.kafka.support.serializer.JsonSerializer
      bindings:
        deviceEvent-out-0:
          binder: kafka
          content-type: application/json

Here is the application-prod.yml file for the properties to be used for prod profile:

spring:
  cloud:
    stream:
      kafka:
        binder:
          auto-create-topics: true
          brokers: ${KAFKA_BROKERS}
          consumer-properties:
            max.poll.records: ${CONSUMER_MAX_POLL_RECORDS}
            schema.registry.url: ${SCHEMA_REGISTRY_URL}
          producer-properties:
            max.poll.records: ${PRODUCER_MAX_POLL_RECORDS}
            schema.registry.url: ${SCHEMA_REGISTRY_URL}
      bindings:
        produceMessage-out-0:
          destination: ${DEVICE_EVENT_TOPIC}

And finally, this the docker-compose file for running the application after its image is created:

version: '2'
services:
  devicemanagerms:
    container_name: MyApp
    image: myappms:latest
    ports:
      - "8097:8097"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - SERVICE_LOG_LEVEL=DEBUG
      - SPRING_SECURITY_OIDC_ISSUER_URI=<URL for Keycloak>
      - OAUTH2_CLIENT_ID=microservice-client
      - OAUTH2_CLIENT_SECRET=<---MASKED--->
      - AWS_IOT_CONNECT_ENDPOINT=<---MASKED--->
      - AWS_IOT_CONNECT_CLIENT_ID=<---MASKED--->
      - SERVER_PORT=8097
      - POSTGRESQL_DATABASE_URL=<---MASKED--->
      - POSTGRESQL_DATABASE_USERNAME=<---MASKED--->
      - POSTGRESQL_DATABASE_PASSWORD=<---MASKED--->
      - POSTGRESQL_DATABASE_SCHEMA=<---MASKED--->
      - SCHEMA_REGISTRY_URL=http://192.168.29.92:8081
      - KAFKA_BROKERS=192.168.29.92:9092
      - CONSUMER_MAX_POLL_RECORDS=10
      - PRODUCER_MAX_POLL_RECORDS=10
      - DEVICE_EVENT_TOPIC=device_event

I am using:

mvn clean package -DskipTests jib:dockerBuild

to package the application and create an image.

The logs I am getting in the container when I run this application and try to publish a message to Kafka is:

WARN 1 --- [| adminclient-1] org.apache.kafka.clients.NetworkClient   : [AdminClient clientId=adminclient-1] Connection to node 2 (/127.0.0.1:9092) could not be established. Broker may not be available.

which appears that the Kafka endpoint in the docker-compose environment variable is not picked up by the application and it is trying to use 127.0.0.1 which points to the container itself.

This application runs fine when I run it as a standalone app using mvn spring-boot:run.

  • Not sure what is going on, but here are some tooling docs we use for Kafka in Spring Cloud Stream to bring up container images: https://github.com/spring-cloud/spring-cloud-stream/blob/main/tools/kafka/docker-compose/README.adoc – sobychacko Apr 27 '23 at 19:48
  • Do **NOT** use IP addresses in Docker Compose. Pull all services in **one** file and [use **service names**](https://docs.docker.com/compose/networking/). Also use port `19092` since that is what you set in `KAFKA_ADVERTISED_LISTENERS` (which I assume you copied from somewhere?) See how `SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS` is configured? Why make your Spring app connect any differently? – OneCricketeer Apr 29 '23 at 05:22
  • @OneCricketeer Thanks. Is there a rationale behind why it is not recommended to use IP addresses in docker-compose? What is Kafka is running as a standalone in some Vm and I need to set the IP of the VM? – Dame Lyngdoh Apr 29 '23 at 11:12
  • @DameLyngdoh I said not for Docker Compose. It has builtin DNS resolution. Your VMs should also have DNS names on your LAN In a production environment ... So, there's usually no reason to use them. But that's besides the point. It's not working because there's two compose files, so different networks, and client is using the incorrect port – OneCricketeer Apr 30 '23 at 01:52

0 Answers0