DevOps

Tomcat MySQL Docker: версии, Config.properties, подключение

Диагностика проблем с Tomcat и MySQL в Docker: определение версий, проверка Config.properties в WAR, исправление поиска в ROOT, логи и команды для JDBC-подключения к БД в docker-compose.

Как определить необходимые версии Tomcat и MySQL и одновременно диагностировать проблему с Config.properties и подключением к базе в Docker?

Описание проблемы:

  • Пытаюсь поднять тестовое Java-приложение в Tomcat внутри Docker. Собираю docker-образ, подкладываю Config.properties в WebContent. Приложение стартует, страница отображается, но при попытке добавить данные приложение не может подключиться к контейнеру с БД. Контейнер и БД доступны по сети. Конфиг почему-то ищется не в каталоге приложения, а в ROOT. В логах контейнера отображена только попытка записать данные — как определить, что не нравится приложению?

Dockerfile:

Dockerfile
FROM maven:3.6.3-openjdk-11 AS build

RUN git clone https://github.com/shephertz/App42PaaS-Java-MySQL-Sample.git /build
WORKDIR /build
COPY ./Config.properties ./WebContent/
RUN mvn package

FROM tomcat:8-jre8-alpine
WORKDIR /usr/local/tomcat/webapps
COPY --from=build /build/target/App42PaaS-Java-MySQL-Sample-0.0.1-SNAPSHOT.war ./App43PaaS.war

docker-compose.yml:

yaml
services:
 tomcat:
 build: 
 context: .
 depends_on:
 - db
 restart: unless-stopped
 ports:
 - '8080:8080'
 - '8443:8443'
 networks:
 - app42paas
 db:
 image: mysql:lts
 restart: unless-stopped
 env_file: .env
 networks:
 - app42paas
 volumes:
 - ./db:/var/lib/mysql
 
networks:
 app42paas:

Конкретные вопросы, на которые прошу ответ:

  1. Как определить, какие версии Tomcat и MySQL необходимы для этого проекта (где смотреть: pom.xml, зависимости, требования проекта)?
  2. Как проверить, что Config.properties действительно попал в WAR и доступен приложению (как проверить содержимое WAR, classpath, WEB-INF)?
  3. Почему приложение может искать конфиг в ROOT (контекст приложения / имя WAR / относительные пути) и как это исправить — правильное имя WAR (ROOT.war) vs контекст, размещение файла конфигурации в Tomcat внутри контейнера)?
  4. Какие шаги по диагностике проблемы с подключением к MySQL в docker-compose: какие лог-файлы и команды смотреть (docker logs, catalina.out, стек-трейсы приложения, mysql logs), как проверить JDBC-URL/хост/пользователя/пароль и время инициализации MySQL?
  5. Какие практические проверки и команды выполнить (например, jar tf/ unzip для просмотра WAR, docker exec + tail, netcat/ telnet для проверки порта, mysql client) и какие изменения в Dockerfile/docker-compose рекомендованы, чтобы гарантировать попадание Config.properties и стабильное подключение к БД?

Подскажите пошаговые проверки и команды для локализации причины и корректной конфигурации.

Проблема чаще всего комбинированная: версия Java/Tomcat не совпадает с тем, на что собирается WAR, JDBC‑драйвер/версия MySQL не подходят, а Config.properties не попал в classpath или читается по относительному пути (поэтому приложение «ищет в ROOT»). Проверьте pom.xml на target/source и зависимость mysql‑connector, распакуйте WAR (jar tf/unzip -l) чтобы убедиться, где лежит Config.properties, и убедитесь, что JDBC‑URL в свойствах указывает на сервис Docker (например db:3306), а не на localhost (см. примеры по сетям в Docker и docker‑compose). Ниже — пошаговая диагностика, команды и рекомендуемые правки Dockerfile/docker‑compose.


Содержание


Определение версий Tomcat и MySQL

  1. Где смотреть (быстро):
  • pom.xml проекта (версия компилятора, mysql‑connector‑java, web/servlet API). Откройте локально или в репозитории, например pom.xml на GitHub.
  • web.xml (требования к версии Servlet/JSP).
  • README/Документация проекта (есть ли указанные требования).
  1. Команды для проверки локально в корне проекта (или в /build после clone):
  • Просмотреть поддерживаемую версию Java/target:
