第八讲《k8s服务:Service》

一、概述

1.Service介绍

Service主要用于提供网络服务,通过Service的定义,能够为客户端应用提供稳定的访问地址(域名或IP地址)和负载均衡功能,以及屏蔽后端Endpoint的变化,是kubernetes实现微服务的核心资源。

Service通过命名空间、标签选择器、后端pod端口绑定指定pod。pod中的容器经常在不停地销毁和重建,因此pod的IP会不停的改变,这时候客户端就没法访问到pod了,现在有了service作为客户端和pod的中间层,它在这里抽象出一个虚拟IP,然后集群内部都可以通过这个虚拟IP访问到具体的pod。

2.Service类型

k8s提供了多种机制将Service暴露出去,供集群外部的客户端访问。这可以通过service资源对象的类型字段“type”进行设置。

目前service的类型如下:

  • ClusterIP:kubernetes默认会自动设置Service的VIP地址,仅可被集群内部的客户端应用访问。用户也可手动指定一个ClusterIP地址,不过需要确保该IP在kubernetes集群设置的ClusterIP地址范围内(通过kube-apiserver服务的启动参数--service-cluster-ip-range设置),并且没有被其他service使用。
  • NodePort:将Service的端口号映射到每个Node的一个端口号上,这样集群中的任意Node都可以作为Service的访问入口地址,即NodeIP:NodePort
  • LoadBalancer:将service映射到一个已存在的负载均衡器的IP地址上,通常在公有云环境中使用。
  • ExternalName:将service映射为一个外部域名地址,通过externalName字段进行设置。

3.kube-proxy介绍

3.1概念

在k8s中,service的集群IP能够实现数据报文请求的转发,需要在node节点上部署的一个组件kube-proxy,具体来说kube-proxy实现的主要有几点:

  • 实时监控API,获取service和pod的信息,来保持pod和虚拟IP的映射关系
  • 维护本地Netfilter、iptables、IPVS等内核组件,实现数据报文的转发规则
  • 实现每个node节点上虚拟IP的发布和路由维护
  • 构建路由信息,通过转发规则转发报文到虚拟IP对应的pod

3.2kube-proxy代理模式

userspace:用户空间模式,由kube-proxy完成代理的实现,效率最低,不在推荐使用。

iptables:kube-proxy通过设置Linux Kernel的iptables规则,实现从Service到后端Endpoint列表的负载分发规则,效率很高。iptables是kube-proxy默认的代理模式。

ipvs:在kubernetes1.11版本中达到Stable阶段,kube-proxy通过设置Linux Kernel的netlink接口设置IPVS规则,转发效率和支持的吞吐率都是最高的。ipvs模式要求Linux Kernel启用IPVS模块,如果未启用ipvs内核模块,kube-proxy会自动切换成iptables。同时,ipvs模式支持更多的负载均衡策略,如下:

  • rr:round-robin,轮询
  • lc:least connection,最小连接数
  • dh:destination hashing,目的地址哈希
  • sh:source hashing,源地址哈希。
  • sed:shortest expected delay,最短期望延时
  • nq:never queue,永不排队

kernelspace:windows server上的代理模式

ipvs sample:

[root@k8s-master ~]# lsmod | grep vs
ip_vs_sh               12688  0
ip_vs_wrr              12697  0
ip_vs_rr               12600  45
ip_vs                 145458  51 ip_vs_rr,ip_vs_sh,ip_vs_wrr
nf_conntrack          143360  9 ip_vs,nf_nat,nf_nat_ipv4,nf_nat_ipv6,xt_conntrack,nf_nat_masquerade_ipv4,nf_conntrack_netlink,nf_conntrack_ipv4,nf_conntrack_ipv6
libcrc32c              12644  4 xfs,ip_vs,nf_nat,nf_conntrack
[root@k8s-master ~]# kubectl edit cm kube-proxy -n kube-system
。。。
    ipvs:
      excludeCIDRs: null
      minSyncPeriod: 0s
      scheduler: ""
      strictARP: false
      syncPeriod: 0s
      tcpFinTimeout: 0s
      tcpTimeout: 0s
      udpTimeout: 0s
    kind: KubeProxyConfiguration
    metricsBindAddress: ""
    mode: "ipvs"			// kube-proxy默认是iptables模式,这里为空,修改为ipvs
    nodePortAddresses: null
    oomScoreAdj: null
    portRange: ""
    showHiddenMetricsForVersion: ""
    udpIdleTimeout: 0s
