Kubernetes中如何使用ClusterDNS進行服務發現?

原創 半夏透心涼 [雲原生技術愛好者社區](javascript:void(0)😉 2019-12-26

“本文主要介紹了kubernetes網絡結構、pod和service之間域名通信”

  • 常見使用場景

​ 在常見集羣中經常會出現服務之間彼此通過http或者tcp、RPC的形式進行訪問,在kubernetes集羣中,pod和pod、service之間的網絡是互通的,但是service的ip地址是存儲在etcd中,如果創建完成之後,一直使用apply,那麼ip不會變化,如果不小心執行了kubectl delete -f yaml,那麼service的ip將發生變化,如果此ip被很多服務使用,將會帶來災難性的修改,這時我們可以藉助kube-dns解決問題。

  • kubernetes網絡模型

​ 一個完整的Kubernetes集羣應該包含三層網絡,首先第一層是mater和node節點之間的網絡,這個網絡需要在部署kubernetes集羣之前配置完成,
第二層網絡是pod的網絡通過kubenet或者cni插件實現,用於pod之間或者內部的通信,集羣中的所有pod均處在同一個網絡平面空間內,可以直接通信,
第三層網絡是Service資源的網絡,是一個虛擬網絡,用於爲Kubernetes集羣配置IP地址,但此地址並不配置於任何主機或者容器的網絡接口之上,而是通過kubeproxy配置爲iptables規則,將發往該地址的所有流量調度至後端的pod之上。

  • Kubernetes網絡中常見四種通信方式
    1 同一個pod的內部通信;
    2 各個pod彼此通信;
    3 pod和service的通信;
    4 集羣外部流向service的通信。

看到上面這些你就不難理解爲什麼在yaml中存在port,targetPort,nodePort?

containerPort:一個信息性數據,他只是爲集羣提供一個可以快速瞭解相關pod可以訪問端口的途徑,而且顯式指定容器端口,無論你是否指定都不影響其他節點上的客戶端pod對其進行訪問。

port:服務提供端口,用於kubernetes集羣內部服務訪問。

targetPort:pod目標端口,如果不設置使用默認port端口,port和nodePort的數據通過這個端口進入到Pod內部,Pod裏面的containers的端口映射到這個端口,提供服務。

nodePort:外部用戶訪問端口

  • kubernetes中如何發現服務?

    通過如下yaml創建兩個nginx服務

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
         labels:
          app: nginx
        spec:
          containers:
          - name: nginx
            image: docker.hub.com/ops/openresty:1.15
            ports:
            - containerPort: 80
    

    通過進入服務內部進行訪問nginx服務

    kubectl exec nginx-deployment-74fd67c98d-26j9r -it /bin/bash
    
    [root@nginx-deployment-74fd67c98d-26j9r /]# curl 10.244.1.49:80  
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to OpenResty!</title>
    <style>
        body {
            width: 35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
        }
    </style>
    </head>
    <body>
    <h1>Welcome to OpenResty!</h1>
    <p>If you see this page, the OpenResty web platform is successfully installed and
    working. Further configuration is required.</p>
    
    <p>For online documentation and support please refer to
    <a href="https://openresty.org/">openresty.org</a>.<br/>
    Commercial support is available at
    <a href="https://openresty.com/">openresty.com</a>.</p>
    
    <p><em>Thank you for flying OpenResty.</em></p>
    </body>
    </html>
    

    看到這裏可能有人要說,這簡直沒法用,每次創建pod ip都要改變,總不能每次手動修改ip地址訪問吧?如此訪問,我怎麼才能做負載均衡?

  • 如何通過service解決問題負載問題

    創建如下service,通過selector選擇nginx服務

    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-service
      labels:
        app: nginx
    spec:
      type: NodePort
      ports:
      - name: http
        port: 80
        targetPort: 80
        nodePort: 30007
      - name: https
        port: 443
        targetPort: 443
        nodePort: 30003
      selector:
        app: nginx
    

    查看服務對應服務ip,並訪問服務。

    [root@k8s-m opt]# kubectl get svc nginx-service
    NAME            TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
    nginx-service   NodePort   10.99.251.122   <none>        80:30007/TCP,443:30003/TCP   29h
    [root@k8s-master opt]# 
    [root@nginx-deployment-745fd7c98d-2xj9r /]# curl 10.99.251.122:80
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to OpenResty!</title>
    <style>
        body {
            width: 35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
        }
    </style>
    </head>
    <body>
    <h1>Welcome to OpenResty!</h1>
    <p>If you see this page, the OpenResty web platform is successfully installed and
    working. Further configuration is required.</p>
    
    <p>For online documentation and support please refer to
    <a href="https://openresty.org/">openresty.org</a>.<br/>
    Commercial support is available at
    <a href="https://openresty.com/">openresty.com</a>.</p>
    
    <p><em>Thank you for flying OpenResty.</em></p>
    </body>
    </html>
    

    通過如上service的方式已經實現了負載均衡,但是我們在服務沒有創建之前仍然是不知道服務對外提供服務IP是什麼?當然我們可以在service的yaml中內置ClusterIP,但是即使如此,還可能會出現ip佔用的問題。

  • kube-dns是如何解決如上問題的?

    在創建pod資源時,kubelet會將其所屬名稱空間中的所有service對象以環境變量的形式注入其中。如下所示:

    [root@nginx-deployment-745fd7c98d-2xj9r /]# printenv|grep NGINX
    NGINX_SERVICE_PORT_443_TCP=tcp://10.99.251.123:443
    NGINX_SERVICE_PORT_80_TCP_PORT=80
    NGINX_SERVICE_PORT_443_TCP_PORT=443
    NGINX_SERVICE_PORT_80_TCP_PROTO=tcp
    NGINX_SERVICE_PORT_443_TCP_PROTO=tcp
    NGINX_SERVICE_SERVICE_HOST=10.99.251.123
    NGINX_SERVICE_SERVICE_PORT_HTTP=80
    NGINX_SERVICE_PORT=tcp://10.99.251.123:80
    NGINX_SERVICE_PORT_80_TCP=tcp://10.99.251.123:80
    NGINX_SERVICE_SERVICE_PORT_HTTPS=443
    NGINX_SERVICE_SERVICE_PORT=80
    NGINX_SERVICE_PORT_80_TCP_ADDR=10.99.251.123
    NGINX_SERVICE_PORT_443_TCP_ADDR=10.99.251.123
    

    所以我們可以直接通過如下形式進行訪問(當然如果存在集羣內服務調用的話,我們就可以直接配置成域名的形式):

    [root@nginx-deployment-745fd7c98d-2xj9r /]# curl nginx-service:80
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to OpenResty!</title>
    <style>
        body {
            width: 35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
        }
    </style>
    </head>
    <body>
    <h1>Welcome to OpenResty!</h1>
    
  • 域名格式

具體爲:<service_name>..svc.<cluster_domain>和<service_name>..<cluster_domain>,當然後面cluster_domain取決於本地/etc/resolv.conf是否配置,如上我的示例就沒有使用命名空間也沒有配置集羣域名,那麼我直接service名稱就可以直接訪問。

  • 總結

    在k8s集羣中,服務是運行在Pod中的,Pod的發現和副本間負載均衡是我們面臨的問題。我們使用Service解決了負載均衡的問題,但是集羣環境中,service經常伴隨着ip的變動而變動,得益於kubedns插件,使其可以直接通過域名進行訪問。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章