Service

k8s 中的流量负载组件: Service (四层路由的负载)和Ingress(七层路由的负载)

Service 介绍

在K8s 中,pod 是应用程序的载体,我们可以通过pod 的ip 来访问应用程序,但是pod 的ip 地址不是固定的,这也就意味着不方便直接采用pod 的ip 对服务进行访问。

为了解决这个问题,K8s 中提供了Service 资源,Service 对提供同一个服务的多个pod 进行聚合,并且提供了一个统一的入口地址,通过访问Service 的入口地址就能访问后面的pod 服务。
在这里插入图片描述

Service 在很多情况下只是一个概念,真正起作用的是kube-proxy 服务进程,每个Node 节点上都运行着一个kube-proxy 服务进程。当创建Service 的时候会通过api-server 向etcd 写入创建的service 的信息,而kube-proxy 会基于监听的机制发现这种Service 的变动,然后它就会将最新的Service 信息转化成对应的访问规则

在这里插入图片描述

service 提供访问入库的ip地址, kube-proxy 会基于轮询 rr(轮询)的策略,将一个请求转发到其中的一个pod 上。实际工作是这个访问规则。

在这里插入图片描述

注意这套访问规则,会同时在集群内的所有节点上生成。任何节点都可以查看到相应的规则。

kube-proxy 支持的三种工作模式

1 userspace 模式

userspace 模式下,kube-proxy 会为每一个Service 创建一个监听的端口,发向Cluster Ip 的请求被iptables 规则重定向到kube-proxy 监听的端口上,kube-proxy 根据LB(负载均衡)算法选择一个提供服务的pod 并和其建立连接,以将请求转发到pod 上。

该模式下,kube-proxy 充当了一个四层负载均衡器的角色,由于kube-proxy 运行在userspace 中,在进行转发处理时会增加内核和用户空间的数据拷贝,虽然比较稳定但是效率比较低。

在这里插入图片描述

2 iptables 模式

iptables 模式下,kube-proxy 为Service 后端的每一个pod 创建对应的iptables 规则,直接将发向Cluster ip 的请求重定向到一个pod ip。

该模式下kube-proxy 不承担四层负载均衡器的角色,只负责创建iptables 规则,该模式相对于userspace模式效率更高,但不能提供灵活的LB(负载均衡) 策略,当后端Pod不可用时,也无法进行重试。

在这里插入图片描述

3 ipvs 模式

ipvs 模式与iptables 模式相似,kube-proxy 监控pod的变换并创建相应的ipvs 规则,ipvs 相对与iptables 的转发效率更高,除此之外,ipvs支持更多的LB 算法。

在这里插入图片描述

查看当前主机是否开启ipvs 命令

ipvsadm -Ln

若没有使用 apt get ipvsadm 进行安装

在这里插入图片描述

里面没有相应对应的规则,说明ipvs 并没有生效。

1开启ipvs命令

kubectl edit cm kube-proxy -n kube-system

/mode 搜索mode 关键字 并修改为ipvs

在这里插入图片描述

2 删除一些当前kube-proxy 的pod ,使其重新的去创建。

kubectl  delete pod -l k8s-app=kube-proxy -n kube-system

在这里插入图片描述

ipvsadm -Ln

命令进行查看。

在这里插入图片描述

使用TCP 模式发一个请求到172.17.0.9:30000 地址,就会基于rr(轮询) 模式转发到172.18.0.2:9090 地址

service 资源清单

Service 资源清单
在这里插入图片描述

K8s 中有四种类型的Service:

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

sessionAffinity: 通过配置Session 亲和性,来实现对指定ip 轮转到相同的pod 上。

Service 使用
实验准备

使用Service 之前,先利用Deployment 创建出3个pod,注意pod 使用app=nginx-pod 标签

创建deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pc-deployment
  namespace: dev
