• 【转】kubernetes之ingress和Ingress Controller


     

    一、什么是Ingress?

    Kubernetes 暴露服务的方式目前只有三种:LoadBlancer Service、NodePort Service、Ingress

    1、Pod 漂移问题

    在 Kubernetes 中,随着 Pod 的创建和销毁,Pod IP 肯定会动态变化;那么如何把这个动态的 Pod IP 暴露出去?可以借助于 Kubernetes 的 Service 机制,Service 可以以标签的形式选定一组带有指定标签的 Pod,并监控和自动负载他们的 Pod IP,那么我们向外只暴露 Service IP 就行了;

    NodePort 模式:在每个节点上开起一个端口,然后转发到内部 Pod IP 上,访问方式:http://nodeip:nodeport,如下图所示:
     

    2、端口管理问题

    采用 NodePort 方式暴露服务面临的问题是,服务一旦多起来,NodePort 在每个节点上开启的端口会极其庞大,而且难以维护;

    这时,我们能否使用一个Nginx直接对内进行转发呢?在集群内,Pod与Pod之间是可以互相通信的,而Pod是可以共享宿主机的网络名称空间(hostNetwork方式)的,也就是说当Pod共享宿主机的网络名称空间(hostNetwork方式)时,Pod上所监听的就是Node上的端口。那么这又该如何实现呢?简单的实现就是使用 DaemonSet 在每个 Node 上监听 80,然后写好规则,因为 Nginx 外面绑定了宿主机 80 端口(就像 NodePort),本身又在集群内,那么向后直接转发到相应 Service IP 就行了,如下图所示:

    3、域名分配及动态更新问题

    从上面的方法,采用 Nginx-Pod 似乎已经解决了问题,但是其实这里面有一个很大缺陷:当每次有新服务加入又该如何修改 Nginx 配置呢??我们知道使用Nginx可以通过虚拟主机域名进行区分不同的服务,而每个服务通过upstream进行定义不同的负载均衡池,再加上location进行负载均衡的反向代理,在日常使用中只需要修改 nginx.conf 即可实现,那在K8S中又该如何实现这种方式的调度呢???

    假设后端的服务初始服务只有ecshop,后面增加了bbs和member服务,那么又该如何将这2个服务加入到Nginx-Pod进行调度呢?总不能每次手动改或者Rolling Update 前端 Nginx Pod 吧!!此时 Ingress 出现了。

    Ingress 包含两大组件:Ingress Controller 和 Ingress。

    Ingress 简单的理解就是你原来需要改 Nginx 配置,然后配置各种域名对应哪个 Service,现在把这个动作抽象出来,变成一个 Ingress 对象,你可以用 yaml 创建,每次不要去改 Nginx 了,直接改 yaml 然后创建/更新就行了;

    Ingress Controoler 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,并按照规则模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下,工作流程如下图:

    二、Ingress的负载均衡机制

    k8s提供了两种内建的云端负载均衡机制用于发布公共应用,一种是工作于传输层的service资源,它实现的是TCP负载均衡器,另一种是Ingress资源,它实现的是HTTP(S)负载均衡器。

    1)TCP负载均衡器

    无论是iptables还是ipvs模型的service资源都配置于Linux内核中的netfilter之上进行四层调度,是一种类型更为通用的调度器,支持调度HTTP、MYSQL等应用层服务。不过,也正是由于工作于传输层从而使得它无法做到https及ssl会话支持等,也不支持基于url的请求调度机制,而且,k8s也不支持为此类负载均衡器配置任何类型的健康检查机制。

    2)HTTP(S)负载均衡器

    HTTP(S)负载均衡器是应用层负载均衡机制的一种,支持根据环境做出更好的调度决策。与传输层调度器相比,它提供了诸如可自定义url映射和tls卸载等功能,并支持多种类型的后端服务器监控状态检测机制。

    Ingress 和 Ingress Controller

    service资源和pod资源的IP地址仅能用于集群网络内部的通信,所有的网络流量都无法穿透边界路由器以实现集群内外通信。尽管可以为service使用NodePort或LoadBalancer类型通过节点引入外部流量,但它依然是4层流量转发,可用的负载均衡器也为传输层负载均衡机制。

    Ingress是k8s的标准资源类型之一,它其实就是一组基于DNS名称或URL路径把请求转发至指定的service资源的规则,用于将集群外部的请求流量转发至集群内部完成服务发布。然而,Ingress资源自身并不能进行流量穿透,它仅是规则的集合,这些规则要想真正发挥作用还需要其他功能的辅助,如监听某套接字,然后根据这些规则的匹配机制路由请求流量。这种能够为Ingress资源监听套接字并转发流量的组件称为Ingress控制器。

    Ingress控制器可以由任何具有反向代理功能的服务程序实现,如Nginx、Envoy和Traefik等。Ingress控制器自身也是运行于集群中的pod资源对象,它与被代理的运行为pod资源的应用运行于同一网络中。使用Ingress资源进行流量分发时,Ingress控制器可基于某Ingress资源定义的规则将客户端的请求流量直接转发至与service对应的后端pod资源之上,这种转发机制会绕过service资源,从而省去了由kube-proxy实现的端口代理开销。Ingress规则需要由一个service资源对象辅助识别相关的所有pod对象,但Ingress-nginx控制器可经由api.ilinux.io规则的定义直接将请求流量调度至后端pod上,而无须经由service对象api的再次转发。

     

    三、如何创建Ingress资源

    Ingress资源时基于HTTP虚拟主机或URL的转发规则,需要强调的是,这是一条转发规则。资源清单中annotation用于识别其所属的Ingress控制器的类型,这一点在集群中部署有多个Ingress控制器时尤为重要。

    Ingress 中的spec字段是Ingress资源的核心组成部分,主要包含以下3个字段:

    • rules:用于定义当前Ingress资源的转发规则列表;由rules定义规则,或没有匹配到规则时,所有的流量会转发到由backend定义的默认后端。
    • backend:默认的后端,用于服务那些没有匹配到任何规则的请求;定义Ingress资源时,必须要定义backend或rules两者之一,该字段用于让负载均衡器指定一个全局默认的后端。
    • tls:TLS配置,目前仅支持通过默认端口443提供服务,如果要配置指定的列表成员指向不同的主机,则需要通过SNI TLS扩展机制来支持该功能。

    rules

    rules对象由一系列的配置的Ingress资源的host规则组成,这些host规则用于将一个主机上的某个URL映射到相关后端Service对象,其定义格式如下:

    1 spec:
    2   rules:
    3   - hosts: <string>
    4     http:
    5       paths:
    6       - path:
    7         backend:
    8           serviceName: <string>
    9           servicePort: <string>
    View Code

    需要注意的是,.spec.rules.host 属性值,目前暂不支持使用IP地址定义,也不支持IP:Port的格式,若该字段留空,代表着通配所有主机名。

    backend

    backend对象的定义由2个必要的字段组成:serviceName和servicePort,分别用于指定流量转发的后端目标Service资源名称和端口。

    tls

    tls对象由2个内嵌的字段组成,仅在定义TLS主机的转发规则上使用。

    • hosts: 包含 于 使用 的 TLS 证书 之内 的 主机 名称 字符串 列表, 因此, 此处 使用 的 主机 名 必须 匹配 tlsSecret 中的 名称。
    • secretName: 用于 引用 SSL 会话 的 secret 对象 名称, 在 基于 SNI 实现 多 主机 路 由 的 场景 中, 此 字段 为 可选。

    四、Ingress资源类型

    基于http暴露的每个service资源均可发布于一个独立的FQDN主机名之上,如www.ik8s.io;也可发布于某主机的URL路径之上,从而将它们整合到同一个web站点,如www.ik8s.io/frafana。至于是否需要发布为https类型的应用则取决于用户的业务需求。

    Ingress的资源类型有以下4种:

    • 1、单Service资源型Ingress
    • 2、基于URL路径进行流量转发
    • 3、基于主机名称的虚拟主机
    • 4、TLS类型的Ingress资源

    1、单Service资源型Ingress

    暴露单个服务的方法有多种,如NodePort、LoadBanlancer等等,当然也可以使用Ingress来进行暴露单个服务,只需要为Ingress指定default backend即可,如下示例:

    1 apiVersion: extensions/v1beta1
    2 kind: Ingress
    3 metadata:
    4   name: my-ingress
    5 spec:
    6   backend:
    7     serviceName: my-svc
    8     servicePort: 80
    View Code

    Ingress控制器会为其分配一个IP地址接入请求流量,并将其转发至后端my-svc。

    2、基于url路径进行流量分发

    垂直拆分或微服务架构中,每个小的应用都有其专用的service资源暴露服务,但在对外开放的站点上,它们可能是财经、新闻、电商等一类的独立应用,可通过主域名的url路径分别接入,用于发布集群内名称为API和WAP的service资源。于是,可对应地创建一个如下的Ingress资源:

     1 apiVersion: extensions/v1beta1
     2 kind: Ingress
     3 metadata:
     4   name: ingress-url-demo
     5   annotations:
     6      nginx.ingress.kubernetes.io/rewrite-target: /
     7 spec:
     8   rules:
     9   - host: myapp.syztoo.com
    10     http:
    11       paths:
    12       - path: /v1
    13         backend:
    14           serviceName: myappv1-svc
    15           servicePort: 80
    16       - path: /v2
    17         backend:
    18           serviceName: myappv2-svc
    19           servicePort: 80
    20  
    21 ---
    22 apiVersion: v1
    23 kind: Service
    24 metadata:
    25   name: myappv1-svc
    26   namespace: default
    27 spec:
    28   selector:
    29     app: myappv1
    30     release: canary
    31   type: ClusterIP
    32   ports: 
    33   - port: 80
    34     targetPort: 80
    35  
    36 ---
    37 apiVersion: apps/v1
    38 kind: Deployment
    39 metadata:
    40   name: myappv1-depoly
    41   namespace: default
    42 spec:
    43   replicas: 2
    44   selector:
    45     matchLabels:
    46       app: myappv1
    47       release: canary
    48   template:
    49     metadata:
    50       labels: 
    51         app: myappv1
    52         release: canary
    53     spec:
    54       containers:
    55       - name: myappv1
    56         image: ikubernetes/myapp:v1
    57         ports:
    58         - name: http
    59           containerPort: 80
    60  
    61 ---
    62 apiVersion: v1
    63 kind: Service
    64 metadata:
    65   name: myappv2-svc
    66   namespace: default
    67 spec:
    68   selector:
    69     app: myappv2
    70     release: canary
    71   type: ClusterIP
    72   ports: 
    73   - port: 80
    74     targetPort: 80
    75  
    76 ---
    77 apiVersion: apps/v1
    78 kind: Deployment
    79 metadata:
    80   name: myappv2-deploy
    81   namespace: default
    82 spec:
    83   replicas: 2
    84   selector:
    85     matchLabels:
    86       app: myappv2
    87       release: canary
    88   template:
    89     metadata:
    90       labels: 
    91         app: myappv2
    92         release: canary
    93     spec:
    94       containers:
    95       - name: myappv2
    96         image: ikubernetes/myapp:v2
    97         ports:
    98         - name: http
    99           containerPort: 80
    View Code

    3、基于主机名称的虚拟主机

     1 apiVersion: extensions/v1beta1
     2 kind: Ingress
     3 metadata:
     4   name: test
     5 spec:
     6   rules:
     7   - host: api.ik8s.io
     8     http: 
     9       paths:
    10       - backend:
    11           serviceName: api
    12           servicePort: 80
    13   - host: wap.ik8s.io
    14     http: 
    15       paths:
    16       - backend:
    17           serviceName: wap
    18           servicePort: 80
    View Code

    4、TLS类型的Ingress资源

    这种类型用于以https发布service资源,基于一个含有私钥和证书的secret对象即可配置TLS协议的Ingress资源,目前来说,Ingress资源仅支持单TLS端口,并且还能卸载TLS会话,在Ingress资源中引用此secret即可让Ingress控制器加载并配置为https服务。

     1 apiVersion: extensions/v1beta1
     2 kind: Ingress
     3 metadata:
     4   name: no-rules-map
     5 spec: 
     6   tls:
     7   - secretName: ikubernetesSecret
     8   backend:
     9     serviceName: homesite
    10     servicePort: 80
    View Code

     

    五、部署Ingress控制器(Nginx)

    1、部署Ingress controller

    下载 官网 配置清单

    [root@master ~]# mkdir ingress-nginx
    [root@master ~]# cd ingress-nginx/
    [root@master ingress-nginx]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml

     部署:

    [root@master ingress-nginx]# kubectl apply -f mandatory.yaml

    ingress-controller 使用的镜像是 quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.25.1,下载的时间较长,耐心等待即可,也可提前准备好镜像。

    [root@master ingress-nginx]# kubectl get pods -n ingress-nginx
    NAME                                        READY   STATUS    RESTARTS   AGE
    nginx-ingress-controller-79f6884cf6-8nb6f   1/1     Running   0          35m

    2、定义 ingress-controller 的 service 资源

    运行为pod资源的Ingress控制器进程接入外部的请求流量常用的有两种解决方案:

    1)以deployment控制器管理Ingress控制器的pod资源,并通过NodePort或LoadBalancer类型的service对象为其接入集群外部的请求流量,这就意味着,定义一个Ingress控制器时,必须在其前端定义一个专用的service资源

    2)借助于DaemonSet控制器,将Ingress控制器的pod资源各自以单一实例的方式运行于集群的所有或部分工作节点之上,并配置这类pod对象以hostPort或hostNetwork的方式在当前节点接入外部流量。

    这里使用nodePort方式,下载官网nodePort文件:

    [root@master ingress-nginx]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/service-nodeport.yaml
     1 [root@master ingress-nginx]# vim service-nodeport.yaml
     2 apiVersion: v1
     3 kind: Service
     4 metadata:
     5   name: ingress-nginx
     6   namespace: ingress-nginx
     7   labels:
     8     app.kubernetes.io/name: ingress-nginx
     9     app.kubernetes.io/part-of: ingress-nginx
    10 spec:
    11   type: NodePort
    12   ports:
    13     - name: http
    14       port: 80
    15       targetPort: 80
    16       protocol: TCP
    17       nodePort: 30080
    18     - name: https
    19       port: 443
    20       targetPort: 443
    21       protocol: TCP
    22       nodePort: 30443
    23   selector:
    24     app.kubernetes.io/name: ingress-nginx
    25     app.kubernetes.io/part-of: ingress-nginx
    26  
    27 ---
    View Code

    上面的文件中,使用了宿主机的固定端口(30080,30443),需保证宿主机的这两个端口未占用。

    [root@master ingress-nginx]# kubectl apply -f service-nodeport.yaml 
    service/ingress-nginx created
    [root@master ingress-nginx]# kubectl get svc -n ingress-nginx
    NAME            TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
    ingress-nginx   NodePort   10.106.97.57   <none>        80:30080/TCP,443:30443/TCP   13s

    3、定义Ingress

    [root@master resourcelist]# vim ingress-demo.yaml
     1 apiVersion: extensions/v1beta1  # api版本
     2 kind: Ingress  # 清单类型
     3 metadata:  # 元数据
     4   name: ingress-myapp  # ingress的名称
     5   namespace: default  # 所属名称空间
     6   annotations:  # 注解信息
     7     kubernetes.io/ingress.class: "nginx"
     8 spec:  # 规格
     9   rules:  # 定义后端转发的规则
    10   - host: myapp.magedu.com  # 通过域名进行转发
    11     http:
    12       paths:
    13       - path:  # 配置访问路径,如果通过url进行转发,需要修改;空默认为访问的路径为"/"
    14         backend:  # 配置后端服务
    15           serviceName: myapp
    16           servicePort: 80
    17  
    18 ---
    19 apiVersion: v1
    20 kind: Service
    21 metadata:
    22   name: myapp
    23   namespace: default
    24 spec:
    25   selector:
    26     app: myapp
    27     release: canary
    28   type: ClusterIP
    29   ports:
    30   - port: 80
    31     targetPort: 80
    32  
    33 ---
    34 apiVersion: apps/v1
    35 kind: Deployment
    36 metadata:
    37   name: myapp-deploy
    38   namespace: default
    39 spec:
    40   replicas: 5
    41   selector:
    42     matchLabels:
    43       app: myapp
    44       release: canary
    45   template:
    46     metadata:
    47       labels:
    48         app: myapp
    49         release: canary
    50     spec:
    51       containers:
    52       - name: myapp
    53         image: ikubernetes/myapp:v2
    54         ports:
    55         - name: http
    56           containerPort: 80
    View Code
    [root@master resourcelist]# kubectl apply -f ingress-demo.yaml              
    ingress.extensions/ingress-myapp created
    service/myapp created
    deployment.apps/myapp-deploy created

    修改本地hosts文件,进行测试访问:

    192.168.56.12 myapp.magedu.com
    192.168.56.13 myapp.magedu.com

    4、总结
    从前面的部署过程中,可以再次进行总结部署的流程如下:
    ①到官网下载ingress-controller一键部署文件(mandatory.yaml);
    ②部署Ingress-controller的service,以实现接入集群外部流量;
    ③部署后端的服务,如myapp,并通过service进行暴露;
    ④定义Ingress规则,使Ingress-controller和后端服务的Pod组进行关联。 

     

    六、构建TLS站点

    (1)准备证书

    [root@master ingress]# openssl genrsa -out tls.key 2048 
    Generating RSA private key, 2048 bit long modulus
    .......+++
    .......................+++
    e is 65537 (0x10001)
     
    [root@master ingress]# openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=myapp.magedu.com

    (2)生成secret

    [root@master ingress]# kubectl create secret tls myapp-ingress-secret --cert=tls.crt --key=tls.key
    secret/tomcat-ingress-secret created
    [root@master ingress]# kubectl get secret
    NAME                   TYPE                                  DATA   AGE
    default-token-9qfpd    kubernetes.io/service-account-token   3      6d22h
    myapp-ingress-secret   kubernetes.io/tls                     2      21m

    (3)创建ingress

    cat ingress-tls-demo.yaml
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: ingress-myapp-tls
      namespace: default
      annotations:
        kubernetes.io/ingress.class: "nginx"
    spec:
      tls:
      - hosts:
        - myapp.magedu.com
        secretName: tomcat-ingress-secret
      rules:
      - host: myapp.magedu.com
        http:
          paths:
          - path:
            backend:
              serviceName: myapp
              servicePort: 80
     
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: myapp
      namespace: default
    spec:
      selector:
        app: myapp
        release: canary
      type: ClusterIP
      ports:
      - port: 80
        targetPort: 80
     
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: myapp-deploy
      namespace: default
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: myapp
          release: canary
      template:
        metadata:
          labels:
            app: myapp
            release: canary
        spec:
          containers:
          - name: myapp
            image: ikubernetes/myapp:v2
            ports:
            - name: http
              containerPort: 80
    [root@master resourcelist]# kubectl apply -f ingress-tls-demo.yaml
    ingress.extensions/ingress-myapp-tls created
    service/myapp created
    deployment.apps/myapp-deploy created
    [root@master resourcelist]# kubectl get ingress
    NAME                HOSTS              ADDRESS   PORTS     AGE
    ingress-myapp-tls   myapp.magedu.com             80, 443   10s

    (4)访问测试:https://myapp.magedu.com:30443

     =========================================================================================================

    k8s修改ingress默认80端口

    有时候80端口被其他服务占用,我们想修改ingress的默认端口

    kubectl edit daemonset nginx-ingress-controller -n ingress-nginx



    containers:
    - args:
    - /nginx-ingress-controller
    - --default-backend-service=$(POD_NAMESPACE)/default-http-backend
    - --configmap=$(POD_NAMESPACE)/nginx-configuration
    - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
    - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
    - --annotations-prefix=nginx.ingress.kubernetes.io




    在后面加上

    - --http-port=8080
    - --https-port=8443 


    删除pod,k8s将重新使用新配置,生成一个新的pod

    作者:张瑞153169

    -------------------------------------------

    个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!

    如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,在此感谢!

  • 相关阅读:
    C#中使用Oracle存储过程返回结果集
    微信公众平台开发教程(九)微信公众平台通用开发框架
    微信公众平台开发教程(八)Session处理
    微信公众平台开发教程(七)安全策略
    微信公众平台开发教程(六)获取个性二维码
    微信公众平台开发教程(五)自定义菜单(含实例源码)
    微信公众平台开发教程(三) 基础框架搭建
    微信公众平台开发教程(一) 微信公众账号注册流程
    当"唐僧"没那么容易
    C#编程总结(六)异步编程
  • 原文地址:https://www.cnblogs.com/zhangrui153169/p/14568867.html
Copyright © 2020-2023  润新知