# Ingress

我们已经知道,Service 对集群之外暴露服务的主要方式有两种:

  • NodePort
  • LoadBalancer

但是这两种方式,都有一定的缺点:

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

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

# 一、Ingress 原理

Ingress介绍.png

实际上,Ingress 相当于一个七层的负载均衡器,是 k8s 对反向代理的一个抽象,它的工作原理类似于 Nginx可以理解为 Ingress 里面建立了诸多映射规则,Ingress Controller 通过监听这些配置规则并转化为 Nginx 的反向代理配置,然后对外提供服务。

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

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

  1. 用户编写 Ingress 规则,说明那个域名对应 k8s 集群中的哪个 Service;
  2. Ingress Controller 动态感知 Ingress 服务规则的变化,然后生成一段对应的 Nginx 的反向代理配置;
  3. Ingress Controller 会将生成的 Nginx 配置写入到一个运行着的 Nginx 服务中,并动态更新;
  4. 到此为止,其实真正在工作的就是一个 Nginx 了,内部配置了用户定义的请求规则。

image-20210709104809548

# 二、Ingress 使用

# 1. 环境准备

# 1.1 搭建 Ingress 环境

  • 创建 ingress 文件夹,并进去其中

    [root@k8s-master k8s]# mkdir ingress
    [root@k8s-master k8s]# cd ingress/
    [root@k8s-master ingress]# 
    
  • 获取 ingress-nginx(v0.30.0)

    wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
    
    wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
    

    其实就是两个 yaml 文件,下载不了的话可以直接复制下面内容:

    mandatory.yaml

    apiVersion: v1
    kind: Namespace
    metadata:
      name: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    
    ---
    
    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: nginx-configuration
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    
    ---
    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: tcp-services
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    
    ---
    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: udp-services
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: nginx-ingress-serviceaccount
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    
    ---
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: ClusterRole
    metadata:
      name: nginx-ingress-clusterrole
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    rules:
      - apiGroups:
          - ""
        resources:
          - configmaps
          - endpoints
          - nodes
          - pods
          - secrets
        verbs:
          - list
          - watch
      - apiGroups:
          - ""
        resources:
          - nodes
        verbs:
          - get
      - apiGroups:
          - ""
        resources:
          - services
        verbs:
          - get
          - list
          - watch
      - apiGroups:
          - ""
        resources:
          - events
        verbs:
          - create
          - patch
      - apiGroups:
          - "extensions"
          - "networking.k8s.io"
        resources:
          - ingresses
        verbs:
          - get
          - list
          - watch
      - apiGroups:
          - "extensions"
          - "networking.k8s.io"
        resources:
          - ingresses/status
        verbs:
          - update
    
    ---
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: Role
    metadata:
      name: nginx-ingress-role
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    rules:
      - apiGroups:
          - ""
        resources:
          - configmaps
          - pods
          - secrets
          - namespaces
        verbs:
          - get
      - apiGroups:
          - ""
        resources:
          - configmaps
        resourceNames:
          # Defaults to "<election-id>-<ingress-class>"
          # Here: "<ingress-controller-leader>-<nginx>"
          # This has to be adapted if you change either parameter
          # when launching the nginx-ingress-controller.
          - "ingress-controller-leader-nginx"
        verbs:
          - get
          - update
      - apiGroups:
          - ""
        resources:
          - configmaps
        verbs:
          - create
      - apiGroups:
          - ""
        resources:
          - endpoints
        verbs:
          - get
    
    ---
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: RoleBinding
    metadata:
      name: nginx-ingress-role-nisa-binding
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: nginx-ingress-role
    subjects:
      - kind: ServiceAccount
        name: nginx-ingress-serviceaccount
        namespace: ingress-nginx
    
    ---
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: ClusterRoleBinding
    metadata:
      name: nginx-ingress-clusterrole-nisa-binding
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: nginx-ingress-clusterrole
    subjects:
      - kind: ServiceAccount
        name: nginx-ingress-serviceaccount
        namespace: ingress-nginx
    
    ---
    
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-ingress-controller
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    spec:
      replicas: 1
      selector:
        matchLabels:
          app.kubernetes.io/name: ingress-nginx
          app.kubernetes.io/part-of: ingress-nginx
      template:
        metadata:
          labels:
            app.kubernetes.io/name: ingress-nginx
            app.kubernetes.io/part-of: ingress-nginx
          annotations:
            prometheus.io/port: "10254"
            prometheus.io/scrape: "true"
        spec:
          # wait up to five minutes for the drain of connections
          terminationGracePeriodSeconds: 300
          serviceAccountName: nginx-ingress-serviceaccount
          nodeSelector:
            kubernetes.io/os: linux
          containers:
            - name: nginx-ingress-controller
              image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
              args:
                - /nginx-ingress-controller
                - --configmap=$(POD_NAMESPACE)/nginx-configuration
                - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
                - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
                - --publish-service=$(POD_NAMESPACE)/ingress-nginx
                - --annotations-prefix=nginx.ingress.kubernetes.io
              securityContext:
                allowPrivilegeEscalation: true
                capabilities:
                  drop:
                    - ALL
                  add:
                    - NET_BIND_SERVICE
                # www-data -> 101
                runAsUser: 101
              env:
                - name: POD_NAME
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.name
                - name: POD_NAMESPACE
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.namespace
              ports:
                - name: http
                  containerPort: 80
                  protocol: TCP
                - name: https
                  containerPort: 443
                  protocol: TCP
              livenessProbe:
                failureThreshold: 3
                httpGet:
                  path: /healthz
                  port: 10254
                  scheme: HTTP
                initialDelaySeconds: 10
                periodSeconds: 10
                successThreshold: 1
                timeoutSeconds: 10
              readinessProbe:
                failureThreshold: 3
                httpGet:
                  path: /healthz
                  port: 10254
                  scheme: HTTP
                periodSeconds: 10
                successThreshold: 1
                timeoutSeconds: 10
              lifecycle:
                preStop:
                  exec:
                    command:
                      - /wait-shutdown
    
    ---
    
    apiVersion: v1
    kind: LimitRange
    metadata:
      name: ingress-nginx
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    spec:
      limits:
      - min:
          memory: 90Mi
          cpu: 100m
        type: Container
    

    service-nodeport.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: ingress-nginx
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    spec:
      type: NodePort
      ports:
        - name: http
          port: 80
          targetPort: 80
          protocol: TCP
        - name: https
          port: 443
          targetPort: 443
          protocol: TCP
      selector:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    
    ---
    
  • 创建 ingress-nginx

    [root@k8s-master ingress]# kubectl apply -f ./
    namespace/ingress-nginx created
    configmap/nginx-configuration created
    configmap/tcp-services created
    configmap/udp-services created
    serviceaccount/nginx-ingress-serviceaccount created
    clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
    role.rbac.authorization.k8s.io/nginx-ingress-role created
    rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
    clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
    deployment.apps/nginx-ingress-controller created
    limitrange/ingress-nginx created
    service/ingress-nginx created
    
  • 查看 ingress-nginx

    service/ingress-nginx created
    [root@k8s-master ingress]# kubectl get pod -n ingress-nginx
    NAME                                        READY   STATUS    RESTARTS   AGE
    nginx-ingress-controller-5bb8fb4bb6-zbb8x   1/1     Running   0          30s
    
  • 查看 Service

    [root@k8s-master ingress]# kubectl get svc -n ingress-nginx
    NAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
    ingress-nginx   NodePort   10.109.184.192   <none>        80:32235/TCP,443:31935/TCP   64s
    

