我在机器上运行的本地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_pass
,mysql_user
,Dockerfile
的值:
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)。
因此,在我看来,几乎所有内容都已正确配置。
唯一不起作用的是,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映像。