[TOC]

一、概述

Service对集群之外暴露服务的主要方式有两种:NotePort和LoadBalancer,但是这两种方式,都有一定的缺点:

 NodePort方式的缺点是会占用很多集群机器的端口,那么当集群服务变多的时候,这个缺点就愈发明显。
  
LB方式的缺点是每个service需要一个LB,浪费、麻烦,并且需要kubernetes之外设备的支持。
  

基于这种现状,kubernetes提供了Ingress资源对象,Ingress只需要一个NodePort或者一个LB就可以满足暴露多个Service的需求。工作机制大致如下图表示:![](/D:\ovf\运维工程师课件\3、Kubernetes运维\1、K8S集群部署与应用/12、K8S-Ingress资源对象.assets/Ingress结构图.png)

实际上,Ingress相当于一个7层的负载均衡器,是kubernetes对反向代理的一个抽象,它的工作原理类似于Nginx,可以理解成在Ingress里建立诸多映射规则,Ingress Controller通过监听这些配置规则并转化成Nginx的反向代理配置 , 然后对外部提供服务。在这里有两个核心概念:

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

**Ingress(以Nginx为例)的工作原理如下:**

* 用户编写Ingress规则,说明哪个域名对应kubernetes集群中的哪个Service
* Ingress控制器**动态感知**Ingress服务规则的变化,然后生成一段对应的**Nginx反向代理配置**
* Ingress控制器会将生成的Nginx配置写入到一个运行着的Nginx服务中的pod,并**动态更新**
* 到此为止,其实真正在工作的就是一个Nginx了,内部配置了用户定义的请求转发规则

[ ](/D:\ovf\运维工程师课件\3、Kubernetes运维\1、K8S集群部署与应用/12、K8S-Ingress资源对象.assets/Ingress-nginx.png)

版本对比图

[image20250115141007603](/D:\ovf\运维工程师课件\3、Kubernetes运维\1、K8S集群部署与应用/12、K8S-Ingress资源对象.assets/image-20250115141007603.png)

 二、 Ingress应用案例

2.1 环境准备

**搭建ingress环境**

    # 创建文件夹
    [root@k8s-master01 ~]# mkdir ingress-controller
    [root@k8s-master01 ~]# cd ingress-controller/
    
    # 获取ingress-nginx,本次案例使用的是1.12.0版本
    [root@k8s-master01 ingress-controller]# wget https://github.com/kubernetes/ingress-nginx/releases/tag/controller-v1.12.0/ingress-nginx-controller-v1.12.0.zip
    [root@k8s-master01 ingress-controller]# unzip ingress-nginx-controller-v1.12.0.zip
    [root@k8s-master01 ingress-controller]# cd ingress-nginx-controller-v1.12.0/deploy/static/provider/cloud
    [root@k8s-master01 cloud]# ls
    deploy.yaml  kustomization.yaml
    
    #####外部访问策略:
    externalTrafficPolicy: Local 
    ### Cluster:流量会在集群内的所有节点之间进行负载均衡,可能会导致网络跳转,即流量可能会先到达一个节点,然后再被转发到其他节点上的服务实例。
    ### Local:流量只会被转发到接收请求的节点上的服务实例,这样可以避免额外的网络跳转,但可能会导致某些节点上的服务实例接收不到流量,尤其是当服务实例在集群中分布不均匀时。
    ##查看并修改镜像源为如下:
    
    [root@k8s-master01 cloud]# cat deploy.yaml | grep -n image
    445:        image: registry.k8s.io/ingress-nginx/controller:v1.12.0
    547:        image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.5.0
    601:        image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.5.0
    
    
    #########部署#############
    [root@k8s-master01 cloud]# kubectl apply -f deploy.yaml 
    namespace/ingress-nginx created
    serviceaccount/ingress-nginx created
    serviceaccount/ingress-nginx-admission created
    role.rbac.authorization.k8s.io/ingress-nginx created
    role.rbac.authorization.k8s.io/ingress-nginx-admission created
    clusterrole.rbac.authorization.k8s.io/ingress-nginx created
    clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
    rolebinding.rbac.authorization.k8s.io/ingress-nginx created
    rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
    clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
    clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
    configmap/ingress-nginx-controller created
    service/ingress-nginx-controller created
    service/ingress-nginx-controller-admission created
    deployment.apps/ingress-nginx-controller created
    job.batch/ingress-nginx-admission-create created
    job.batch/ingress-nginx-admission-patch created
    ingressclass.networking.k8s.io/nginx created
    validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
    [root@k8s-master01 cloud]# kubectl -n ingress-nginx get pod
    NAME                                        READY   STATUS      RESTARTS   AGE
    ingress-nginx-admission-create-sgksd        0/1     Completed   0          77s
    ingress-nginx-admission-patch-f4rdc         0/1     Completed   1          77s
    ingress-nginx-controller-565cc5ddd9-2qwnm   1/1     Running     0          77s
    
    [root@k8s-master01 cloud]# kubectl -n ingress-nginx get svc
    NAME                                 TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
    ingress-nginx-controller             LoadBalancer   10.10.103.132   <pending>     80:31502/TCP,443:31020/TCP   96s
    ingress-nginx-controller-admission   ClusterIP      10.10.227.21    <none>        443/TCP                      96s
    
    
    ##查看集群已经存在的nginx类型
    [root@k8s-master01 cloud]# kubectl get ingressclass
    NAME    CONTROLLER             PARAMETERS   AGE
    nginx   k8s.io/ingress-nginx   <none>       2m53s
    

