mysql - 无法通过 Kubernetes 集群中的主机名连接到 MariaDB

标签 mysql docker kubernetes docker-compose mariadb

如果我在 Docker Compose 配置中从官方镜像中设置 MariaDB,我可以通过它的主机名访问它 - 例如,如果在 MariaDB 容器内的 bash shell 中:

# host db
db has address 172.21.0.2


# curl telnet://db:3306
Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: <FILE>" to save to a file.
  • 这里没有连接被拒绝的问题

  • 但是如果在 Kubernetes 集群中从官方镜像部署了 MariaDB(尝试了 MicroK8s 和 GKE),我可以通过 localhost 连接到它。但不是通过它的主机名:
    # host db
    db.my-namspace.svc.cluster.local has address 10.152.183.124
    
    # curl telnet://db:3306
    curl: (7) Failed to connect to db port 3306: Connection refused
    
    # curl telnet://localhost:3306
    Warning: Binary output can mess up your terminal. Use "--output -" to tell 
    Warning: curl to output it to your terminal anyway, or consider "--output 
    Warning: <FILE>" to save to a file.
    
  • 服务主机名的连接被拒绝,但 localhost 响应

  • 我试图替换包含的 my.cnf使用简化版本,例如:
    [mysqld]
    skip-grant-tables
    skip-networking=0
    #### Unix socket settings (making localhost work)
    user            = mysql
    pid-file        = /var/run/mysqld/mysqld.pid
    socket          = /var/run/mysqld/mysqld.sock
    
    #### TCP Socket settings (making all remote logins work)
    port         = 3306
    bind-address = *
    
  • 没有运气

  • MariaDB Kubernetes 部署如下:
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: db
    spec:
      replicas: 1
      strategy:
        type: Recreate
      selector:
        matchLabels:
          name: db
      template:
        metadata:
          labels:
            name: db
        spec:
          containers:
          - env:
            - name: MYSQL_PASSWORD
              value: template
            - name: MYSQL_ROOT_PASSWORD
              value: root
            - name: MYSQL_USER
              value: template
            image: mariadb:10.4
            name: db
            ports:
            - containerPort: 3306
            resources: {}
            volumeMounts:
            - mountPath: /var/lib/mysql
              name: dbdata
          restartPolicy: Always
          volumes:
          - name: dbdata
            persistentVolumeClaim:
              claimName: dbdata
    status: {}
    

    和相应的持久卷声明:
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      labels:
        io.kompose.service: dbdata
      name: dbdata
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 100Mi
    status: {}
    

    令我感到困惑的是,相同的配置适用于 Docker Compose,但不适用于 Kubernetes 集群。

    任何想法可能会发生什么?

    更新 2020-03-18
    我忘记包含数据库的服务声明并在此处添加:
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: db
      name: db
    spec:
      ports:
      - name: "3306"
        port: 3306
        targetPort: 3306
      selector:
        app: db
        name: db
      type: ClusterIP
    status:
      loadBalancer: {}
    
    

    ...包括两者 appnamespec.selector - 习惯只有 name但@Al-waleed Shihadeh 的例子包括 app所以我也会包括在内,以防万一 - 但没有成功。

    以下是几个 kubectl 列表命令的输出:
    $ sudo microk8s.kubectl get svc db -n my-namespace
    NAME   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    db     ClusterIP   10.152.183.246   <none>        3306/TCP   35m
    
    $ sudo microk8s.kubectl get pods -owide -n my-namespace
    NAME                           READY   STATUS             RESTARTS   AGE   IP            NODE          NOMINATED NODE   READINESS GATES
    db-77cbcf87b6-l44lm            1/1     Running            0          34m   10.1.48.118   microk8s-vm   <none>           <none>
    

    解决方案
    比较 KoopaKiller 发布的服务声明,证明有效,我终于注意到设置 protocol缺少端口声明中的“TCP”属性 - 这部分:
    spec:
      ports:
      - protocol: TCP
    ...
    

    最佳答案

    由于您使用的是 Kubernetes 部署,您的 Pod 的名称将根据您在规范文件中提供的名称动态生成,在您的示例中,将使用名称 db-xxxxxxxxxx-xxxxx 创建 Pod。 .

    为了创建“固定”主机名,您需要创建一个服务来访问您的 pod,例如:

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

    并检查是否已成功部署:
    $ kubectl get svc db
    NAME   TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
    db     ClusterIP   10.96.218.18   <none>        3306/TCP   89s
    

    您的服务的全名将是:<name>.<namespace>.cluster.local在这种情况下使用 default命名空间将为 db.default.cluster.local指向ip 10.96.218.18如上例所示。

    要获得您的服务,您需要使用他的信息配置您的/etc/hosts:
    echo -ne "10.96.218.18\tdb.default.cluster.local db db.default" >> /etc/hosts
    

    之后,您将能够通过 dns 访问您的服务:
    $ dig +short db
    10.96.218.18
    
    $ mysql -h db -uroot -p
    Enter password: 
    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Your MySQL connection id is 10
    Server version: 5.5.5-10.4.12-MariaDB-1:10.4.12+maria~bionic mariadb.org binary distribution
    
    Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
    
    Oracle is a registered trademark of Oracle Corporation and/or its
    affiliates. Other names may be trademarks of their respective
    owners.
    
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    
    mysql> 
    

    众所周知,您还可以使用 HELM 模板来设置带有复制功能的 mariadb。看到这个 article

    引用文献:

    https://kubernetes.io/docs/concepts/services-networking/service/

    https://kubernetes.io/docs/concepts/workloads/controllers/deployment/

    关于mysql - 无法通过 Kubernetes 集群中的主机名连接到 MariaDB,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60729205/

    相关文章:

    mysql - 如何将当前时间与 MySQL 中的时间变量进行比较

    mysql - 连接字符串错误。无法找到请求的 .Net Framework 数据提供程序

    java - 如何将数据库结果集加载到jeditorpane中

    node.js - 清理 Docker 容器 kill

    python - 如何设置pycharm解释器使用docker

    java - 从 GKE 连接到 Google Cloud SQL 数据库的方法比较

    php - 选择排除表中特定值的查询

    Docker 守护进程更新后无法启动

    kubernetes - 探索Azure Kubernetes卷内容

    amazon-web-services - 如何在启用 MFA 的情况下将 Docker 镜像从 AWS ECR 拉取到 Minikube Kubernetes 集群