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

Kubernetes部署的Spring Boot应用无法连接外部AWS RDS MySQL

问题描述

将Spring Boot应用部署到Kubernetes集群后,无法连接AWS RDS上的外部MySQL,使用了ExternalName Service进行配置,相关配置、错误日志及Service信息如下:

配置文件

MySQL ExternalName Service(mysql.yml)

apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  type: ExternalName
  externalName: mysql.ap-northeast-2.rds.amazonaws.com
  ports:
    - port: 3306

应用部署配置(app-dev.yml)

apiVersion: v1
kind: Service
metadata:
  name: app-dev
spec:
  type: NodePort
  ports:
  - nodePort: 30000
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: app-dev
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-dev
  labels:
    app: app-dev
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app-dev
  template:
    metadata:
      labels:
        app: app-dev
    spec:
      containers:
      - name: app-dev
        image: registry.ap-northeast-2.compute.amazonaws.com:5000/app/app-dev:1
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: dev
        - name: SPRING_DATASOURCE_URL
          # 尝试过mysql.default, default.mysql, mysql.default.svc.cluster.local.
          value: jdbc:mysql://mysql.default:3306/db?serverTimezone=UTC&characterEncoding=UTF-8
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
      nodeSelector:
        app: app-dev

错误日志

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
    at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:174)
    at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64)
    at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:836)
    at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:456)
    at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:246)
    at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:197)
    at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138)
    at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:358)
    at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:206)
    at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:477)
    at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:560)
    at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:115)
    at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112)
    at org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:158)
    at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:116)
    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:79)
    ... 60 common frames omitted
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:64)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
    at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:61)
    at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:105)
    at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:151)
    at com.mysql.cj.exceptions.ExceptionFactory.createCommunicationsException(ExceptionFactory.java:167)
    at com.mysql.cj.protocol.a.NativeSocketConnection.connect(NativeSocketConnection.java:91)
    at com.mysql.cj.NativeSession.connect(NativeSession.java:144)
    at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:956)
    at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:826)
    ... 73 common frames omitted
Caused by: java.net.UnknownHostException: mysql.default: Name or service not known
    at java.base/java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method)
    at java.base/java.net.InetAddress$PlatformNameService.lookupAllHostAddr(InetAddress.java:932)
    at java.base/java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1517)
    at java.base/java.net.InetAddress$NameServiceAddresses.get(InetAddress.java:851)
    at java.base/java.net.InetAddress.getAllByName0(InetAddress.java:1507)
    at java.base/java.net.InetAddress.getAllByName(InetAddress.java:1366)
    at java.base/java.net.InetAddress.getAllByName(InetAddress.java:1300)
    at com.mysql.cj.protocol.StandardSocketFactory.connect(StandardSocketFactory.java:132)
    at com.mysql.cj.protocol.a.NativeSocketConnection.connect(NativeSocketConnection.java:65)
    ... 76 common frames omitted

MySQL Service描述

# kubectl -n default describe service mysql
Name:              mysql
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          <none>
Type:              ExternalName
IP Families:       <none>
IP:
IPs:               <none>
External Name:     mysql.ap-northeast-2.rds.amazonaws.com
Port:              <unset>  3306/TCP
TargetPort:        3306/TCP
Endpoints:         <none>
Session Affinity:  None
Events:            <none>

解决方案与排查步骤

从错误日志的java.net.UnknownHostException: mysql.default: Name or service not known可知,核心问题是容器无法解析ExternalName Service的域名,以下是具体排查和修复步骤:

1. 修正数据库连接URL的域名格式

Kubernetes内部Service的标准域名格式为{{service-name}}.{{namespace}}.svc.cluster.local,你的ExternalName Service在default命名空间,正确的连接地址应为:

jdbc:mysql://mysql.default.svc.cluster.local:3306/db?serverTimezone=UTC&characterEncoding=UTF-8

如果应用和Service在同一命名空间,直接用mysql:3306即可,Kubernetes会自动解析同命名空间的Service。

2. 验证ExternalName Service的DNS解析

进入应用容器内部,执行以下命令确认是否能正确解析到RDS的IP:

# 同命名空间下直接解析service名
kubectl exec -it <你的应用Pod名称> -- nslookup mysql
# 或使用完整域名
kubectl exec -it <你的应用Pod名称> -- nslookup mysql.default.svc.cluster.local

如果解析失败,需检查:

  • Kubernetes集群的CoreDNS/ClusterDNS组件是否正常运行
  • 集群所在VPC的DNS配置是否允许外部域名解析

3. 检查AWS RDS的网络访问控制

即使DNS解析正常,还需确认:

  • RDS安全组是否允许Kubernetes集群节点的IP段访问3306端口
  • RDS与Kubernetes集群是否在同一VPC,或通过VPC peering连通(优先使用内网访问)
  • RDS数据库用户是否授权从应用所在IP段连接(例如GRANT ALL ON db.* TO 'user'@'%' IDENTIFIED BY 'password';)

4. 简化测试:直接使用RDS域名连接

如果ExternalName Service的解析存在问题,可以先跳过它,直接在SPRING_DATASOURCE_URL中使用RDS原始域名:

jdbc:mysql://mysql.ap-northeast-2.rds.amazonaws.com:3306/db?serverTimezone=UTC&characterEncoding=UTF-8

如果能正常连接,说明问题出在ExternalName Service的配置或集群DNS解析上;如果仍无法连接,重点排查RDS的网络权限和数据库用户配置。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 19:46:00