## 2.2 验证-NodePort模式

**准备service和pod**

创建nginx.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: nginx-deploy
      name: nginx-deploy
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx-deploy
      template:
        metadata:
          labels:
            app: nginx-deploy
        spec:
          containers:
          - image: nginx:latest
            imagePullPolicy: IfNotPresent
            name: nginx
            ports:
            - containerPort: 80
    ---
    
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: nginx-deploy
      name: nginx-svc
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        app: nginx-deploy
      type: ClusterIP
    

    # 创建
    [root@k8s-master01 ingress-controller]# kubectl apply  -f nginx.yaml 
    deployment.apps/nginx-deploy created
    service/nginx-svc created
    
    
    # 查看
    [root@k8s-master01 ingress-controller]# kubectl get pod
    NAME                            READY   STATUS    RESTARTS   AGE
    nginx-deploy-7c7b68644b-26jtl   1/1     Running   0          20s
    nginx-deploy-7c7b68644b-5jsmb   1/1     Running   0          20s
    nginx-deploy-7c7b68644b-rjc4r   1/1     Running   0          20s
    
    [root@k8s-master01 ingress-controller]# kubectl get svc
    NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
    kubernetes   ClusterIP   10.10.0.1      <none>        443/TCP   13d
    nginx-svc    ClusterIP   10.10.199.33   <none>        80/TCP    36s
    

**修改ingress代理模式**

    [root@k8s-master01 ingress-controller]# kubectl -n ingress-nginx edit svc ingress-nginx-controller 
         49   type: NodePort
         50 status:
         51   loadBalancer: {}
    ##查看
    [root@k8s-master01 ingress-controller]# kubectl -n ingress-nginx get svc
    NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
    ingress-nginx-controller             NodePort    10.10.103.132   <none>        80:31502/TCP,443:31020/TCP   10m
    ingress-nginx-controller-admission   ClusterIP   10.10.227.21    <none>        443/TCP                      10m
    

### 设置Http代理

