You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker Compose启动失败:0.0.0.0:3307端口已被占用求助

问题:Spring Boot容器化与MySQL通信启动失败

我有一个连接MySQL数据库的Spring Boot应用,尝试将其容器化,并编写docker-compose.yml来启动MySQL容器和可与其通信的Spring Boot容器。

项目结构

myapp/
  src/
    main/
      java/
        <All the Java code here>
      resources/
        application.yml
  build/
    libs/
      myapp.jar
  Dockerfile
  .env
  docker-compose.yml

执行./gradlew clean bootJar可构建出build/libs/myapp.jar。

.env文件内容

MAIN_DB_HOST=127.0.0.1
MAIN_DB_PORT=3307
MAIN_DB_DOCKER_PORT=3306
MAIN_DB_USERNAME=root
MAIN_DB_PASSWORD=123456
MAIN_DB_ROOT_PASSWORD=123456
MAIN_DB_DATABASE=myapp_db

SERVER_PORT=9200
WS_PORT=9200
WS_DOCKER_PORT=9201

Dockerfile内容

FROM eclipse-temurin:11

RUN mkdir /opt/app

COPY app/build/libs/myapp.jar myapp

ENTRYPOINT ["java","-jar","myapp"]

docker-compose.yml内容

version: "3.8"

services:
  myapp_db:
    image: mysql:8.0.32
    restart: unless-stopped
    environment:
      - MYSQL_ROOT_PASSWORD=$MAIN_DB_ROOT_PASSWORD
      - MYSQL_DATABASE=$MAIN_DB_DATABASE
      - MYSQL_CHARSET=utf8mb4
      - MYSQL_COLLATION=utf8mb4_0900_ai_ci
      - MYSQL_ENGINE=InnoDB
    ports:
      - $MAIN_DB_PORT:$MAIN_DB_DOCKER_PORT
    volumes:
      - db:/var/lib/mysql
  myapp:
    depends_on:
      - myapp_db
    build: .
    restart: on-failure
    ports:
      - $WS_PORT:$WS_DOCKER_PORT
      - $MAIN_DB_PORT:$MAIN_DB_DOCKER_PORT
volumes:
  db:

执行命令与错误信息

执行./gradlew clean bootJar && docker-compose --env-file .env up -d后,镜像构建成功,但启动时出现以下错误:

WARNING: Image for service myapp was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating myapp_myapp_db_1         ... done
Creating myapp_myapp_db_1         ... 
Creating myapp_myapp_db_1         ... error

ERROR: for myapp_myapp_db_1 Cannot start service myapp: driver failed programming external connectivity on endpoint myapp_myapp_db_1 (33899c0810d03db26ef7b48e67328ea9eb4e0f75cebc0201e667db72ce21d7ba): Bind for 0.0.0.0:3307 failed: port is already allocated

ERROR: Encountered errors while bringing up the project.

问题分析与解决

核心问题1:端口冲突

错误提示显示无法启动myapp服务,原因是宿主机的3307端口已被占用——你在docker-compose.yml里同时给myapp_db和myapp两个服务配置了相同的端口映射$MAIN_DB_PORT:$MAIN_DB_DOCKER_PORT。myapp_db先启动占用了3307端口,后续myapp服务尝试绑定同一个端口就会失败。

而且Spring Boot容器完全不需要映射MySQL的端口,容器之间通过Docker内部网络直接通信,只需要用服务名(比如myapp_db)就能访问MySQL,不需要把MySQL端口暴露给Spring Boot容器。

核心问题2:数据库连接地址错误

.env里的MAIN_DB_HOST=127.0.0.1是错误的:在Docker容器中,127.0.0.1指向容器自身,而非宿主机的MySQL服务。容器间通信应该使用Docker Compose中定义的服务名myapp_db作为数据库主机地址。

核心问题3:Dockerfile路径错误

你的Dockerfile中写的COPY app/build/libs/myapp.jar myapp路径有误,项目结构里myapp.jar实际在build/libs/下,且未指定正确的容器内存储路径,会导致启动时找不到jar包。


修正后的文件内容

1. 修正后的.env

# 用Docker服务名作为数据库主机
MAIN_DB_HOST=myapp_db
# MySQL容器内部端口固定为3306
MAIN_DB_PORT=3306
# 宿主机映射的MySQL端口(供外部工具连接用,可选)
MAIN_DB_DOCKER_HOST_PORT=3307
MAIN_DB_USERNAME=root
MAIN_DB_PASSWORD=123456
MAIN_DB_ROOT_PASSWORD=123456
MAIN_DB_DATABASE=myapp_db

SERVER_PORT=9200
WS_PORT=9200
WS_DOCKER_PORT=9201

2. 修正后的Dockerfile

FROM eclipse-temurin:11

RUN mkdir -p /opt/app

# 复制正确路径的jar包到容器目录
COPY build/libs/myapp.jar /opt/app/myapp.jar

# 切换工作目录到jar包所在路径
WORKDIR /opt/app

ENTRYPOINT ["java","-jar","myapp.jar"]

3. 修正后的docker-compose.yml

version: "3.8"

services:
  myapp_db:
    image: mysql:8.0.32
    restart: unless-stopped
    environment:
      - MYSQL_ROOT_PASSWORD=${MAIN_DB_ROOT_PASSWORD}
      - MYSQL_DATABASE=${MAIN_DB_DATABASE}
      - MYSQL_USER=${MAIN_DB_USERNAME}
      - MYSQL_PASSWORD=${MAIN_DB_PASSWORD}
      - MYSQL_CHARSET=utf8mb4
      - MYSQL_COLLATION=utf8mb4_0900_ai_ci
    ports:
      # 仅映射MySQL端口到宿主机(如果需要外部工具连接,不需要可删除)
      - ${MAIN_DB_DOCKER_HOST_PORT}:3306
    volumes:
      - db:/var/lib/mysql
    # 可选:解决MySQL 8.0的认证插件及时区问题
    command: --default-authentication-plugin=mysql_native_password --init-connect='SET NAMES utf8mb4;'

  myapp:
    depends_on:
      - myapp_db
    build: .
    restart: on-failure
    ports:
      # 仅映射Spring Boot的服务端口
      - ${WS_PORT}:${WS_DOCKER_PORT}
    environment:
      # 传递数据库连接信息给Spring Boot容器
      - SPRING_DATASOURCE_URL=jdbc:mysql://${MAIN_DB_HOST}:${MAIN_DB_PORT}/${MAIN_DB_DATABASE}?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
      - SPRING_DATASOURCE_USERNAME=${MAIN_DB_USERNAME}
      - SPRING_DATASOURCE_PASSWORD=${MAIN_DB_PASSWORD}

volumes:
  db:

额外注意事项

  1. depends_on仅保证容器启动顺序,不保证MySQL服务完全就绪。如果Spring Boot启动时MySQL还未初始化完成,会导致连接失败,可添加wait-for-it脚本或在Spring Boot中配置数据库连接重试机制。
  2. 确保application.yml中的数据库配置支持环境变量覆盖,示例配置:
    spring:
      datasource:
        url: ${SPRING_DATASOURCE_URL:jdbc:mysql://localhost:3306/myapp_db}
        username: ${SPRING_DATASOURCE_USERNAME:root}
        password: ${SPRING_DATASOURCE_PASSWORD:123456}
    

内容的提问来源于stack exchange,提问作者hotmeatballsoup

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 03:25:13