Bootstrap

Kubernetes【四】:客户端发现pod并与之通信(服务发现)

1.简介

  pod的生命是短暂的,所以他的ip是琢磨不定的,而这时候就需要有一个对外的服务,他有固定的ip和端口,客户端可以通过该服务来访问那些处在该服务作用域的pod
服务的作用域,操作哪些pod,也是通过标签选择器来决定的。

apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  sessionAffinity: ClientIP #将来自同一ip的请求转发至同一个pod,类似hash负载均衡,默认none
  ports:   #可暴露多个接口
    - name: http
      port: 80 #服务监听的端口
      targetPort: 8080 #路由到服务作用域内的pod的8083端口上,如果容器给端口起别称为http,也可用http代替
    - name: https
      port: 443
      targetPort: 8043
  selector:
    app: kubia

2.服务发现

2.1 通过环境变量发现服务

  一个pod在运行的时候,kubernetes会初始化一系列的环境变量指向现在存在的服务,然后pod通过环境变量获取服务的ip地址和端口号,如果服务比pod晚创建,则需要将现有的pod全部删除,让资源自动去创建新的pod,初始化新的服务列表。
在这里插入图片描述

2.2 通过DNS+FQDN(全限定域名)来发现服务

  kube-system命名空间下有个运行着dns服务的pod,集群中其他的pod都被配置为使用这个pod作为dns服务器(通过修改容器的/etc/resolv.conf文件实现)。该dns服务器知道所有服务,其他的pod可对该服务器进行dns查询从而得到响应。

是否使用内部的DNS服务器是根据pod模板中的dnsPolicy属性决定的

在这里插入图片描述

域名组成:[服务名].[服务所在命名空间].[所有集群本地服务名称中使用的可配置集群域后缀]

  • 通过域名访问只可访问标准的端口号(如http 80或Postgres的5432),如果不是这样的标准端口,则还是需要从环境变量中去获取端口号
  • 如果两个pod处在同一个命名空间,则互相访问的域名则只需要服务名即可
  • 集群的ip是虚拟ip,无法ping通,需要与端口结合才有意义

3.连接集群外服务

3.1 通过Endpoint访问外部服务

  服务并不是和pod直接相连的,而是通过介于两者之间的资源—endpoint
  创建服务的时候,会根据服务的标签选择器创建Endpoint资源(这是个独立资源,并不是服务的属性),而记载的内容就是服务作用域下的pod ip以及端口,表示访问服务时最终会将请求去重定向到这些列表
在这里插入图片描述

  1. 创建不带标签选择器的服务
apiVersion: v1
kind: Service
metadata:
  name: external-service
spec:
  ports:
    - port: 80
  1. 创建Endpoint
  • endpint需要与服务同名
  • 之后创建的pod的环境变量就会有该服务的ip和port,通过该服务重定向到目标服务。
apiVersion: v1
kind: Endpoints
metadata:
  name: external-service
subsets:
  - addresses:
      - ip: 11.11.11.11 #外部的目标服务ip
      - ip: 22.22.22.22
    ports:
      - port: 80 

3.2 通过FQDN(完全限定域名)访问

  1. 新建externalName服务,通过访问该服务来重定向到目标服务
  2. 之后pod可通过服务的 FQDN 访问外部服务 ,对于pod来说外部服务的域名是隐藏的
apiVersion: v1
kind: Service
metadata:
  name: external-service
spec:
  type: ExternalName #创建类型为ExternalName的服务
  externalName: api.somecompany.com #目标服务域名,更改目标服务域名只需要更改这个属性
  ports:
    - port: 80

4.将服务暴露给外部客户端

4.1 使用NodePort类型的服务(比较适用于demo应用)

在这里插入图片描述

新建NodePort监听节点接口,此时可以通过集群内所有节点的任意一个IP+端口,将请求转发重定向到指定到标签选择器的基础服务
可通过集群虚拟ip:80或节点ip:30123访问到具体服务

apiVersion: v1
kind: Service
metadata:
  name: kubia-nodeport
spec:
  type: NodePort #创建NodePort类型服务
  ports:
    - port: 80   #服务集群内的端口,集群内pod访问的端口
      targetPort: 8080 #背后pod的目标端口,服务进行重定向的端口
      nodePort: 30123 #集群节点的端口,节点外客户端访问的端口
  selector:
    app: kubia

