kubernetes--服务发现与路由

前言

Kubernetes 中为了实现服务实例间的负载均衡和不同服务间的服务发现,创造了 Serivce 对象,同时又为从集群外部访问集群创建了 Ingress 对象。


一、service

1.1、什么是service

Kubernetes Service 定义了这样一种抽象:Pod 的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector(查看下面了解,为什么可能需要没有 selector 的 Service)实现的。

举个例子,假设有一个用于图片处理的运行了三个副本的 backend。这些副本是可互换的 —— frontend 不需要关心它们调用了哪个 backend 副本。然而组成这一组 backend 程序的 Pod 实际上可能会发生变化,frontend 客户端不应该也没必要知道,而且也不需要跟踪这组 backend 的状态。Service 定义的抽象能够解耦这种关联。
在这里插入图片描述

  • 对 Kubernetes 集群中的应用,Kubernetes 提供了简单的 Endpoints API,只要 Service 中的一组 Pod 发生变更,应用程序就会被更新。对非 Kubernetes 集群中的应用,Kubernetes 提供了基于 VIP 的网桥的方式访问 Service,再由 Service 重定向到 backend Pod。

在这里插入图片描述

上图解析

首先监听服务和端点是由apiserver来完成的,通过kuber-proxy去监控。kube-proxy去监控到对应的匹配pod信息,将规则写到iptables规则中,客户访问的时候其实就是先经过iptables, 而iptables是由kuber-proxy来定制的规则

1.2 虚拟 IP 和服务代理

  • Kubernetes 集群中的每个节点都运行了一个 kube-proxy,负责为 Service(ExternalName 类型的除外)提供虚拟 IP 访问。

为何不使用 round-robin DNS?

一直以来,DNS 软件都不确保严格检查 TTL(Time to live),并且在缓存的 dns 解析结果应该过期以后,仍然继续使用缓存中的记录
某些应用程序只做一次 DNS 解析,并一直使用缓存下来的解析结果
即使应用程序对 DNS 解析做了合适的处理,为 DNS 记录设置过短(或者 0)的 TTL 值,将给 DNS 服务器带来过大的负载
最主要的是dns缓存模式,要去清理,不然就不是负载均衡了

2、Service

2.1、Service 的类型

2.1.1、Service 在 K8s 中有以下四种类型

  • ClusterIp:默认类型,自动分配一个仅 Cluster 内部可以访问的虚拟 IP
  • NodePort:在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过 : NodePort 来访问该服务
  • LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部负载均衡器,并将请求转发到: NodePort
  • ExternalName:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有 kubernetes 1.7 或更高版本的 kube-dns 才支持

2.2、Service的资源清单文件:

kind: Service  # 资源类型
apiVersion: v1  # 资源版本
metadata: # 元数据
  name: service # 资源名称
  namespace: dev # 命名空间
spec: # 描述
  selector: # 标签选择器,用于确定当前service代理哪些pod
    app: nginx
  type: # Service类型,指定service的访问方式
  clusterIP:  # 虚拟服务的ip地址
  sessionAffinity: # session亲和性,支持ClientIP、None两个选项,可以把同一个源的请求,发到一个具体的Pod上
  ports: # 端口信息
    - protocol: TCP 
      port: 3017  # service端口
      targetPort: 5003 # pod端口
      nodePort: 31122 # 主机端口

2.2.1、type:

type也是可以更改其类型的参数

ClusterIP:默认值,它是Kubernetes系统自动分配的虚拟IP,只能在集群内部访问
NodePort:将Service通过指定的Node上的端口暴露给外部,通过此方法,就可以在集群外部访问服务
LoadBalancer:使用外接负载均衡器完成到服务的负载分发,注意此模式需要外部云环境支持
ExternalName: 把集群外部的服务引入集群内部,直接使用

2.2.2、service和pod关联:

service和pod是通过标签选择器进行关联的

pod中设置

template:
    metadata:
      labels:  # 标签
        app: 标签名

service中设置

spec:
  type: service类型
  selector: #匹配选择器
    app: 标签名   #对应的pod的deployment中的app标签名
  • 两者是通过标签名进行关联的

2.3、ClusterIP

  • ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 ServiceType

2.3.1、ClusterIP 关联:

service和pod关联

  • nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx  
  replicas: 2
  template:
    metadata:
      labels:  # 标签
        app: nginx
        release: stabel
    spec:
      containers:
      - name: nginx
        image: 192.168.25.69/overseas/nginx:v1   # 对应的镜像仓库地址 如果是想设置公版本的可以设置 wangyanglinux/myapp:v2
        ports:
        - containerPort: 80

nginx-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  type: ClusterIP
  selector: #匹配选择器
    app: myapp   #对应的pod的deployment中的app标签名
    release: stabel
  ports:
  - name: http
    port: 80
    targetPort: 80


注意点:

  • pod和service是通过标签进行关联的当标签不对或者不完全匹配时,service将会无法访问,因为相当于service后面挂了一个空的pod找不到访问目标

2.3.2、示例