spec:
  strategy: # 策略
    type: RollingUpdate # 滚动重建更新策略
    rollingUpdate:
      maxUnavailable: 25%
      maxSurge: 25%
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80

使用命令

kubectl create ns dev

kubectl create -f deployment.yaml

在这里插入图片描述

kubectl get pods -n dev -o wide

在这里插入图片描述

使用

 curl 172.18.0.9:80 

访问nginx 服务

在这里插入图片描述

为了方便测试进入三台nginx 的index.html 页面(三台修改的ip 地址不一致), 进入容器修改index 页面

kubectl exec -it pc-deployment-5ffc5bf56c-r4n7x  -n dev  /bin/sh

在这里插入图片描述

echo "172.18.0.9" >/usr/share/nginx/html/index.html

插入其节点的ip地址到index.html 文件中

echo “172.18.0.7” >/usr/share/nginx/html/index.html

echo “172.18.0.8” >/usr/share/nginx/html/index.html

curl 172.18.0.7:80

在这里插入图片描述

ClusterIP 类型Service

创建service-cluster.yaml 文件

apiVersion: v1 #固定的,可以查看
kind: Service
metadata:
  name: service-clusterip
  namespace: dev
spec:
  selector:
    app: nginx-pod # 选择标签为 app:nginx-pod 的pod
  clusterIP:   # service的ip 地址,如果不写会默认生成一个
  type: ClusterIP
  ports:
  - port: 80 # Service 端口  Service 端口可以随便设置
    targetPort: 80 # pod 端口

因为nginx 服务运行在80 端口上,所以 targetPort 必须设置为80。

kubectl create -f service-cluster.yaml

kubectl get service -n dev 查看service 创建出的情况

在这里插入图片描述

kubectl describe svc service-clusterip -n dev 查看service 详细情况

在这里插入图片描述

​ 可以看到在Endpoints 中有选择的pod 对应的ip地址,Endpoint 是K8s 中对应的一个资源对象,存储在etcd 中,用来记录一个Service 对应的所有pod的访问地址。它是根据service 配置文件中的selector 描述产生的。

Endpoints 是实现实际服务的端点集合

在这里插入图片描述

使用下列命令查看endpoints

kubectl get endpoints -n dev -o wide 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fxeWLnHc-1638610423114)(D:\java workstation\笔记\浪潮\images\image-20211129205051094.png)]

测试

1 查看ipvs 的映射规则

2 循环访问测试

while true; do curl  10.102.208.75:80;sleep 5; done;

在这里插入图片描述

轮询策略

负载分发策略

对Service 的访问被分发到了后端的pod 上去,目前K8s 提供了两种负载均衡的策略:

  • 如果不定义,默认使用kube-proxy 策略,比如随机,轮询
  • 基于客户端地址的会话保持模式,即来自同一个客户端发起的所有请求都会转发到固定的一个pod 上,此模式通过在spec 中添加 sessionAffinity:ClientIP 选项
apiVersion: v1 #固定的,可以查看
kind: Service
metadata:
  name: service-clusterip
  namespace: dev
spec:
  sessionAffinity: ClientIP
  selector:
    app: nginx-pod
  clusterIP:     # service的ip 地址,如果不写会默认生成一个
  type: ClusterIP
  ports:
  - port: 80 # Service 端口
    targetPort: 80 # pod 端口

ClusterIP 类型的service 只能在其集群内部使用

HeadLiness 类型

在某些场景下,开发人员可能不想使用Service 提供的负载均衡功能。而是希望自己来控制负载均衡策略,针对这种情况,K8s 提供了HeadLiness Service, 这类Service 不会分配Cluster ip,如果要访问 service, 只能通过service 的域名进行查询。

创建service-headliness.yaml

apiVersion: v1 #固定的,可以查看
kind: Service
metadata:
  name: service-headlines
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None    #将clusterIP 设置为None,即可创建 headliness Service
  type: ClusterIP
  ports:
  - port: 80 # Service 端口
    targetPort: 80 # pod 端口

