目录
kubernetes网络简介(上)
/    

kubernetes网络简介(上)

一、Service

1.1 Service存在的意义:

  • 防止Pod失联(服务发现)
  • 定义一组Pod的访问策略(负载均衡)

1.2 Pod与Service的关系

  • 通过label-selector相关联
  • 通过Servic实现Pod的负载均衡( TCP/UDP 4层)

创建service的时候必须打标签,并且与创建的deployment或者pod的标签一致

image.png

通过kubectl create deployment web --image=nginx --dry-run=client -o yaml > web-dp.yaml命令导出deployment文件:

yaml示例:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: web             # deployment的标签
  name: web
spec:
  replicas: 3
  selector:                # 标签选择器
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web         # Pod的标签
        project: blog
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}

注意:

  • 标签选择器里的标签是筛选Pod用的
  • Pod的标签支持多个

应用:

kubectl apply -f web-dp.yaml

查看标签:

[root@k8s-master k8s]# kubectl get pod --show-labels 
NAME                   READY   STATUS    RESTARTS   AGE   LABELS
web-5b9bff6674-8wjlq   1/1     Running   0          12s   app=web,pod-template-hash=5b9bff6674,project=blog
web-5b9bff6674-99ltd   1/1     Running   0          33s   app=web,pod-template-hash=5b9bff6674,project=blog
web-5b9bff6674-skgsj   1/1     Running   0          15s   app=web,pod-template-hash=5b9bff6674,project=blog

暴露服务:

kubectl expose deployment web --port=80 --target-port=80 --name=web --dry-run=client -o yaml > web-svc.yaml

参数解释:

  • --port:k8s集群内部访问端口
  • --target-port:容器中服务提供端口,即应用程序端口,如nginx提供80 ,mysql提供3306
  • --protocol:指定协议类型,如TCP、UDP,SCTP等
  • --name:给svc起名,一般svc的名称与deployment一致

yaml示例:

apiVersion: v1
kind: Service
metadata:
  labels:
    app: web
  name: web
spec:
  ports:
  - port: 80           # 内部访问端口
    protocol: TCP
    targetPort: 80   # 容器提供服务的端口
  selector:
    app: web         # 标签与deployment中Pod定义的标签一致
    project: blog

应用:

kubectl apply -f web-svc.yaml

查看svc标签:

[root@k8s-master k8s]# kubectl get svc --show-labels 
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE   LABELS
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   47m   component=apiserver,provider=kubernetes
web          ClusterIP   10.101.205.162   <none>        80/TCP    18m   app=web

注意:从中可以发现,web这个Service的标签中并没有Project=blog这个标签,这是因为svc中app=web标签是svc本身的,它不是用于去关联Pod的,svc的详细信息可以使用kubectl get svc -o wide:

[root@k8s-master k8s]# kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE   SELECTOR
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   47m   <none>
web          ClusterIP   10.101.205.162   <none>        80/TCP    18m   app=web,project=blog

正常来讲,在任何节点机器上curl 10.101.205.162是可以访问到的,而且svc中的IP地址是非常稳定的,只要这个svc资源不被删除,这个IP就会一直存在。

1.3 Service三种常用类型

1.3.1 ClusterIP:集群内部使用

expose的默认类型,为一组pod分配一个稳定的虚拟IP,作为这组Pod提供统一入口,集群之外无法问问,只能在集群内部访问
(同Namespace内的Pod)

image.png

1.3.2 NodePort:对外暴露应用

在每个节点上启用一个端口来暴露服务,可以在集群外部访问。也会分配一个稳定内部集群IP地址。访问地址:<NodeIP>:<NodePort>

image.png

apiVersion: v1
kind: Service
metadata:
  labels:
    app: web
  name: web
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: web
    project: blog
  type:	NodePort

注意:typeports同级

[root@k8s-master k8s]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        61m
web          NodePort    10.101.205.162    <none>        80:31495/TCP   11m

其中,31495为宿主机端口,每个节点都会监听这个端口,而且这个端口是kube-proxy创建的

