ingress-nginx实现原理和部署
作者:mmseoamin日期:2023-12-19

一、ingress 简介

Ingress-nginx是基于Nginx的一个开源反向代理软件,用于Kubernetes集群中运行的应用程序。它为Kubernetes集群中的服务提供了外部访问和负载均衡功能。Ingress-nginx通过HTTP或HTTPS路由网络流量来管理应用程序的入口。在Kubernetes中配置Ingress时,可以使用Ingress规则指定需要路由的主机名和路径,并将它们转发到相应的后端服务。

Ingress-nginx具有以下特点:

  • 开源免费:Ingress-nginx是一个完全免费、开源的软件,可以在GitHub上获取源代码。
  • 支持多种协议:Ingress-nginx支持TCP、UDP、HTTP和HTTPS等多种协议。
  • 高性能:Ingress-nginx使用Nginx作为反向代理,具有高性能和稳定性。
  • 可扩展性:Ingress-nginx可以通过添加插件来扩展其功能。
  • 易于使用:Ingress-nginx具有简单易用的API和用户友好的文档,使其容易配置和管理。

    总之,Ingress-nginx是一个非常强大的工具,用于Kubernetes集群中的应用程序管理和负载均衡。

    Ingress 是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。

    Ingress 可以提供负载均衡、SSL 终结和基于名称的虚拟托管。

    1.1 什么是ingress

    Ingress 公开了从集群外部到集群内服务的 HTTP 和 HTTPS 路由。流量路由由 Ingress 资源上定义的规则控制。

    下面是一个将所有流量都发送到同一 Service 的简单 Ingress 示例:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QdfEh8iq-1681962991771)(images/1.png)]

    Ingress 可为 Service 提供外部可访问的 URL、负载均衡流量、终止 SSL/TLS,以及基于名称的虚拟托管。Ingress 控制器通常负责通过负载均衡器来实现 Ingress,尽管它也可以配置边缘路由器或其他前端来帮助处理流量。

    Ingress 不会公开任意端口或协议。将 HTTP 和 HTTPS 以外的服务公开到 Internet 时,通常使用 Service.Type=NodePort 或 Service.Type=LoadBalancer 类型的 Service。

    1.2 ingress组成

    K8s集群对外暴露服务的方式目前只有三种:Loadblancer;Nodeport;ingress。前两种熟悉起来比较快,而且使用起来也比较方便,在此就不进行介绍了。下面详细讲解下ingress这个服务。

    ​ ingress由两部分组成:

    ingress controller:将新加入的Ingress转化成Nginx的配置文件并使之生效。

    ingress服务:将Nginx的配置抽象成一个Ingress对象,每添加一个新的服务只需写一个新的Ingress的yaml文件即可。

    ​ ingress controller目前主要有两种:

    基于nginx服务的ingress controller和基于traefik的ingress controller。其中traefik的ingress controller,目前支持http和https协议。由于对nginx比较熟悉,而且需要使用TCP负载,所以在此我们选择的是基于nginx服务的ingress controller。基于nginx服务的ingress controller根据不同的开发公司,又分为k8s社区的ingres-nginx和nginx公司的nginx-ingress。在此根据github上的活跃度和关注人数,我们选择的是k8s社区的ingres-nginx。

    k8s社区提供的ingress,github地址如下:https://github.com/kubernetes/ingress-nginx

    nginx社区提供的ingress,github地址如下:https://github.com/nginxinc/kubernetes-ingress

    1.3 ingress的工作原理

    ingress具体的工作原理如下:

    1. ingress contronler通过与k8s的api进行交互,动态的去感知k8s集群中ingress服务规则的变化,然后读取它,并按照定义的ingress规则,转发到k8s集群中对应的service。
    2. 这个ingress规则写明了哪个域名对应k8s集群中的哪个service,然后再根据ingress-controller中的nginx配置模板,生成一段对应的nginx配置。
    3. 然后再把该配置动态的写到ingress-controller的pod里,该ingress-controller的pod里面运行着一个nginx服务,控制器会把生成的nginx配置写入到nginx的配置文件中,然后reload一下,使其配置生效,以此来达到域名分配置及动态更新的效果。

    1.4 ingress可以解决的问题

    1)动态配置服务

    如果按照传统方式, 当新增加一个服务时, 我们可能需要在流量入口加一个反向代理指向我们新的k8s服务. 而如果用了Ingress, 只需要配置好这个服务, 当服务启动时, 会自动注册到Ingress的中, 不需要而外的操作。

    2)减少不必要的端口暴露

    配置过k8s的都清楚, 第一步是要关闭防火墙的, 主要原因是k8s的很多服务会以NodePort方式映射出去, 这样就相当于给宿主机打了很多孔, 既不安全也不优雅. 而Ingress可以避免这个问题, 除了Ingress自身服务可能需要映射出去, 其他服务都不要用NodePort方式。

    二、部署ingress-nginx

    镜像下载

    镜像下载地址

    docker pull xin053/controller:v1.6.4
    docker pull dyrnq/kube-webhook-certgen:v20230312-helm-chart-4.5.2-28-g66a760794
    

    2.1 创建namespace

    apiVersion: v1
    kind: Namespace
    metadata:
      labels:
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
      name: ingress-nginx
    

    2.2 创建ConfigMap

    apiVersion: v1
    data:
      allow-snippet-annotations: "true"
    kind: ConfigMap
    metadata:
      labels:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.6.4
      name: ingress-nginx-controller
      namespace: ingress-nginx
    

    2.3 创建RBAC

    ---
    apiVersion: v1
    automountServiceAccountToken: true
    kind: ServiceAccount
    metadata:
      labels:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.6.4
      name: ingress-nginx
      namespace: ingress-nginx
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      labels:
        app.kubernetes.io/component: admission-webhook
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.6.4
      name: ingress-nginx-admission
      namespace: ingress-nginx
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      labels:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.6.4
      name: ingress-nginx
      namespace: ingress-nginx
    rules:
    - apiGroups:
      - ""
      resources:
      - namespaces
      verbs:
      - get
    - apiGroups:
      - ""
      resources:
      - configmaps
      - pods
      - secrets
      - endpoints
      verbs:
      - get
      - list
      - watch
    - apiGroups:
      - ""
      resources:
      - services
      verbs:
      - get
      - list
      - watch
    - apiGroups:
      - networking.k8s.io
      resources:
      - ingresses
      verbs:
      - get
      - list
      - watch
    - apiGroups:
      - networking.k8s.io
      resources:
      - ingresses/status
      verbs:
      - update
    - apiGroups:
      - networking.k8s.io
      resources:
      - ingressclasses
      verbs:
      - get
      - list
      - watch
    - apiGroups:
      - coordination.k8s.io
      resourceNames:
      - ingress-nginx-leader
      resources:
      - leases
      verbs:
      - get
      - update
    - apiGroups:
      - coordination.k8s.io
      resources:
      - leases
      verbs:
      - create
    - apiGroups:
      - ""
      resources:
      - events
      verbs:
      - create
      - patch
    - apiGroups:
      - discovery.k8s.io
      resources:
      - endpointslices
      verbs:
      - list
      - watch
      - get
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      labels:
        app.kubernetes.io/component: admission-webhook
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.6.4
      name: ingress-nginx-admission
      namespace: ingress-nginx
    rules:
    - apiGroups:
      - ""
      resources:
      - secrets
      verbs:
      - get
      - create
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      labels:
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.6.4
      name: ingress-nginx
    rules:
    - apiGroups:
      - ""
      resources:
      - configmaps
      - endpoints
      - nodes
      - pods
      - secrets
      - namespaces
      verbs:
      - list
      - watch
    - apiGroups:
      - coordination.k8s.io
      resources:
      - leases
      verbs:
      - list
      - watch
    - apiGroups:
      - ""
      resources:
      - nodes
      verbs:
      - get
    - apiGroups:
      - ""
      resources:
      - services
      verbs:
      - get
      - list
      - watch
    - apiGroups:
      - networking.k8s.io
      resources:
      - ingresses
      verbs:
      - get
      - list
      - watch
    - apiGroups:
      - ""
      resources:
      - events
      verbs:
      - create
      - patch
    - apiGroups:
      - networking.k8s.io
      resources:
      - ingresses/status
      verbs:
      - update
    - apiGroups:
      - networking.k8s.io
      resources:
      - ingressclasses
      verbs:
      - get
      - list
      - watch
    - apiGroups:
      - discovery.k8s.io
      resources:
      - endpointslices
      verbs:
      - list
      - watch
      - get
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      labels:
        app.kubernetes.io/component: admission-webhook
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.6.4
      name: ingress-nginx-admission
    rules:
    - apiGroups:
      - admissionregistration.k8s.io
      resources:
      - validatingwebhookconfigurations
      verbs:
      - get
      - update
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      labels:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.6.4
      name: ingress-nginx
      namespace: ingress-nginx
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: ingress-nginx
    subjects:
    - kind: ServiceAccount
      name: ingress-nginx
      namespace: ingress-nginx
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      labels:
        app.kubernetes.io/component: admission-webhook
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.6.4
      name: ingress-nginx-admission
      namespace: ingress-nginx
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: ingress-nginx-admission
    subjects:
    - kind: ServiceAccount
      name: ingress-nginx-admission
      namespace: ingress-nginx
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      labels:
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.6.4
      name: ingress-nginx
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: ingress-nginx
    subjects:
    - kind: ServiceAccount
      name: ingress-nginx
      namespace: ingress-nginx
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      labels:
        app.kubernetes.io/component: admission-webhook
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.6.4
      name: ingress-nginx-admission
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: ingress-nginx-admission
    subjects:
    - kind: ServiceAccount
      name: ingress-nginx-admission
      namespace: ingress-nginx
    

    2.4 创建Service

    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.6.4
      name: ingress-nginx-controller
      namespace: ingress-nginx
    spec:
      #externalTrafficPolicy: Cluster 
      ipFamilies:
      - IPv4
      ipFamilyPolicy: SingleStack
      ports:
      - appProtocol: http
        name: http
        port: 80
        protocol: TCP
        targetPort: http
      - appProtocol: https
        name: https
        port: 443
        protocol: TCP
        targetPort: https
      selector:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
      type: ClusterIP 
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.6.4
      name: ingress-nginx-controller-admission
      namespace: ingress-nginx
    spec:
      ports:
      - appProtocol: https
        name: https-webhook
        port: 443
        targetPort: webhook
      selector:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
      type: ClusterIP
    

    2.5 创建DaemonSet

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      labels:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.6.4
      name: ingress-nginx-controller
      namespace: ingress-nginx
    spec:
      minReadySeconds: 0
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app.kubernetes.io/component: controller
          app.kubernetes.io/instance: ingress-nginx
          app.kubernetes.io/name: ingress-nginx
      template:
        metadata:
          labels:
            app.kubernetes.io/component: controller
            app.kubernetes.io/instance: ingress-nginx
            app.kubernetes.io/name: ingress-nginx
            app.kubernetes.io/part-of: ingress-nginx
            app.kubernetes.io/version: 1.6.4
        spec:
          containers:
          - args:
            - /nginx-ingress-controller
            - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
            - --election-id=ingress-nginx-leader
            - --controller-class=k8s.io/ingress-nginx
            - --ingress-class=nginx
            - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
            - --validating-webhook=:8443
            - --validating-webhook-certificate=/usr/local/certificates/cert
            - --validating-webhook-key=/usr/local/certificates/key
            env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: LD_PRELOAD
              value: /usr/local/lib/libmimalloc.so
            image: 192.168.17.40/ingress-nginx/controller:v1.6.4
            imagePullPolicy: IfNotPresent
            lifecycle:
              preStop:
                exec:
                  command:
                  - /wait-shutdown
            livenessProbe:
              failureThreshold: 5
              httpGet:
                path: /healthz
                port: 10254
                scheme: HTTP
              initialDelaySeconds: 10
              periodSeconds: 10
              successThreshold: 1
              timeoutSeconds: 1
            name: controller
            ports:
            - containerPort: 80
              name: http
              protocol: TCP
            - containerPort: 443
              name: https
              protocol: TCP
            - containerPort: 8443
              name: webhook
              protocol: TCP
            readinessProbe:
              failureThreshold: 3
              httpGet:
                path: /healthz
                port: 10254
                scheme: HTTP
              initialDelaySeconds: 10
              periodSeconds: 10
              successThreshold: 1
              timeoutSeconds: 1
            resources:
              requests:
                cpu: 100m
                memory: 90Mi
            securityContext:
              allowPrivilegeEscalation: true
              capabilities:
                add:
                - NET_BIND_SERVICE
                drop:
                - ALL
              runAsUser: 101
            volumeMounts:
            - mountPath: /usr/local/certificates/
              name: webhook-cert
              readOnly: true
          dnsPolicy: ClusterFirstWithHostNet
          nodeSelector:
            kubernetes.io/os: linux
            ingress: "true" 
          serviceAccountName: ingress-nginx
          terminationGracePeriodSeconds: 300
          volumes:
          - name: webhook-cert
            secret:
              secretName: ingress-nginx-admission
    

    2.6 创建Job

    ​ 当ingress-nginx-controller创建完成后再去创建ingress-nginx-admission-create和ingress-nginx-admission-patch

    ​ 在此会使用kube-webhook-certgen:v20230312-helm-chart-4.5.2-28-g66a760794创建ingress-nginx-admission。

    ingress-nginx-admission 是 Kubernetes Ingress-Nginx 控制器的一个插件,其作用是验证使用该控制器创建的 Ingress 对象的配置是否正确,并确保它们可以成功部署和运行。

    具体来说,ingress-nginx-admission 插件会拦截 Ingress 对象的创建或更新请求,并执行以下操作:

    • 验证 Ingress 规则中所定义的后端服务是否存在;
    • 验证 Ingress 规则中指定的 TLS 证书是否存在;
    • 通过发送 HTTP 请求测试后端服务是否可达;
    • 检查 Ingress 中的注释以确定是否需要启用一些功能;
    • 进行其他相关的验证,例如检查主机名、路径等。

      如果所有的验证都通过,则 Ingress 对象将被创建或更新。否则,请求将被拒绝,并返回相应的错误信息,从而帮助用户及时发现配置问题并进行修复。

      总之,ingress-nginx-admission 在 Kubernetes 中起着非常重要的作用,它可以保证 Ingress 规则的正确性和有效性,减少因配置错误而导致的故障和损失,提高整个系统的可靠性和稳定性。

      apiVersion: batch/v1
      kind: Job
      metadata:
        labels:
          app.kubernetes.io/component: admission-webhook
          app.kubernetes.io/instance: ingress-nginx
          app.kubernetes.io/name: ingress-nginx
          app.kubernetes.io/part-of: ingress-nginx
          app.kubernetes.io/version: 1.7.0
        name: ingress-nginx-admission-create
        namespace: ingress-nginx
      spec:
        template:
          metadata:
            labels:
              app.kubernetes.io/component: admission-webhook
              app.kubernetes.io/instance: ingress-nginx
              app.kubernetes.io/name: ingress-nginx
              app.kubernetes.io/part-of: ingress-nginx
              app.kubernetes.io/version: 1.7.0
            name: ingress-nginx-admission-create
          spec:
            containers:
            - args:
              - create
              - --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
              - --namespace=$(POD_NAMESPACE)
              - --secret-name=ingress-nginx-admission
              env:
              - name: POD_NAMESPACE
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.namespace
              image: 192.168.17.40/ingress-nginx/kube-webhook-certgen:v20230312-helm-chart-4.5.2-28-g66a760794
              imagePullPolicy: IfNotPresent
              name: create
              securityContext:
                allowPrivilegeEscalation: false
            nodeSelector:
              kubernetes.io/os: linux
            restartPolicy: OnFailure
            securityContext:
              fsGroup: 2000
              runAsNonRoot: true
              runAsUser: 2000
            serviceAccountName: ingress-nginx-admission
      ---
      apiVersion: batch/v1
      kind: Job
      metadata:
        labels:
          app.kubernetes.io/component: admission-webhook
          app.kubernetes.io/instance: ingress-nginx
          app.kubernetes.io/name: ingress-nginx
          app.kubernetes.io/part-of: ingress-nginx
          app.kubernetes.io/version: 1.7.0
        name: ingress-nginx-admission-patch
        namespace: ingress-nginx
      spec:
        template:
          metadata:
            labels:
              app.kubernetes.io/component: admission-webhook
              app.kubernetes.io/instance: ingress-nginx
              app.kubernetes.io/name: ingress-nginx
              app.kubernetes.io/part-of: ingress-nginx
              app.kubernetes.io/version: 1.7.0
            name: ingress-nginx-admission-patch
          spec:
            containers:
            - args:
              - patch
              - --webhook-name=ingress-nginx-admission
              - --namespace=$(POD_NAMESPACE)
              - --patch-mutating=false
              - --secret-name=ingress-nginx-admission
              - --patch-failure-policy=Fail
              env:
              - name: POD_NAMESPACE
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.namespace
              image: 192.168.17.40/ingress-nginx/kube-webhook-certgen:v20230312-helm-chart-4.5.2-28-g66a760794
              imagePullPolicy: IfNotPresent
              name: patch
              securityContext:
                allowPrivilegeEscalation: false
            nodeSelector:
              kubernetes.io/os: linux
            restartPolicy: OnFailure
            securityContext:
              fsGroup: 2000
              runAsNonRoot: true
              runAsUser: 2000
            serviceAccountName: ingress-nginx-admission
      

      2.7 创建IngressClass

      通过它来识别ingress

      apiVersion: networking.k8s.io/v1
      kind: IngressClass
      metadata:
        labels:
          app.kubernetes.io/component: controller
          app.kubernetes.io/instance: ingress-nginx
          app.kubernetes.io/name: ingress-nginx
          app.kubernetes.io/part-of: ingress-nginx
          app.kubernetes.io/version: 1.6.4
        name: nginx
      spec:
        controller: k8s.io/ingress-nginx
      

      2.8 创建ValidatingWebhookConfiguration

      ValidatingWebhookConfiguration 是 Kubernetes 中的一种资源对象,它用于配置 Admission Controller 中的 Validating Webhook,从而对 Kubernetes API 对象进行验证(validation)。

      具体来说,ValidatingWebhookConfiguration 可以定义一个或多个 ValidatingWebhook,每个 ValidatingWebhook 都会配置一个 HTTP 或 HTTPS 端点,用于接收 Kubernetes API 对象的 admission 请求。当一个 API 请求到达 Admission Controller 时,它会被发送到每个定义的 ValidatingWebhook 的端点上,在这里进行验证操作,如果所有的验证都通过了,该请求才会继续处理;否则,请求将被拒绝,并返回验证失败的错误信息。

      通过 ValidatingWebhookConfiguration,Kubernetes 用户可以方便地自定义验证规则,应用于 Kubernetes API 中的各种对象,例如 Pod、Deployment、Service 等。此外,通过使用 ValidatingWebhook,用户可以在不影响集群状态的情况下,对现有的 Kubernetes 集群进行安全升级和更新。

      apiVersion: admissionregistration.k8s.io/v1
      kind: ValidatingWebhookConfiguration
      metadata:
        labels:
          app.kubernetes.io/component: admission-webhook
          app.kubernetes.io/instance: ingress-nginx
          app.kubernetes.io/name: ingress-nginx
          app.kubernetes.io/part-of: ingress-nginx
          app.kubernetes.io/version: 1.7.0
        name: ingress-nginx-admission
      webhooks:
      - admissionReviewVersions:
        - v1
        clientConfig:
          service:
            name: ingress-nginx-controller-admission
            namespace: ingress-nginx
            path: /networking/v1/ingresses
        failurePolicy: Fail
        matchPolicy: Equivalent
        name: validate.nginx.ingress.kubernetes.io
        rules:
        - apiGroups:
          - networking.k8s.io
          apiVersions:
          - v1
          operations:
          - CREATE
          - UPDATE
          resources:
          - ingresses
        sideEffects: None
      

      三、补充

      1、在客户端访问我们k8s服务时,四层调度器本身是没有办法解除ssl会话的,这就意味着客户端必须与后端服务器(pod)之间直接建立ssl会话,这里还有个显著的问题在于如果调度器在ssl会话建立以后的下一个请求被调度到第二台服务器上那么这个ssl还要重新建立,因此我们只要认为内部网络是安全的那么我们可以把会话在前端调度器上卸载,但是四层调度是不能卸载的,因此我们需要七层的负载均衡机制。因此如果他们是http服务我们又期望构建https,那么我们只需要他在互联网上这个不安全的网络中传输实现https,内网中使用http,因此我们需要使用卸载器,但是我们Service调度时,无论是iptables还是ipvs都只是四层调度,因此也就意味着如果你想要在k8s上运行一个应用基于https提供服务,我们就必须得在后端每一个pod上配置https,因为只有这样他们才会建立起https联系,所以我们现在也期望在接入那一层上就能够卸载ssl,向内部调度时就不再是ssl了。对这种需求,k8s采用一种很独特的方式来实现,我们在整个集群中,在进行调度时后端被代理的pod资源是不配置https的,就是明文的http,但是我使用一个独特的调度器(运行在pod中),对于此pod来讲,其是一个运行在七层(用户空间)的正常的应用程序,比如nginx,haproxy等,当用户试图访问某一服务时,我们不让他先去到达前端的service,而是先到这个pod,然后pod与pod之间不需要service而是直接通信来完成反向代理,我们用一个pod来反代至后端我们真正提供服务的pod,此前我们用service代理的,现在用pod,而这个pod如果需要被访问到那么还是需要经过service,因此客户端经过此pod的service调度以后,与我们专门配置了https的此pod进行交互,这里的service我们定义成nodePort,依然没有什么问题,依然老路径还是存在的,但是等到达这个pod以后由此pod直接代理至两个明文的pod,因此此pod就成为https的会话卸载器了。如果这种方式进行调度那么调度方式如下: client --> LB --> nodePort --> service -->会话卸载器pod --> 后端pod 这种方式性能肯定会非常非常差,如图。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u7VBNkrL-1681962991774)(images/2)]

      2、其实我们还可以这样干,可以让我们pod直接共享我们节点的网络名称空间,于是,上述中的会话卸载器pod我们可以直接让他共享节点网络名称空间,这就意味着其监听着宿主机的地址,这样我们客户端的请求就可以之间到达这个pod,然后再由他进行调度。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-reHnQBUR-1681962991775)(images/3)]

      3、在一个节点上运行的容器,容器可以使用自己的虚拟网络,也可以共享宿主机的网络,如果这个容器共享宿主机的网络也就意味着这个容器内的进程一旦监听套接字时它监听的是宿主机的地址,相当于一个进程运行在宿主机上一样的,这样一来这个pod在每个节点上就只能运行一个了,一般来讲集群中只有一个,那么其只需要运行在集群的某一个节点即可,但是如果 监听在节点的端口时就会有问题,service时无论访问哪一个节点的端口都行,因为你访问哪一个节点的nodePort他都能通过它的ip地址送达到后端pod上,但是现在这个Pod要监听节点的网络名称空间,并且通过这个节点的网络名称空间直达这个pod,那么如果运行这种类型的pod那么就一定只能运行在一个节点上,访问时客户端就只能访问这个节点,并且如果这个节点挂了呢?

      4、要解决这个问题,我们可以用DaemonSet控制器,它可以在每个节点上都运行相应的pod 副本并且只运行一个,这样假如我们有三个节点那么我们三个节点上都可以运行这个pod。这样就都能实现代理和负载均衡,但是又回到了调度到哪一个节点都可以的问题,这样无论哪个节点挂掉了都还是可以访问到,但是如果我们有太多的节点那么每个节点都运行一个这样的pod就太占资源。daemonset还可以让pod运行在有限的节点的范围上(部分节点),于是再将来做k8s集群时可以这样干,比如我们有三千个节点,那么我们专门拿三个节点出来做pod的接入式的负载均衡的专用主机,并且给这三个节点打上污点让其它pod无法调度上来,然后我们就定义这个DaemonSet控制器上的pod只运行在这三个节点上各自运行一份并且能容忍这些污点,所以这三个主机在集群中只允许这一个类型的pod,专门负责为集群接入外部的七层调度的流量。而这个pod在k8s中有个专门的称呼叫 Ingress Controller。这个Ingress Controller比较独特,之前讲的DaemonSet,deployment,replacSet等控制器都不一样,DaemonSet deployment,replaciSet等等都是作为Controller manager的一部分存在,众多控制器都是作为Controller manager的一个子组件作为其组成部分组成的。而Ingress Controller却是自己独立运行的一个或一组pod资源,它通常就是一个应用程序,这个应用程序就是拥有七层代理能力和调度能力的应用程序,目前k8s上的选择有四种,其中最不受待见的就是Haproxy,一般默认是nginx,现在在服务网格中大家比较倾向Envoy,当然还有其它与nginx相竞争的据说本来就是为微服务而生的Traefik,所以用Ingress Controller时会发现我们有三种选择:

      a、nginx:这是后来改造的

      b、Traefik:这种设计就是为微服务这种动态生成而生的

      c、Envoy :去做微服务的大家都比较倾向于Envoy

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-93pM8RcG-1681962991776)(images/4)]

      5、作为调度器,有时候要调度不只一个后端服务,假如有一个调度器pod,后端有一组pod提供电商服务,第二组pod提供了社交服务,第三组pod提供了论坛服务,第四组pod提供了网关服务。那么我们这四组http服务怎么能够分别调度呢?

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PSPDdDnv-1681962991777)(images/5)]

      a、从nginx的角度来讲,接入服务端时我们通过uptream_server即可,但是接入客户端时我们应该如何标识这四种不同的请求呢,首先我们可以在nginx上做四个虚拟主机,在四个主机名上做四个主机,每一个主机名对应一组后端的pod。那万一我们没那么多主机名呢?此时我们可以通过不同的路径来做url映射,然后每一组路径就映射到一组后端pod上,但是pod存在生命周期,随时都可能挂掉替换为一个新pod,新pod的ip就会变了,另外我们pod的应用的规模也可以动态伸缩的,我们简单改一下副本数其数量也会变,这种一变前面代理的配置也就无效了,我们service通过关联标签来解决这个问题,而且service随时 watch着api server上的api时刻来关注自己关联的slector的资源是否变动了,只要变动我们api server就会立即通知service然后service立即改变。 所以service通过label selector始终关联着对应label能适配的后端pod,无论怎么变都能应付而且能及时作出反应,那么此处nginx运行在pod中也就意味着这个配置是在pod内部并且后端pod随时还会发生变动,Ingress 也会时刻watch着api 中的后端pod资源的改变。那它怎么知道这是哪个pod资源呢?Ingress Controller自己没有这个能力,它并不知道目前符合自己条件关联的被代理的pod资源有哪些,它必须借助于service来实现,我们要想定义一个这种调度能力功能其实还是需要建service,这个service通过label selector关联至后端的pod上来,但这个service不是被当做被代理时的中间节点,它仅仅是帮忙分类的,这个service 关联了几个pod那么我们就将这几个pod配置写在这个upstream中,调度时是不会经过service的,service在此处仅仅是帮忙分组的,分完组以后我们需要得到的也不是service的IP,而是pod的ip,因此此时可以使用headless service,但是这个service却没有用,是不是headless都无所谓,它只要帮忙完成分组知道找哪几个pod就可以了,pod一变,service对应的资源也就变了,问题是变了后这个结果怎么反应到这个配置文件中来,此时需要依赖于一个专门的资源 Ingress。

      6、在k8s上有一种特殊的资源叫Ingress,Ingress 和Ingress Controller是两回事,我们定义一个Ingress 时就是说了它其实就是定义我们期望这个Ingress Controller是如何给我们建一个前端(可能是一个虚拟主机,也可能是一个url映射)接入层,同时又给我们定义一个后端upstream_server,这个upstream_server中有几个主机 Ingress是通过这个service 得到的,并且Ingress有一个特点,作为资源来讲他可以通过编辑注入到Ingress Controller里面来,直接把它注入并保存为配置文件,而且一旦Ingress发现Service选定的后端的pod资源发生改变了,这个改变一定会及时返回到Ingress中,这个Ingress会及时注入到这个前端调度器pod中,就是注入到upstream配置文件中,而且还能触发这个pod中的主容器中的进程重载配置文件。所以我们要想使用这个功能我们需要在集群中:

      a、要有个service去对后端某一个特定类型的pod资源进行分类,这个service只是起分类作用的。

      b、Ingress基于这个分类识别出有几个pod,并且识别其ip地址是什么,并且将这个ip地址返回的结果生成配置信息注入到upstream_server(以nginx为例),但是nginx又不是特别适用这个场景,每次变动都在重载,如果是Traefik和Envoy 等天生就是为这种场景而生的,只要动了就加载生效,不需要重载。(它可以监控这个配置文件发生变化,只要发生变化就会动态重载)。

      7、如果我们想要使用代理,我们应该怎么做?

      a、需要先部署一个Ingress Controller,然后部署一个pod进来,这个pod可能本来是空的,没有什么有效的东西,接下来我们要根据自己的需要 通过虚拟主机的方式或者通过url代理的方式来配置一个前端,然后再根据我们Service收集到的后端pod的IP定义成upstream_server,把这些信息反应在Ingress当中由Ingress动态注入到Ingress Controller中才可以

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0fSiAH56-1681962991779)(images/6)]

      b、从图中我们可以看到,当访问我们服务时首先由外部的负载均衡器将请求调度到我们nodePort的Service上,而nodePort上的Service再将请求调度至我们内部的一个pod 叫IngressController上来,Ingress Controller根据Ingress中的定义(虚拟主机或url),每一个主机名对应后面的一组pod资源(通过service分组),因此此处用到两组Service,第一个Service是帮集群接入外部流量的(当然也可以不用,可以把这个Ingress Controller pod运行为共享网络节点网络名称空间方式并且将其定义为Dameset方式运行在特定节点上就可以了),那么我们在定义pod资源时只需要在pod的一个配置选项中加入hostnetwork即可。第二个Service只用来做pod归组不被调度时使用。

      c、接下来我们要使用ingress的功能得先去安装部署Ingress Controller 这个pod,而后再定义Ingress,而后再定义后端pod生成Service,然后再建立关联关系。