创建了只能通过service 的域名进行访问

进入pod

kubectl  exec -it pc-deployment-66667x8s8- gdbxj -n dev /bin/bash

查看 /etc/resolv.conf

在这里插入图片描述

默认的域名解析服务器 为: 10.96.0.10

NodePort 类型的Service

NodePort 类型的工作原理就是将service 的端口映射到Node (节点)的一个端口上,然后可以通过 NodeIp:NodePort来访问service。

在这里插入图片描述

创建service-nodeport.yaml

apiVersion: v1 #固定的,可以查看
kind: Service
metadata:
  name: service-nodeport
  namespace: dev
spec:
  selector:
    app: nginx-pod
  type: NodePort #service 类型
  ports:
  - port: 80 # Service 端口
    nodePort: 30002 # 指定绑定node 的端口(默认取值范围是30000-32767),如果不指定就会默认分配
    targetPort: 80 # pod 端口
    
    

创建并查看

kubectl create -f service-nodeport.yaml 
kubectl get svc service-nodeport -n dev

在这里插入图片描述

访问节点ip:30002 会转发到 Cluster-IP:80 端口

在这里插入图片描述

ip 地址为172.17.0.85

在这里插入图片描述

LoadBalance 类型的Service

LoadBalance 类型的service 和NodePort 很类似,目的都是向外暴露一个端口,区别在与LoadBalancer 会在集群的外部再来做一个负载均衡设备,这个设备需要外部环境支持,外部服务器发送到这个设备上的请求,会被设备负载之后转发到集群中。

在这里插入图片描述

ExternalName 类型的Service

ExternalName 类型的service 用于引入集群外部的服务,它通过 externalName 属性指定外部一个服务的地址。然后在集群内部访问该service 就可以访问到外部的服务。与NodePort 是反方向的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gvfHvhYB-1638610423130)(D:\java workstation\笔记\浪潮\images\image-20211130192318693.png)]

在这里插入图片描述

Ingress 介绍

前面介绍,service 对集群之外暴露服务的主要方式有两种: NotePort 和LoadBalancer ,但是这两种方式都存在一定的缺点。

  • NodePort 方式的缺点在于会占用很多集群机器的端口,当集群变多的时候,这个缺点也就更加明显。
  • LB 这种方式的缺点是每一个service 需要一个LB设备,浪费,麻烦,并且需要K8s 之外的设备的支持。

基于这种现状,K8s 提供了Ingress 资源对象,Ingress 只需要一个NodePort 或者一个LB 就可以暴露多个Service 需求。工作机制大致如下图所示:

在这里插入图片描述

Ingress 相当于一个七层的负载均衡器,是K8s 对反向代理的一个抽象。 它的工作原理类似与nginx。,可以理解成ingress 里建立诸如多映射规则。Ingress Controller 通过监听这些配置规则并转化为nginx 的反向代理配置,然后对外部提供服务。 两大概念:

  • ingress: K8s 中的一个对象,作用是定义请求如何转发到service 的规则。
  • ingress controller: 具体实现反向代理和负载均衡的程序。对ingress 定义的规则进行解析,根据配置的规则来实现请求转发。实现方式有很多: nginx,Contour, Haproxy 等

ingress(以Nginx 为例)的工作原理:

在这里插入图片描述

ingress 实例
1 ingress 环境准备

本次选用基于nginx 的 ingress controller

创建ingress controller 文件夹

mkdir ingress-controller

cd ingress-controller
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.0/deploy/static/provider/baremetal/deploy.yaml
kubectl apply -f deploy.yaml

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5PbPP701-1638610423141)(D:\java workstation\笔记\浪潮\images\image-20211130210752980.png)]

可以看到有一个nginx-controller

kubectl get svc -n ingress-nginx

在这里插入图片描述

Service 也产生了并且是NodePort类型,外部可以访问。