[root@k8s-master k8s]# netstat -antp | grep 31495
tcp        0      0 0.0.0.0:31495           0.0.0.0:*               LISTEN      2581/kube-proxy 

当然,这个宿主机端口号也可以固定,写法如下(端口号范围:3000-32767):

apiVersion: v1
kind: Service
metadata:
  labels:
    app: web
  name: web
spec:
  ports:
  - port: 80               # 集群内部端口
    protocol: TCP       # 协议
    targetPort: 80       # 容器端口
    nodePort: 30000    # 节点端口
  selector:                # 标签选择器,关联对应Pod
    app: web
    project: blog
  type: NodePort       # 指定类型

[root@k8s-master k8s]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        74m
web          NodePort    10.101.205.162   <none>        80:30000/TCP   23m

[root@k8s-master k8s]# netstat -antp | grep 3000
tcp        0      0 0.0.0.0:30000           0.0.0.0:*               LISTEN      2581/kube-proxy 

补充:kube-proxy:实现Service的功能,包含服务发现和提供负载均衡的能力。

1.3.3 LoadBalancer:对外暴露应用,适用公有云

NodePort类似,在每个节点上启用一个端口来暴露服务。除此之外,Kubernetes会请求底层云平台上的负载均衡器,将每个Node ([NodeIP]:[NodePort])作为后端添加进去。

image.png

LB解决的问题
前面加一个负载均衡器(公网):

  • 把内网节点的端口提供的服务给暴露到公网
  • 为nodeport提供高可用能力

工作流程:user -> lb -> node:port -> [service] -> pod

1.4 Service代理模式

Service代理模式分为:IptablesIPVS

proxy模式:

  • iptables (默认使用):用户态的工具主要用于netfilter规则管理
    入口流量规则->轮训pod机制->实际DNAT规则(目标地址转化)->容器
  • ipvs :
  # kubectl edit configmap kube-proxy -n kube-system
  mode: "ipvs"
  # kubectl delete pod kube-proxy-btz4p -n kube-system
  # yum install ipvsadm -y
  # ipvsadm -L -n

查看Service网络规则

iptables-save | grep <svc-name>

image.png

1.4.1 iptables改为ipvs步骤:

二进制部署

1.将/opt/kubernetes/cfg/kube-proxy-config.yaml配置文件中,注销mode参数,并在后面添加ipvs(下面的一些参数是ipvs的调度算法)

image.png

2.重启kube-proxy服务即可生效:

systemctl restart kube-proxy

3.安装ipvsadm工具去查看ipvs规则:

yum -y install ipvsadm
ipvsadm -L -n

参数解释:

  • -L:列出规则
  • -n:以数字而不是以主机名的形式显示IP地址
kubeadm部署

1.由于kube-proxy保存在k8s资源中,故需要编辑configmap的配置文件

[root@k8s-master k8s]# kubectl get pod -n kube-system 
NAME                                       READY   STATUS    RESTARTS   AGE
kube-proxy-grnpw                           1/1     Running   11         12d
kube-proxy-mshjk                           1/1     Running   11         12d
kube-proxy-nkkk4                           1/1     Running   11         12d

[root@k8s-master k8s]# kubectl get configmaps -n kube-system 
NAME                                 DATA   AGE
kube-proxy                           2      12d

2.打开kube-peoxy的configmap:

kubectl edit configmap kube-proxy -n kube-system

3.找到mode参数,在引号中写入ipvs,保存即可

image.png

4.删除kube-proxy的pod重建,等待集群自动拉起,ipvs即可生效:

kubectl delete pod kube-proxy-grnpw -n kube-system
kubectl delete pod kube-proxy-mshjk -n kube-system
kubectl delete pod kube-proxy-nkkk4 -n kube-system

[root@k8s-master k8s]# kubectl get pod -n kube-system 
NAME                                       READY   STATUS    RESTARTS   AGE
kube-proxy-272qn                           1/1     Running   0          42s
kube-proxy-gvq2n                           1/1     Running   0          33s
kube-proxy-jbjfc                           1/1     Running   0          61s

