Рубрики
Без рубрики

Приложение Data flow + SpringBoot не запускается при настройке.

Создание экстрактора данных между Google Cloud SQL и BigQuery с использованием потока данных. Помечен как spring boot, java, докер, поток данных.

Установка и проблема

У нас есть архитектура микросервисов, в которой каждая служба имеет свой отдельный экземпляр облачного SQL (как и должно быть). Эти базы данных доступны только внутри сети виртуального частного облака (VPC), и хранилище Hashicorp используется для создания динамических учетных данных для них. Нам нужно было хранилище данных для анализа и отчетности. Однако настройка немного усложнила задачу, так как мы не хотели использовать внешнюю службу ETL или иметь учетные данные базы данных с длительным сроком службы. Мы договорились, что данные необходимо извлечь в BigQuery Набор данных, из которого мы бы выставили его с помощью Метабаза

Извлечение должно происходить постепенно и периодически, поэтому службе потребуется:

1) Подключитесь к хранилищу, чтобы сгенерировать учетные данные только для чтения для каждой базы данных. 2) Прочитайте необходимые таблицы и данные. Применяйте любые преобразования, такие как преобразование типов, анонимизация или псевдонимизация. 3) Запись в набор данных BigQuery.

Поскольку данные могут быть огромными, я решил использовать Поток данных , который является сервисом потоковой и пакетной обработки Google. Поток данных построен на Apache Beam модели программирования и выполнения, которая ожидает, что вы определите Конвейер , который соединяет источник и приемник данных и позволяет применять любые преобразования или логику обработки между потоком данных. Затем он выполняет задание Конвейер над парком вычислительных экземпляров с автоматическим масштабированием.

Решение

Мое решение – это служба загрузки Spring (с любовью называемая data-extractor ), которая будет периодически запускаться и создавать необходимые конвейеры потоков данных. Я использовал DSL Kotlin от Gradle для управления зависимостями.

Микросервису потребуются разрешения на доступ к следующим сервисам Google – BigQuery, хранилище Google (используется для хранения временных файлов), Поток данных, экземпляры вычислений. Итак, я создал специальную учетную запись службы с необходимыми разрешениями. Учетные записи служб – это особый тип учетной записи, используемой приложением или экземпляром виртуальной машины (VM), а не человеком.

Я создал службу и протестировал несколько запусков, которые все были успешными, когда я запускал службу из IDE или когда я запускал ./gradlew из командной строки.

Служба успешно загрузится, подключится к хранилищу, чтобы получить учетные данные, создаст задание потока данных, которое определит Конвейер и создаст необходимые вычислительные экземпляры, которые будут обрабатывать данные, а затем завершат их после выполнения задания ETL.

На всю работу ушло примерно 5 минут. Пользовательский интерфейс консоли Google показывает красивый график всего потока данных с несколькими пользовательскими и внутренними этапами, а также содержит журналы и показатели для каждого шага.

В чем проблема:

Мы развертываем все наши микросервисы в движке Google Kubernetes (GKE), и поэтому, как только сервис был в хорошей форме, я выполнил обычный процесс создания uber fat-jar и его настройки. Вот файл Dockerfile, который я скопировал из одного из наших других репозиториев Spring Boot.

FROM gcr.io/distroless/java:11
VOLUME /tmp
COPY build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-Dspring.profiles.active=${ENV_SPRING_PROFILE}", "-jar", "/app.jar"]

Предполагая, что ./gradlew сборка была успешно запущена ранее, она копирует файл fat-jar внутри изображения, а затем запускает его при запуске контейнера. Довольно стандартно, не так ли?

Вот тут-то все и начало рушиться. Когда я запустил контейнер (локально, а также в GKE), я заметил, что служба успешно загрузится, подключится к хранилищу для считывания учетных данных, создаст задание потока данных, запустит экземпляр, но задание просто застрянет. В журналах просто говорилось бы, что

Проверка разрешений, предоставленных учетной записи службы контроллера.

Журнал этого будет печататься каждые 5-6 минут в течение часа, после чего задание завершится неудачей.

Здесь начался болезненный процесс отладки. Я отчаянно искал какие-либо известные ошибки или проблемы, соответствующие ответы на StackOverflow или что-нибудь, что я мог найти в документах Google, но ничего не смог найти.

Задание будет успешно работать в среде IDE или с помощью Gradle, но завершится неудачей при настройке .

Это случалось 10/10 раз или, скорее, сотни раз, когда я пытался.

Журналы намекали на возможную проблему с разрешениями для учетной записи службы. Однако это не имело полного смысла, поскольку выполнение было успешным из среды IDE или при запуске с помощью Gradle. Я убедился, что в моей локальной среде не было других учетных данных Google, и учетная запись службы была единственной учетной записью, введенной в качестве переменной среды. Все переменные среды были одинаковыми, за исключением части контейнеризации.

