У меня есть приложение микросервиса Java Spring Boot, использующее Postgresql и Kafka в MacOS. Есть 2 модуля - киносервис и ивент-сервис. Filmservice получил производителя кафки, eventservice получил потребителя кафки. Когда я пытаюсь запустить его в контейнере Docker, модули приложения не могут подключиться к серверу Kafka.
Filmservice (продюсер) получил эту ошибку:
2024-09-05 14:12:10 filminator-filmservice | 2024-09-05T11:12:10.978Z INFO 1 --- [ main] o.a.k.c.c.internals.LegacyKafkaConsumer : [Consumer clientId=consumer-my-group-id-1, groupId=my-group-id] Subscribed to topic(s): my-topic
2024-09-05 14:12:10 filminator-filmservice | 2024-09-05T11:12:10.990Z INFO 1 --- [ main] c.z.f.filmservice.FilminatorFilmService : Started FilminatorFilmService in 1.974 seconds (process running for 2.223)
2024-09-05 14:12:11 filminator-filmservice | 2024-09-05T11:12:11.102Z INFO 1 --- [ntainer#0-0-C-1] org.apache.kafka.clients.NetworkClient : [Consumer clientId=consumer-my-group-id-1, groupId=my-group-id] Node -1 disconnected.
2024-09-05 14:12:11 filminator-filmservice | 2024-09-05T11:12:11.103Z WARN 1 --- [ntainer#0-0-C-1] org.apache.kafka.clients.NetworkClient : [Consumer clientId=consumer-my-group-id-1, groupId=my-group-id] Connection to node -1 (localhost/127.0.0.1:9092) could not be established. Node may not be available.
2024-09-05 14:12:11 filminator-filmservice | 2024-09-05T11:12:11.103Z WARN 1 --- [ntainer#0-0-C-1] org.apache.kafka.clients.NetworkClient : [Consumer clientId=consumer-my-group-id-1, groupId=my-group-id] Bootstrap broker localhost:9092 (id: -1 rack: null) disconnected
eventservice(consumer) получил эту ошибку:
2024-09-05 14:14:58 filminator-eventservice | 2024-09-05T11:14:58.843Z WARN 1 --- [ntainer#1-0-C-1] org.apache.kafka.clients.NetworkClient : [Consumer clientId=consumer-my-group-id-2, groupId=my-group-id] Connection to node -1 (localhost/127.0.0.1:9092) could not be established. Node may not be available.
Я пытаюсь остановить приложение в контейнере и запустить его из IDE - приложение успешно подключено к серверу контейнера Kafka.
docker-compose
services:
zookeeper:
image: 'bitnami/zookeeper:latest'
ports:
- '2182:2182'
environment:
- ALLOW_ANONYMOUS_LOGIN=yes
kafka:
image: 'bitnami/kafka:latest'
ports:
- '9092:9092'
environment:
- KAFKA_BROKER_ID=1
- KAFKA_LISTENERS=PLAINTEXT://:9092
- KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://127.0.0.1:9092
- KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
- ALLOW_PLAINTEXT_LISTENER=yes
depends_on:
- zookeeper
userservice:
build: eventservice
image: eventservice-image
container_name: filminator-eventservice
ports:
- "8082:8082"
depends_on:
- kafka
- filmservice
- postgres_db
environment:
- SPRING_DATASOURCE_URL=jdbc:postgresql://postgres_db:5432/filminator
filmservice:
build: filmservice
image: filmservice-image
container_name: filminator-filmservice
ports:
- "8081:8081"
depends_on:
- kafka
- postgres_db
environment:
- SPRING_DATASOURCE_URL=jdbc:postgresql://postgres_db:5432/filminator
postgres_db:
image: postgres:13.7-alpine
volumes:
- /var/lib/postgresql/data/
container_name: db_postgres
ports:
- "6541:5432"
environment:
- POSTGRES_DB=filminator
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=iamroot
Докерфайл:
FROM openjdk:19
COPY target/*.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
application.properties
киносервис:
server.port=8081
spring.datasource.driver-class-name=org.postgresql.Driver
spring.sql.init.mode=always
spring.datasource.url=jdbc:postgresql://localhost:5432/filminator
spring.datasource.username=postgres
spring.datasource.password=iamroot
spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.consumer.group-id=my-group-id
служба событий:
server.port=8082
другое приложение eventservice.свойства идентичны FilmService
Есть ли способ запустить мое приложение и сервер Kafka в одном докер-контейнере?
...вероятно, установив SPRING_KAFKA_BOOTSTRAPSERVERS
почти так же, как вы установили SPRING_DATASOURCE_URL
.
Вам нужно добавить хост в файл docker-compose, см. этот пример
kafka:
image: 'bitnami/kafka:latest'
hostname: kafka
ports:
- '9092:9092'
environment:
- KAFKA_BROKER_ID=1
- KAFKA_LISTENERS=PLAINTEXT://:9092
- KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://127.0.0.1:9092
- KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
- ALLOW_PLAINTEXT_LISTENER=yes
depends_on:
- zookeeper
Затем вы можете подключиться внутри сети докера следующим образом.
spring.kafka.bootstrap-servers=kafka:9092
Я думаю, что имя хоста по умолчанию соответствует имени контейнера.
Я добавляю имя хоста: kafka в службу kafka и имя хоста: Zookeeper в службу Zookeeper. В моем application.properties я изменил Spring.kafka.bootstrap-servers=localhost:9092 на Spring.kafka.bootstrap-servers=kafka:9092. В моих классах конфигурации потребителей/производителей я меняю configProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "kafka:9092"); с «localhost:9092» на «kafka:9092»);
При запуске в докере появляется предупреждение: kafka: WARN [Controller id=1, targetBrokerId=1] Не удалось установить соединение с узлом 1 (/127.0.0.1:9092). Узел может быть недоступен. (org.apache.kafka.clients.NetworkClient) 06.09.2024 10:07:56 Кафка | [2024-09-06 07:07:56,652] ПРЕДУПРЕЖДЕНИЕ [RequestSendThread ControllerId=1] Подключение контроллера 1 к брокеру 127.0.0.1:9092 (идентификатор: 1 стойка: ноль) не удалось (kafka.controller.RequestSendThread) 2024-09- 06 10:07:56 Кафка | java.io.IOException: подключение к 127.0.0.1:9092 (идентификатор: 1 стойка: ноль) не удалось. но приложение, запущенное в IDE, может его использовать
фильмсервис (продюсер) из того же контейнера - запускается без ошибок, но при попытке отправить сообщение Кафки - получена ИНФОРМАЦИЯ [Producer clientId=producer-1] Узел 1 отключен WARN [Producer clientId=producer-1] Соединение с узлом 1 (/127.0) .0.1:9092) не удалось установить. Узел может быть недоступен. Пользовательская служба (потребитель) получила ошибки при запуске: INFO [Consumer clientId=consumer-my-group-id-2, groupId=my-group-id] Узел 1 отключен. ПРЕДУПРЕЖДЕНИЕ [Consumer clientId=consumer-my-group-id-2, groupId=my-group-id] Не удалось установить соединение с узлом 1 (/127.0.0.1:9092). Узел может быть недоступен.
Я решил проблему.
В файле docker-compose я меняю настройки сервисов Zookeeper и Kafka:
zookeeper:
image: confluentinc/cp-zookeeper:latest
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
ports:
- 22181:2181
kafka:
image: confluentinc/cp-kafka:latest
depends_on:
- zookeeper
ports:
- 29092:29092
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
в application.properties измените загрузочные серверы с localhost
на kafka
: spring.kafka.bootstrap-servers=kafka:9092
В моих классах конфигурации потребителей/производителей изменяются с localhost
на kafka
:
configProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "kafka:9092");
Теперь это работает.
localhost
— это Docker-контейнер. Kafka работает в другом контейнере. Вам необходимо указать имена этих контейнеров.