4.2 通过负载均衡器(Loadbalance)

在这里插入图片描述

效果像NodePort,但是不同的是,客户端访问的是负载均衡器,然后再将流量转发给服务节点,服务节点ip列表对客户端来说是隐藏的

apiVersion: v1
kind: Service
metadata:
  name: kubia-loadbalancer
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 8080
  selector:
    app: kubia

会话亲和性:表示的是多次请求打到了同一个pod,原因是因为keep-alive的建立了长连接,从而表现出多次请求达到一个pod的情况

减少网络跳数:避免请求—>负载均衡器—>服务—>非本地pod,正确的走向是服务->本地pod,减少连接跳转次数
使用该属性需要注意的问题

  • 如果连接到服务本地没有pod,不会将连接转发给其他由pod的服务节点,而是会将连接挂起,不跳越是为了保留客户端ip
  • 确保负载均衡器将连接转发给至少具有一个pod的节点
  • 弊端:服务节点的pod数量不同会导致pod接收的流量相差较大
  • 保留查看客户端ip
    .spec.externalTrafficPolicy: Local .spec.healthCheckNodePort: 端口号(可以不指定)
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local //表示流量给集群范围内的端点(Cluster)还是节点本地

4.3 使用Ingress类型的服务

在这里插入图片描述

4.3.1 与Loadbalancer的区别

  每个LoadBalancer都有自己的负载均衡器以及独有的公网ip,但是Ingress只需要一个公网ip就能为许多服务提供访问,根据域名和请求路径来决定请求流量的转发,类似nginx反向代理

4.3.2 工作原理

Ingress并不是通过服务来间接访问pod的,而是获取服务的endpoints列表,然后选择一个pod进行访问。(大多数控制器都是这样工作的)
在这里插入图片描述

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx-example

  rules:
    - host: xxx.xxx.com  #将域名与 服务进行映射
      http:
        paths:
          - path: /testpath  #转发到域名的某个路径
            pathType: Prefix
            backend:
              service:
                name: test   #服务名
                port:
                  number: 80  #服务端口

4.3.3 安装

需要自己做调整

  docker pull registry.cn-hangzhou.aliyuncs.com/yutao517/ingress_nginx_controller:v1.1.0
  docker tag registry.cn-hangzhou.aliyuncs.com/yutao517/ingress_nginx_controller:v1.1.0 k8s.gcr.io/ingress-nginx/controller:v1.1.1 
  docker pull registry.cn-hangzhou.aliyuncs.com/yutao517/kube_webhook_certgen:v1.1.1 
  docker tag registry.cn-hangzhou.aliyuncs.com/yutao517/ingress_nginx_controller:v1.1.0 k8s.gcr.io/ingress-nginx/controller:v1.1.1
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx-example

  rules:
    - host: xxx.xxx.com  #将域名与 服务进行映射
      http:
        paths:
          - path: /testpath  #转发到域名的某个路径
            pathType: Prefix
            backend:
              service:
                name: test   #服务名
                port:
                  number: 80  #服务端口

5.就绪探针

5.1 作用

避免pod初始化未完成就开始接受请求,导致响应过慢或超时。如果pod初始化过慢,只要一创建pod,几乎会立即成为服务端点
不要将停止pod 的逻辑纳入就绪探针,保证程序停止的时候,就绪探针就应该返回失败结果,确保从所有服务中移除该容器

5.2 存活vs就绪

  存活探针如果失败,会删除并重建容器。而就绪探针则是将pod从服务的Endpoint中移除,保证流量不流向未准备好的pod。

5.3 就绪探针类型

  • Exec探针:执行进程的地方。容器的状态由进程退出的状态码决定。

  • HTTP GET探针:通过响应码判断容器是否准备好。

  • TCP socket探针:打开一个TCP连接到容器的指定端口,如果建立连接,则代表容器准备就绪。
spec:
  nodeSelector: #节点选择器,将pod部署到包含以下标签的工作节点
    gpu: "true"
  containers:
    - image: linzd/test:kubia-js #镜像
      name: kubia #容器名
      readinessProbe: #存活探针
        httpGet:     #http探针
          path: /
          port: 8080
;