【日常小问】解决 Jenkins 部署 Spring Cloud 微服务到 Docker 容器启动失败的问题

0 阅读1分钟

一、问题出现

在使用 Jenkins 进行 CI/CD 部署 Spring Cloud 微服务项目时,遇到了一个让人头疼的问题:所有通过 Jenkins 构建的 Docker 容器启动后立即退出,状态码为 Exited (1)

查看容器日志,报错信息如下:

***************************
APPLICATION FAILED TO START
***************************

Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

Reason:
Failed to determine a suitable driver class

看起来是数据库配置没有加载到,但奇怪的是,同样的项目在其他人的电脑上可以正常运行,唯独到了我的环境就各种报错。

二、问题原因

经过一番排查,发现这个问题其实是三个独立的问题叠加导致的:

2.1 Docker 网络不通

项目的各个微服务(Nacos、MySQL、Redis 等)部署在同一个 Linux 虚拟机的 Docker 中,但它们分布在不同的 Docker 网络里:

容器

所在网络

说明

Nacos、MySQL、Redis

tjxt

手动部署时创建的网络

Jenkins 构建的应用容器

heima-net

启动脚本中指定的网络

两个网络互相隔离,导致应用容器根本访问不到 Nacos 和 MySQL。

2.2 Nacos 认证信息缺失

项目使用了 Spring Cloud Alibaba Nacos 作为配置中心和服务注册发现中心。但 bootstrap.yml没有配置 Nacos 的地址和认证信息,默认使用 localhost:8848

在 Docker 容器中,localhost 指向的是容器自己,而不是宿主机的 Nacos 服务。即使网络通了,没有正确的地址和认证信息也无法连接。

2.3 共享配置位置错误

在修改 bootstrap.yml 添加 Nacos 配置时,不小心把 shared-configs(共享配置)放在了 discovery(服务发现)下面,而不是 config(配置中心)下面。这导致应用虽然能连接 Nacos,但无法加载共享的数据库配置

# ❌ 错误的结构
spring:
  cloud:
    nacos:
      config:
        server-addr: 192.168.150.101:8848
        username: nacos
        password: nacos
        file-extension: yaml
      discovery:
        server-addr: 192.168.150.101:8848
        username: nacos
        password: nacos
        shared-configs:  # ❌ 放在 discovery 下面,不会被加载
          - data-id: shared-mybatis.yaml
            refresh: false

三、解决问题

3.1 解决 Docker 网络问题

方法一:修改 Jenkins 启动脚本(推荐)

编辑 /usr/local/src/script/startup.sh,将 --network heima-net 改为 --network tjxt

# 修改前
--network heima-net ${IMAGE_NAME} \

# 修改后
--network tjxt ${IMAGE_NAME} \

方法二:手动连接网络

如果不想修改脚本,也可以手动将容器连接到正确的网络:

docker network connect tjxt tj-user
docker network connect tjxt tj-trade
docker restart tj-user tj-trade

3.2 配置 Docker 镜像加速器

在国内网络环境下,Docker Hub 经常超时。配置镜像加速器可以显著提升拉取镜像的速度:

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": [
    "https://docker.1ms.run",
    "https://docker.xuanyuan.me"
  ]
}
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker

3.3 添加 Nacos 认证配置

在每个微服务的 bootstrap.yml 中添加 Nacos 的地址和认证信息。注意 shared-configs 必须在 config 下面

spring:
  cloud:
    nacos:
      config:
        server-addr: 192.168.150.101:8848
        username: nacos
        password: nacos
        file-extension: yaml
        shared-configs: # ✅ 正确位置:在 config 下面
          - data-id: shared-spring.yaml
            refresh: false
          - data-id: shared-redis.yaml
            refresh: false
          - data-id: shared-mybatis.yaml
            refresh: false
          - data-id: shared-logs.yaml
            refresh: false
          - data-id: shared-feign.yaml
            refresh: false
      discovery:
        server-addr: 192.168.150.101:8848
        username: nacos
        password: nacos

为什么需要配置两份认证?

Nacos 在 Spring Cloud 中承担了两个角色:

  • 配置中心(Config):存储和管理配置文件,应用启动时从这里拉取数据库、Redis 等配置
  • 服务注册发现(Discovery):服务启动时注册自己的地址,让其他服务能找到自己

两个功能是独立的请求,所以需要分别配置认证信息。

3.4 重新构建部署

完成以上修改后:

  1. 将代码提交到 Gogs

  2. 删除旧的 Docker 容器和镜像

  3. 重新触发 Jenkins 构建

    删除旧容器和镜像

    docker rm -f tj-user tj-trade docker rmi tj-user:latest tj-trade:latest

四、总结

这次问题的根本原因是环境差异:在 IDE 中直接运行时,localhost 指向宿主机,Nacos 认证信息可以通过其他方式注入;但在 Docker 容器中,网络隔离和配置缺失的问题被放大了。

排查这类问题的思路是:

  1. 先看日志docker logs 容器名 是最直接的排查手段
  2. 分层排查:网络 → 连接 → 认证 → 配置,逐层检查
  3. 对比差异:和能正常运行的环境对比,找出配置差异

希望这篇文章能帮到遇到类似问题的朋友。