创建ingress-http.yaml

    apiVersion: networking.k8s.io/v1
    kind: Ingress # 创建一个类型为Ingress的资源
    metadata:
      name: nginx-ingress # 这个资源的名字为 nginx-ingress
    spec:
      ingressClassName: nginx # 使用nginx
      rules:
      - host: nginx.jx.com # 访问此内容的域名
        http:
          paths:
          - backend:
              service:
                name: nginx-svc # 对应nginx的服务名字,该规则的namespace必须与service的一致
                port:
                  number: 80 # 访问的端口
            path: / # 匹配规则
            pathType: Prefix # 匹配类型,这里为前缀匹配
    
    ######
    #Exact(精确匹配):
    #当 PathType 的值为 Exact 时,意味着服务的路由规则将仅在传入请求的路径与指定的路径完全相同时才会被匹配。
    #例如,如果一个服务的路径配置为 /api/v1/resource 且 PathType 为 Exact,那么只有当请求的路径是 /api/v1/resource 时,该服务才会被选中处理请求,多一个字符或少一个字符都不会匹配,包括 /api/v1/resource/ 或者 /api/v1/resource?id=1 这样的请求路径都不会被该服务处理,这是一种非常严格的精确匹配规则。
    #Prefix(前缀匹配):
    #当 PathType 的值为 Prefix 时,服务将匹配以指定路径作为前缀的请求路径。
    #例如,如果一个服务的路径配置为 /api/v1 且 PathType 为 Prefix,那么 /api/v1、/api/v1/resource、/api/v1/resource/1 等以 /api/v1 开头的请求路径都会被该服务处理,只要请求路径以 /api/v1 开头,该服务就会处理该请求,而不要求请求路径完全等于 /api/v1。

    # 创建
    [root@k8s-master01 ~]# kubectl create -f ingress-http.yaml
    ingress.extensions/ingress-http created
    
    # 查看
    [root@k8s-master01 ingress-controller]# kubectl get ingress nginx-ingress 
    NAME            CLASS   HOSTS          ADDRESS         PORTS   AGE
    nginx-ingress   nginx   nginx.jx.com   10.10.103.132   80      31s
    
    
    
    # 查看详情
    [root@k8s-master01 ~]# kubectl describe ingress nginx-ingress 
    Name:             nginx-ingress
    Labels:           <none>
    Namespace:        default
    Address:          10.10.26.150
    Ingress Class:    nginx
    Default backend:  <default>
    Rules:
      Host          Path  Backends
      ----          ----  --------
      nginx.jx.com  
                    /   nginx-svc:80 (172.16.69.202:80,172.16.79.74:80,172.16.79.75:80)
    Annotations:    <none>
    Events:
      Type    Reason  Age                 From                      Message
      ----    ------  ----                ----                      -------
      Normal  Sync    9m2s (x2 over 14m)  nginx-ingress-controller  Scheduled for sync
    
    [root@k8s-master ~]# kubectl -n ingress-nginx get po -o wide
    NAME                                        READY   STATUS      RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
    ingress-nginx-admission-create-qmdj9        0/1     Completed   0          21m   10.244.36.89     k8s-node1   <none>           <none>
    ingress-nginx-admission-patch-htkxb         0/1     Completed   0          21m   10.244.36.90     k8s-node1   <none>           <none>
    ingress-nginx-controller-7d7455dcf8-5s9q5   1/1     Running     0          21m   10.244.169.157   k8s-node2   <none>           <none>
    
    #在访问节点写入hosts解析记录,由于ingress-controller运行再node2节点,所以hosts要写成node2的节点IP地址
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    192.168.158.17    nginx.jx.com
    
    ##测试,只能使用域名访问
    [root@k8s-master01 ingress-controller]# curl nginx.jx.com:31502
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
    html { color-scheme: light dark; }
    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>
    

### ingress service配置解析

## externalTrafficPolicy: Local

### 含义

`externalTrafficPolicy: Local` 表示来自集群外部的流量只会被路由到运行有服务后端 Pod 的节点上。

### 工作原理

1. 当外部请求到达某个节点的 NodePort 时:
  * 如果该节点上有服务对应的 Pod 在运行,请求会被转发到本地的 Pod
  * 如果该节点上没有服务对应的 Pod,请求会被丢弃(返回 TCP RST)
2. 特点:
  * 保留原始客户端 IP(不会做 SNAT)
  * 可能导致流量分布不均(只有有 Pod 的节点才会接收流量)
  * 适合需要保留客户端源 IP 的场景

## internalTrafficPolicy: Cluster

### 含义

`internalTrafficPolicy: Cluster` 表示来自集群内部的流量会被均匀分配到所有可用的后端 Pod,无论这些 Pod 运行在哪个节点上。

### 工作原理

1. 当集群内部的服务请求发生时:
  * 请求会被均匀分配到所有健康的 Pod
  * 不考虑 Pod 所在的节点位置
