1 service概述
Service资源基于标签选择器将一组Pod定义成一个逻辑组合,并通过自己的IP地址和端口调度代理请求至组内的Pod对象之上,它向客户端隐藏了真实的、处理用户请求的Pod资源,使得客户端的请求看上去就像是由Service直接处理并进行响应的一样。 Service对象的IP地址位于为Kubernetes集群配置指定专用IP地址的范围之内,而且是一种虚拟IP地址,它在Service对象创建后即保持不变,并且能够被同一集群中的Pod资源所访问。Service端口用于接收客户端请求并将其转发至其后端的Pod中应用的相应端口之上。 通过其标签选择器匹配到的后端Pod资源不止一个时,Service资源能够以负载均衡的方式进行流量调度,实现了请求流量的分发机制。Service与Pod对象之间的关联关系通过标签选择器以松耦合的方式建立,它可以先于Pod对象创建而不会发生错误。 Service并不直接链接至Pod对象,它们之间还有一个中间层——Endpoints资源对象,它是一个由IP地址和端口组成的列表,这些IP地址和端口则来自于由Service的标签选择器匹配到的Pod资源。默认情况下,创建Service资源对象时,其关联的Endpoints对象会自动创建。
2 service存在的意义
- 防止pod失联(服务发现)
- 定义一组pod的访问策略(负载均衡)
3 service和pod关系
- service通过label-selector管理pod
- 通过service提供pod的负载均衡(tcp/udp四层负载均衡)
4 service三种常用类型
- ClusterIP 集群内部使用ip
- NodePort 对外暴露应用的ip
- LoadBalancer 对外暴露应用,适用公有云
4.1 ClusterIP
通过集群内部IP地址暴露服务,此地址仅在集群内部可达,而无法被集群外部的客户端访问. 分配一个稳定的ip地址,即vip 实现过程 1.apiserver:用户通过kubectl命令向apiserver发送创建service的命令,apiserver接收到请求后将数据存储到etcd中 2.kube-proxy:kubernetes的每个节点中都有一个叫做kube-porxy的进程,这个进程负责感知service,pod的变化,并将变化的信息写入本地的iptables规则中 3.iptables:使用NAT等技术将virtualIP的流量转至endpoint中
创建一个service模板
[root@k8s-master01 ~]# kubectl expose deployment nginx --port=80 --target-port=80 --name=nginx --dry-run -o yaml > service.yaml
查看yaml
[root@k8s-master01 ~]# cat service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: web
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: web
[root@k8s-master01 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-65b7447c7-wzpjf 1/1 Running 0 8m35s 10.244.2.123 k8s-node02 <none> <none>
[root@k8s-master01 ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 80d
nginx NodePort 10.110.114.9 <none> 80:30604/TCP 73d
web ClusterIP 10.98.72.53 <none> 80/TCP 10m
[root@k8s-master01 ~]# kubectl get ep
NAME ENDPOINTS AGE
kubernetes 192.168.10.71:6443 80d
nginx 10.244.1.11:80 73d
web 10.244.2.123:80 10m
如上所示 我们创建的service 关联到了 web这个pod上了 生成了一个clusterip 10.98.72.53 访问这个ip就可以在集群内部访问到这个pod
[root@k8s-master01 ~]# curl 10.98.72.53
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
4.2 NodePort
这种模式同样会创建一个clusterip关联对应的pod,其在每个node节点的IP地址的某静态端口(NodePort)暴露服务,因此,它依然会为Service分配集群IP地址,并将此作为NodePort的路由目标。 NodePort类型就是在工作节点的IP地址上选择一个端口用于将集群外部的用户请求转发至目标Service的ClusterIP和Port,因此,这种类型的Service既可如ClusterIP一样受到集群内部客户端Pod的访问,也会受到集群外部客户端通过套接字:进行的请求。
iptables规则
Nodeport-->svc-->sep--> pod( -j DNAT --to-destination clusterip:80)
实例:创建一个nodeport类型的service
[root@k8s-master01 ~]# cat nodepord.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: web-2
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: web
type: NodePort
[root@k8s-master01 ~]# kubectl apply -f nodepord.yaml
service/web-2 created
[root@k8s-master01 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 80d
nginx NodePort 10.110.114.9 <none> 80:30604/TCP 73d
web ClusterIP 10.98.72.53 <none> 80/TCP 26m
web-2 NodePort 10.107.45.167 <none> 80:32053/TCP 2m32s
[root@k8s-master01 ~]# kubectl get ep
NAME ENDPOINTS AGE
kubernetes 192.168.10.71:6443 80d
nginx 10.244.1.11:80 73d
web 10.244.2.123:80 26m
web-2 10.244.2.123:80 2m43s
我们现在就创建了一个NodePort类型的service并关联了对应的pod,并且也生成了一个clusterip,然后在每一个node上都启动了一个对应的nodeport的端口(32053)
然后通过外部网络就能通过nodeip:nodeport访问对应的pod了
![](https://devopstack.cn/wp-content/uploads/2021/03/b9be142c34d2ddd9297bd20287e1fe33.png)
上面是随机生成的NodePort ,也可以指定NodePort 端口
[root@k8s-master01 ~]# cat nodepord.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: web-2
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
NodePort: 30009
selector:
app: web
type: NodePort
[root@k8s-master01 ~]# kubectl apply -f nodepord.yaml
service/web-2 configured
[root@k8s-master01 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 80d
web ClusterIP 10.98.72.53 <none> 80/TCP 35m
web-2 NodePort 10.107.45.167 <none> 80:30009/TCP 10m
如上就更新端口成功了
4.3 LoadBalancer
LoadBalancer相当于对nodeport的负载均衡 这种类型建构在NodePort类型之上,创建一个具有公网IP地址的云供应商提供的负载均衡器,由它接入外部客户端的请求并调度至集群节点相应的NodePort之上。因此LoadBalancer一样具有NodePort和ClusterIP。 简而言之,一个LoadBalancer类型的Service会指向关联至Kubernetes集群外部的、切实存在的某个负载均衡设备,该设备通过工作节点之上的NodePort向集群内部发送请求流量。 例如Amazon云计算环境中的ELB实例即为此类的负载均衡设备。此类型的优势在于,它能够把来自于集群外部客户端的请求调度至所有节点(或部分节点)的NodePort之上,而不是依赖于客户端自行决定连接至哪个节点,从而避免了因客户端指定的节点故障而导致的服务不可用。
4.4 kube-proxy
Kube-proxy 工作原理
1.Service在很多情况下知识一个概念,真正起到Service作用的是kube-proxy服务进程。
2.每个Node节点上都会运行一个kube-proxy服务进程
3.对每个TCP类型的Kubernetes Service,Kube-proxy都会在本地Node节点上建立一个SocketServer来负责接收请求,然后均匀发送到后端某个Pod的端口上,这个过程默认采用Round Robin(rr)负责均衡算法
4.kube-proxy通过查询和监听Api Server中Service与Endpoints的变化,为每个Service都建立一个"服务代理对象",并自动同步。
5.服务代理对象是kube-proxy程序内部的一种架构,它包括一个用于监听此服务请求的SocketServer,SocketServer的端口是随机选择一个本地空闲端口,此外kube-proxy内部创建了一个负载均衡器LoadBalancer
6.针对发生变化的Service列表,kube-proxy会逐个处理
如果没有设置集群IP,则不做任何处理,否则,取该Service的所有端口定义列表
为Service端口分配服务代理对象并为该Service创建相关的iptables规则
更新负载均衡组件中对应Service的转发地址列表
7.kube-proxy在启动时和监听到Service或Endpoint的变化后,会在本机Iptables的NAT表中添加4条规则链。
KUBE-PORTABLS-CONTAINER: 从容器中通过Cluster IP和端口号访问service
KUBE-PORTALS-HOST: 从主机中通过Cluster IP和端口号访问service
KUBE-NODEPORT-CONTAINER: 从容器中通过NODE IP和端口号访问service
KUBE-NODEPORT-HOST: 从主机中通过Node IP和端口号访问service
注意:我们也可以给kube-proxy设置一个默认的策略是随机选择一个 pod。 我们也可以实现基于客户端 IP 的会话亲和性,可以将 service.spec.sessionAffinity的值设置为 "ClientIP"(默认值为 "None")。
4.5 启动ipvs转发模式
当应用比较多的时候,使用ipvs比较好点
lsmod |grep ip_vs
修改配置,启动ipvs
kubectl edit configmap kube-proxy -n kube-system 修改
mode: "ipvs"
重建kube-proxy
kubectl get pods -n kube-system -o wide
kubectl delete pod kube-proxy-xxx -n kube-system
[root@k8s-master01 ~]# kubectl delete pod kube-flannel-ds-amd64-gmzm6 -n kube-system
pod "kube-flannel-ds-amd64-gmzm6" deleted
5 内部服务发现(coredns)
Kubernetes DNS 在群集上调度 DNS Pod 和服务,并配置 kubelet 以告知各个容器使用 DNS 服务的 IP 来解析 DNS 名称。 DNS服务不是一个独立的系统服务,而是作为一种 addon 插件而存在,也就是说不是 Kubernetes 集群必须安装的,当然我们强烈推荐安装,可以将这个插件看成是一种运行在 Kubernetes 集群上的一直比较特殊的应用,现在比较推荐的两个插件:kube-dns 和 CoreDNS。我们在前面使用 kubeadm 搭建集群的时候直接安装的 kube-dns 插件,如果不记得了可以回头去看一看。当然如果我们想使用 CoreDNS 的话也很方便,只需要执行下面的命令即可: $ kubeadm init --feature-gates=CoreDNS=true 通过coredns能解决我们不需要去记vip的问题.
查看coredns详情:
[root@k8s-master01 ~]# kubectl describe pod coredns-7ff77c879f-b72lh -n kube-system
Name: coredns-7ff77c879f-b72lh
Namespace: kube-system
Priority: 2000000000
Priority Class Name: system-cluster-critical
Node: k8s-master01/192.168.10.71
Start Time: Mon, 14 Dec 2020 20:59:05 +0800
Labels: k8s-app=kube-dns
pod-template-hash=7ff77c879f
Annotations: <none>
Status: Running
IP: 10.244.0.5
IPs:
IP: 10.244.0.5
Controlled By: ReplicaSet/coredns-7ff77c879f
Containers:
coredns:
Container ID: docker://36e58879a140c99b142b523b9558676c20aaa27c0c4a335de45e86af92a5021f
Image: registry.aliyuncs.com/google_containers/coredns:1.6.7
Image ID: docker-pullable://registry.aliyuncs.com/google_containers/coredns@sha256:695a5e109604331f843d2c435f488bf3f239a88aec49112d452c1cbf87e88405
Ports: 53/UDP, 53/TCP, 9153/TCP
Host Ports: 0/UDP, 0/TCP, 0/TCP
Args:
-conf
/etc/coredns/Corefile
State: Running
Started: Thu, 21 Jan 2021 11:24:45 +0800
Last State: Terminated
Reason: Error
Exit Code: 255
Started: Mon, 14 Dec 2020 20:59:06 +0800
Finished: Thu, 21 Jan 2021 11:24:14 +0800
Ready: True
Restart Count: 1
Limits:
memory: 170Mi
Requests:
cpu: 100m
memory: 70Mi
Liveness: http-get http://:8080/health delay=60s timeout=5s period=10s #success=1 #failure=5
Readiness: http-get http://:8181/ready delay=0s timeout=1s period=10s #success=1 #failure=3
Environment: <none>
Mounts:
/etc/coredns from config-volume (ro)
/var/run/secrets/kubernetes.io/serviceaccount from coredns-token-r989d (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
config-volume:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: coredns
Optional: false
coredns-token-r989d:
Type: Secret (a volume populated by a Secret)
SecretName: coredns-token-r989d
Optional: false
QoS Class: Burstable
Node-Selectors: kubernetes.io/os=linux
Tolerations: CriticalAddonsOnly
node-role.kubernetes.io/master:NoSchedule
node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events: <none>
测试是否可以通过coredns访问具体的pod的服务:
我们启动一个busybox来测试下dns解析
[root@k8s-master01 ~]# kubectl run --rm -i --tty test-dns --image=busybox:1.28.4 /bin/sh
查看dns信息
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local localdomain
options ndots:5
解析我们创建的服务
/ # nslookup web-2
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-2
Address 1: 10.107.45.167 web-2.default.svc.cluster.local
/ # wget -q -O- web-2.default.svc.cluster.local
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
参考: https://kubernetes.io/zh/docs/concepts/services-networking/
- 我的微信
- 这是我的微信扫一扫
- 我的微信公众号
- 我的微信公众号扫一扫