# 1.2 准备 Pod 和 Service

  • 为了后面的实验比较方便,创建如下图所示的模型:

    image-20210709105648149

  • 创建 tomcat-nginx.yaml 文件,内容如下:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      namespace: dev
    spec:
      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:
      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
      ports:
      - port: 80
        targetPort: 80
    
    ---
    
    apiVersion: v1
    kind: Service
    metadata:
      name: tomcat-service
      namespace: dev
    spec:
      selector:
        app: tomcat-pod
      clusterIP: None
      type: ClusterIP
      ports:
      - port: 8080
        targetPort: 8080
    
  • 清理环境

    [root@k8s-master ingress]# kubectl delete ns dev
    namespace "dev" deleted
    [root@k8s-master ingress]# kubectl create ns dev
    namespace/dev created
    
  • 创建 Pod 和 Service

    [root@k8s-master ingress]# kubectl apply -f tomcat-nginx.yaml 
    deployment.apps/nginx-deployment created
    deployment.apps/tomcat-deployment created
    service/nginx-service created
    service/tomcat-service created
    
  • 查看 Pod 和 Service

    [root@k8s-master ingress]# kubectl get pod,service -n dev
    NAME                                     READY   STATUS    RESTARTS   AGE
    pod/nginx-deployment-7d7dd5499b-bt96d    1/1     Running   0          69s
    pod/nginx-deployment-7d7dd5499b-bwsnp    1/1     Running   0          69s
    pod/nginx-deployment-7d7dd5499b-pbvzs    1/1     Running   0          69s
    pod/tomcat-deployment-7d5fcd4756-4j2sv   1/1     Running   0          69s
    pod/tomcat-deployment-7d5fcd4756-dv5n8   1/1     Running   0          69s
    pod/tomcat-deployment-7d5fcd4756-lpqbk   1/1     Running   0          69s
    
    NAME                     TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
    service/nginx-service    ClusterIP   None         <none>        80/TCP     69s
    service/tomcat-service   ClusterIP   None         <none>        8080/TCP   69s
    

