第六章 Kubernetes進階之Service與外界連通


  1.Pod與Service的關系

  Pod出現故障以后Deployment會根據策略重啟Pod,但是重啟Pod會生成新的IP,需要引入Service概念保證訪問正常

  Service

  • 防止Pod失聯
  • 定義一組Pod訪問策略
  • 支持ClusterIP,NodePort以及LoadBanlancer三種類型
  • Service的底層主要有Iptables和IPVS兩種網絡模式

  2.Service的定義

  Pod與Service的關系

  • 通過label-selector相關聯
  • 通過Service實現Pod的負載均衡(TCP/UDP 4層)

  示例service.yaml

#版本
apiVersion: v1
#類型是service
kind: Service
metadata:
  name: my-service
  namespace: default
spec:
  #service默認clusterIP
  clusterIP: 10.10.10.123
  ports:
  - name: http
    #service端口
    port: 80
    protocol: TCP
    #后端容器端口
    targetPort: 80
  #標簽選擇器關聯后端的一組Pod
  selector:
    run: nginx
      

   創建

kubectl apply -f service.yaml

   因為該service標簽匹配一個nginx所以如果沒有創建nginx的deployment需要創建一個

kubectl run nginx --replicas=3 --image=nginx --port=80

   創建以后可以查看有對應標簽的pod

# kubectl get pod -l run=nginx
NAME                     READY   STATUS    RESTARTS   AGE
nginx-57867cc648-b4rct   1/1     Running   0          9m53s
nginx-57867cc648-qgbwl   1/1     Running   0          9m53s
nginx-57867cc648-qmbbw   1/1     Running   0          9m53s

  查看

# kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.10.10.1     <none>        443/TCP   6d23h
my-service   ClusterIP   10.10.10.123   <none>        80/TCP    6m25s

   其中name為kubernetes的service是k8s安裝以后默認的一個service默認IP的service的第一個IP 10.10.10.1端口是443

  默認的svc的作用是負載均衡后端master的IP

  service需要動態感知后端ip變化可以通過以下命令查看,每個svc管理后端的一組容器

# kubectl get endpoints
NAME         ENDPOINTS                                      AGE
kubernetes   192.168.1.63:6443,192.168.1.64:6443            6d23h
my-service   172.17.41.2:80,172.17.55.2:80,172.17.55.4:80   9m59s

   在集群內部node例如192.168.1.65可以使用ClusterIP訪問

curl 10.10.10.123

  PS:這里配置文件指定了clusterIP為10.10.10.123,默認不知道該clusterIP是隨機的

apiVersion: v1
kind: Service
metadata:
  labels:
    run: nginx
  name: my-service
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: nginx

   不能直接應用生效

# kubectl apply -f service.yaml 
The Service "my-service" is invalid: spec.clusterIP: Invalid value: "": field is immutable

   需要刪除原svc再應用生效

kubectl delete svc my-service

kubectl apply -f service.yaml 

   查看生成了隨機的clusterIP

# kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.10.10.1     <none>        443/TCP   7d5h
my-service   ClusterIP   10.10.10.196   <none>        80/TCP    29s

 

  3.service類型

  service提供四層負載均衡把請求發送到后端的pod,默認規則是輪訓

  • ClusterIP:默認,分配一個集群內部可以訪問的虛擬IP
  • NodePort:在每個node上分配一個端口作為外部訪問入口
  • LoadBanlancer:工作在特定的Cloud Provider上,例如Google,AWS,OpenStack
  ClusterIP

  分配一個內部集群IP地址,只能在集群內部訪問(同Namespace內的Pod),默認ServiceType。 ClusterIP 模式的 Service 為你提供的,就是一個 Pod 的穩定的 IP 地址,即 VIP。

 

   NodePort

  分配一個內部集群IP地址,並在每個節點上啟用一個端口來暴露服務,可以在集群外部訪問。 訪問地址:: node端口范圍30000-32067
Client→NodeIP:NodePort→ClusterIP:ServicePort→PodIP:containerPort

 

   

#版本
apiVersion: v1
#類型是service
kind: Service
metadata:
  name: my-service
  namespace: default
spec:
  type: NodePort
  ports:
  - name: http
    #service端口
    port: 80
    protocol: TCP
    #后端容器端口
    targetPort: 80
  #標簽選擇器關聯后端的一組Pod
  selector:
    run: nginx

   應用,service定義類型不支持自動更新,需要刪除原有的配置再重新應用

kubectl delete -f service.yaml 
kubectl apply -f service.yaml 

   查看,類型變成NodePort了並且隨機產生一個端口,本次隨機端口是46194

# kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.10.10.1     <none>        443/TCP        7d3h
my-service   NodePort    10.10.10.238   <none>        80:46194/TCP   104s

   即使是使NodePort類型也會分配一個ClusterIP在集群內部可以訪問,NodePort是供集群外部訪問使用的

  使用NodePort會在多個node上可以訪問,企業應用可以加一台負載均衡負載到一個或多個node

  LoadBalancer

  分配一個內部集群IP地址,並在每個節點上啟用一個端口來暴露服務。 除此之外,Kubernetes會請求底層雲平台上的負載均衡器,將每個Node([NodeIP]:[NodePort])作為后端添加進去

  4.Service代理模式

  底層流量轉發與負載均衡實現

  • Iptables
  • IPVS

  service通過部署在node的應用kube-proxy實現

  可以通過kube-proxy配置文件查看模式