2 搭建 三个nginx pod 和三个 tomcat pod 以及对应的service

在这里插入图片描述

创建tomcat-nginx.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: dev
spec:
  strategy: # 策略
    type: RollingUpdate # 滚动重建更新策略
    rollingUpdate:
      maxUnavailable: 25%
      maxSurge: 25%
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deployment
  namespace: dev
spec:
  strategy: # 策略
    type: RollingUpdate # 滚动重建更新策略
    rollingUpdate:
      maxUnavailable: 25%
      maxSurge: 25%
  replicas: 3
  selector:
    matchLabels:
      app: tomcat-pod
  template:
    metadata:
      labels:
        app: tomcat-pod
    spec:
      containers:
      - name: tomcat
        image: tomcat:8.5-jre10-slim
        ports:
        - containerPort: 8080
---
apiVersion: v1 #固定的,可以查看
kind: Service
metadata:
  name: nginx-service
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None  
  type: ClusterIP #service 类型
  ports:
  - port: 80 # Service 端口
    targetPort: 80 # pod 端口
---
apiVersion: v1 #固定的,可以查看
kind: Service
metadata:
  name: tomcat-service
  namespace: dev
spec:
  selector:
    app: tomcat-pod
  clusterIP: None    
  type: ClusterIP #service 类型
  ports:
  - port: 8080 # Service 端口
    targetPort: 8080 # pod 端口

在这里插入图片描述

http 代理

创建 ingress-http.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-http
  namespace: dev
spec:
  rules: # 策略
  - host: nginx.itheima.com
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx-service
          servicePort: 80
  - host: tomcat.itheima.com
    http:
      paths:
      - path: /
        backend:
          serviceName: tomcat-service
          servicePort: 8080         
          

host 主机域名

定义相应的规则

在这里插入图片描述

kubectl get  ing ingress-http -n dev

在这里插入图片描述

在这里插入图片描述

访问 nginx.itheima.com/ 会转到 后面

因为该域名不能正常解析,只能做模拟。 更改本机的host 目录 : 在 C:\Windows\System32\drivers\etc 目录下。

添加

172.18.0.1 nginx.itheima.com 172.18.0.1 是master 节点的地址

172.18.0.1 tomcat.itheima.com

在这里插入图片描述

注意172.18.0.1 是google 内部的内网所以ping 不同,在自己的环境下应该可以ping 通。

查看 kubectl get svc -n ingress-nginx

在这里插入图片描述

如果本地或网址为公网访问地址http://nginx.itheima.com:32696/会出现nginx 页面

https 代理

1 生成证书

openssl req -newkey rsa:4096 -nodes -sha256 -keyout tls.key -x509 -out tls.crt -subj /C=CN/ST=BJ/L=BJ/O=DEVOPS/CN=wangzy -days 3650
req     产生证书签发申请命令
-newkey  生成新私钥
rsa:4096  生成秘钥位数
-nodes   表示私钥不加密
-sha256  使用SHA-2哈希算法
-keyout  将新创建的私钥写入的文件名
-x509   签发X.509格式证书命令。X.509是最通用的一种签名证书格式。
-out 指定要写入的输出文件名
-subj    指定用户信息
-days    有效期

2 创建密钥

kubectl create secret tls tls-secret --key=tls.key --cert tls.crt

创建 ingress-https.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-https
  namespace: dev
spec:
  tls: 
    - hosts:
      - nginx.itheima.com
      - tomcat.itheima.com
      secretName: tls-secret #指定密钥
  rules: # 策略
  - host: nginx.itheima.com
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx-service
          servicePort: 80
  - host: tomcat.itheima.com
    http:
      paths:
      - path: /
        backend:
          serviceName: tomcat-service
          servicePort: 8080         
          

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UxikjtJa-1638610423167)(D:\java workstation\笔记\浪潮\images\image-20211201104757568.png)]

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