zoukankan      html  css  js  c++  java
  • Kubernetes Ingress管理

    概述

    Kubernetes暴露服务的方式目前有三种:

    • LoadBlancer Service
    • NodePort Service
    • Ingress

    在《kubernetes资源之service》中我们提到,通过NodePort Service和LoadBlancer Service可以将集群内服务对外暴露。但事实上,各自又存在各自的问题:

    • LoadBalancer Service 通常用于与公有云厂商对接,当然也可以自行实现其接口以完成与企业自建的负载均衡器对接。事实上LoadBanlacer Service的工作机制就是调用外部的负载均衡器以实现服务暴露,这依托于外部的负载均衡器。

    • NodePort Service 它的实现机制其实就是在每个node节点上都开启一个端口,并通过iptables的dnat方式将这个宿主机端口映射至集群内部的service ip上。nodeport的问题是,当集群当中的服务越来越多的时候,在每个node上开启的端口也越来越多,最终我们要维护大量的端口映射关系,这使得业务管理工作变得非常复杂。

    为此,从kubernetes 1.2版本开始,官方引入了ingress。

    Ingress架构及原理

    ingress

    针对上述nodeport暴露服务的问题,其实可以有一个解决办法,即使用一个nginx/haproxy这样的负载均衡器,只监听在一个端口上,比如80或443,然后按照域名往后端转发。将这样的负载均衡器以pod的方式运行在集群中,并通过hostNetwork或者nodeport的方式只暴露负载均衡器监听的端口即可。

    这里其实有一个问题,就是nginx/haproxy怎么知道什么域名应该转发至什么后端? 后端应用的pod如果发生变化,nginx/haproxy又应该如何感知到,并同步更新自己的配置文件然后重载配置?

    而这就是ingress的作用。官方的ingress由三部分组成:

    • Ingress类型的资源:其实就是个规则文件,其定义流量的转发规则
    • Ingress Controller: 通过与kubernetes api交互,动态的去感知集群中ingress规则变化,然后读取它,再按照自己的模板生成一段nginx配置,再写到nginx pod里,最后reload一下nginx
    • Nginx:真正负责流量转发的负载均衡器

    事实上,kubernetes已经将ingress Controller和nginx结合到一起,统称之ingress controller,所以在实际部署中,只需要部署ingress controller即可。

    Nginx Ingress配置

    ingress-nginx代码托管地址:https://github.com/kubernetes/ingress-nginx

    ingress-nginx官方文档地址:https://kubernetes.github.io/ingress-nginx/

    1. Ingress Controller部署

    官方的Ingress Controller部署文件: https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.26.2/deploy/static/mandatory.yaml

    下面是我修改过的部署文件:

    ...
    
    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
          hostNetwork: true
          nodeSelector:
            kubernetes.io/os: linux
            ingress-nginx: enable
          tolerations:
            - key: ingress-nginx
              operator: "Exists"
              effect: NoExecute
          containers:
            - name: nginx-ingress-controller
              image: quay.azk8s.cn/kubernetes-ingress-controller/nginx-ingress-controller:0.26.2
              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
    ...
    

    修改说明:

    1. 将nginx监听的端口直接通过host模式监听至宿主机
    2. 将ingress controller运行在带有ingress-nginx=enable标签的节点上(所以需要给集群中要运行该ingress controller的节点打上对应的标签)
    3. ingress controller能够容器带有ingress-nginx污点的节点(如果要让ingress controller专机专用,可为相应节点打上ingress-nginx=:NoExecute的污点)

    部署:

    kubectl create -f mandatory.yaml
    

    为ingress controller创建一个service:

    # cat ingress-nginx.svc.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: ingress-nginx
      namespace: ingress-nginx
    spec:
      type: ClusterIP
      ports:
      - port: 80
        name: http
        targetPort: 80
      - port: 443
        name: https
        targetPort: 443
      selector:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    

    创建service:

    kubectl apply -f ingress-nginx.svc.yaml
    

    创建service之后,集群内部可直接通过这个service的ip访问到相应的应用(需要加header头)

    还需要说明的是,ingress-nginx部署完成以后,默认提供两个location,一个是/healthz,用于健康检查,返回状态码200,另外一个是/,默认返回404

    2. 配置Ingress资源以实现流量接入

    前面我们说到Ingress其实就是个规则,指定哪个域名转发到哪个service,所以说首先得有个service。不过service的具体配置这里不作说明。我们就以kubernetes-dashboard和kibana为例:

    kubectl get svc kubernetes-dashboard --namespace=kube-system
    NAME                   CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE       
    kubernetes-dashboard   10.254.213.109   <none>        80/TCP    13d       
    kibana                 10.254.213.110   <none>        5601/TCP    13d       
    

    创建一个dashboard-kibana-ingress.yml如下:

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: dashboard-kibana-ingress
      namespace: kube-system
    spec:
      rules:
      - host: dashboard.dz11.com
        http:
          paths:
          - path: /
            backend:
              serviceName: kubernetes-dashboard
              servicePort: 80
      - host: kibana.dz11.com
        http:
          paths:
          - backend:
              serviceName: kibana
              servicePort: 5601
    

    部署:

    kubectl create -f dashboard-kibana-ingress.yml
    

    3. 配置Ingress TLS

    默认情况下,ingress只提供了http服务,而没有https服务,要部署一个https服务,首先得有https证书。证书的生成,这里不做说明。

    创建secret

    假定,我们现在已经有了一个ca.crt的证书文件和一个server.key的密钥文件。我们需要创建一个secret。在创建secret之前,先要把证书及密钥内容通过base64编码。如下:

    cat ca.crt | base64 -w 0
    cat server.key|base64 -w 0
    

    创建ingress-secret.yml文件,内容如下:

    apiVersion: v1
    kind: Secret
    metadata:
      name: ingress-secret
      namespace: default
    type: kubernetes.io/tls
    data:
      tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlIWlRDQ0JrMmdBd0lCQWdJTUxQbnRoUStHZlJJOTNHd0dNQTBHQ1NxR1NJYjNEUUVCQ3dVQU1HQXhDekFKDQpCZ05WQkFZVEFrSkZNUmt3RndZRFZRUUtFeEJIYkc5aVlXeFRhV2R1SUc1MkxYTmhNVFl3TkFZRFZRUURFeTFIDQpiRzlpWVd4VGFXZHVJRVJ2YldGcGJpQldZV3hwWkdGMGFXOXVJRU5CSUMwZ1UwaEJNalUySUMwZ1J6SXdIaGNODQpNVGN3TlRJMU1EWTBNRFEyV2hjTk1UZ3hNVEk0TWpNMU9UVTVXakE0TVNFd0h3WURWUVFMRXhoRWIyMWhhVzRnDQpRMjl1ZEhKdmJDQldZV3hwWkdGMFpXUXhFekFSQmdOVkJBTU1DaW91WkhveE1TNWpiMjB3Z2dFaU1BMEdDU3FHDQpTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDaTA5bjg0WGdhWGo0YStvaERyQXJONWVLeEpYbXV0QmJNDQpqNVFJdEZDa2l0dUg3OWxtNmtMcThSL2E0ZHdEc1h6czZXVWNRRHBjbUlqNzdOYlBQYzJrZVZlcDMxeVZLSUpKDQpkYWhFd2V5NlVFBQeWwwS2xOeFdMODhETGtMZUFvby8rNVNBaUIzUktsUUswMXREWnIrem4rYkxZVUQ4YzU4DQ
      tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBb3RQWi9PRjRHbDQrR3ZxSVE2d0t6ZVhpc1NWNXJyUVd6SStVQ0xSUXBJcmJoKy9aClp1cEM2dkVmMnVIY0E3Rjg3T2xsSEVBNlhKaUkrK3pXenozTnBIbFhxZDljbFNpQ1NYV29STUhzdWtKL1RFbUcKRUhsOTI3M1BFZU1QclhqSUpEeC85K1ZQRUlFRnlHc3hYamFaR2FtZnJYNmJvMVVFaExlMlEySVpWMDh1UU1EMQpUTVArb0VyZHY1MkUzZlAyxxxxxNBSjNUNWtrUm5IaE5TWDFIankySnFBcHNDYW5pKzI4MmV2NGlYYkwwCks1NVA4N3BqdGw4WGtWTGZDbXJYTSt6dEs4aGNkQ3ZCOHU0NkpNRWQ2R1JjeXpBWHJ6b1dYM3RxUGVDdGxrazgKcEVMRXVFSmJpV2hYRjZEVUtlK1NpeHIyMTJHdm5JcncreTBxendJREFRQUJBb0lCQVFDTFhTSWQ1R2xrd0RjTgo1bE1OQU1xNmtrRmw5N3BmZ25wbEdack5uRy9OZGFBU2lJS2VLSEdnSDBOeGw1RTFoQXQxeHdvb2xQeWUxbHVnCnJJVHJHbTNSa1o0cm9pYmU
    

    执行创建:

    kubect create -f ingress-secret.yml
    

    也可以通过命令行的方式直接创建一个secret:

    kubectl create secret tls ingress-secret --key server.key --cert ca.crt
    

    修改ingress,开启tls

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: dashboard-kibana-ingress
      namespace: kube-system
    spec:
      tls:
      - hosts:
        - dashboard.dz11.com
        - kibana.dz11.com
        secretName: ingress-secret
      rules:
      - host: dashboard.dz11.com
        http:
          paths:
          - path: /
            backend:
              serviceName: kubernetes-dashboard
              servicePort: 80
      - host: kibana.dz11.com
        http:
          paths:
          - path: /
            backend:
              serviceName: kibana
              servicePort: 5601
    

    注意:一个 Ingress 只能使用一个 secret(secretName 段只能有一个),也就是说只能用一个证书,更直白的说就是如果你在一个 Ingress 中配置了多个域名,那么使用 TLS 的话必须保证证书支持该 Ingress 下所有域名;并且这个 secretName 一定要放在上面域名列表最后位置,否则会报错 did not find expected key 无法创建;同时上面的 hosts 段下域名必须跟下面的 rules 中完全匹配

    更需要注意一点:Kubernetes Ingress默认情况下,当你不配置证书时,会默认给你一个 TLS 证书的,也就是说你 Ingress 中配置错了,比如写了2个 secretName、或者 hosts 段中缺了某个域名,那么对于写了多个 secretName 的情况,所有域名全会走默认证书;对于 hosts 缺了某个域名的情况,缺失的域名将会走默认证书,部署时一定要验证一下证书,不能 “有了就行”;更新 Ingress 证书可能需要等一段时间才会生效

    一旦部署了https,默认请求的http会自动跳转到https,所以在同时需要https和http并存的应用场景,也需要注意

    最后重新部署下ingress即可:

    kubectl delete -f dashboard-kibana-ingress.yml
    kubectl create -f dashboard-kibana-ingress.yml
    

    4. 通过ingress暴露tcp服务

    通过ingress暴露tcp服务,我们需要先定义一个nginx-tcp-ingress-configmap.yaml的configmap,示例如下:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: tcp-configmap-example
    data:
      9000: "default/redis:6379"
    

    以上表示暴露 default namespace 下服务名为 redis,端口为 6379 的服务到 nginx-ingress-lb 所在节点的 9000 端口。

    5. 通过configmap修改nginx controller的全局变量

    通过上面启动nginx controller的yaml文件,其实我们可以看出来,在启动controller的时候,向启动命令传递了一大堆参数,包括--default-backend-service以及--apiserver-host等。更多的参数,可以直接参考这里

    我们知道,nginx controller本质上就是一个nginx代理,这个代理使用了一大堆nginx默认参数启动。而在某些特定场景下,这些我们需要定制这些参数以更适用于我们的需求。在controller启动的时候,提供了一个--configmap的参数,我们可以将需要定制的参数保存到一个configmap中,并在controller启动的时候,来读取这个configmap,获取其值,应用到controller中。具体哪些值可以通过configmap来传递,可以直接参考这里

    下面是一个简单的示例:

    定义一个名为nginx-controller-configmap的yaml内容如下:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: nginx-ingress-configmap
      namespace: default
    data:
      proxy-body-size: 1024m
    

    这个configmap定义了一个proxy-body-size的大小为1024m,即nginx中client_max_body_size的参数为1024m。

    然后我们通过kubectl exec -it <podname> /bin/sh的方式登录到新的pod,查看/etc/nginx/nginx.conf文件,以确认相应配置是否生效

  • 相关阅读:
    Format中的转换说明符
    网络通信数据包与串口通信数据包异同:
    指针容器的类型和用法
    cimge 这次能够图片大小尺寸
    三分钟快速上手TensorFlow 2.0 (后续)——扩展和附录
    三分钟快速上手TensorFlow 2.0 (下)——模型的部署 、大规模训练、加速
    三分钟快速上手TensorFlow 2.0 (中)——常用模块和模型的部署
    三分钟快速上手TensorFlow 2.0 (上)——前置基础、模型建立与可视化
    检查自己的numpy是否有依赖blas
    TensorFlow 2.0快速上手指南12条
  • 原文地址:https://www.cnblogs.com/breezey/p/9494994.html
Copyright © 2011-2022 走看看