zoukankan      html  css  js  c++  java
  • k8s踩坑记第2篇--3个IP折磨人的故事

    例子来源于《Kubernetes实践指南》一书。问题依然没有解决,求助大神。

    测试环境

    • Centos 7.0
    • docker 1.13.1
    • kubectl v1.5.2
    • etcd 3.2.18
      都是通过yum安装,防火墙已关闭。

    入坑问题

    浏览器输入:http://ip:30001/demo/

    Error:com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.

    相关资源rc、pod、service、ep都创建成功,但是myweb的pods无法访问到mysql提供的数据库服务。

    # kubectl get all
    NAME       DESIRED   CURRENT   READY     AGE
    rc/mysql   1         1         1         4h
    rc/myweb   1         1         1         2h
    
    NAME             CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
    svc/kubernetes   10.254.0.1      <none>        443/TCP          5d
    svc/mysql        10.254.67.31    <none>        3306/TCP         4h
    svc/myweb        10.254.62.177   <nodes>       8080:30001/TCP   2h
    
    NAME             READY     STATUS    RESTARTS   AGE
    po/mysql-vc9x6   1/1       Running   0          4h
    po/myweb-6k7s3   1/1       Running   0          2h
    # kubectl get ep
    NAME         ENDPOINTS            AGE
    kubernetes   192.168.1.171:6443   5d
    mysql        172.17.0.4:3306      4h
    myweb        172.17.0.2:8080      2h
    

    定义文件

    mysql-rc.yaml

    apiVersion : v1
    kind : ReplicationController
    metadata : 
        name : mysql
    spec : 
      replicas : 1
      selector : 
        app : mysql
      template : 
        metadata : 
          labels : 
            app : mysql
        spec : 
          containers : 
          - name : mysql
            image : mysql
            ports : 
            - containerPort : 3306
            env : 
            - name : MYSQL_ROOT_PASSWORD
              value : "123456"
    

    mysql-svc.yaml

    apiVersion : v1 
    kind : Service 
    metadata :  
      name : mysql 
    spec :  
      ports : 
        - port : 3306
      selector :
        app : mysql
    

    myweb-rc.yaml

    apiVersion : v1 
    kind : ReplicationController 
    metadata :  
      name : myweb 
    spec :  
      replicas : 1 
      selector :  
        app : myweb 
      template :  
        metadata :  
          labels :  
            app : myweb 
        spec :  
          containers :  
            - name : myweb 
              image : tomcat-app:v1 
              ports :  
                - containerPort : 8080 
              env :
                - name : MYSQL_SERVICE_HOST
                  value : 'mysql'
                - name : MYSQL_SERVICE_PORT
                  value : '3306'
    

    myweb-svc.yaml

    apiVersion : v1 
    kind : Service 
    metadata :  
      name : myweb 
    spec :  
      type : NodePort
      ports : 
      - port : 8080
        nodePort : 30001
      selector :
        app : myweb
    

    启动方式是顺序执行kubectl create -f yaml

    kubectl create -f mysql-rc.yaml
    kubectl create -f mysql-svc.yaml
    kubectl create -f myweb-rc.yaml
    kubectl create -f myweb-svc.yaml
    

    启动后即前面提到的问题。

    查看源代码

    既然无法建立连接,那先看下是如何建立连接的。登录到myweb的docker容器里面,查看index.jsp文件,主要内容如下:

    java.sql.Connection conn=null;
    java.lang.String strConn;
    java.sql.Statement stmt=null;
    java.sql.ResultSet rs=null;
    Class.forName("com.mysql.jdbc.Driver").newInstance();
    try{
          Class.forName("com.mysql.jdbc.Driver");
           String ip=System.getenv("MYSQL_SERVICE_HOST");
           String port=System.getenv("MYSQL_SERVICE_PORT");
           ip=(ip==null)?"localhost":ip;
           port=(port==null)?"3306":port;
          System.out.println("Connecting to database...");
    
          System.out.println("jdbc:mysql://"+ip+":"+port+"?useUnicode=true&characterEncoding=UTF-8");
          conn = java.sql.DriverManager.getConnection("jdbc:mysql://"+ip+":"+port+"?useUnicode=true&characterEncoding=UTF-8", "root","123456");
    
          stmt = conn.createStatement();
    }catch(Exception ex){
      ...
    }
    

    就是用jsp创建了一个连接,连接的地址通过ENV方式注入。即在myweb-rc.yaml中配置的MYSQL_SERVICE_HOST和MYSQL_SERVICE_PORT环境变量指定。
    既然指定名称为mysql无法解决,那换成mysql容器的IP是否可行呢?

    更新配置

    通过kubectl get ep 可以看到mysql暴露出的服务接口,那就用这个Ip试试。
    修改myweb-rc.yaml:

            env :
                - name : MYSQL_SERVICE_HOST
                  value : '172.17.0.4'
    

    然后重新部署pod。但是结果还是一样。

    网上看来的

    网上有个说法说把 MYSQL_SERVICE_HOST 去掉不配置。但是从源码看,不配置的默认值是localhost,显然不能具备3306的端口服务。

    网络谜团

    通过docker登录到容器内,互相ping网络都是通的。

    mysql:/# ping 172.17.0.4
    PING 172.17.0.4 (172.17.0.4): 56 data bytes
    64 bytes from 172.17.0.4: icmp_seq=0 ttl=64 time=0.155 ms
    64 bytes from 172.17.0.4: icmp_seq=1 ttl=64 time=0.139 ms
    --- 172.17.0.4 ping statistics ---
    2 packets transmitted, 2 packets received, 0% packet loss
    round-trip min/avg/max/stddev = 0.139/0.147/0.155/0.000 ms
    
    myweb:/# ping 172.17.0.2
    PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
    64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.089 ms
    64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.062 ms
    --- 172.17.0.2 ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 999ms
    rtt min/avg/max/mdev = 0.062/0.075/0.089/0.016 ms
    

    很显然网络是互通,但不知为何无法通过端口访问。

    clusterIP

    除了ep暴露的端口服务外,还有一个ClusterIP存在,是否可以通过ClusterIP访问呢。

    # kubectl get svc
    NAME             CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
    svc/kubernetes   10.254.0.1      <none>        443/TCP          5d
    svc/mysql        10.254.67.31    <none>        3306/TCP         4h
    svc/myweb        10.254.62.177   <nodes>       8080:30001/TCP   2h
    

    发现ping ClusterIP全部都不通。至此不明白了。

    三个IP

    Kubernetes中管理主要有三种类型的IP:Pod IP 、Cluster IP 和 外部IP。

    Pod IP

    Kubernetes的最小部署单元是Pod。利用Flannel作为不同HOST之间容器互通技术时,由Flannel和etcd维护了一张节点间的路由表。Flannel的设计目的就是为集群中的所有节点重新规划IP地址的使用规则,从而使得不同节点上的容器能够获得“同属一个内网”且”不重复的”IP地址,并让属于不同节点上的容器能够直接通过内网IP通信。

    每个Pod启动时,会自动创建一个镜像为gcr.io/google_containers/pause:0.8.0的容器,容器内部与外部的通信经由此容器代理,该容器的IP也可以称为Pod IP。

    Cluster IP

    Pod IP 地址是实际存在于某个网卡(可以是虚拟设备)上的,但Service Cluster IP就不一样了,没有网络设备为这个地址负责。它是由kube-proxy使用Iptables规则重新定向到其本地端口,再均衡到后端Pod的。

    外部IP

    Service对象在Cluster IP range池中分配到的IP只能在内部访问,如果服务作为一个应用程序内部的层次,还是很合适的。如果这个Service作为前端服务,准备为集群外的客户提供业务,我们就需要给这个服务提供公共IP了。

    结论

    依然不懂为什么会出现链接失败的情况,网络ping通的情况下,无法访问,这个坑填不上
    怀疑方向:应该是配置层面的问题,可能是k8s的,也可能是docker的。

  • 相关阅读:
    mybatis之关联关系映射
    spa项目开发之tab页实现
    mybatis整合redis实现二级缓存
    mybatis整合spring
    mybatis动态sql和分页
    Mybatis入门
    使用java代码操作redis
    Redis安装
    IDEA的安装和使用
    Linux入门——安装jdk、tomcat、MySQL以及项目部署
  • 原文地址:https://www.cnblogs.com/jason0529/p/9146724.html
Copyright © 2011-2022 走看看