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即可