bash
grep -n "<maven.compiler" -n pom.xml || mvn help:evaluate -Dexpression=maven.compiler.target -q -DforceStdout
  • Проверить зависимость драйвера:
bash
mvn dependency:tree | grep -i mysql
  • Если вы уже получили WAR, то проверить, под какую Java его собрали (ошибки на старте Tomcat будут выдавать UnsupportedClassVersionError):
bash
docker-compose exec tomcat sh -c "catalina.sh version"
# и смотреть логи на UnsupportedClassVersionError
docker-compose logs tomcat | grep -i UnsupportedClassVersionError
  1. Типичные несоответствия и как их решать (чеклист):
  • Если maven собирает под Java 11, а образ Tomcat — на jre8 (как в вашем Dockerfile: build на openjdk‑11, runtime tomcat:8‑jre8), возможен UnsupportedClassVersionError. Решение: либо собрать с source/target 1.8, либо использовать образ Tomcat с JDK11 (например tomcat:9‑jdk11).
  • Если в pom.xml стоит mysql‑connector‑java 5.x, а вы запускаете MySQL 8 — может возникнуть проблема с аутентификацией (caching_sha2_password). Решение: обновить драйвер до 8.x или задать опцию сервера --default-authentication-plugin=mysql_native_password при запуске контейнера MySQL.
  • Если web.xml требует Servlet 3.x/4.x — убедитесь, что Tomcat версии соответствует (Tomcat 8 ≈ Servlet 3.1, Tomcat 9 ≈ Servlet 4.0).