5.利用ipvsadm -L -n命令查看规则

1.4.2 Iptables VS IPVS 优缺点

Iptables

  • 灵活,功能强大
  • 规则遍历匹配和更新,呈线性时延

IPVS

  • 工作在内核态,有更好的性能
  • 调度算法丰富:rr,wrr,lc,wlc,ip hash...

参数解释:

  • rr:轮询模式
  • wrr:加权轮询模式
  • lc:最小连接模式
  • wlc:加权连接模式
  • ip hash

1.5 Service DNS名称

[root@k8s-master k8s]# kubectl get pod -n kube-system 
NAME                                       READY   STATUS    RESTARTS   AGE
coredns-7ff77c879f-cgfjw                   1/1     Running   11         12d
coredns-7ff77c879f-pn8qk                   1/1     Running   12         12d

DNS服务监视Kubernetes API,为每一个Service创建DNS记录用于域名解析。

测试coredns,使用busybox:1.28.4镜像并进入pod中

[root@k8s-master k8s]# kubectl run  -it --rm --image=busybox:1.28.4 sh
If you don't see a command prompt, try pressing enter.
/ #

正常来讲,在这个busybox的Pod中是ping的通上面创建的svc的IP地址的,也可以访问svc的页面。

/ # ping 10.101.205.162
PING 10.101.205.162 (10.101.205.162): 56 data bytes
64 bytes from 10.101.205.162: seq=0 ttl=64 time=0.101 ms
64 bytes from 10.101.205.162: seq=1 ttl=64 time=0.099 ms
64 bytes from 10.101.205.162: seq=2 ttl=64 time=0.101 ms
64 bytes from 10.101.205.162: seq=3 ttl=64 time=0.107 ms
^C
--- 10.101.205.162 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.099/0.102/0.107 ms
/ # wget 10.101.205.162
Connecting to 10.101.205.162 (10.101.205.162:80)
index.html           100% |******************************************************************************************|   612   0:00:00 ETA
/ # 

可以使用nslookup命令解析dns名称

/ # nslookup web
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web
Address 1: 10.101.205.162 web.default.svc.cluster.local

解析出来的IP对应svc的IP地址

注意:nslookup默认不能跨命名空间使用,若想解析跨命名空间的dns,则需要使用全格式

ClusterIP A记录格式:<service-name>.<namespace-name>.svc.cluster.local

示例:my-svc.my-namespace.svc.cluster.local

Pod在发送dns请求的时候,实际上是请求的/etc/resolv.conf文件中的dns,这个dns就是部署corednsService,所以执行nslookup命令时是向coredns发出请求,而coredns里面有Service对应IP的记录,之后响应记录结果,并且coredns对域名也有区分,若判断为外部域名,则走上层宿主机dns进行解析,然后再响应给Pod。

总结:
pod -> coredns service(10.0.0.2) -> coredns(service/clusterip记录) ->响应A记录结果

/ # cat /etc/resolv.conf 
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

[root@k8s-node1 manifests]# kubectl get svc -n kube-system 
NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                  AGE
kube-dns         ClusterIP   10.96.0.10      <none>        53/UDP,53/TCP,9153/TCP   12d

总结:

  1. 采用NodePort对外暴露应用,前面加一个LB实现统一访问入口

  2. 优先使用IPVS代理模式
    IPVS性能高,调度算法丰富,可以满足多业务大并发的场景下

  3. 集群内应用采用DNS名称访问
    当切换集群或者换ServiceIP的时候对应于程序没什么影响


“The first 90% of the code accounts for the first 90% of the development time. The remaining 10% of the code accounts for the other 90% of the development time.” – Tom Cargill

标  题kubernetes网络简介(上)
作  者Leif160519
出  处https://leif.fun/articles/2020/06/13/1592043038278.html
关于博主:坐标南京,运维工程师,如有问题探讨可以直接下方留言。
声援博主:如果您觉得文章对您有帮助,可以评论、订阅、收藏。您的鼓励是博主的最大动力!