Ingress 介绍

Kubernetes 暴露服务的有三种方式,分别为 LoadBlancer Service、NodePort Service、Ingress。官网对 Ingress 的定义为管理对外服务到集群内服务之间规则的集合,通俗点讲就是它定义规则来允许进入集群的请求被转发到集群中对应服务上,从来实现服务暴漏。 Ingress 能把集群内 Service 配置成外网能够访问的 URL,流量负载均衡,终止SSL,提供基于域名访问的虚拟主机等等。

Ingress 是个什么玩意

可能从大致印象上 Ingress 就是能利用 Nginx、Haproxy 啥的负载均衡器暴露集群内服务的工具;那么问题来了,集群内服务想要暴露出去面临着几个问题:

  • Pod 漂移问题

众所周知 Kubernetes 具有强大的副本控制能力,能保证在任意副本(Pod)挂掉时自动从其他机器启动一个新的,还可以动态扩容等,总之一句话,这个 Pod 可能在任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上;那么自然随着 Pod 的创建和销毁,Pod IP 肯定会动态变化;那么如何把这个动态的 Pod IP 暴露出去?这里借助于 Kubernetes 的 Service 机制,Service 可以以标签的形式选定一组带有指定标签的 Pod,并监控和自动负载他们的 Pod IP,那么我们向外暴露只暴露 Service IP 就行了;这就是 NodePort 模式:即在每个节点上开起一个端口,然后转发到内部 Service IP 上,如下图所示:

  • 端口管理问题

采用 NodePort 方式暴露服务面临一个坑爹的问题是,服务一旦多起来,NodePort 在每个节点上开启的端口会及其庞大,而且难以维护;这时候引出的思考问题是 “能不能使用 Nginx 啥的只监听一个端口,比如 80,然后按照域名向后转发?” 这思路很好,简单的实现就是使用 DaemonSet 在每个 node 上监听 80,然后写好规则,因为 Nginx 外面绑定了宿主机 80 端口(就像 NodePort),本身又在集群内,那么向后直接转发到相应 Service IP 就行了,如下图所示:

  • 域名分配及动态更新问题

从上面的思路,采用 Nginx 似乎已经解决了问题,但是其实这里面有一个很大缺陷:每次有新服务加入怎么改 Nginx 配置?总不能手动改或者来个 Rolling Update 前端 Nginx Pod 吧?这时候 “伟大而又正直勇敢的” Ingress 登场,如果不算上面的 Nginx,Ingress 只有两大组件:Ingress Controller 和 Ingress
Ingress 这个玩意,简单的理解就是 你原来要改 Nginx 配置,然后配置各种域名对应哪个 Service,现在把这个动作抽象出来,变成一个 Ingress 对象,你可以用 yml 创建,每次不要去改 Nginx 了,直接改 yml 然后创建/更新就行了;那么问题来了:”Nginx 咋整?”Ingress Controller 这东西就是解决 “Nginx 咋整” 的;Ingress Controoler 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取他,按照他自己模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下,工作流程如下图:

当然在实际应用中,最新版本 Kubernetes 已经将 Nginx 与 Ingress Controller 合并为一个组件,所以 Nginx 无需单独部署,只需要部署 Ingress Controller 即可。

ingress与ingress-controller

要理解ingress,需要区分两个概念,ingress和ingress-controller:

  • ingress对象:

指的是k8s中的一个api对象,一般用yaml配置。作用是定义请求如何转发到service的规则,可以理解为配置模板。

  • ingress-controller:

具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发。简单来说,ingress-controller才是负责具体转发的组件,通过各种方式将它暴露在集群入口,外部对集群的请求流量会先到ingress-controller,而ingress对象是用来告诉ingress-controller该如何转发请求,比如哪些域名哪些path要转发到哪些服务等等。

ingress-controller原理

ingress-controller并不是k8s自带的组件,实际上ingress-controller只是一个统称,用户可以选择不同的ingress-controller实现,目前,由k8s维护的ingress-controller只有google云的GCE与ingress-nginx两个,其他还有很多第三方维护的ingress-controller,具体可以参考官方文档。但是不管哪一种ingress-controller,实现的机制都大同小异,只是在具体配置上有差异。一般来说,ingress-controller的形式都是一个pod,里面跑着daemon程序和反向代理程序。daemon负责不断监控集群的变化,根据ingress对象生成配置并应用新配置到反向代理,比如nginx-ingress就是动态生成nginx配置,动态更新upstream,并在需要的时候reload程序应用新配置。为了方便,后面的例子都以k8s官方维护的nginx-ingress为例。

nginx反向代理原理

Nginx-ingress 是 Kubernetes 生态中的重要成员,主要负责向外暴露服务,同时提供负载均衡等附加功能;截至目前,nginx-ingress 已经能够完成 7/4 层的代理功能(4 层代理基于 ConfigMap,感觉还有改进的空间);
Nginx 的 7 层反向代理模式,可以简单用下图表示:


 Nginx 对后端运行的服务(Service1、Service2)提供反向代理,在配置文件中配置了域名与后端服务 Endpoints 的对应关系。客户端通过使用 DNS 服务或者直接配置本地的 hosts 文件,将域名都映射到 Nginx 代理服务器。当客户端访问 service1.com 时,浏览器会把包含域名的请求发送给 nginx 服务器,nginx 服务器根据传来的域名,选择对应的 Service,这里就是选择 Service 1 后端服务,然后根据一定的负载均衡策略,选择 Service1 中的某个容器接收来自客户端的请求并作出响应。过程很简单,nginx 在整个过程中仿佛是一台根据域名进行请求转发的“路由器”,这也就是7层代理的整体工作流程了!
       对于 Nginx 反向代理做了什么,我们已经大概了解了。在 k8s 系统中,后端服务的变化是十分频繁的,单纯依靠人工来更新nginx 的配置文件几乎不可能,nginx-ingress 由此应运而生。Nginx-ingress 通过监视 k8s 的资源状态变化实现对 nginx 配置文件的自动更新,下面本文就来分析下其工作原理。

