例子來源於《Kubernetes實踐指南》一書。問題依然沒有解決,求助大神。前端
瀏覽器輸入:http://ip:30001/demo/java
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.node
相關資源rc、pod、service、ep都建立成功,可是myweb的pods沒法訪問到mysql提供的數據庫服務。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.yamlweb
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.yamlsql
apiVersion : v1 kind : Service metadata : name : mysql spec : ports : - port : 3306 selector : app : mysql
myweb-rc.yamldocker
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.yamlshell
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
很顯然網絡是互通,但不知爲什麼沒法經過端口訪問。
除了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所有都不通。至此不明白了。
Kubernetes中管理主要有三種類型的IP:Pod IP 、Cluster IP 和 外部IP。
Kubernetes的最小部署單元是Pod。利用Flannel做爲不一樣HOST之間容器互通技術時,由Flannel和etcd維護了一張節點間的路由表。Flannel的設計目的就是爲集羣中的全部節點從新規劃IP地址的使用規則,從而使得不一樣節點上的容器可以得到「同屬一個內網」且」不重複的」IP地址,並讓屬於不一樣節點上的容器可以直接經過內網IP通訊。
每一個Pod啓動時,會自動建立一個鏡像爲gcr.io/google_containers/pause:0.8.0的容器,容器內部與外部的通訊經由此容器代理,該容器的IP也能夠稱爲Pod IP。
Pod IP 地址是實際存在於某個網卡(能夠是虛擬設備)上的,但Service Cluster IP就不同了,沒有網絡設備爲這個地址負責。它是由kube-proxy使用Iptables規則從新定向到其本地端口,再均衡到後端Pod的。
Service對象在Cluster IP range池中分配到的IP只能在內部訪問,若是服務做爲一個應用程序內部的層次,仍是很合適的。若是這個Service做爲前端服務,準備爲集羣外的客戶提供業務,咱們就須要給這個服務提供公共IP了。
依然不懂爲何會出現連接失敗的狀況,網絡ping通的狀況下,沒法訪問,這個坑填不上。 懷疑方向:應該是配置層面的問題,多是k8s的,也多是docker的。