Kubernetes(五):Ingress

目录

一、介绍

二、安装Ingress控制器Controller

  2.1 下载清单文件

  2.2 外部负载均衡器

  2.3 部署Ingress NGINX Controller

三、完整示例

  3.1 准备后端应用

  3.2 定义Ingress规则(单Host多Path)

  3.3 定义Ingress规则(多Host)

  3.4 探究访问路径

  3.5 探究Ingress规则如何生效


一、介绍

   在Kubernetes中Service是工作在第四层(既网络模型中的第四层,既TCP/UDP层)。而HTTP和HTTPS是在网络模型中第七层,Ingress就是工作在第七层的路由机制。

Open Systems Interconnection Model (OSI  Model):
  • 第四层L4 refer to layer 4 (Transport Layer; TCP, UDP)
  • 第七层L7 refer to layer 7 (Application Layer; HTTP) 

  在Kubernetes中已经有了Service,为什么还需要Ingress呢?

  • 由于Ingress工作在第七层,所以不再局限于在IP和端口层面控制。而是可以基于HTTP/HTTPS进行分发。比如根据URL中包含特定的字符进行分发,比如根据HTTP请求头的内容进行分发,比如基于Cookie的回话亲和性等规则。
  • 为多个不同Service提供统一代理和分发。例如:对于type=LoadBalancer类型的Service,在云厂商托管情况会自动创建云负载均衡器。所以每个Service都会有一个负载均衡器,这种做法既浪费资源,也难以管理,更合理的做法是Kubernetes提供相对统一的负载均衡器。因此这种统一的、为不同Service提供代理和分发就是Ingress。例如对外由Ingress统一暴露某个域名http://www.zyp.com,其中访问http://www.zyp.com/coffee域名分发至后端的Coffee服务,访问http://www.zyp.com/tea域名分发至后端的Tea服务。

  所以Ingress本身就是Service及Pod等各类资源,可以说Ingress是“Service”的“Service”

  Ingress示意图如下::

在Ingress中分为:

二、安装Ingress控制器Controller

  下面选择比较常用的Ingress NGINX Controller进行演示。安装部署Ingress NGINX Controller可以有多种方式,下面通过yaml清单文件方式部署。

官网网站:https://kubernetes.github.io/ingress-nginx/     

Github地址:https://github.com/kubernetes/ingress-nginx   有与Kubernetes版本对应关系表。

  2.1 下载清单文件

安装部署Ingress NGINX Controller可以有多种方式,比如Helm方式,比如yaml清单文件方式。下面通过yaml清单文件方式部署。该清单文件创建如下类型的资源:

  • 1个Namespace,名为“ingress-nginx”的。 (以下资源在该Namespace下创建)
  • 2个ServiceAccount,名为“ingress-nginx”、“ingress-nginx-admission
  • 2个Role,名为“ingress-nginx”、“ingress-nginx-admission
  • 2个ClusterRole,名为“ingress-nginx”、“ingress-nginx-admission
  • 2个RoleBinding
  • 2个ClusterRoleBinding
  • 1个ConfigMap,名为“ingress-nginx-controller
  • 2个Service,type=LoadBalancer名为“ingress-nginx-controller”、type=ClusterIP名为“ingress-nginx-controller-admission”。 type=LoadBalancer的Service用途是把“Ingress NGINX Controller”作为统一入口对外暴露(端口80与443),由其接收流量后,再根据分发规则Rules分发至后端各Service。
  • 1个Deployment,使用镜像“registry.k8s.io/ingress-nginx/controller”
  • 2个Job,名为“ingress-nginx-admission-create”、“ingress-nginx-admission-patch
  • 1个IngressClass,名为“nginx”,并且controller指定关联到具体实现的Deployment中Pod。
  • 1个ValidatingWebhookConfiguration

在Kubernetes的Control控制平面上:

# 下载yaml清单文件并重命名
curl -o ingress-nginx-controller.yaml https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.13.3/deploy/static/provider/cloud/deploy.yaml

# 查看该yaml文件中有哪些资源类型
grep "^kind" ingress-nginx-controller.yaml

#若国内无法直接访问registry.k8s.io,则替换为国内源
sed -i 's#registry.k8s.io#k8s.nju.edu.cn#' ingress-nginx-controller.yaml

  2.2 外部负载均衡器