2. 特点:
  * 提供更好的负载均衡
  * 可能导致跨节点流量(pod 在节点 A,请求来自节点 B)
  * 默认行为

## 2.3 验证-LoadBalancer模式

### 修改ARP模式,启用严格ARP模式

    # 执行修改操作
    kubectl get configmap kube-proxy -n kube-system -o yaml | \
    sed -e "s/strictARP: false/strictARP: true/" | \
    kubectl apply  -f - -n kube-system
    
    
    #或者
    kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e "s/strictARP: false/strictARP: true/" | kubectl apply  -f - -n kube-system
    #查看修改结果
    kubectl edit configmap -n kube-system kube-proxy
    
    
    kubectl get configmap kube-proxy -n kube-system -o yaml | \
    sed -e "s/strictARP: true/strictARP: false/" | \
    kubectl apply  -f - -n kube-system

**为什么要修改严格模式?**

* 避免 ARP 冲突
  * 在默认情况下,容器网络可能会出现一些非预期的 ARP 行为。在 Load Balancer 模式下,流量需要准确地被分发到后端的 Pod。如果不启用严格 ARP 模式,可能会出现多个 Pod 响应同一个 ARP 请求的情况。
  * 例如,假设在一个集群中有多个 Pod 提供相同的服务,并且它们在同一个子网中。如果没有严格的 ARP 控制,负载均衡器可能会收到来自多个 Pod 的 ARP 响应,导致流量分发混乱,影响服务的正常运行。
* 确保流量正确分发
  * 严格 ARP 模式可以确保只有正确的后端 Pod 响应 ARP 请求。这样,负载均衡器能够准确地将流量发送到预期的 Pod。
  * 以一个 Web 应用程序为例,当外部用户通过负载均衡器访问该应用时,负载均衡器需要将请求发送到正确的 Web 服务器 Pod。通过启用严格 ARP 模式,就像是给每个 Pod 一个 “专属标签”,只有拥有该标签(正确 MAC 地址)的 Pod 才会响应 ARP 请求,从而保证请求能够准确无误地到达提供服务的 Pod。
* 增强网络安全性和稳定性
  * 限制 ARP 响应可以防止恶意的 Pod 或者受到攻击的 Pod 干扰网络通信。如果一个被入侵的 Pod 随意响应 ARP 请求,可能会导致中间人攻击或者流量劫持等安全问题。
  * 严格 ARP 模式可以防止这种情况的发生,使得网络通信更加安全和稳定。例如,在一个多租户的 Kubernetes 集群环境中,不同租户的 Pod 之间通过严格的 ARP 模式来隔离网络通信,避免租户之间的相互干扰和安全威胁。

### 搭建metallb支持LoadBalancer

Metallb 在 Kubernetes 中的作用主要是为没有运行在如 AWS、GCP 等具有完善网络服务的云平台上的集群,提供网络负载均衡器的实现。

* **实现 LoadBalancer 服务类型**:在 Kubernetes 中,Service 有多种类型,其中 LoadBalancer 类型通常需要外部的负载均衡器支持。Metallb 可以在缺乏原生云平台负载均衡支持的环境下,模拟实现 LoadBalancer 类型的 Service。它能够为应用提供可从集群外部访问的固定 IP 地址。
* **IP 地址分配与管理**:负责在指定的 IP 地址范围(IP address pool)内,为 LoadBalancer 类型的 Service 分配 IP 地址,并确保这些 IP 地址的正确映射和管理,使外部流量能够准确地路由到相应的 Kubernetes 服务后端 Pod。
* **提供高可用的网络连接**:通过实现 BGP(Border Gateway Protocol)或 Layer2 模式的负载均衡机制,确保即使在节点故障或网络波动的情况下,也能维持应用的外部网络连接的稳定性和可靠性。

    #版本
    metallb-0.14.8
    cd /root/metallb-0.14.8/config/manifests
    kubectl apply -f metallb-native.yaml
    ##编写地址段分配configmap
    #创建IP地址池
    cat > IPAddressPool.yaml<<EOF
    apiVersion: metallb.io/v1beta1
    kind: IPAddressPool
    metadata:
      name: planip-pool #这里与下面的L2Advertisement的ip池名称需要一样
      namespace: metallb-system
    spec:
      addresses:
      - 192.168.166.135-192.168.166.150 #自定义ip段
    EOF
    #关联IP地址池
    cat >L2Advertisement.yaml<<EOF
    apiVersion: metallb.io/v1beta1
    kind: L2Advertisement
    metadata:
      name: planip-pool
      namespace: metallb-system
    spec:
      ipAddressPools:
      - planip-pool #这里需要跟上面ip池的名称保持一致
    EOF
    
    
    ####
    
    
    
    kubectl apply -f IPAddressPool.yaml
    kubectl apply -f L2Advertisement.yaml
    
    
    [root@k8s-master01 manifests]# kubectl -n metallb-system get pod
    NAME                          READY   STATUS    RESTARTS   AGE
    controller-7476b58756-q7cql   1/1     Running   0          6m
    speaker-55l64                 1/1     Running   0          6m
    speaker-8jjg8                 1/1     Running   0          6m1s
    
    

