k8s基础入门之service

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中
k8s基础入门之service
创建一个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)

k8s基础入门之service

实例:创建一个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
如上就更新端口成功了
k8s基础入门之service

4.3 LoadBalancer

LoadBalancer相当于对nodeport的负载均衡 这种类型建构在NodePort类型之上,创建一个具有公网IP地址的云供应商提供的负载均衡器,由它接入外部客户端的请求并调度至集群节点相应的NodePort之上。因此LoadBalancer一样具有NodePort和ClusterIP。 简而言之,一个LoadBalancer类型的Service会指向关联至Kubernetes集群外部的、切实存在的某个负载均衡设备,该设备通过工作节点之上的NodePort向集群内部发送请求流量。 例如Amazon云计算环境中的ELB实例即为此类的负载均衡设备。此类型的优势在于,它能够把来自于集群外部客户端的请求调度至所有节点(或部分节点)的NodePort之上,而不是依赖于客户端自行决定连接至哪个节点,从而避免了因客户端指定的节点故障而导致的服务不可用。
k8s基础入门之service

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/

  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin
avatar

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: