• Post author:
  • Post category:运维
  • Post comments:0评论
  • Reading time:5 mins read

什么是Ingress

K8S的Service有三种对外暴露提供服务的方式,分别是ClusterIP、NodePort、与LoadBalance,除了对pod副本的负载均衡机制外,Service主要作用体现在两个方面,一是对集群内部,其不断跟踪pod的ip变化,更新endpoint中对应的pod对象,提供了IP不断变化的pod的服务发现机制,而是对集群外部,其提供了NodePort等方式使外部请求可以正确的映射到pod进行处理,但是,仅仅使用Service来暴露集群服务的方式,在实际生产环境中是不太合适的:

  • ClusterIP只能集群内访问。
  • NodePort端口映射的方式在生产环境下管理困难。
  • LoadBalance受限云平台,而且在云平台部署ELB需要额外费用成本。

所幸K8S还提供了一种从集群维度暴露服务的方式,也就是Ingress。Ingress可以理解为Service的Service,通过K8S中Ingress资源类型来制定请求的转发规则,把请求路由到一个或多个Service中,可以从业务维度统一考虑服务的对外暴露,而不用对每个service都单独考虑。

举个例子,现在集群有API,文件存储,前端UI三个Service,可以通过一个Ingress对象实现图中的请求转发:

Ingress可以根据不同域名、不同path转发到不同的service。

Ingress与Ingress-Controller

Ingress 使用开源的反向代理负载均衡器来实现对外暴漏服务,比如 Nginx、Apache、Haproxy等。Nginx Ingress 一般有三个组件组成:

  • Ingress对象:代指K8S中的一个资源对象,一般使用Yaml配置,作用是定义请求的路由规则。
  • Ingress-Controller:监听apiserver,获取服务新增,删除等变化,并结合ingress规则动态更新到反向代理负载均衡器上,并重载配置使其生效。
  • 反向代理负载均衡器:通常以Service的NodePort方式运行,接收并按照Ingress定义的规则进行转发,通常为Nginx,Haproxy,Traefik等,本文使用Nginx。

以上三者有机的协调配合起来,就可以完成 Kubernetes 集群服务的暴漏。

组件说明

  • externalLB : 外部的4层负载均衡器
  • <Service>Ingress-Nginx:NodePort类型的Service为IngressController的Pod接入外部流量
  • <IngressController> Ingress-nginx:负责创建负载均衡(一个安装了Nginx的Pod)
  • <Ingrees>Ingress:根据后端Service实时识别分类及IP把结果生成配置文件注入到Ingress-Nginx的Pod中
  • <Service>Site1:Service对后端Pod进行分类。

Ingress的部署方式

Ingress的部署需要考虑两个方面:

  • ingress-controller是作为pod来运行的,以哪种负载类型部署比较好
  • ingress解决了如何把请求路由到集群内部,那ingress本身该如何暴露到外部环境

下面列举一些常见的部署和暴露方式,具体使用哪种还是需要根据实际需求和环境来决定,本文部署的方式采用HostNetwork方式。

Deployment+LoadBalancer模式的Service

如果要把Ingress部署在公有云,使用此种方式较为合适。用Deployment部署ingress-controller,创建一个type为LoadBalancer的Service关联这组Pod,大部分公有云都会为LoadBalancer的Service自动创建一个负载均衡器,通常还绑定了公网IP,只需要把域名解析到该地址,就实现了集群服务的对外部署。

Deployment+NodePort模式的Service

同样使用Deployment模式部署ingress-controller,并创建Type为NodePort的Service,这样ingress就会暴露在集群节点ip的特定端口上,但由于NodePort的端口是随机端口,一般会在更上层搭建一套负载均衡器来转发请求,该方式一般用于宿主机是相对固定的环境IP地址不变的场景。NodePort方式暴露ingress虽然简单,但NodePort多了一层NAT,在请求量级很大时可能会对性能有影响。

DaemonSet+HostNetwork+NodeSelector

使用DaemonSet结合NodeSelector来部署Ingress-Controller到指定的Node上,然后使用HostNetwork直接把该pod与宿主机的Node网络打通,直接访问宿主机的80/443端口就能访问服务。这时ingress-controller所在的node服务器就很类似传统架构的边缘节点,比如机房入口的Nginx服务器。该方式整个请求链路最为简单,性能相比NodePort方式更好,缺点是由于依赖宿主机的网络和端口,一个Node只能部署一个ingress-controller的pod,比较时候大并发的生产环境使用。

使用HostNetwork方式部署Ingress-Nginx

原本安装过程应该是一行命令就能完成的,但还是因为那个不可描述的原因,有些镜像拉取不到,需要我们自行下载。

或者你也可以使用我提供的Yaml,链接在此

如果你想自己获取最新的Yaml,首先先到Ingress-Nginx的官方仓库,选择main分支,进入/deploy/static/provider/baremetal/文件夹下,下载deploy.yaml,注意里面的两个镜像:

  • ingress-nginx-controller:v1.x.x
  • kube-webhook-certgen:v1.x

其中kube-webhook-certgen:v1.0需要在yaml里替换两处,ingress-nginx-controller:v1.0.0需要替换1处,我们去docker官方仓库进行搜索,找找其他用户上传的镜像,在你集群内的每一台节点下进行docker pull提前拉取镜像,然后将deploy.yaml内的三处image替换为你下载的镜像的tag。

除此之外,还要进行几处修改,以使用HostNetwork的方式占用宿主机80/443端口作为流量入口:

apiVersion: apps/v1
kind: DaemonSet
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
        ingressHost: "yes"
      hostNetwork: true

之后执行以下命令完成安装:

kubectl create -f deploy.yaml

安装后先不要急,你会看到ingress-controller的pod处于pending状态,这是因为我们添加了nodeSelector的label,此时我们需要在你想部署ingress的节点上,为其添加一个label:ingressHost: “yes”,如果你想在master节点上部署ingress的话,仅仅添加这个label是不够的,需要为master节点去除污点或为ingress添加容忍度,在此不再赘述,可自行搜索K8S的污点和容忍度相关文献。

全都添加好后,可以看到IngressController已经处于正常运行状态。

配置Ingress资源

部署完Ingress-Controller后,就可以创建Ingress资源文件来进行路由分配,Ingress的资源文件实际上就是告诉Ingress-controller如何配置Nginx的conf文件,对Nginx的特定配置都可以在annotation里进行配置。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: wordpress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
    - host: www.hafuhafu.cn
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: wordpress
                port:
                  number: 80

使用kubectl apply -f命令就可以创建该路由规则了。

注意annotation里必须指明ingress.class为你安装的ingress实现,本文使用的是Nginx所以自然填写为nginx。

host为可选项,如果你有域名的话可以在host内填写你的域名,我的域名是泛解析到服务器的:*.hafuhafu.cn,无论前缀是什么都会解析到我的服务器上,而ingress作为7层负载均衡会根据请求的原始url进行路由转发到具体的Service上。

配置成功后访问你的域名就可以了。

葫芦

葫芦,诞生于1992年8月11日,游戏宅,胶佬,爱好摸鱼,一个干过超市收银,工地里搬过砖,当过广告印刷狗,做过电焊铁艺的现役.Net程序员。

发表回复