在该yaml清单文件中,type=LoadBalancer名为“ingress-nginx-controller”的Service用途是作为统一入口对外暴露,由其接收流量。如果是云厂商托管的Kubernetes(如Amazon的EKS、阿里云的ACK)会自动检测到type=LoadBalancer的Service,并通过云控制器管理器调用云厂商的 API(如 AWS EC2 API、阿里云 SLB API)自动创建一个云负载均衡器,并将云负载均衡器IP自动注入到“ingress-nginx-controller”的Service中。

但本文演示环境不属于云上托管,是本地自行搭建的私有环境,因此没有云会自动创建负载均衡器,也不能将IP自动注入Service。此处为了简易起见,通过手工配置一个IP来模拟外部负载均衡器。模块方式具体为:

  1. 在Kubernetes集群找其中任意一台节点机器,对该节点增加配置一个IP地址作为外部负载均衡器IP。要求该IP地址能被集群外部直接访问。在本文中增加配置IP为192.168.43.50
  2. 在yaml清单文件里,“ingress-nginx-controller”的Service配置下手工增加externelIPs,模拟云厂商托管场景下自动注入外部负载均衡器IP。

注:type=LoadBalancer的Service相关知识可参见:https://blog.csdn.net/zyplanke/article/details/151224929

针对模拟方式第1步,在一台Kubernetes节点机器上,以root用户执行以下命令增加IP:

#在已有的网卡设备(以下为ens33为例)上增加配置一个IP,并设定别名为“ens33:2”
#以下命令仅当前临时有效。若希望Linux重启后仍有效,则还应配置在网卡配置文件中
sudo ip addr add 192.168.43.50 dev ens33 label ens33:2

#以上命令执行成功后,则可以ping通该IP。可对该IP再进一步配置域名(本文略)