。。。
[root@k8s-master ~]# kubectl delete pod -l k8s-app=kube-proxy -n kube-system
[root@k8s-master ~]# ipvsadm -Ln 		// 如果服务器没有ipvsadm命令,那么需要安装
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.17.0.1:30718 rr
  -> 10.244.58.200:80             Masq    1      0          0
  -> 10.244.58.201:80             Masq    1      0          0
TCP  172.17.0.1:31427 rr
  -> 10.244.58.200:443            Masq    1      0          0
  -> 10.244.58.201:443            Masq    1      0          0
TCP  10.5.0.211:30718 rr
  -> 10.244.58.200:80             Masq    1      0          0
  -> 10.244.58.201:80             Masq    1      0          0

二、Service yaml 定义

apiVersion: v1						// required
kind: Service							// required
metadata:									// required
  name: string						// required
  namespace: string			// required
  labels:
    - name: string
  annotations:						// 注解
    - name: string
spec:											// required
  selector: []						// required	标签选择器
  type: string						// required 类型
  clusterIP: string				// clusterIP地址,如果不指定会自动生成
  sessionAffinity: string	// 会话保持,可选值:ClientIP,默认为None
  ports:									// 端口列表
    - name: string				// 端口名称
      protocol: TCP				// 协议,支持TCP和UDP,默认值为TCP
      port: int						// service的端口
      targetPort: int			// Pod的端口
      nodePort: int				// 当type为NodePort时,映射到宿主机的端口
  status:									// 当type为loadbalance时,外部负载均衡器的地址,用于公有云
    loadBalancer:					
      ingress:
        ip: string				// 外部负载均衡器IP
        hostname: string	// 外部负载均衡器主机名

三、演示(base on ipvs mode)

1.无service演示

[root@k8s-master test]# cat deploy-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
  namespace: test
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx-app
    spec:
      containers:
      - name: nginx
        image: core.harbor.domain/test/nginx-1.16.1:v4
        ports:
        - containerPort: 80
      imagePullSecrets:
      - name: harbor-secret
[root@k8s-master test]# kubectl apply -f deploy-nginx.yaml
deployment.apps/nginx-app created
[root@k8s-master nginx-image]# kubectl get pod -n test -owide
NAME                         READY   STATUS    RESTARTS   AGE     IP              NODE         NOMINATED NODE   READINESS GATES      <none>
nginx-app-64c47d8f97-nzw9w   1/1     Running   0          5m48s   10.244.58.223   k8s-node02   <none>           <none>
nginx-app-64c47d8f97-qs4gd   1/1     Running   0          5m46s   10.244.85.205   k8s-node01   <none>           <none>
[root@k8s-master nginx-image]# kubectl delete pod nginx-app-64c47d8f97-qs4gd -n test
pod "nginx-app-64c47d8f97-qs4gd" deleted
[root@k8s-master nginx-image]# kubectl get pod -n test -owide		// Pod IP变了
NAME                         READY   STATUS    RESTARTS   AGE     IP              NODE         NOMINATED NODE   READINESS GATES
nginx-app-64c47d8f97-992xm   1/1     Running   0          44s     10.244.58.224   k8s-node02   <none>           <none>
nginx-app-64c47d8f97-nzw9w   1/1     Running   0          9m51s   10.244.58.223   k8s-node02   <none>           <none>
[root@k8s-master nginx-image]# curl 10.244.58.224
10.244.58.224
[root@k8s-master nginx-image]# curl 10.244.58.223
10.244.58.223

需要访问每个pod,且pod重启之后,ip就会变化,客户端就会丢失ip,无法再获取请求内容

2.ClusterIP类型

创建svc

[root@k8s-master test]# cat deploy-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
  namespace: test
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-app
  template:
    metadata:
      labels:
        app: nginx-app
    spec:
      containers:
      - name: nginx
        image: core.harbor.domain/test/nginx-1.16.1:v4
        ports:
        - containerPort: 80
      imagePullSecrets:
      - name: harbor-secret
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: test
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: nginx-app
  type: ClusterIP
[root@k8s-master test]# kubectl apply -f deploy-nginx.yaml
deployment.apps/nginx-app created
service/nginx-svc created

查看Pod和svc

[root@k8s-master test]# kubectl get pod -n test
NAME                         READY   STATUS    RESTARTS   AGE
nginx-app-68c44578b7-2w8j7   1/1     Running   0          33s
nginx-app-68c44578b7-4cxwr   1/1     Running   0          33s
nginx-app-68c44578b7-5zv57   1/1     Running   0          33s
[root@k8s-master test]# kubectl get svc -n test -o wide
NAME        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE   SELECTOR
nginx-svc   ClusterIP   10.102.127.32    <none>        80/TCP     20d   app=nginx-app

