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的。

原文地址:https://www.cnblogs.com/jason0529/p/9146724.html

时间: 2024-11-09 01:52:53

k8s踩坑记第2篇--3个IP折磨人的故事的相关文章

阿里云ECS搭建Kubernetes集群踩坑记

阿里云ECS搭建Kubernetes集群踩坑记 [TOC] 1. 现有环境.资源 资源 数量 规格 EIP 1 5M带宽 ECS 3 2 vCPU 16 GB内存 100G硬盘 ECS 3 2 vCPU 16 GB内存 150G硬盘 SLB 2 私网slb.s1.small 2. 规划 坑: 上网问题,因为只有一个EIP,所有其它节点只能通过代理上网; 负载均衡问题,因为阿里不支持LVS,负载均衡TCP方式后端又不支持访问负载均衡,HTTP和HTTPS方式,只支持后端协议为HTTP; 为了避免上

coding的svn服务踩坑记

https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/https://www.hojun.cn/ 前言 Q:咳咳,为啥会用到Coding的SVN?A:博主电脑上已经配好一个co

&lt;&lt;Python编程:从入门到实践&gt;&gt;踩坑记 Django

<<Python编程:从入门到实践>>踩坑记 Django Django Python 19.1.1.5 模板new_topic 做完书上的步骤后,对主题添加页面经行测试,但是浏览器显示 服务器异常. 个人采用的开发环境是virtual studio code , 测试起来很是难受,因为我配置的debug环境,断点操作没有作用. 经过我不断的测试,才发现我失败的原因是由于之前的误操作,先建立new_pizzas.py后改为new_pizzas.html的,错误就在这里.在我之后新建

踩坑记:httpComponents 的 EntityUtils

今天写的一个服务程序,有人报告获得的数据中文乱码,而我是用 apache 通过 httpComponents 去取得数据的,于是开启日志的 debug 级别. 在日志里果然发现中文不见了,有乱码出现: 2014-07-02 16:35:01.348 DEBUG [Wire.java:86] http-outgoing-8 << "<?xml version="1.0" encoding="UTF-8"?>... subject=&q

Spark踩坑记——数据库(Hbase+Mysql)转

转自:http://www.cnblogs.com/xlturing/p/spark.html 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streaming进行实时的数据流处理时,我需要将计算好的数据更新到hbase和mysql中,所以本文对spark操作hbase和mysql的内容进行总结,并且对自己踩到的一些坑进行记录. Spark Streaming持久化设计

Spring @Transactional踩坑记

@Transactional踩坑记 总述 ? Spring在1.2引入@Transactional注解, 该注解的引入使得我们可以简单地通过在方法或者类上添加@Transactional注解,实现事务控制. 然而看起来越是简单的东西,背后的实现可能存在很多默认规则和限制.而对于使用者如果只知道使用该注解,而不去考虑背后的限制,就可能事与愿违,到时候线上出了问题可能根本都找不出啥原因. 踩坑记 1. 多数据源 事务不生效 背景介绍 ? 由于数据量比较大,项目的初始设计是分库分表的.于是在配置文件中

[转]Spark 踩坑记:数据库(Hbase+Mysql)

https://cloud.tencent.com/developer/article/1004820 Spark 踩坑记:数据库(Hbase+Mysql) 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值. 最近一个实时消费者处理任务,在使用spark streaming进行实时的数据流处理时,我需要将计算好的数据更新到hbase和mysql中,所以本文对spark操作hbase和mysql的内容进行总结,并且对自己

记一次 Spring 事务配置踩坑记

记一次 Spring 事务配置踩坑记 问题描述:(SpringBoot + MyBatisPlus) 业务逻辑伪代码如下.理论上,插入数据 t1 后,xxService.getXxx() 方法的查询条件会不满足,会查询不到数据.结果事与愿违,后一次的查询,居然查到了数据. void saveXxx(){  xxService.getXxx(); // 查到一条数据 data1  xxService.insert(); // 插入一条数据 t1  xxService.getXxx(); // 查到

HttpWebRequest 改为 HttpClient 踩坑记-请求头设置

HttpWebRequest 改为 HttpClient 踩坑记-请求头设置 Intro 这两天改了一个项目,原来的项目是.net framework 项目,里面处理 HTTP 请求使用的是 WebReauest,但是 WebRequest 已经不再推荐使用了,你如果在项目中使用的话,编译器会警告, WebRequest已过时,新项目要 .Net standard 重写就直接 HttpClient 来处理 HTTP 请求了,在改的过程中踩了几个坑,记录一下 请求头处理 HttpClient 通常