Java应用无法连接到在Minikube上运行的本地Mysql Pod

时间:2019-03-08 23:24:04

标签: java mysql docker kubernetes minikube

我在机器上运行的本地Minikube集群上部署了Java Spring引导应用程序。

Java应用程序连接到mysql数据库,并在运行时通过使用DataSource Configuration进行配置。这是数据库配置类:

public class DatasourceConfig {
  @Bean
  @Primary
  public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setUrl(System.getProperty("mysql_user"));
    dataSource.setUsername(System.getProperty("mysql_user"));
    dataSource.setPassword(System.getProperty("mysql_pass"));

    return dataSource;
  }
}

我在这样的运行时(来自mysql_url)传递mysql_passmysql_userDockerfile的值:

ENTRYPOINT java -Dmysql_url=$mysql_url \
    -Dmysql_user=$mysql_user \
    -Dmysql_pass=$mysql_pass \
    -jar myapp.jar

我为本地mysql容器映像创建了另一个pod /部署,并通过本地服务公开了它。

这是kubernetes的mysql.yml文件:

apiVersion: v1
kind: Service
metadata:
  name: mysql-svc
  labels:
    app: mysql
spec:
  ports:
  - port: 3306
    nodePort: 30306
    targetPort: mysql-port
    protocol: TCP
  selector:
    app: mysql
  type: NodePort 
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: mysql
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-deployment
  labels:
    app: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
        tier: mysql
    spec:
      containers:
      - name: mysql
        image: mysql
        imagePullPolicy: Never
        ports:
          - name: mysql-port
            containerPort: 3306
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: pass
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim

因此,现在我在Minikube上分别运行两个pods + deployment + services,一个用于我的应用程序,另一个用于mysql容器:(下面是kubectl get all的输出

NAME                                    READY   STATUS    RESTARTS   AGE
pod/mysql-deployment-8464d4875d-jlszz   1/1     Running   0          168m
pod/myapp-deployment-6469d8554b-4sbhz   1/1     Running   0          38m

NAME                TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
service/kubernetes  ClusterIP   10.96.0.1        <none>        443/TCP          7d
service/mysql-svc   NodePort    10.105.186.178   <none>        3306:30306/TCP   168m
service/myapp-svc   NodePort    10.96.243.6      <none>        8080:31001/TCP   41m

NAME                                   READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mysql-deployment       1/1     1            1           168m
deployment.apps/myapp-deployment   1/1     1            1           41m

NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/mysql-deployment-8464d4875d   1         1         1       168m
replicaset.apps/myapp-deployment-6469d8554b   1         1         1       41m

通过执行以下操作,我可以从主机正确运行Java应用程序:

minikube service myapp-svc

我还可以通过以下操作从主机连接到Mysql:

运行minikube service mysql-svc --url,它会给我:http://<mysql-ip>:30306

然后我可以这样(从主机)连接到它:

mysql -h <mysql-ip> -P 30306 -u root -p

这可以通过minikube将我正确地连接到在本地kubernetes集群上运行的mysql。

我什至可以从minikube上运行的java容器内部连接到mysql服务:

首先,我像这样连接到Java pod:

kubectl exec -it myapp-deployment-6469d8554b-4sbhz /bin/bash

然后我在豆荚里跑mysql -h <mysql-ip> -P 30306 -u root -p。这样也可以正确地将我连接到另一个Pod中运行的mysql。

唯一的问题是:

从Java容器内部,当我检查应用程序日志时,看到以下内容:

  

错误1 --- [main] com.zaxxer.hikari.pool.HikariPool:   HikariPool-1-池初始化期间发生异常。

     

com.mysql.cj.jdbc.exceptions.CommunicationsException:通讯   链接失败

     

成功发送到服务器的最后一个数据包是0毫秒   前。驱动程序尚未收到来自服务器的任何数据包。

并且,当我尝试调用其中具有数据库操作的任何API时,都会出现以下错误:Unable to acquire JDBC Connection; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection

这意味着我的Java代码实际上无法连接到另一个Pod上部署的MySql。

我已验证Java Pod能够成功连接到Mysql Pod,那么为什么我的Java代码无法连接?

我什至验证了这一点,我能够通过传递部署在minikube上的pod的mysql url来本地运行docker java映像:

docker run -e mysql_url=jdbc:mysql://<mysql-ip>:<mysql-port>/my_db \
    -e mysql_user=root \
    -e mysql_pass=pass \
    --rm -p 8081:8080 --name myApp -it me/myapp

这验证了我在本地运行时,我的Java代码是否已正确配置为连接到mysql(甚至是部署在pod上的mysql)。

因此,在我看来,几乎所有内容都已正确配置。

  • mysql pod本身运行正常,我首先通过在本地使用mysql客户端连接到它进行了验证。
  • 当我在本地运行docker image时,Java代码能够连接到在Minikube上运行的mysql。
  • Minikube上的Java pod可以连接到mysql pod,我通过使用来自bash的mysql客户端从java pod中连接到mysql pod进行了验证。
  • Java代码也在运行(没有db连接部分)。

唯一不起作用的是,Minikube中部署的Java应用程序无法连接到另一个Pod中部署的mysql。

为此,我唯一想到的失败点就是Kubernetes在运行时将ENV变量传递给docker映像的方式。但是我什至通过在bash中运行env来验证这一点。在我的Java pod上运行。显示所有必需的环境变量均已正确设置。

这是我的Java部署文件:

myapp.deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
  labels:
    app: myapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: me/myapp
        imagePullPolicy: Never
        env:
        - name: mysql_url
          value: jdbc:mysql://<mysql-ip>:30306/my_db
        - name: mysql_user
          value: root
        - name: mysql_pass
          value: pass
        ports:
          - name: java-port
            containerPort: 8080

我还应该定义一个pod定义并在那里提供ENV变量吗?

在这里我还需要做其他事情吗?

我该如何解决?

PS :我已经在当前的终端窗口中运行eval $(minikube docker-env),以便Minikube可以使用本地docker映像。

0 个答案:

没有答案