查看ipvs规则

[root@k8s-master nginx-image]# ipvsadm -Ln | grep -A 2 10.102.127.32
TCP  10.102.127.32:80 rr
  -> 10.244.58.223:80             Masq    1      0          0
  -> 10.244.58.224:80             Masq    1      0          0

ipvsadm 是 ipvs规则管理命令

10.102.127.32:80 rr SvcIP:Port rr 负载均衡策略:轮询

10.244.58.223:80 PodIP:Port

10.244.58.224:80 PodIP:Port

访问测试

[root@k8s-master nginx-image]# curl 10.102.127.32
10.244.58.224
[root@k8s-master nginx-image]# curl 10.102.127.32
10.244.58.223
[root@k8s-master nginx-image]# curl 10.102.127.32
10.244.58.224
[root@k8s-master nginx-image]# curl 10.102.127.32
10.244.58.223
[root@k8s-master nginx-image]# curl 10.102.127.32
10.244.58.224
[root@k8s-master nginx-image]# curl 10.102.127.32
10.244.58.223
[root@k8s-master nginx-image]# curl 10.102.127.32
10.244.58.224
[root@k8s-master nginx-image]# curl 10.102.127.32
10.244.58.223
// 请求由svc均匀分发给后端pod

无法通过nodeIP:port访问

[root@k8s-master nginx-image]# curl k8s-node02
curl: (7) Failed connect to k8s-node02:80; Connection refused

3.NodePort类型

修改svc类型为nodeport

[root@k8s-master test]# vim deploy-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
  namespace: test
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-app
  template:
    metadata:
      labels:
        app: nginx-app
    spec:
      containers:
      - name: nginx
        image: core.harbor.domain/test/nginx-1.16.1:v2
        ports:
        - containerPort: 80
      imagePullSecrets:
      - name: harbor-secret
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: test
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: nginx-app
  type: NodePort			// 修改为nodeport
[root@k8s-master test]# kubectl apply -f deploy-nginx.yaml
deployment.apps/nginx-app unchanged
service/nginx-svc configured

查看svc信息

[root@k8s-master test]# kubectl get svc -n test -o wide // 将80端口映射到主机32752端口
NAME        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE   SELECTOR
nginx-svc   NodePort    10.102.127.32    <none>        80:32752/TCP   20d   app=nginx-app

使用nodeIP:Port访问

[root@k8s-master test]# curl k8s-node02:32752		// 访问node02
10.244.85.214
[root@k8s-master test]# curl k8s-node02:32752
10.244.58.229
[root@k8s-master test]# curl k8s-node02:32752
10.244.85.214
[root@k8s-master test]# curl k8s-node01:32752		// 访问node01
10.244.58.229
[root@k8s-master test]# curl k8s-node01:32752
10.244.85.214
[root@k8s-master test]# curl k8s-node01:32752
10.244.58.229

Note:nodeport类型会在每一个node上面都做映射,所以生产环境必须规划nodeport的使用

通过公网访问(需要做策略)

[root@k8s-master test]# curl http://106.14.27.13:32752/
10.244.58.229
[root@k8s-master test]# curl http://106.14.27.13:32752/
10.244.85.214
[root@k8s-master test]# curl http://106.14.27.13:32752/
10.244.58.229
[root@k8s-master test]# curl http://106.14.27.13:32752/
10.244.85.214
[root@k8s-master test]# curl http://106.14.27.13:32752/

4.Loadbalance类型

没有公有云环境,放一张图解释一下loadbalance

nodeport和loadbalance是用一种方式,但loadbalance多了LB这一层,在服务创建成功之后,云服务商会在Service的定义中补充LoadBalance的IP地址:

status:
  loadBanlancer:
    ingress:
    - ip: 192.0.2.127

5.externalName

创建externalName svc

[root@k8s-master test]# vim svc-external.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-external
  namespace: test
spec:
  type: ExternalName
  externalName: nginx-svc.test.svc.cluster.local
[root@k8s-master test]# kubectl apply -f svc-external.yaml
service/nginx-external created

查看svc

[root@k8s-master ~]# kubectl get svc -n test
NAME             TYPE           CLUSTER-IP       EXTERNAL-IP                        PORT(S)        AGE
nginx-external   ExternalName   <none>           nginx-svc.test.svc.cluster.local   <none>         63m
nginx-svc        NodePort       10.102.127.32    <none>                             80:32752/TCP   20d