# 2. HTTP 代理

  • 创建 ingress-http.yaml 文件

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: ingress-http
      namespace: dev
    spec:
      rules:
        - host: nginx.hedon.com #可以通过这个域名来访问我们的Nginx
          http:
            paths:
              - path: /
                backend:
                  serviceName: nginx-service
                  servicePort: 80
        - host: tomcat.hedon.com #可以通过这个域名来访问我们的Tomcat
          http:
            paths:
              - path: /
                backend:
                  serviceName: tomcat-service
                  servicePort: 8080
    

    image-20210709110948793

  • 创建 ingress-http

    [root@k8s-master ingress]# kubectl create -f ingress-http.yaml
    ingress.extensions/ingress-http created
    
  • 查看 ingress

    [root@k8s-master ingress]# kubectl get ingress ingress-http -n dev
    NAME           CLASS    HOSTS                              ADDRESS          PORTS   AGE
    ingress-http   <none>   nginx.hedon.com,tomcat.hedon.com   10.109.184.192   80      4m33s
    
  • 查看对应的 Service

    [root@k8s-master ingress]# kubectl get service -n ingress-nginx
    NAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
    ingress-nginx   NodePort   10.109.184.192   <none>        80:32235/TCP,443:31935/TCP   21m
    
  • 在宿主机的 /etc/hosts 文件中添加如下映射:(172.16.58.200 为 Master 节点的 IP 地址)

    172.16.58.200 nginx.hedon.com
    172.16.58.200 tomcat.hedon.com
    
  • 查看端口

    [root@k8s-master ingress]# kubectl get service -n ingress-nginx
    NAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
    ingress-nginx   NodePort   10.109.184.192   <none>        80:32235/TCP,443:31935/TCP   27m
    
  • 访问

    http://nginx.hedon.com:32235
    http://tomcat.hedon.com:32235
    

# 3. HTTPS 代理

  • 生成证书

    openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=BJ/L=BJ/O=nginx/CN=hedon.com"
    
  • 创建密钥

    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.hedon.com
          - tomcat.hedon.com
          secretName: tls-secret # 指定秘钥
      rules:
      - host: nginx.hedon.com
        http:
          paths:
          - path: /
            backend:
              serviceName: nginx-service
              servicePort: 80
      - host: tomcat.hedon.com
        http:
          paths:
          - path: /
            backend:
              serviceName: tomcat-service
              servicePort: 8080
    
  • 创建 ingress

    [root@k8s-master ingress]# kubectl create -f ingress-https.yaml
    ingress.extensions/ingress-https created
    
  • 查看端口号

    [root@k8s-master ingress]# kubectl get service -n ingress-nginx
    NAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
    ingress-nginx   NodePort   10.109.184.192   <none>        80:32235/TCP,443:31935/TCP   46m
    
  • 访问

    https://nginx.hedon.com:31935
    https://tomcat.hedon.com:31935
    
上次更新: 7/9/2021, 12:00:10 PM