nginx-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-one
spec:
  selector:
    matchLabels:
      app: nginx    # 此为启动的容器名称必须和标签名称一致,也必须和deployment的app一致
  replicas: 2
  template:
    metadata:
      labels:  # 标签 
        app: nginx   # 此为标签名必须和启动的容器名称一致
        release: stabel
    spec:
      containers:
      - name: nginx
        image: 192.168.25.69/overseas/nginx:v1   # 对应的镜像仓库地址 如果是想设置公版本的可以设置 wangyanglinux/myapp:v2
        ports:
        - containerPort: 80
  • 生成deployment: kubectl apply -f nginx-deployment.yaml
    在这里插入图片描述

  • 可以看到deployment已经创建

nginx-service-ont.yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx-one
  namespace: default
spec:
  type: ClusterIP
  selector:
    app: nginx  # 必须和pod的标签名一致
    # 此处没有填写对应的release
  ports:
  - name: http
    port: 80
    targetPort: 80
~                   


  • 创建对应的service: kubectl apply -f nginx-service-error.yaml

在这里插入图片描述

  • 这个时候访问service的端口即可请求分发的到对应的pod

curl -v 10.100.111.168
在这里插入图片描述

2.4、NodePort :

如果你选择了“NodePort”,那么 Kubernetes master 会分配一个区域范围内,(默认是30000-32767),并且,每一个node,都会代理(proxy)这个端口到你的服务中,我们可以在spec.ports[*].nodePort 找到具体的值

  • 如果需要指定的端口号,可以配置 nodePort 的值,系统将分配这个端口,否则调用 API 将会失败(比如,需要关心端口冲突的可能性)
  • 这可以让开发人员自由地安装他们自己的负载均衡器,并配置 Kubernetes 不能完全支持的环境参数,或者直接暴露一个或多个 Node 的 IP 地址。
  • 需要注意的是,Service 将能够通过 <NodeIP>: spec.ports[*].nodePort 和 spec.clusterIp:spec.ports[*].port 而对外可见。

2.4.1、nodeport简介:

  • nodeport范围:(默认是30000-32767)
  • nodeport 相当于在你的搭建的k8s容器集群的外部围墙上,凿开一个口子将内部服务暴漏给外部访问

2.4.1、nodeport–service不指定nodeport端口关联

当service的type设置为NodePort不指定nodeport端口时,将会自动生成一个30000-32767中的随机端口
** myapp-deploy.yaml
*

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
      release: stabel
  template:
    metadata:
      labels:
        app: myapp
        release: stabel
        env: test
    spec:
       containers:
       - name: myapp
         image: wangyanglinux/myapp:v2
         imagePullPolicy: IfNotPresent
         ports:
         - name: http
           containerPort: 80

myapp-nodeport-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  type: NodePort  # nodeport形式
  selector:
    app: myapp   # 通过标签和deployment部署的pod关联
    release: stabel
  ports:
  - name: http
    port: 80
    targetPort: 80
   # nodePort: 端口号  这里未指定端口号的话则会自动生成一个随机的端口 

  • 这个时候查看我们启动的svc

kubectl get svc -n default

在这里插入图片描述

  • 上图可以看到我们启动一个svc,内部端口是80,外部的端口是31362

  • 可以使用我们的任意节点访问这个nodeport,就会转发到对应的pod服务

  • 任意节点的ip_nodeport
    在这里插入图片描述

2.4.2、 2.4.1、nodeport–service指定nodeport端口关联

  • 我们也可以对service的type设置为nodeport时,指定要设置的端口(推荐),方便管理

** myapp-deploy.yaml**

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
      release: stabel
  template:
    metadata:
      labels:
        app: myapp
        release: stabel
        env: test
    spec:
       containers:
       - name: myapp
         image: wangyanglinux/myapp:v2
         imagePullPolicy: IfNotPresent
         ports:
         - name: http
           containerPort: 80

指定NodePort端口 myapp-nodeport-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  type: NodePort
  selector:
    app: myapp
    release: stabel
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30316  #指定暴漏的端口为30316

  • service的name必须和标签名一致

2.5、LoadBalancer 类型

使用支持外部负载均衡器的云提供商的服务,设置 type 的值为 “LoadBalancer”,将为 Service 提供负载均衡器。负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过 Service 的 status.loadBalancer 字段被发布出去

kind: Service
apiVersion: v1
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
      nodePort: 30061
  clusterIP: 10.0.171.239
  loadBalancerIP: 78.11.24.19
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
      - ip: 146.148.47.155

2.6、多端口 Service

  • 多 Service 需要暴露多个端口。对于这种情况,Kubernetes 支持在 Service 对象中定义多个端口。 当使用多个端口时,必须给出所有的端口的名称,这样 Endpoint 就不会产生歧义,例如:
kind: Service
apiVersion: v1
metadata:
  name: my-service
spec:
    selector:
      app: MyApp
    ports:
      - name: http
        protocol: TCP
        port: 80
        targetPort: 9376
      - name: https
        protocol: TCP
        port: 443
        targetPort: 9377


总结

例如:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lovely_red_scarf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值