Я включил журналы отладки , но это также не дало никакой полезной информации. Задание застряло бы с той же ошибкой. Консоль Google отобразила неудачное задание с сообщением:

Сбой рабочего процесса. Причины: Задание потока данных, похоже, застряло, потому что за последние 1 час не было замечено никакой активности работника. Пожалуйста, проверьте рабочие журналы в журнале драйверов стека. Вы также можете получить помощь с облачным потоком данных по адресу https://cloud.google.com/dataflow/support .

Расстроенный, я перепробовал все, начиная от подключения к компьютеру и заканчивая проверкой сетевого подключения и чтением системных журналов, но нигде не было никакой подсказки. Я даже открыл обращение в службу поддержки Google из нашей учетной записи, но не получил полезного ответа. В основном потому, что они не могли найти ничего плохого на своей стороне.

Во время выступления я пошутил по этому поводу, что мне, возможно, придется развернуть свой ноутбук.

В перерывах между другими задачами я потратил на это 2 дня – все больше и больше расстраиваясь и уставая.

Эксперимент

Работая в сжатые сроки, я решил закрепить весь свой репозиторий и запустить /gradlew run изнутри него. Создание банки с жиром и ее докеризация

Это не должно сработать. Верно?

К моему удивлению, так оно и было.

Теперь это сработало 10/10 раз. Я был ошеломлен.

Теперь я был еще более озадачен, чем раньше, но в то же время испытал облегчение оттого, что меня разблокировали. Я потратил впустую 2 дня, застряв на этой проблеме – проблеме, которую я не понял, не смог развернуть приложение. Это были 2 дня моей жизни, которые я не собирался возвращать.

Оказывается, есть что-то в сгенерированном fat-jar из ./gradlew сборка , из-за которой он не может работать с потоком данных. Я проверил это, также запустив fat jar напрямую из командной строки:

# data-extractor.jar is the fat uber jar containing all dependencies.
java -jar data-extractor.jar

Он вышел из строя, как контейнер Docker, и в той же точке.

Проверка разрешений, предоставленных учетной записи службы контроллера.

Это было дикое путешествие. Я решил, что буду развертывать то, что работает параллельно, я пытаюсь понять и понять, что происходит.

Вот мой обновленный Dockerfile , который копирует код в контейнер и запускает классы gradlew для извлечения зависимостей и компиляции кода.

FROM adoptopenjdk:11-jdk-hotspot

VOLUME /app/data-extractor
WORKDIR /app/data-extractor
# Copy source code
COPY src /app/data-extractor/src
# Copy gradle configuration and runner
COPY *.gradle.kts /app/data-extractor/
COPY gradlew /app/data-extractor/
COPY gradle /app/data-extractor/gradle

# This will install the dependencies in the image
RUN ./gradlew  --no-daemon classes

EXPOSE 8080
ENTRYPOINT ["./gradlew" "--no-daemon" "run"]

Я не знаю, почему здесь не работает банка с жиром. Это первый раз, когда я столкнулся с этим, и я хотел бы лучше понять. Возможно, кто-то еще в сообществе знает почему и поделится этим.

  • Есть ли еще такие случаи?
  • Как люди работают вокруг них?
  • Есть ли что-то, что я могу сделать лучше?

Поделиться этим, чтобы кто-то другой, работающий над чем-то подобным, мог сэкономить время и разочарование.

Вывод

  • Компьютеры и современное программное обеспечение сложны и сложны. Во всем подвиге интеграции сочетания сложных технологий, таких как Vault, Kubernetes, BigQuery, поток данных и сама логика сервиса, эта мелочь причинила мне наибольшую боль. Части, которые, как вам кажется, вы хорошо понимаете, могут неожиданно выйти из строя при совместной работе.
  • В облачной среде с несколькими движущимися частями журналы иногда могут вводить в заблуждение. Когда это происходит, важно тщательно проверять даже самые мелкие вещи. Большую часть времени я подозревал, что что-то связано с разрешениями, и тщательно проверял роли и разрешения. Помогает сделать перерыв и посмотреть в другом направлении.
  • Я уверен, что этому есть вполне разумное объяснение. Может быть, это даже задокументировано. Но я не мог легко найти его, и ошибка не была очевидной. Обмен таким опытом – хороший способ учиться друг у друга, не совершая одних и тех же ошибок. Я узнал и смирился с тем, что я не знаю всего, и это прекрасно.

Если вы уже сделали это, пожалуйста, дайте мне знать, что вы думаете.

Первоначально опубликовано на https://suspendfun.com

Оригинал: “https://dev.to/therajsaxena/dataflow-springboot-app-fails-to-run-when-dockerized-1fo5”