### 普通的service测试

    [root@k8s-master01 ingress-controller]# cat nginx.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: nginx-deploy1
      name: nginx-deploy1
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx-deploy1
      template:
        metadata:
          labels:
            app: nginx-deploy1
        spec:
          containers:
          - image: nginx
            imagePullPolicy: IfNotPresent
            name: nginx1
            ports:
            - containerPort: 80
    ---
    
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: nginx-deploy1
      name: nginx-svc1
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        app: nginx-deploy1
      type: LoadBalancer  ###### 无所谓是什么类型
    ##提交
    [root@k8s-master01 ingress-controller]# kubectl apply -f nginx.yaml 
    ##查看
    [root@k8s-master01 ingress-controller]# kubectl get pod
    NAME                            READY   STATUS    RESTARTS   AGE
    nginx-deploy-5f87d95c-7ph78     1/1     Running   0          50m
    nginx-deploy-5f87d95c-dswvq     1/1     Running   0          50m
    nginx-deploy-5f87d95c-vk9vg     1/1     Running   0          50m
    nginx-deploy1-c8d58b5c7-7dfrd   1/1     Running   0          12m
    nginx-deploy1-c8d58b5c7-d2hd7   1/1     Running   0          12m
    nginx-deploy1-c8d58b5c7-pfvhn   1/1     Running   0          12m
    
    
    [root@k8s-master ingress]# kubectl get svc
    NAME         TYPE           CLUSTER-IP       EXTERNAL-IP       PORT(S)        AGE
    kubernetes   ClusterIP      10.96.0.1        <none>            443/TCP        8d
    nginx-svc    ClusterIP      10.110.232.77    <none>            80/TCP         95m
    nginx-svc1   LoadBalancer   10.107.207.235   192.168.158.136   80:30099/TCP   10m
    
    ##测试访问
    [root@k8s-master01 ingress-controller]# curl 192.168.158.136
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
    html { color-scheme: light dark; }
    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>
    

    apiVersion: networking.k8s.io/v1
    kind: Ingress # 创建一个类型为Ingress的资源
    metadata:
      name: nginx-ingress # 这个资源的名字为 nginx-ingress
    spec:
      ingressClassName: nginx # 使用nginx
      rules:
      - host: nginx.jx.com # 访问此内容的域名
        http:
          paths:
          - backend:
              service:
                name: nginx-svc # 对应nginx的服务名字
                port:
                  number: 80 # 访问的端口
            path: / # 匹配规则
            pathType: Prefix # 匹配类型,这里为前缀匹配
      - host: nginx2.jx.com # 访问此内容的域名
        http:
          paths:
          - backend:
              service:
                name: nginx-svc1 # 对应nginx的服务名字
                port:
                  number: 80 # 访问的端口
            path: / # 匹配规则
            pathType: Prefix # 匹配类型,这里为前缀匹配
    

**修改ingress模式:**

    [root@k8s-master01 ~]# kubectl -n ingress-nginx edit svc ingress-nginx-controller
      type: LoadBalancer
    status:
      loadBalancer: {}
    

### ingress访问测试:

使用域名直接访问即可!!!

    curl nginx.jx.com
    curl nginx2.jx.com

更多推荐