k8s中SpringBoot访问外部MySQL

1,206 阅读1分钟

Minikube 使用host.minikube.internal访问宿主机

如果使用Minikube搭建的本地K8s集群,那么事情变得很容易,因为MiniKube默认提供了映射外部主机网络的hostname:host.minikube.internal.使用这个hostname即可访问宿主机上的所有服务了。例如MySQL服务,使用如下url即可:jdbc:mysql://host.minikube.internal:3306/

minikube ssh进入虚拟机,查看hosts文件。

$ cat /etc/hosts
127.0.0.1       localhost
127.0.1.1       minikube
172.20.32.1     host.minikube.internal
172.20.34.234   control-plane.minikube.internal

使用Service Endpoints映射外部IP

Endpoints 是实现实际服务的端点的集合

集群内部应用通过Service互相访问,Service通过Selector选择带有相同标签的Pod。这些选择的Pod就是Service的Endpoints。如果未设置 selector,则需要通过手动构造 Endpoints 或 EndpointSlice 的对象来确定。

我们这个场景显然不是通过Selector来选择Pod,而是使用无头服务自定义Endpoints访问外部IP地址。

image.png

apiVersion: v1
kind: Service
metadata:
  name: mysql-svc
spec:
  clusterIP: None
  ports:
    - port: 3306
      targetPort: 3306
      protocol: TCP
---
kind: Endpoints
apiVersion: v1
metadata:
  name: mysql-svc
subsets:
  - addresses:
      # 外部网络IP
      - ip: 192.168.3.63
    ports:
      - port: 3306

使用Service externalName访问外部hostname

类型为 ExternalName 的服务将服务映射到 DNS 名称,而不是典型的选择算符。查找Service时,集群DNS返回CNAME记录,其值即为externalName指定的值。访问此类服务的方式与其他服务的方式相同,但主要区别在于重定向发生在 DNS 级别,而不是通过代理或转发。

由于 ExternalName使用 CNAME 重定向,因此无法执行端口重映射。

apiVersion: v1
kind: Service
metadata:
  name: mysql-svc
spec:
  # minikube 可用 externalName:host.minikube.internal
  externalName: mysql–instance1.123456789012.us-east-1.rds.amazonaws.com
  type: ExternalName

Spring Boot访问外部MySQL示例

image.png

bootstrap.yaml

spring:
  cloud:
    kubernetes:
      reload:
        enabled: true
      config:
        name: extenal-mysql
      secrets:
        enabled: true
        name: extenal-mysql

MySQL数据库用户名和密码从Secrets读取,其它配置从ConfigMap读取.

ConfigMap配置

metadata:
  name: ${project.artifactId}
data:
  application.properties: |-
    spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
    spring.datasource.type = com.alibaba.druid.pool.DruidDataSource
    spring.datasource.url = jdbc:mysql://mysql-svc:3306/ecp?useUnicode=true&characterEncoding=utf8&useSSL=false&autoReconnect=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true

Secrets配置

metadata:
  name: ${project.artifactId}
data:
  spring.datasource.username : cm9vdA==
  spring.datasource.password : cm9vdA==

Secrets中的数据转换成环境变量。

spec:
  template:
    spec:
      serviceAccount: ${project.artifactId}
      containers:
        - env:
            - name: spring.datasource.username
              valueFrom:
                secretKeyRef:
                  name: ${project.artifactId}
                  key: spring.datasource.username
            - name: spring.datasource.password
              valueFrom:
                secretKeyRef:
                  name: ${project.artifactId}
                  key: spring.datasource.password

这种方式缺点很明显,配置量大了将是一场灾难。此时可以选择使用envFrom来将某个Secrets中所有数据加载到容器环境中:

spec:
  template:
    spec:
      serviceAccount: ${project.artifactId}
      containers:
        - envFrom:
            - secretRef:
                name: ${project.artifactId}

MySQL.yml

apiVersion: v1
kind: Service
metadata:
  name: mysql-svc
spec:
  clusterIP: None
  ports:
    - port: 3306
      targetPort: 3306
      protocol: TCP
---
kind: Endpoints
apiVersion: v1
metadata:
  name: mysql-svc
subsets:
  - addresses:
      # 外部网络IP
      - ip: 192.168.3.63
    ports:
      - port: 3306