ingress controller工作流程分析

首先,上一张整体工作模式架构图(只关注配置同步更新):

不考虑 nginx 状态收集等附件功能,nginx-ingress 模块在运行时主要包括三个主体:NginxController、Store、SyncQueue。其中,Store 主要负责从 kubernetes APIServer 收集运行时信息,感知各类资源(如 ingress、service等)的变化,并及时将更新事件消息(event)写入一个环形管道;SyncQueue 协程定期扫描 syncQueue 队列,发现有任务就执行更新操作,即借助 Store 完成最新运行数据的拉取,然后根据一定的规则产生新的 nginx 配置,(有些更新必须 reload,就本地写入新配置,执行 reload),然后执行动态更新操作,即构造 POST 数据,向本地 Nginx Lua 服务模块发送 post 请求,实现配置更新;NginxController 作为中间的联系者,监听 updateChannel,一旦收到配置更新事件,就向同步队列 syncQueue 里写入一个更新请求。

k8s安装ingress nginx

部署ingress controller

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
## 注意:不同k8s版本需要不同的ingress版本,笔者的kuberctl:1.16.0,ingress:/nginx-0.26.0

大部分教程的做法都是直接输入命令,但是我喜欢先下载

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml

因为是在国内,所以你需要确定里面的镜像能不能下载到机器里,如果不行,推荐使用我下面这个方法

https://juejin.im/post/5d5a0c40e51d4561b072dcfe

下载完成镜像之后部署
kubectl apply -f mandatory.yaml
值得注意的是这个yaml档并不包含service(注意:这里的service是值nginx代理的service,是ingress controller中的nginx的service),创建service要使用下面这个yaml档

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

把这个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

因为我们要实现文章图片上面这个状态,所以这个service还要写一个nodePort: 80和nodePort: 443字段,比如下面

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
      # 增加nodePort
      nodePort: 80
      protocol: TCP
    - name: https
      port: 443
      targetPort: 443
      # 增加nodePort
      nodePort: 443
      protocol: TCP
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

在apply这个service之前,我们要注意的是我们的apiserver 默认的node port端口范围是30000-32767,但是我们所需要的nodeport端口不在这个范围之内,所以要修改apiserver的nodeport端口。
因为我是使用kubeadm搭建的集群,所以编辑下面这个文件,

vim /etc/kubernetes/manifests/kube-apiserver.yaml

在command下新增

- --service-node-port-range=30-3000

之后保存即可,apiserver会自动重启并且应用配置,修改完成一个节点之后,其他的master节点也需要修改。保证apiserver的配置相同。接着应用这个yaml档即可最后查看这个svc是否正常kubectl get svc -A

测试

准备后端pod和service

编写yaml文件,并创建创建3个myapp服务的pod,并创建一个service绑定

apiVersion: v1kind: Servicemetadata:
  name: myapp
  namespace: defaultspec:
  selector:
    app: myapp
    release: canary
  ports:
  - name: http
    targetPort: 80
    port: 80---apiVersion: apps/v1kind: Deploymentmetadata:
  name: myapp-deploy
  namespace: defaultspec:
  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

创建ingress,绑定后端nginx服务

编写ingress的yaml文件,并创建

apiVersion: extensions/v1beta1kind: Ingressmetadata:
  name: ingress-myapp
  namespace: defaultspec:
  rules:
  - host: myapp.along.com
    http:
      paths:
      - path:
        backend:
          serviceName: myapp
          servicePort: 80

查询验证

root@debian-1:~# kubectl get all -n ingress-nginx 
NAME                                            READY   STATUS    RESTARTS   AGE
pod/nginx-ingress-controller-568867bf56-8w2g4   1/1     Running   1          109m

NAME                    TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
service/ingress-nginx   NodePort   10.110.61.84   <none>        80:30080/TCP,443:30443/TCP   90m

NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-ingress-controller   1/1     1            1           109m

NAME                                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-ingress-controller-568867bf56   1         1         1       109m
root@debian-1:~# 
root@debian-1:~# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
myapp-deploy-798dc9b584-nwv6n   1/1     Running   0          81m
myapp-deploy-798dc9b584-slwtn   1/1     Running   0          81m
myapp-deploy-798dc9b584-wkwq4   1/1     Running   0          81m
root@debian-1:~# kubectl get ingress
NAME            HOSTS             ADDRESS        PORTS   AGE
ingress-myapp   myapp.along.com   10.110.61.84   80      77m
root@debian-1:~#

在集群外,查询服务验证

① 可以先修改一下主机的hosts,给域名绑定一个k8s节点的ip
192.168.130.103 myapp.along.com
② 访问业务成功

参考

https://www.cnblogs.com/along21/p/10333086.html

https://www.kancloud.cn/huyipow/kubernetes/531995

https://segmentfault.com/a/1190000019908991

https://blog.csdn.net/shida_csdn/article/details/84032019

https://jimmysong.io/kubernetes-handbook/concepts/ingress.html

https://juejin.im/post/5d5be81ae51d453bdb1d9b56

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