Minikube中Kubernetes应用无法连接MySQL的问题求助
问题场景
在Minikube的Kubernetes环境中部署mysql-service和user-service后,user-service抛出MySQL连接失败错误,但相同配置在Docker Compose环境中可正常运行。
错误日志
com.mysql.cj.jdbc.exceptions.CommunicationsException: 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 com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:175) ~[mysql-connector-j-8.0.33.jar!/:8.0.33]
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64) ~[mysql-connector-j-8.0.33.jar!/:8.0.33]
at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:825) ~[mysql-connector-j-8.0.33.jar!/:8.0.33]
at com.mysql.cj.jdbc.ConnectionImpl.(ConnectionImpl.java:446) ~[mysql-connector-j-8.0.33.jar!/:8.0.33]
at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:239) ~[mysql-connector-j-8.0.33.jar!/:8.0.33]
at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:188) ~[mysql-connector-j-8.0.33.jar!/:8.0.33]
at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138) ~[HikariCP-5.0.1.jar!/:na]
at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:359) ~[HikariCP-5.0.1.jar!/:na]
at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201) ~[HikariCP-5.0.1.jar!/:na]
at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:470) ~[HikariCP-5.0.1.jar!/:na]
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561) ~[HikariCP-5.0.1.jar!/:na]
at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:100) ~[HikariCP-5.0.1.jar!/:na]
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) ~[HikariCP-5.0.1.jar!/:na]
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) ~[hibernate-core-6.2.6.Final.jar!/:6.2.6.Final]
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:316) ~[hibernate-core-6.2.6.Final.jar!/:6.2.6.Final]
配置文件
docker-compose.yml
version: "3" services: mysqldb-docker: image: mysql:8.0 container_name: mysqldb networks: - app-mysql environment: - MYSQL_ROOT_PASSWORD=root - MYSQL_DATABASE=flight_booking ports: - "3306:3306" volumes: - ./db:/var/lib/mysql user-service: image: user-service:1.0 build: context: ./UserService container_name: user-service ports: - "8081:8080" networks: - app-mysql depends_on: - mysqldb-docker environment: - SPRING_DATASOURCE_DB_HOST=mysqldb-docker - SPRING_DATASOURCE_URL=jdbc:mysql://mysqldb-service:3306/flight_booking?createDatabaseIfNotExist=true - SPRING_DATASOURCE_USERNAME=root - SPRING_DATASOURCE_PASSWORD=root # Volumes volumes: mysqldb-docker: networks: app-mysql:
mysqldb-deployment.yaml
# mysqldb-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: mysqldb-deployment spec: replicas: 1 selector: matchLabels: app: mysqldb template: metadata: labels: app: mysqldb spec: containers: - name: mysqldb image: mysql:8.0 ports: - containerPort: 3306 name: mysqldb env: - name: MYSQL_ROOT_PASSWORD value: root - name: MYSQL_DATABASE value: flight_booking volumeMounts: - name: mysqldb-persistent-storage # Reference the PVC name mountPath: /var/lib/mysql volumes: - name: mysqldb-persistent-storage # Define the volume name persistentVolumeClaim: claimName: mysqldb-pvc # Reference the PVC name you created earlier
mysqldb-service.yaml
apiVersion: v1 kind: Service metadata: name: mysqldb-service spec: selector: app: mysqldb ports: - port: 3306
mysqldb-pv.yaml
apiVersion: v1 kind: PersistentVolume metadata: name: mysqldb-pv spec: capacity: storage: 5Gi # Set the desired storage size accessModes: - ReadWriteOnce # Adjust based on your use case persistentVolumeReclaimPolicy: Retain storageClassName: standard # Set the appropriate storage class hostPath: path: /path/to/host/mysqldb-data # Adjust the host path to your desired location
mysqldb-pvc.yaml
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysqldb-pvc spec: accessModes: - ReadWriteOnce # Must match the access mode in the PV resources: requests: storage: 5Gi # Must match the storage size in the PV
user-service-deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: user-service-deployment spec: replicas: 1 # Set the desired number of replicas selector: matchLabels: app: user-service template: metadata: labels: app: user-service spec: containers: - name: user-service image: sweetyrv/flight_booking:user-service imagePullPolicy: IfNotPresent ports: - containerPort: 8081 env: - name: MYSQL_DATABASE value: flight_booking - name: MYSQL_ROOT_PASSWORD value: root - name: SPRING_DATASOURCE_DB_HOST value: mysqldb-service - name: SPRING_DATASOURCE_URL value: jdbc:mysql://mysqldb-service:3306/flight_booking?createDatabaseIfNotExist=true - name: SPRING_DATASOURCE_USERNAME value: root - name: SPRING_DATASOURCE_PASSWORD value: root
user-service-service.yaml
apiVersion: v1 kind: Service metadata: name: user-service spec: selector: app: user-service ports: - protocol: TCP port: 8081 targetPort: 8081
已排查项
- 网络策略:确认无限制Pod间通信的策略
- 主机名解析:在
user-servicePod内可正常解析mysqldb-service - MySQL服务器配置:Docker环境中配置正常,K8s中使用相同镜像参数
问题分析与解决建议
1. MySQL初始化完成前User-Service尝试连接
Kubernetes的Pod启动顺序控制不等待服务就绪,而Docker Compose环境中MySQL启动速度可能更快,或者隐含了就绪等待逻辑。
- 解决:给
user-service添加启动等待机制,比如在启动脚本中使用wait-for-it.sh工具,等待mysqldb-service:3306端口可访问后再启动应用;或者在Spring Boot配置中添加连接重试:
同时给MySQL Deployment添加spring.datasource.hikari.connection-timeout=30000 spring.datasource.hikari.maximum-pool-size=10 spring.datasource.hikari.idle-timeout=600000 spring.datasource.hikari.max-lifetime=1800000 spring.datasource.hikari.validation-timeout=5000 spring.datasource.hikari.connection-test-query=SELECT 1readinessProbe,确保服务就绪后才被Service关联:# 在mysqldb-deployment的containers下添加 readinessProbe: tcpSocket: port: 3306 initialDelaySeconds: 15 periodSeconds: 10
2. MySQL远程连接权限限制
MySQL 8.0默认仅允许root@localhost登录,K8s中User-Service从其他Pod连接,需要授权root@%访问权限。
- 解决:进入MySQL Pod执行授权命令:
或者通过ConfigMap挂载初始化脚本,实现自动授权:kubectl exec -it $(kubectl get pods -l app=mysqldb -o jsonpath='{.items[0].metadata.name}') -- mysql -uroot -proot mysql> GRANT ALL PRIVILEGES ON flight_booking.* TO 'root'@'%' WITH GRANT OPTION; mysql> FLUSH PRIVILEGES;
修改# 创建mysql-init-config ConfigMap apiVersion: v1 kind: ConfigMap metadata: name: mysql-init-config data: init.sql: | GRANT ALL PRIVILEGES ON flight_booking.* TO 'root'@'%' WITH GRANT OPTION; FLUSH PRIVILEGES;mysqldb-deployment.yaml,挂载该ConfigMap到MySQL初始化目录:# 在containers的volumeMounts中添加 - name: init-script mountPath: /docker-entrypoint-initdb.d # 在volumes中添加 - name: init-script configMap: name: mysql-init-config
3. PV/PVC挂载权限问题
Minikube节点内的hostPath路径如果不存在或权限不足,会导致MySQL无法写入数据,启动异常。
- 解决:进入Minikube节点创建路径并设置权限:
或者改用Minikube动态存储,删除手动创建的PV,直接使用PVC,Minikube会自动分配符合要求的存储。minikube ssh sudo mkdir -p /path/to/host/mysqldb-data sudo chmod 777 /path/to/host/mysqldb-data
4. JDBC URL参数缺失
MySQL 8.0需要指定时区参数,否则可能引发连接失败。
- 解决:修改JDBC URL为:
jdbc:mysql://mysqldb-service:3306/flight_booking?createDatabaseIfNotExist=true&serverTimezone=UTC&useSSL=false
5. 服务端点验证
确认mysqldb-service正确关联到mysqldb Pod,执行以下命令检查:
kubectl get svc mysqldb-service kubectl describe svc mysqldb-service kubectl get endpoints mysqldb-service
确保Endpoints中存在mysqldb Pod的IP地址。
内容的提问来源于stack exchange,提问作者Varshini