启动测试pod

[root@k8s-master ~]# kubectl run -i --tty --image core.harbor.domain/library/busybox dns-test --restart=Never --rm -n test
If you don't see a command prompt, try pressing enter.
/ #
/ #
/ # nslookup nginx-svc.test.svc.cluster.local
Server:         10.96.0.10
Address:        10.96.0.10:53

Name:   nginx-svc.test.svc.cluster.local
Address: 10.102.127.32


/ # nslookup nginx-external.test.svc.cluster.local
Server:         10.96.0.10
Address:        10.96.0.10:53


nginx-external.test.svc.cluster.local   canonical name = nginx-svc.test.svc.cluster.local
Name:   nginx-svc.test.svc.cluster.local
Address: 10.102.127.32

/ #

scenario sample

应用A和应用B通过nginx-external service 访问 nginx-svc service,当nginx-svc修改为nginx-svc1,那么只需要修改nginx-external service的externalName字段,减少了因为外部域名变动而引起的变更操作

四、高级用法

1.将外部服务定义为service

普通的Service通过Label Selector对后端Endpoint列表进行一次抽象,如果后端Endpoint不是Pod副本提供的,则Service还可以抽象定义任意其它服务,将一个Kubernetes集群外部的已知服务定义为Kubernetes内的一个Service,提供集群内的其他应用访问,常见的应用常见包括:

  • 已部署的集群外服务,例如数据库服务、缓存服务等
  • 其他Kubernetes集群的某个服务
  • 迁移过程中对某个服务进行Kubernetes内的服务名访问机制的验证

对与这种场景,用户创建Service资源对象时不设置Label Selector(后端Pod也不存在),同时再定义一个Service关联的Endpoint资源对象,在Endpoint中设置外部服务的IP地址和端口号,例如:

############
apiVersion: v1
kind: Service
metadata:
  name: myservice
sepc:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
 
################
apiVersion: v1
kind: Endpoints
metadata:
  name: myservice
subsets:
- addresses:
  - IP: 1.2.3.4
  ports:
  - port: 80

2.Headless service

在某些应用场景中,客户端应用不需要通过k8s内置service实现的负载均衡功能,或者需要自行完成对服务后端个实例的服务发现机制,或者需要自行实现负载均衡功能,此时可以通过创建一种特殊的名为“headless”的服务来实现。

Headless Service的概念是这种服务没有入口访问地址(无ClusterIP地址),kube-proxy不会为其创建负载转发规则,而服务名(DNS域名)的解析机制取决于该Headless Service是否设置了label selector。

[root@k8s-master test]# vim headless-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: headless-svc
  namespace: test
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: nginx-app
  type: ClusterIP
  clusterIP: None			// 这里为None,表示不需要clusterIP
[root@k8s-master test]# kubectl apply -f headless-svc.yaml
service/headless-svc created
[root@k8s-master test]# kubectl get svc -n test
NAME             TYPE           CLUSTER-IP       EXTERNAL-IP                        PORT(S)        AGE
headless-svc     ClusterIP      None             <none>                             80/TCP         19s
nginx-external   ExternalName   <none>           nginx-svc.test.svc.cluster.local   <none>         123m
nginx-svc        NodePort       10.102.127.32    <none>                             80:32752/TCP   20d

查看详情

[root@k8s-master test]# kubectl describe svc headless-svc -n test
Name:              headless-svc
Namespace:         test
Labels:            <none>
Annotations:       <none>
Selector:          app=nginx-app
Type:              ClusterIP
IP Families:       <none>
IP:                None
IPs:               None
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.58.229:80,10.244.85.214:80		// 后端pod的IP和端口
Session Affinity:  None
Events:            <none>

nslookup测试

[root@k8s-master test]# kubectl run -i --tty --image core.harbor.domain/library/busybox dns-test --restart=Never --rm -n test
If you don't see a command prompt, try pressing enter.
/ #
/ #
/ # nslookup headless-svc.test.svc.cluster.local
Server:         10.96.0.10
Address:        10.96.0.10:53


Name:   headless-svc.test.svc.cluster.local
Address: 10.244.58.229
Name:   headless-svc.test.svc.cluster.local
Address: 10.244.85.214

当客户端通过DNS服务名“headless-svc”和服务端口号访问该Headless服务时,将得到Service后端Endpoint列表“10.244.58.229,10.244.85.214”,然后由客户端程序自行决定如何操作,例如通过轮询机制访问各个Endpoint

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值