k8s 如何使用 ClusterIP + ingress 从集群外部访问内部的 mysql?

作者站长头像
站长
· 阅读数 9

我搭建了一个 minikube 环境

pod 和 service、ingress 的声明如下:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/data/mysql-data" # Change this path to your desired host path

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql8
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql8
  template:
    metadata:
      labels:
        app: mysql8
    spec:
      containers:
        - name: mysql8
          image: mysql:8.0.34
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: "123456"
          ports:
            - containerPort: 3306
          volumeMounts:
            - name: mysql-persistent-storage
              mountPath: /var/lib/mysql
            - name: custom-config
              mountPath: /etc/mysql/conf.d
          resources:
            limits:
              memory: "512Mi"
              cpu: "500m"
            requests:
              memory: "256Mi"
              cpu: "250m"
      volumes:
        - name: mysql-persistent-storage
          persistentVolumeClaim:
            claimName: mysql-pv-claim
        - name: custom-config
          configMap:
            name: mysql-custom-config # Create a ConfigMap with your custom configuration

---
apiVersion: v1
kind: Service
metadata:
  name: mysql8-service
spec:
  selector:
    app: mysql8
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306
  type: ClusterIP

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: mysql8-ingress
spec:
  rules:
    - host: mysql.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: mysql8-service
                port:
                  number: 3306

然后应用他们

minikube kubectl -- apply -f application/stateful/mysql.yaml

查看 pod 状态正常

─➤  minikube kubectl get pods                                                                                                                                                                                                                           130 ↵
NAME                            READY   STATUS    RESTARTS        AGE
mysql8-5db94fb5d5-22nhc         1/1     Running   2 (3d16h ago)   53d

查看 services 状态正常

╰─➤  minikube kubectl get services
NAME                   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes             ClusterIP   10.96.0.1        <none>        443/TCP          53d
mysql8-service         ClusterIP   10.110.118.91    <none>        3306/TCP         53d

查看 ingress 状态正常

─➤  minikube kubectl get ingress 

NAME             CLASS    HOSTS               ADDRESS   PORTS   AGE
mysql8-ingress   <none>   mysql.example.com             80      33m

修改本地的 /etc/hosts

╰─➤  cat /etc/hosts                                                                                                                                                                                                                                        1 ↵
127.0.0.1 localhost
127.0.1.1 vobiler740

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

192.168.49.2  mysql.example.com

我的 minikube 的 ip 就是 192.168.49.2

╭─pon@T4GPU ~/code/me/k8s-console  ‹master*› 
╰─➤  minikube ip                  
192.168.49.2

然后从宿主机访问, 但是连接失败

╰─➤  mycli -uroot -p123456 -hmysql.example.com -P3306
(2003, "Can't connect to MySQL server on 'mysql.example.com' ([Errno 111] Connection refused)")

然后我把 ClusterIP 改成 NodePort 却可以

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/data/mysql-data" # Change this path to your desired host path

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql8
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql8
  template:
    metadata:
      labels:
        app: mysql8
    spec:
      containers:
        - name: mysql8
          image: mysql:8.0.34
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: "123456"
          ports:
            - containerPort: 3306
          volumeMounts:
            - name: mysql-persistent-storage
              mountPath: /var/lib/mysql
            - name: custom-config
              mountPath: /etc/mysql/conf.d
          resources:
            limits:
              memory: "512Mi"
              cpu: "500m"
            requests:
              memory: "256Mi"
              cpu: "250m"
      volumes:
        - name: mysql-persistent-storage
          persistentVolumeClaim:
            claimName: mysql-pv-claim
        - name: custom-config
          configMap:
            name: mysql-custom-config # Create a ConfigMap with your custom configuration

---
apiVersion: v1
kind: Service
metadata:
  name: mysql8-service
spec:
  selector:
    app: mysql8
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306
      nodePort: 30001
  type: NodePort

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: mysql8-ingress
spec:
  rules:
    - host: mysql.example.com # 设置你想要的域名
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: mysql8-service # 这里填写你的 Service 名称
                port:
                  number: 3306 # 这里填写 Service 的端口号

然后应用

minikube kubectl -- apply -f application/stateful/mysql.yaml

再次从宿主机连接 mysql, 就成功了

─➤  mycli -uroot -p123456 -hmysql.example.com -P30001                                                                                                                                                                                                     1 ↵
MySQL 
mycli 1.27.0
Home: http://mycli.net
Bug tracker: https://github.com/dbcli/mycli/issues
Thanks to the contributor - chainkite
MySQL root@mysql.example.com:(none)>

所以为什么呢?为什么 ClusterIP 不行,但是 NodePort 却可以呢?

回复
1个回答
avatar
test
2024-06-24

我看懂了,这样的,你使用Ingress其实已经是已经把80端口映射到3306了 ( mysql.example.com:80 => mysql8-service:3306 ), 所以如果这样方案能行的话,正确的访问应该是 mycli -uroot -p123456 -hmysql.example.com -P80 (不过这样理论也也不能用,一个是http协议一个是tcp协议, Ingress实现tcp的转发是要额外配置的)

至于为什么NodePort可以使用, 因为你使用 NodePort 已经把 3306 的端口映射到宿主机的30001了,你使用 mycli -uroot -p123456 -hmysql.example.com -P30001 通过 ip 访问到数据库了,根本没有通过 Ingress 进行访问, 也就是 -hmysql.example.com 是把域名解析成 ip 也就是你宿主机 ip , mysql 客户端再通过 ip+端口 访问到数据库,不知道我说清楚了没

至于你想通过 Ingress 来转发tcp协议 我没玩过,不过可以参考一下这篇文章 https://blog.csdn.net/w851685279/article/details/115911686

回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容