Kubernetes中如何使用ClusterDNS進行服務發現?
- 2020 年 1 月 23 日
- 筆記
「本文主要介紹了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 andworking. 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-serviceNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEnginx-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 andworking. 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 NGINXNGINX_SERVICE_PORT_443_TCP=tcp://10.99.251.123:443NGINX_SERVICE_PORT_80_TCP_PORT=80NGINX_SERVICE_PORT_443_TCP_PORT=443NGINX_SERVICE_PORT_80_TCP_PROTO=tcpNGINX_SERVICE_PORT_443_TCP_PROTO=tcpNGINX_SERVICE_SERVICE_HOST=10.99.251.123NGINX_SERVICE_SERVICE_PORT_HTTP=80NGINX_SERVICE_PORT=tcp://10.99.251.123:80NGINX_SERVICE_PORT_80_TCP=tcp://10.99.251.123:80NGINX_SERVICE_SERVICE_PORT_HTTPS=443NGINX_SERVICE_SERVICE_PORT=80NGINX_SERVICE_PORT_80_TCP_ADDR=10.99.251.123NGINX_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>.<namespace>.svc.<cluster_domain>和<service_name>.<namespace>.<cluster_domain>,當然後面cluster_domain取決於本地/etc/resolv.conf是否配置,如上我的示例就沒有使用命名空間也沒有配置集群域名,那麼我直接service名稱就可以直接訪問。
- 總結
在k8s集群中,服務是運行在Pod中的,Pod的發現和副本間負載均衡是我們面臨的問題。我們使用Service解決了負載均衡的問題,但是集群環境中,service經常伴隨著ip的變動而變動,得益於kubedns插件,使其可以直接通過域名進行訪問。
原創不易,請隨手關注或者「在看」