(Ссылки по поведению в сети и использованию имени сервиса вместо localhost: см. обсуждения на StackOverflow: использовать имя контейнера вместо localhost, и пример с jdbc URL в docker‑compose jdbc://db:3306/….)


Проверка Config.properties в WAR и classpath

Почему важно: приложение обычно загружает конфиг либо с classpath (WEB-INF/classes), либо через ServletContext (внутри webapp), либо из внешнего пути. Если Config.properties не в ожидаемой папке — приложение не найдёт его и продолжит работать частично.

  1. Как проверить содержимое WAR (локально перед деплоем):
bash
# в корне проекта, после mvn package
jar tf target/*.war | grep -i Config.properties
# или
unzip -l target/*.war | grep -i Config.properties

Ожидаемые пути внутри WAR:

  • WEB-INF/classes/Config.properties — файл на classpath (лучше всего для Properties).
  • WEB-INF/Config.properties — доступен через ServletContext.getResourceAsStream(“/WEB-INF/Config.properties”).
  • /Config.properties (в корне WAR) — доступен через ServletContext.getResourceAsStream(“/Config.properties”) или при развёртывании в ROOT.
  1. Если WAR уже в контейнере — проверить так:
bash
docker-compose up -d --build
docker-compose exec tomcat sh -c "jar tf /usr/local/tomcat/webapps/App43PaaS.war | grep -i Config.properties || ls -l /usr/local/tomcat/webapps/App43PaaS/WEB-INF/classes | grep -i Config.properties"

Если WAR распакован:

bash
docker-compose exec tomcat sh -c "ls -la /usr/local/tomcat/webapps/App43PaaS/WEB-INF/classes | grep -i Config.properties"
docker-compose exec tomcat sh -c "ls -la /usr/local/tomcat/webapps/ROOT | head -n 40"
  1. Почему файл может не попасть в WAR:
  • Проект использует нестандартную структуру (WebContent вместо src/main/webapp) и maven не копирует. Проверьте pom.xml на webResources или resources.
  • COPY в Dockerfile до mvn package: в вашем Dockerfile вы делаете git clone внутри build‑стадии и затем COPY ./Config.properties ./WebContent/ — учтите, что COPY берёт файл из build‑контекста (локальная машина), а git clone внутри контейнера создаёт /build. Это рабочая, но хрупкая схема — лучше положить Config.properties в src/main/resources или src/main/webapp/WEB-INF перед mvn package.
  • Решение: поместите Config.properties в src/main/resources (тогда он попадёт в WEB‑INF/classes) или настройте maven‑war‑plugin/webResources для включения WebContent. Пример упрощения:
xml
<!-- pom.xml: maven-compiler-plugin и webResources -->
<build>
 <resources>
 <resource>
 <directory>src/main/resources</directory>
 </resource>
 </resources>
</build>
  1. Если нужно быстро проверить и отладить: временно монтируйте файл в контейнер:
yaml
volumes:
 - ./Config.properties:/usr/local/tomcat/webapps/ROOT/WEB-INF/classes/Config.properties:ro

Так можно гарантированно поставлять файл в ожидаемое место.


Почему приложение может искать конфиг в ROOT и как исправить

Причины:

  • WAR переименован в ROOT.war — Tomcat разворачивает его в webapps/ROOT и приложение доступно на /. Тогда относительные обращения к корню будут находить этот ROOT.
  • Код читает конфиг через абсолютный путь ServletContext.getRealPath(“/Config.properties”) или напрямую из файловой системы /Config.properties — это может вести в системный корень или в корень развернутого приложения (ROOT).
  • Контекст приложения и имя WAR не совпадают с ожиданиями (вы собираете App42PaaS…, а копируете в образ как App43PaaS.war — несоответствие имени может влиять на места поиска в логике приложения).

Как исправить (варианты, зависимо от требований):

  1. Лучший подход — класть конфиг на classpath и читать через ClassLoader:
java
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("Config.properties");
  1. Если приложение ждёт файл в корне webapp, развёрните как ROOT (если хотите root‑контекст):
  • Переименуйте при копировании: COPY ... /usr/local/tomcat/webapps/ROOT.war
    или
  • Создайте context.xml с нужным path (менее рекомендуемо).
  1. Если нужен внешний конфиг (удобно для Docker) — положите файл в conf и передайте путь через JVM‑опцию:
yaml
environment:
 - JAVA_OPTS=-Dconfig.file=/usr/local/tomcat/conf/Config.properties
volumes:
 - ./Config.properties:/usr/local/tomcat/conf/Config.properties:ro

и в коде читать System.getProperty("config.file").

  1. Проверьте текущие имена/пути в контейнере:
bash
docker-compose exec tomcat sh -c "ls -la /usr/local/tomcat/webapps"
docker-compose exec tomcat sh -c "grep -R \"Config.properties\" /usr/local/tomcat/logs || true"

Коротко: не полагайтесь на относительные пути и имя WAR — либо используйте classpath, либо явный внешний путь.


Диагностика подключения к MySQL в docker-compose

  1. Быстрая проверка логов:
  • Логи Tomcat/приложения:
bash
docker-compose logs --tail=200 tomcat
docker-compose exec tomcat sh -c "tail -n 200 /usr/local/tomcat/logs/catalina.out"

Ищите строки: SQLException, Communications link failure, Access denied, Unknown database, No suitable driver, ClassNotFoundException для com.mysql.*.

  • Логи MySQL:
bash
docker-compose logs --tail=200 db
# или
docker-compose exec db sh -c "cat /var/log/mysql/error.log || echo 'no file'; mysql --version"

(офиц. образ mysql пишет в stdout — docker logs видны).

  1. Частые причины и их распознавание:
  • Неправильный хост (localhost) — в контейнере Tomcat localhost = сам Tomcat. Ошибка: Communications link failure / Connection refused. Решение: в JDBC URL использовать db:3306 (имя сервиса в docker‑compose) — см. обсуждение прямо на StackOverflow.
  • База ещё не готова — вы видите ошибки соединения на старте; depends_on не ждёт готовности. Решение: healthcheck / wait‑for / retry. Пример healthcheck для MySQL ниже.
  • Неправильные credentials — SQLException: Access denied for user. Проверьте .env и переменные MYSQL_USER/MYSQL_PASSWORD/MYSQL_DATABASE.
  • Несовместимость аутентификации MySQL8 и старого драйвера — ошибки типа Authentication plugin not supported. Решение: обновить mysql‑connector‑java до 8.x или запустить MySQL с --default-authentication-plugin=mysql_native_password.
  • Драйвера нет в classpath — No suitable driver / ClassNotFoundException. Проверьте WEB-INF/lib на mysql-connector или поместите драйвер в Tomcat/lib.
  1. Проверки изнутри Tomcat‑контейнера:
  • Проверка TCP:
bash
# если в образе есть netcat
docker-compose exec tomcat sh -c "nc -zv db 3306 && echo ok || echo fail"
# или пытаться mysql-клиентом (если установлен)
docker-compose exec tomcat sh -c "mysql -h db -u${MYSQL_USER} -p${MYSQL_PASSWORD} -e 'SELECT 1'"

Если nc отсутствует, установите временно: apk add --no-cache netcat-openbsd (alpine).

  1. Проверка JDBC‑URL и driver:
  • Откройте Config.properties (или где хранятся): ищите jdbc.url, jdbc.user, jdbc.password, driverClassName. Пример корректного URL для docker compose:
jdbc:mysql://db:3306/your_db?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
  • Убедитесь, что driverClassName соответствует пакету драйвера (для Connector/J8: com.mysql.cj.jdbc.Driver).
  1. Проверить инициализацию MySQL и время старта:
    В логах MySQL ищите строки о “ready for connections” — пока их нет, сервис не готов. depends_on не ждёт готовности. Решение: добавить healthcheck или wait‑for.

Практические команды и шаги для локализации причины (чек‑лист)

  1. Пересобрать и запустить с логами:
bash
docker-compose build --no-cache
docker-compose up --force-recreate --remove-orphans
docker-compose logs -f
  1. Проверить содержимое WAR до/после копирования:
bash
# локально
jar tf target/*.war | sed -n '1,200p' | grep -i Config.properties || echo "not found in war"

# в контейнере
docker-compose exec tomcat sh -c "jar tf /usr/local/tomcat/webapps/App43PaaS.war | grep -i Config.properties || true"
docker-compose exec tomcat sh -c "ls -la /usr/local/tomcat/webapps | sed -n '1,200p'"
  1. Искать ошибки соединения/драйвера в логах:
bash
docker-compose logs tomcat | grep -Ei "SQLException|No suitable|Communications link|Access denied|UnsupportedClassVersionError|ClassNotFoundException"
  1. Проверить, доступен ли MySQL с точки зрения Tomcat:
bash
docker-compose exec tomcat sh -c "apk add --no-cache mysql-client netcat-openbsd || true"
docker-compose exec tomcat sh -c "nc -zv db 3306 && echo 'port ok' || echo 'cannot connect to port'"
docker-compose exec tomcat sh -c "mysql -h db -u${MYSQL_USER} -p${MYSQL_PASSWORD} -e 'SELECT VERSION(), DATABASE();' ${MYSQL_DATABASE}"
  1. Проверить наличие драйвера в WEB‑INF/lib:
bash
docker-compose exec tomcat sh -c "jar tf /usr/local/tomcat/webapps/App43PaaS.war | grep -i mysql-connector || ls -la /usr/local/tomcat/webapps/App43PaaS/WEB-INF/lib | grep -i mysql"
  1. Проверить, где приложение пытается читать конфиг — искать в логах упоминания Config.properties, стек‑трэйсы:
bash
docker-compose exec tomcat sh -c "grep -R \"Config.properties\" /usr/local/tomcat/logs || true"
docker-compose exec tomcat sh -c "grep -R \"Config.properties\" /usr/local/tomcat/webapps || true"
  1. Проверить .env и переменные окружения:
bash
cat .env
docker-compose exec db env | grep MYSQL
  1. Быстрый grep в pom.xml на потенциальные проблемы:
bash
grep -n "mysql" pom.xml || true
grep -n "maven.compiler" pom.xml || true

Ключевые принципы: согласовать версию Java, включить конфиг в classpath либо монтировать его как внешний файл, обеспечить ожидание готовности БД и включить драйвер в WAR.

  1. Исправленный пример Dockerfile (вариант: использовать Tomcat с JDK11):
Dockerfile
# Build (с JDK11)
FROM maven:3.6.3-openjdk-11 AS build
WORKDIR /app
# Копируем код из build context вместо git clone
COPY pom.xml .
COPY src ./src
# Помещаем Config.properties в src/main/resources перед сборкой
COPY Config.properties src/main/resources/
RUN mvn -B -DskipTests package

# Runtime — Tomcat на Java11
FROM tomcat:9-jdk11
WORKDIR /usr/local/tomcat/webapps
# Разворачиваем как ROOT, если хотим root-контекст
COPY --from=build /app/target/*.war ./ROOT.war

Если по каким‑то причинам вам нужен Tomcat 8/JRE8 — то в build‑стадии явно ставьте maven‑compiler target 1.8 в pom.xml.

  1. docker-compose: добавить healthcheck в MySQL и примитивный wait‑for (вариант):
yaml
version: '3.8'
services:
 db:
 image: mysql:8.0
 env_file: .env
 command: --default-authentication-plugin=mysql_native_password
 volumes:
 - ./db:/var/lib/mysql
 healthcheck:
 test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
 interval: 10s
 timeout: 5s
 retries: 10
 networks:
 - app42paas

 tomcat:
 build: .
 ports:
 - "8080:8080"
 depends_on:
 - db # учтите: в v3 depends_on не ждёт health, поэтому используйте wait-for скрипт
 environment:
 - JAVA_OPTS=-Dconfig.file=/usr/local/tomcat/conf/Config.properties
 volumes:
 - ./Config.properties:/usr/local/tomcat/conf/Config.properties:ro
 networks:
 - app42paas

networks:
 app42paas:

Примечание: depends_on в версии 3 не ждёт состояния health. Чтобы действительно ждать — добавьте в образ tomcat утилиту ожидания (wait‑for.sh/wait‑for-it/dockerize) и в ENTRYPOINT запуск Tomcat после проверки доступности db:3306.

  1. Обязательные доработки в pom.xml:
  • Включите mysql‑connector‑java в dependencies (версия 8.x для MySQL 8):
xml
<dependency>
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 <version>8.0.33</version>
</dependency>
  • Убедитесь, что maven‑compiler‑plugin target соответствует образу Tomcat.
  1. Если хотите быстро отлаживать: монтируйте Config.properties внутрь контейнера (volume) и делайте tail -f логов — тогда менять файл не нужно пересобирать WAR.

Источники

  1. https://github.com/shephertz/App42PaaS-Java-MySQL-Sample/blob/master/pom.xml
  2. https://stackoverflow.com/questions/35510964/unable-to-connect-mysql-container-to-tomcat-container-in-docker
  3. https://stackoverflow.com/questions/64101683/spring-boot-unable-to-communicate-with-mysql-db-in-docker-environment
  4. https://stackoverflow.com/questions/34024504/tomcats-spring-app-properties-with-docker-container-linking
  5. https://stackoverflow.com/questions/29389184/docker-connect-apache-tomcat-web-server-to-mysql-server
  6. https://stackoverflow.com/questions/51947553/cannot-connect-tomcat-container-to-mysql-container
  7. https://stackoverflow.com/questions/52011016/connect-tomcat-and-mysql-in-docker-compose

Заключение

Коротко: начните с проверки pom.xml (версия компилятора и mysql‑connector), проверьте содержимое WAR (jar tf/unzip -l) — должен быть Config.properties в WEB-INF/classes либо файл должен монтироваться в контейнер, и замените в конфиге jdbc‑host на имя сервиса в сети docker (db). Приведённые команды, правки Dockerfile и docker‑compose (healthcheck/wait‑for и согласование JDK/Tomcat) позволят локализовать проблему и обеспечить стабильное подключение Docker MySQL к Tomcat. Удачи — если пришлёте выводы команд (логи, результат jar tf, строки из pom.xml), помогу интерпретировать и предложить точечные правки.

Авторы
Проверено модерацией
Модерация
Tomcat MySQL Docker: версии, Config.properties, подключение