针对模拟方式第2步,在yaml清单文件中对“ingress-nginx-controller”的Service配置下,新增externalIPs、调整externalTrafficPolicy配置:

  2.3 部署Ingress NGINX Controller

    Kubernetes的Control控制平面上:

    # 根据修改后的清单文件部署
    kubectl apply -f ingress-nginx-controller.yaml
    
    # 查看该命名空间下的资源
    kubectl get all -n ingress-nginx

    根据该namespace查看已创建的资源如下(注意输出展示Service的EXTERNAL-IP、PORT):

    查看Pod并访问该Pod,可以看到Nginx的应答。由于此时还为配置Ingress的分发规则,因此HTTP返回的是Nginx自身,而不是后端服务(更准确说Pod中容器)返回的应答。

      自此,Ingress Controller已安装部署完毕,但还没有配置分发规则。下一步以示例来展示。

    三、完整示例

      3.1 准备后端应用

     分别准备两个后端应用如下:

    • coffee服务:1个的Service(端口11110)、两个Pod副本(端口1111)
    • tea服务:1个的Service(端口22220)、两个Pod副本(端口2222)

      为便于演示,Pod中容器使用alpine镜像并通过nc命令启动简易HTTP服务端。

      1、创建coffee服务。准备demo-coffee.yaml文件如下:

    apiVersion: v1
    kind: Service
    metadata:
      name: svc-coffee
    spec:
      selector:                # 标签选择器,选择满足条件的后端Pod
        app: http-coffee
      type: ClusterIP
      ports:
      - port: 11110              # Service在clusterIP上的监听端口
        targetPort: 1111         # 转发至后端Pod上的端口,若未指定则等于port
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: p-alpine-coffee
    spec:
      replicas: 2                   # 期望的副本数,默认为1
      selector:                     # 标签选择器。若多个matchLabels则为AND关系;还可以用matchExpressions来表达复杂选择关系
        matchLabels:
           app: http-coffee         # 需与.spec.template.metadata.labels一致
      template:                     # Pod模版定义
        metadata:
          labels:
            app: http-coffee
        spec:
          containers:
          - name: c-alpine          #容器名(需符合RFC 1123,不能有下划线)
            image: alpine           #镜像名
            command:                #容器启动时执行命令,通过nc命令启动简易HTTP服务端
            - sh
            - -c
            - |
                while : ;
                do
                   (echo "HTTP/1.1 200 OK";
                    echo "";
                    echo "Demo HTTP Server by nc! "
                    echo "HTTP serverHostname=`hostname`  serverIP=`hostname -i`  serverTime=`date`";
                   ) | nc -v -l -p 1111;
                done
            ports:
            - containerPort: 1111   #展示性申明容器对外暴露的端口,可多个

      2、创建后,可以看到直接通过其Service访问,其应答分别是由不同的Pod(容器)返回的:

     3、创建tea服务。准备demo-tea.yaml文件如下:

    apiVersion: v1
    kind: Service
    metadata:
      name: svc-tea
    spec:
      selector:                # 标签选择器,选择满足条件的后端Pod
        app: http-tea
      type: ClusterIP
      ports:
      - port: 22220              # Service在clusterIP上的监听端口
        targetPort: 2222         # 转发至后端Pod上的端口,若未指定则等于port
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: p-alpine-tea
    spec:
      replicas: 2                   # 期望的副本数,默认为1
      selector:                     # 标签选择器。若多个matchLabels则为AND关系;还可以用matchExpressions来表达复杂选择关系
        matchLabels:
           app: http-tea            # 需与.spec.template.metadata.labels一致
      template:                     # Pod模版定义
        metadata:
          labels:
            app: http-tea
        spec:
          containers:
          - name: c-alpine          #容器名(需符合RFC 1123,不能有下划线)
            image: alpine           #镜像名
            command:                #容器启动时执行命令,通过nc命令启动简易HTTP服务端
            - sh
            - -c
            - |
                while : ;
                do
                   (echo "HTTP/1.1 200 OK";
                    echo "";
                    echo "Demo HTTP Server by nc! "
                    echo "HTTP serverHostname=`hostname`  serverIP=`hostname -i`  serverTime=`date`";
                   ) | nc -v -l -p 2222;
                done
            ports:
            - containerPort: 2222   #展示性申明容器对外暴露的端口,可多个

      4、创建后,可以看到直接通过其Service访问,应答分别是由不同的Pod(容器)返回的:

      3.2 定义Ingress规则(单Host多Path)

          这里对外提供一个域名,每个域名后分别两个子Path分别对应后端coffee与tea两个应用服务。对此将Ingress Resource(既规则)写成yaml清单文件one-host-ingress.yaml,内容如下:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: one-host-ingress
    spec:
      ingressClassName: nginx         #指定本规则由哪种Ingress Controller实现
      rules:
      - host: "*.zyp.com"             #与HTTP请求头中Host对应(可带通配符)。不能为IP格式
        http:
          paths:
          - path: /coffee             #HTTP请求中URL,必须以“/” 开头
            pathType: Prefix          #path匹配类型:Exact完全精准匹配;按“/”拆分URL路径前缀匹配
            backend:
              service:                #后端服务需与本Ingress同属一个namespace
                name: svc-coffee      #流量分发至后端服务名
                port:                 #流量分发至后端服务中哪个端口(可以为name端口名 或 number数字端口号)
                  number: 11110
          - path: /tea                #HTTP请求中URL,必须以“/” 开头
            pathType: Prefix          #path匹配类型:Exact完全精准匹配;按“/”拆分URL路径前缀匹配
            backend:
              service:                #后端服务需与本Ingress同属一个namespace
                name: svc-tea         #流量分发至后端服务名
                port:                 #流量分发至后端服务中哪个端口(可以为name端口名 或 number数字端口号)
                  number: 22220
    

    Kubernetes的Control控制平面上:

    # 部署Ingress清单文件部署
    kubectl apply -f one-host-ingress.yaml
    
    # 查看Ingress资源(注意输出展示的Address刚开始可能无值,需等几十秒后才自动有值)
    kubectl describe ingress/one-host-ingress

    注意输出展示的Rules中,Ingress通过服务已直接获得后端Pod的IP与端口,因此通过Ingress分发时可直接一步到位分发至Pod。

    然后再Kubernetes集群之外,找台机器通过访问外部负载均衡器:

    # 设置HTTP请求头
    curl -H "Host: www.zyp.com" http://192.168.43.50/coffee
    curl -H "Host: www.zyp.com" http://192.168.43.50/tea

    注1:Ingress规则中Host是与HTTP请求头中Host匹配,不是与URL。

    注2:curl或者浏览器默认会根据请求URL中内容自动设置Host请求头。但由于本环境中没有对外部负载均衡器配置DNS域名,因此在URL中只能写IP,对此需要手工设置HTTP请求头以便通过Host与Ingress规则匹配。

    至此,通过同个Host不同子Path均成功访问。

      3.3 定义Ingress规则(多Host)

       有时需要在同一入口(比如一个入口公网IP)上同时对外提供多个域名(既Host)。虽然是同一入口,但通过不同的域名访问,返回的内容是不同的。 

         对此,在Ingress中配置多个Host,并将不同Host分发到不同的后端服务上。写成yaml清单文件multi-host-ingress.yaml,内容如下:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: multi-host-ingress
    spec:
      ingressClassName: nginx         #指定本规则由哪种Ingress Controller实现
      rules:
      - host: "*.coffee.ltd"          #与HTTP请求头中Host对应(可带通配符)。不能为IP格式
        http:
          paths:
          - path: /coffee             #HTTP请求中URL,必须以“/” 开头
            pathType: Prefix          #path匹配类型:Exact完全精准匹配;按“/”拆分URL路径前缀匹配
            backend:
              service:                #后端服务需与本Ingress同属一个namespace
                name: svc-coffee      #流量分发至后端服务名
                port:                 #流量分发至后端服务中哪个端口(可以为name端口名 或 number数字端口号)
                  number: 11110
      - host: "*.tea.ltd"             #与HTTP请求头中Host对应(可带通配符)。不能为IP格式
        http:
          paths:
          - path: /tea                #HTTP请求中URL,必须以“/” 开头
            pathType: Prefix          #path匹配类型:Exact完全精准匹配;按“/”拆分URL路径前缀匹配
            backend:
              service:                #后端服务需与本Ingress同属一个namespace
                name: svc-tea         #流量分发至后端服务名
                port:                 #流量分发至后端服务中哪个端口(可以为name端口名 或 number数字端口号)
                  number: 22220
    

    Kubernetes的Control控制平面上:

    # 部署Ingress清单文件部署
    kubectl apply -f multi-host-ingress.yaml
    
    # 查看Ingress资源(注意输出展示的Address刚开始可能无值,需等几十秒后才自动有值)
    kubectl describe ingress/multi-host-ingress

    注意输出展示的Rules中,Ingress通过服务已直接获得后端Pod的IP与端口,因此通过Ingress分发时可直接一步到位分发至Pod。

    然后再Kubernetes集群之外,找台机器通过访问外部负载均衡器:

    # 设置HTTP请求头
    curl -H "Host: a.coffee.ltd" http://192.168.43.50/coffee
    curl -H "Host: b.tea.ltd" http://192.168.43.50/tea

    注1:Ingress规则中Host是与HTTP请求头中Host匹配,不是与URL。

    注2:curl或者浏览器默认会根据请求URL中内容自动设置Host请求头。但由于本环境中没有对外部负载均衡器配置DNS域名,因此在URL中只能写IP,对此需要手工设置HTTP请求头以便通过Host与Ingress规则匹配。

    至此,通过不同Host均成功访问。

      3.4 探究访问路径

        客户端通过Ingress访问后端应用的路径理论上为:

    客户端(curl等)→外部负载均衡器→Ingress(对应Controller实现)→Service→Pod中容器应用

        但实际访问路径为:

    客户端(curl等)→外部负载均衡器→Ingress(对应Controller实现)→Pod中容器应用

    注意1:不同的外部负载均衡器实现方式可能不同,在本例中从“外部负载均衡器”至“Ingress(对应Controller实现)”通过NAT转发完成(通过IPVS或者iptables转发),所以无法看到外部负载均衡器IP上监听LISTEN端口。

    注意2:上文实际访问路径中,在Pod前没有Service。因为Ingress通过服务已直接获得后端Pod的IP与端口,因此在Ingress(对应Controller实现)分发时可一步到位直接分发至Pod。

      3.5 探究Ingress规则如何生效

        Ingress Resource只是规则定义,最终如何生效还是靠Ingress Controller的具体实现,不同的Controller类型有不同的具体实现方式。对于本文选择的“Ingress NGINX Controller”这款,它是对Ingress定义规则是如何具体实现的呢?

        在以上Ingress规则定义后,可以进入到NGINX Controller容器内

    #先进入容器内
    kubectl exec -it pod/ingress-nginx-controller-dcfb8c47-l8msj -n ingress-nginx -- /bin/bash
    
    #再进入容器内部后,查看最新的nginx.conf
    vi /etc/nginx/nginx.conf

    可以看到根据Ingress中定义的规则,已自动写入到nginx.conf文件中。这就是“Ingress NGINX Controller”这款对Ingress定义规则的具体实现方式。

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

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

    余额充值