# cat /opt/kubernetes/cfg/kube-proxy
KUBE_PROXY_OPTS="--logtostderr=true \
--v=4 \
--hostname-override=192.168.31.65 \
--cluster-cidr=10.0.0.0/24 \
--proxy-mode=ipvs \
--masquerade-all=true \
--kubeconfig=/opt/kubernetes/cfg/kube-proxy.kubeconfig"

   查看Iptables的轉發方式

  刪除其中一台node192.168.1.66的ipvs配置

KUBE_PROXY_OPTS="--logtostderr=true \
--v=4 \
--hostname-override=192.168.31.66 \
--cluster-cidr=10.0.0.0/24 \
--kubeconfig=/opt/kubernetes/cfg/kube-proxy.kubeconfig"

   重啟kube-proxy組件

 systemctl restart kube-proxy

   查看service對應的Iptables規則

iptables-save|grep 10.10.10.238

   查看對應的規則

iptables-save|grep KUBE-SVC-I37Z43XJW6BD4TLV

 

 

   繼續查看對應規則

iptables-save|grep KUBE-SEP-ETBSYW4QFKX7DP4Z

 

 

   Iptables的問題

  1,創建很多Iptables(更新,非增量式)

  2,Iptables規則是從上至下逐條匹配(規則多了,匹配延時大)

  無法大規模應用,救世主IPVS

  查看IPVS的工作方式

  LVS基於IPVS內核調度模塊實現的負載均衡

  查看ipvs規則,需要kube-proxy設置ipvs工作模式才能查看到

ipvsadm -ln

   會生成虛擬網卡kube-ipvs0,所有的ClusterIP會綁定在該網卡上

 

   默認使用rr輪訓負載均衡策略,因為工作在內核態所以速度快

 

   對比

  Iptables

  • 靈活功能強大(可以在數據包不同階段對包進行操作)
  • 規則遍歷匹配和更新,呈線性時延

  IPVS

  • 工作在內核態,有更好的性能
  • 調度算法豐富:rr,wrr,lc,wlc,ip hash

  設置調度算法,一般使用默認即可無需配置

 

 

   Iptables和ipvs示意圖

  5.DNS

  service創建以后在集群內部可以通過cluserIP訪問,但是涉及遷移時IP會發生變化,需要部署內部DNS服務

  DNS服務監視Kubernetes API,為每一個Service創建DNS記錄用於域名解析

  DNS配置文件官方下載地址https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dns

 

   

   下載以后需要修改以下幾處

 

   修改后

 

   修改鏡像

 

   修改后

 

   修改資源限制

 

   修改后

 

   修改集群DNS地址

 

  修改后

 

 

   應用

 kubectl apply -f coredns.yaml

   排錯:應用以后pod顯示pending狀態

kubectl get pod -n kube-system
kubectl describe pod  coredns-65589b968c-s7m28 -n kube-system

   錯誤信息為

nodes are available: 2 node(s) didn't match node selector

   標簽不匹配

  查看系統標簽

kubectl get node --show-labels
NAME           STATUS   ROLES    AGE   VERSION   LABELS
192.168.1.65   Ready    <none>   10d   v1.13.4   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=192.168.1.65
192.168.1.66   Ready    <none>   10d   v1.13.4   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=192.168.1.66

   查看配置文件發現確實不匹配實際beta.kubernetes.io/os=linux 配置文件為beta.kubernetes.io/os=linux

 

   修改或者注釋這兩行即可

   部署DNS以后測試

kubectl run -it --image=busybox:1.28.4 --rm --restart=Never sh

   PS:鏡像需要使用1.28.4版本

  解析 nslookup加svc名

nslookup kubernetes

 

 

   默認的service是在默認的命名空間default下

# kubectl get svc -n default
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.10.10.1     <none>        443/TCP        9d
my-service   NodePort    10.10.10.196   <none>        80:37159/TCP   2d18h

   創建一個容器使用命名空間為kube-system

 kubectl run -it --image=busybox:1.28.4 --rm --restart=Never sh -n kube-system

   因為該容器的命名空間是kube-system所以無法解析默認命名空間default下的service需要在域名后加命名空間名稱訪問

# nslookup kubernetes
Server:    10.10.10.2
Address 1: 10.10.10.2 coredns.kube-system.svc.cluster.local

nslookup: can't resolve 'kubernetes'
/ # nslookup kubernetes.default
Server:    10.10.10.2
Address 1: 10.10.10.2 coredns.kube-system.svc.cluster.local

Name:      kubernetes.default
Address 1: 10.10.10.1 kubernetes.default.svc.cluster.local

   

  排錯:nslookup可以正確解析外網DNS例如www.baidu.com但是無法解析內網DNS

  查看core日志

 kubectl logs  -n kube-system coredns-7777dd7b8c-7dv26

   

E0309 03:15:43.061842       1 reflector.go:205] github.com/coredns/coredns/plugin/kubernetes/controller.go:318: Failed to list *v1.Namespace: Get https://10.10.10.1:443/api/v1/namespaces?limit=500&resourceVersion=0: x509: certificate is valid for 10.0.0.1, 127.0.0.1, 192.168.1.60, 192.168.1.61, 192.168.1.62, 192.168.1.63, 192.168.1.64, 192.168.1.65, 192.168.1.66, not 10.10.10.1

   原因是因為在創建api證書的時候填寫hosts信息錯誤

 

   修改IP地址以后重新創建證書重啟api即可


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM