使用ingress+service机制实现高可用负载均衡
coredns是实现pods之间通过域名访问,如果外部需要访问service服务,需访问对应的NodeIP:Port。但是由于NodePort需要指定宿主机端口,一旦服务多起来,多个端口就难以管理。那么,这种情况下,使用Ingress暴露服务更加合适。
四层和七层区别(不明白就这样去理解,七层最常见就是应用层的http,也就是url,四层是传输层,为tcp/udp端口)
Ingress 是一个规则的集合,它允许集群外的流量通过一定的规则到达集群内的 Service 。如下图:
Ingress三个组件:
反向代理负载均衡器
Ingress Controller
Ingress
反向代理负载均衡器,即常见的负载均衡软件,如 nginx、Haproxy 等。
Ingress Controller 与 kubernetes API 进行交互,实时的感知后端 service、pod 等变化, Ingress Controller 再结合下文的 Ingress 生成配置,然后更新反向代理负载均衡器,并刷新其配置,实现动态服务发现与更新。
Ingress是规则集合;定义了域名与Kubernetes的service的对应关系;这个规则将与 Ingress Controller 结合, Ingress Controller 将其动态写入到负载均衡器配置中,从而实现整体的服务发现和负载均衡。
Kubernetes外部访问流程图
https://www.kubernetes.org.cn/2812.html
LVS主要是用来实现ingress的高可用,LVS可以是F5.也可以keepalve等
这里k8s中的ingress组件急速openshift中的router组件
https://www.kubernetes.org.cn/2812.html
简化应用发布的操作流程,域名与服务实现了自动更新与配置,只需定义ingress与添加外部DNS条目两步操作,即可完成应用的对外发布,减少操作流程,提高维护效率。
Kubernetes 提供了两种内建的云端负载均衡机制( cloud load balancing )用于发布公共应用, 一种是工作于传输层的 Service 资源,它实现的是 TCP 负载均衡器”,另一种是Ingress 资源,它 现的是“ HTTP(S )负载均衡器”
( 1) TCP 载均衡器
无论是 iptables 还是ipvs 模型的 Service 资源都配置于 Linux 内核中的 Netfilter 之上进行四层调度,是一种类型更为通用的调度器, 支持调度 HTTP、MySQL 应用层服务。不过,也正是由于 作于传输层从而使得它无法做到类似卸载 HTTPS 中的 SSL 会话等一类作,也不支持基于 URL 的请求调度机制,而且, Kubernetes 也不支持为此类负载均衡器配置任何类型的健康状态检查机制
( 2) HTTP(S )负载均衡器
HTTP(S )负载均衡器是应用层负载均衡机制的 种,支持根据环境做出更好的调度决策。与传输层调度器相比,它提供了诸如可自定义 URL 映射和 TLS 卸载 功能,并支持多种类型 的后端服务器健康状态检查机制
k8s的ingress实现证书卸载功能
对于Kubernetes的Service,无论是Cluster-Ip和NodePort均是四层的负载,集群内的服务如何实现七层的负载均衡,这就需要借助于Ingress,Ingress控制器的实现方式有很多,比如nginx, Contour, Haproxy, trafik, Istio,我们以nginx的实现为例做演示。
Ingress-nginx是7层的负载均衡器 ,负责统一管理外部对k8s cluster中service的请求。主要包含:
-
ingress-nginx-controller:根据用户编写的ingress规则(创建的ingress的yaml文件),动态的去更改nginx服务的配置文件,并且reload重载使其生效(是自动化的,通过lua脚本来实现);
-
ingress资源对象:将Nginx的配置抽象成一个Ingress对象,每添加一个新的Service资源对象只需写一个新的Ingress规则的yaml文件即可(或修改已存在的ingress规则的yaml文件)
1)ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化2)然后读取ingress规则(规则就是写明了哪个域名对应哪个service),按照自定义的规则,生成一段nginx配置3)再写到nginx-ingress-controller的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器把生成的nginx配置写入/etc/nginx.conf文件中4)然后reload一下使配置生效。以此达到域名分别配置和动态更新的问题。
上面的案例中ingress-control按照的时候使用的是本地网络,安装在label为inggess的机器上面的,这台机器的ip地址是192.168.136.128
在生产上面ingress-control是高可用要安装多台,我们可以使用haproxy使用高可用实现一个vip,或者利用F5使用vip,这里配置dns的时候,就要配置vip集群的ip
第二个如何实现ingress的证书https卸载
相当的经典呀,这里证书卸载是在ingress中进行卸载的,类似nginx进行证书的卸载,如果ingress前面使用了f5,证书卸载也可以放在f5中进行卸载管理
ingrees-control生产的是一组pod资源,这组pod资源的外部的是externalLB, externalLB可能是F5,也可能是其他高可用的负载
部署 Ingress 控制器( Nginx)
Ingress 控制器自身是运行 Pod 中的容器应用,一般是 Nginx或Envoy -类的具有代理及负载均衡功能的守护进程,它监视着来自于API Server的Ingress 对象状态,并以其规则生成相应的应用程序专有格式的配置文件并通过重载或开启守护进程而使新配置生效。例如,对于 Nginx 来说,Ingress 规则需要转换为 Nginx 的配置信息,简单来说, Ingress 控制器其实就是托管于Kubemetes 系统之上的用于实现在应用层发布服务的Pod 资源,它将跟跟踪Ingress 资源并实时生成配置规则。那么,同样运行为 Pod 资源的 Ingress 控制器进程又该如何接入外部的请求流量那? 常用的解决方案有如下两种:
以 Deployment 控制器管理Ingress 控制器的 Pod 资源,并通过 NodePort或Load Balancer 类型的 Service 对象为其接入集群外部的请求流量,这就意味着,定义一个Ingress 控制器时,必须在其前端定义一个专用的 Service 资源:如图 所示
2.借助于 DaemonSet 控制器,将 Ingress控制器的 Pod 资源各自以单一实例的方式运行于集群的所有或部分工作节点之上,并配置这类Pod对象以hostPort(如图a)或 hostNetwork (如图b)的方式在当前节点接入外部流量
上面博客部署采用的是方式2中的b模式来进行部署 ,参加博客http://www.kendd.cn/?p=2492
博客2:http://www.dockone.io/article/9745
浅谈Kubernetes Ingress控制器的技术选型
浅谈Kubernetes Ingress控制器的技术选型
名词解释
阅读本文需要熟悉以下基本概念:- 集群:是指容器运行所需云资源的集合,包含了若干台云服务器、负载均衡器等云资源。
- 实例(Pod):由相关的一个或多个容器构成一个实例,这些容器共享相同的存储和网络空间。
- 工作负载(Node):Kubernetes 资源对象,用于管理 Pod 副本的创建、调度以及整个生命周期的自动控制。
- 服务(Service):由多个相同配置的实例(Pod)和访问这些实例(Pod)的规则组成的微服务。
- Ingress:Ingress 是用于将外部 HTTP(S)流量路由到服务(Service)的规则集合。
Kubernetes 访问现状
Kubernetes 的外部访问方式
在 Kubernetes 中,服务跟 Pod IP 主要供服务在集群内访问使用,对于集群外的应用是不可见的。怎么解决这个问题呢?为了让外部的应用能够访问 Kubernetes 集群中的服务,通常解决办法是 NodePort 和 LoadBalancer。
这两种方案其实各自都存在一些缺点:
- NodePort 的缺点是一个端口只能挂载一个 Service,而且为了更高的可用性,需要额外搭建一个负载均衡。
- LoadBalancer 的缺点则是每个服务都必须要有一个自己的 IP,不论是内网 IP 或者外网 IP。更多情况下,为了保证 LoadBalancer 的能力,一般需要依赖于云服务商。
在Kubernetes的实践、部署中,为了解决像 Pod 迁移、Node Pod 端口、域名动态分配,或者是 Pod 后台地址动态更新这种问题,就产生了 Ingress 解决方案。
Ingress 选型
Nginx Ingress 的缺点
Ingress 是 Kubernetes 中非常重要的外网流量入口。在Kubernetes中所推荐的默认值为Nginx Ingress,为了与后面Nginx 提供的商业版 Ingress 区分开来,我就称它为Kubernetes Ingress。Kubernetes Ingress,顾名思义基于 Nginx 的平台,Nginx 现在是世界上最流行的 Nginx HTTP Sever,相信大家都对 Nginx 也比较熟悉,这是一个优点。它还有一个优点是 Nginx Ingress 接入 Kubernetes 集群所需的配置非常少,而且有很多文档来指引你如何使用它。这对于大部分刚接触 Kubernetes 的人或者创业公司来说,Nginx Ingress 的确是一个非常好的选择。
但是当 Nginx Ingress 在一些大环境上使用时,就会出现很多问题:
- 第一个问题:Nginx Ingress用了一些 OpenResty 的特性,但最终配置加载还是依赖于原有的 Nginx config reload。当路由配置非常大时,Nginx reload 会耗时很久,时间长达几秒甚至十几秒,这样就会严重影响业务,甚至造成业务中断。
- 第二个问题: Nginx Ingress 的插件开发非常困难。如果你认为 Nginx Ingress 本身插件不够用,需要使用一些定制化插件,这个额外的开发任务对程序员来说是十分痛苦的。 因为Nginx Ingress自身的插件能力和可扩展性非常差。
Ingress 选型原则
既然发现了 Nginx Ingress 有很多问题,那是不是考虑选择其他开源的、更好用的 Ingress?市场上比 Kubernetes Ingress 好用的Ingress起码有十几家,那么如何从这么多 Ingress 中选择适合自己的呢?Ingress 最终是基于 HTTP 网关的,市面上 HTTP 网关主要有这么几种:Nginx、Golang 原生的网关,以及新崛起的 Envoy 。但是每个开发人员所擅长的技术栈不同,所以适合的 Ingress 也会不一样。
那么问题来了,我们如何选择一个更加好用的 Ingress 呢?或者缩小点范围,熟悉 Nginx 或 OpenResty 的开发人员,应该选择哪一个 Ingress 呢?
下面来介绍一下我对 Ingress 控制器选型的一些经验。
选型原则
基本特点
首先我认为 Ingress 控制器应该具备以下基本功能,如果连这些功能都没有,那完全可以直接pass。
- 必须开源的,不开源的无法使用。
- Kubernetes 中 Pod 变化非常频繁,服务发现非常重要。
- 现在 HTTPS 已经很普及了,TLS 或者 SSL 的能力也非常重要,比如证书管理的功能。
- 支持 WebSocket 等常见协议,在某些情况下,可能还需要支持 HTTP2、QUIC 等协议。
基础软件
前面有提到,每个人擅长的技术平台不一样,所以选择自己更加熟悉的 HTTP 网关也显得至关重要。比如 Nginx、HAProxy、Envoy 或者是 Golang 原生网关。因为你熟悉它的原理,在使用中可以实现快速落地。
在生产环境上,高性能是一个很重要的特性,但比之更重要的是高可用。这意味着你选择的网关,它的可用性、稳定性一定要非常强,只有这样,服务才能稳定。
功能需求
抛开上述两点,就是公司业务对网关的特殊需求。你选择一个开源产品,最好肯定是开箱能用的。比如你需要 GRPC 协议转换的能力,那当然希望选的网关具备这样的功能。这里简单列一下影响选择的因素:
- 协议:是否支持 HTTP2、HTTP3;
- 负载均衡算法:最基本的WRR、一致性哈希负载均衡算法是否能够满足需求,还是需要更加复杂的类似EWMA负载均衡算法。
- 鉴权限流:仅需要简单的鉴权,或更进阶的鉴权方式。又或者需要集成,能够快速的开发出像腾讯云 IM 的鉴权功能。Kubernetes Ingress除了前面我们提到的存在Nginx reload 耗时长、插件扩展能力差的问题,另外它还存在后端节点调整权重的能力不够灵活的问题。
选择 APISIX 作为 Ingress controller
相比Kubernetes Ingress,我个人更推荐 APISIX。虽然它在功能上比 Kong 会少很多,但是 APISIX 很好的路由能力、灵活的插件能力,以及本身的高性能,能够弥补在 Ingress 选型上的一些缺点。对于基于 Nginx 或 Openresty 开发的程序员,如果对现在的 Ingress 不满意,我推荐你们去使用 APISIX 作为 Ingress。如何将 APISIX 作为 Ingress 呢?我们首先要做出一个区分,Ingress 是 Kubernetes 名称的定义或者规则定义,Ingress controller 是将 Kubernetes 集群状态同步到网关的一个组件。但 APISIX 本身只是 API 网关,怎么把 APISIX 实现成 Ingress controller 呢?我们先来简要了解一下如何实现 Ingress。
实现 Ingress,本质上就只有两部分内容:
- 第一部分:需要将 Kubernetes 集群中的配置、或 Kubernetes 集群中的状态同步到 APISIX 集群。
- 第二部分:需要将 APISIX中 的一些概念,比如像服务、upstream 等概念定义为 Kubernetes 中的 CRD。
如果实现了第二部分,通过 Kubernetes Ingress 的配置,便可以很快的产生 APISIX。通过 APISIX Ingress controller 就可以产生 APISIX 相关的配置。当前为了快速的将 APISIX 落地为能够支持 Kubernetes 的 Ingress,我们创建了一个开源项目,叫 Ingress controller。
Ingress controller 架构图
上图为Ingress controller 项目的整体架构图。左边部分为 Kubernetes 集群,这里可以导入一些 yaml 文件,对 Kubernetes 的配置进行变更。右边部分则是 APISIX 集群,以及它的控制面和数据面。从架构图中可以看出,APISIX Ingress 充当了 Kubernetes 集群以及 APISIX 集群之间的连接者。它主要负责监听 Kubernetes 集群中节点的变化,将集群中的状态同步到 APISIX 集群。另外,由于Kubernetes 倡导所有组件都要具备高可用的特性,所以在 APISIX Ingress 设计之初,我们通过双节点或多节点的模式来保证 APISIX Ingress controller 的保障高可用。
总结
各类 Ingress 横向对比
相对于市面上流行的 Ingress 控制器,我们简单对比来看看 APISIX Ingress 有什么优缺点。上图是外国开发人员针对 Kubernetes Ingress 选型做的一张表格。我在原来表格的基础上,结合自己的理解,将 APISIX Ingress 的功能加入了进来。我们可以看到,最左边的是APISIX,后边就是 Kubernetes Ingress 和 Kong Ingress,后面的 Traefik,就是基于 Golang 的 Ingress。HAproxy 是比较常见的,过去是比较流行的负载均衡器。Istio 和 Ambassador 是国外非常流行的两个Ingress。
接下来我们总结下这些 Ingress各自的优缺点:
- APISIX Ingress:APISIX Ingress 的优点前面也提到了,它具有非常强大的路由能力、灵活的插件拓展能力,在性能上表现也非常优秀。同时,它的缺点也非常明显,尽管APISIX开源后有非常多的功能,但是缺少落地案例,没有相关的文档指引大家如何使用这些功能。
- Kubernetes Ingress:即 Kubernetes 推荐默认使用的 Nginx Ingress。它的主要优点为简单、易接入。缺点是Nginx reload耗时长的问题根本无法解决。另外,虽然可用插件很多,但插件扩展能力非常弱。
- Nginx Ingress:主要优点是在于它完全支持 TCP 和 UDP 协议,但是缺失了鉴权方式、流量调度等其他功能。
- Kong:其本身就是一个 API 网关,它也算是开创了先河,将 API 网关引入到 Kubernetes 中当 Ingress。另外相对边缘网关,Kong 在鉴权、限流、灰度部署等方面做得非常好。Kong Ingress 还有一个很大的优点:提供了一些 API、服务的定义,可以抽象成 Kubernetes 的 CRD,通过Kubernetes Ingress 配置便可完成同步状态至 Kong 集群。缺点就是部署特别困难,另外在高可用方面,与 APISIX 相比也是相形见绌。
- Traefik:基于 Golang 的 Ingress,它本身是一个微服务网关,在 Ingress 的场景应用比较多。他的主要平台基于 Golang,自身支持的协议也非常多,总体来说是没有什么缺点。如果大家熟悉 Golang 的话,也推荐一用。
- HAproxy:是一个久负盛名的负载均衡器。它主要优点是具有非常强大的负载均衡能力,其他方面并不占优势。
- Istio Ingress 和 Ambassador Ingress 都是基于非常流行的 Envoy。说实话,我认为这两个 Ingress 没有什么缺点,可能唯一的缺点是他们基于 Envoy 平台,大家对这个平台都不是很熟悉,上手门槛会比较高。
综上所述,大家在了解了各个 Ingress 的优劣势后,可以结合自身情况快速选择适合自己的 Ingress。
Ingress 总览:https://github.com/Miss-you/awesome-ingress
作者:厉辉,腾讯云中间件API网关核心研发成员,Apache APISIX PPMC。热爱开源,乐于分享,活跃于Apache APISIX社区。
参考博客2:https://www.jianshu.com/p/4b7ae360b3b6
1.1 Ingress简介
1.1.1需求
coredns是实现pods之间通过域名访问,如果外部需要访问service服务,需访问对应的NodeIP:Port。但是由于NodePort需要指定宿主机端口,一旦服务多起来,多个端口就难以管理。那么,这种情况下,使用Ingress暴露服务更加合适。
1.1.2 Ingress组件说明
使用Ingress时一般会有三个组件:反向代理负载均衡器、Ingress Controller、Ingress
1、反向代理负载均衡器
反向代理负载均衡器很简单,说白了就是 nginx、apache 等中间件,新版k8s已经将Nginx与Ingress Controller合并为一个组件,所以Nginx无需单独部署,只需要部署Ingress Controller即可。在集群中反向代理负载均衡器可以自由部署,可以使用 Replication Controller、Deployment、DaemonSet 等等方式
2、Ingress Controller
Ingress Controller 实质上可以理解为是个监视器,Ingress Controller 通过不断地跟 kubernetes API 打交道,实时的感知后端 service、pod 等变化,比如新增和减少 pod,service 增加与减少等;当得到这些变化信息后,Ingress Controller 再结合下文的 Ingress 生成配置,然后更新反向代理负载均衡器,并刷新其配置,达到服务发现的作用
3、Ingress
Ingress 简单理解就是个规则定义;比如说某个域名对应某个 service,即当某个域名的请求进来时转发给某个 service;这个规则将与 Ingress Controller 结合,然后 Ingress Controller 将其动态写入到负载均衡器配置中,从而实现整体的服务发现和负载均衡
整体关系如下图所示:
从上图中可以很清晰的看到,实际上请求进来还是被负载均衡器拦截,比如 nginx,然后 Ingress Controller 通过跟 Ingress 交互得知某个域名对应哪个 service,再通过跟 kubernetes API 交互得知 service 地址等信息;综合以后生成配置文件实时写入负载均衡器,然后负载均衡器 reload 该规则便可实现服务发现,即动态映射。
3.1.3 Nginx-Ingress工作原理
ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化;然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置;再写到nginx-ingress-control的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中;然后reload一下使配置生效。以此达到域名分配置和动态更新的问题。
说明:基于nginx服务的ingress controller根据不同的开发公司,又分为:
- k8s社区的ingres-nginx(https://github.com/kubernetes/ingress-nginx)
- nginx公司的nginx-ingress(https://github.com/nginxinc/kubernetes-ingress)
3.2.4 Ingress Controller高可用架构
作为集群流量接入层,Ingress Controller的高可用性显得尤为重要,高可用性首先要解决的就是单点故障问题,一般常用的是采用多副本部署的方式,我们在Kubernetes集群中部署高可用Ingress Controller接入层同样采用多节点部署架构,同时由于Ingress作为集群流量接入口,建议采用独占Ingress节点的方式,以避免业务应用与Ingress服务发生资源争抢。
如上述部署架构图,由多个独占Ingress实例组成统一接入层承载集群入口流量,同时可依据后端业务流量水平扩缩容Ingress节点。当然如果您前期的集群规模并不大,也可以采用将Ingress服务与业务应用混部的方式,但建议进行资源限制和隔离。 ingree单独找机器部署,不要和k8s的业务节点混在一起,ingress的前面采用slb进行负载
在openshift中的router就是这里k8s中的ingress,生产中ingress都是找单独的机器进行部署,前面采用f5进行负载ingress
https://blog.csdn.net/w50feng/article/details/106539476
kubernetes部署ingress+keepalived高可用
参考博客:https://blog.csdn.net/w50feng/article/details/106539476
kubernetes版本:1.17.3(快速安装:https://blog.csdn.net/w50feng/article/details/106470888)
ingress定义
Ingress 公开了从集群外部到集群内 services 的HTTP和HTTPS路由。 流量路由由 Ingress 资源上定义的规则控制。具体详解见官方文档:https://v1-17.docs.kubernetes.io/zh/docs/concepts/services-networking/ingress/
keepalived介绍:
Keepalived提供了用于负载平衡和高可用性的框架。负载平衡框架依赖于广为人知的Linux虚拟服务器(IPVS)内核模块,该模块提供第4层负载平衡。Keepalived实施一组运行状况检查器,以根据其运行状况动态,自适应地维护和管理负载平衡的服务器池。虚拟冗余路由协议(VRRP)实现了高可用性。VRRP是路由器故障转移的基础砖。此外,keepalived还实现了一组VRRP有限状态机的挂钩,从而提供了低级和高速协议交互。每个Keepalived框架可以独立使用,也可以一起使用以提供弹性基础架构。附官方文档:https://www.keepalived.org/doc/index.html
ingress部署:
给需要安装ingress的node打标签,例为node01和node02
kubectl label nodes node01 ingress=true
kubectl label nodes node02 ingress=true
查询label:kubectl get node --show-labels
ingress的yaml文件下载:https://github.com/kubernetes/ingress-nginx/blob/nginx-0.30.0/deploy/static/mandatory.yaml
修改文件:
kind: Deployment改成kind: DaemonSet;
注释#spec.replicas: 1;
spec.spec内增加配置:
hostNetwork: true #使用hostNetwork:true配置网络,pod中运行的应用程序可以直接看到宿主主机的网络接口,宿主主机所在的局域网上所有网络接口都可以访问到该应用程序
dnsPolicy: ClusterFirstWithHostNet #该设置是使POD使用的k8s的dns,如果不加上dnsPolicy: ClusterFirstWithHostNet ,pod默认使用所在宿主主机使用的DNS,这样也会导致容器内不能通过service name 访问k8s集群中其他POD
nodeSelector:
ingress: 'true' #node标签
运行文件:kubectl apply -f mandatory1.yaml
查看pod启动状态:kubectl get pod -n ingress-nginx
、
dashboard查看部署node为node01和node02
keepalived安装:
node01和node02使用yum安装:yum install keepalived -y
修改配置文件,node01为MASTER,node02为BACKUP
vi /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id k8singress #标识信息,随便取
}
vrrp_instance VI_1 {
state MASTER #角色,node01为MASTER,node02为BACKUP
interface eth0 #vip绑定的网络端口
virtual_router_id 66 #让master和backup在同一个虚拟路由里,id号必须相同
priority 120 #优先级,谁的优先级高谁就是master;node01为120,node02为110
advert_int 1 #心跳间隔时间
authentication {
auth_type PASS #认证
auth_pass 1111 #密码
}
virtual_ipaddress {
192.168.2.11 #虚拟ip
}
}
启动keepalived:systemctl start keepalived
自启动:systemctl enable keepalived
查询VIP:node01上可见VIP,node02没有
node01:
node02:
验证VIP飘移,断开node01,vip飘移到node02,成功验证
注:可添加脚本监控ingress状态,后续更新。。。
验证ingree+vip:
vim nginx.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx-test
namespace: ingress-nginx
labels:
name: nginx-test
spec:
replicas: 1
template:
metadata:
labels:
name: nginx-test
spec:
containers:
- name: nginx-test
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-test
namespace: ingress-nginx
labels:
name: nginx-test
spec:
type: ClusterIP
ports:
- port: 80
protocol: TCP
targetPort: 80
name: http
selector:
name: nginx-test
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-test
namespace: ingress-nginx
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: test.nginx.com
http:
paths:
- path:
backend:
serviceName: nginx-test
servicePort: 80
启动应用:kubectl apply -f nginx.yaml
查看pod状态
更改客户端的hosts文件(windows路径:C:\Windows\System32\drivers\etc):
192.168.2.11 test.nginx.com
浏览器测试,访问成功:
-----------日常记录---------------
————————————————
版权声明:本文为CSDN博主「叼不起的烟斗」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/w50feng/article/details/106539476
https://blog.51cto.com/u_12643266/2455788
Kubernetes Ingress-Nginx实现高可用
原创JasonMingHao2019-12-03 18:27:28©著作权
文章分类kubernetes阅读数4823
假定我们在Kubernetes 指定两个worker节点中部署了ingress nginx来为后端的pod做proxy,这时候我们就需要通过keepalived实现高可用,提供对外的VIP
首先我们要先确保有两个worker节点部署了ingress nginx
在本实验中,环境如下:
IP地址 | 主机名 | 描述 |
---|---|---|
10.0.0.31 | k8s-master01 | |
10.0.0.34 | k8s-node02 | ingress nginx、keepalived |
10.0.0.35 | k8s-node03 | ingress nginx、keepalived |
1、查看ingress nginx状态
创建一个用于测试环境的namespace
2、部署一个Deployment(用于测试)
执行kubectl create 创建deployment
查看deployment是否部署成功
3、在两个worker节点部署keepalived
VIP:10.0.0.130,接口:eth0
1.安装keepalived
1.k8s-node03节点作为master配置keepalived
2.k8s-node03节点作为配置keepalived
3.k8s-node02节点配置keeplived
4.两个节点启动keepalived并加入开机启动
启动完成后检查k8s-node03的IP地址是否已有VIP
5.在宿主机上配置hosts文件,实现IP和域名的解析
6.浏览器测试访问
4.测试vip漂移
现在我将k8s-node03的keepalived进程关闭,那么vip就会漂移到k8s-node02
再次访问
这篇文章相当的经典呀:https://segmentfault.com/a/1190000019908991/
k8s ingress原理及ingress-nginx部署测试
前篇文章说了service,这篇文章来折腾下ingress这个玩意。
ingress是啥东东
上篇文章介绍service时有说了暴露了service的三种方式ClusterIP、NodePort与LoadBalance,这几种方式都是在service的维度提供的,service的作用体现在两个方面,对集群内部,它不断跟踪pod的变化,更新endpoint中对应pod的对象,提供了ip不断变化的pod的服务发现机制,对集群外部,他类似负载均衡器,可以在集群内外部对pod进行访问。但是,单独用service暴露服务的方式,在实际生产环境中不太合适:
ClusterIP的方式只能在集群内部访问。
NodePort方式的话,测试环境使用还行,当有几十上百的服务在集群中运行时,NodePort的端口管理是灾难。
LoadBalance方式受限于云平台,且通常在云平台部署ELB还需要额外的费用。
所幸k8s还提供了一种集群维度暴露服务的方式,也就是ingress。ingress可以简单理解为service的service,他通过独立的ingress对象来制定请求转发的规则,把请求路由到一个或多个service中。这样就把服务与请求规则解耦了,可以从业务维度统一考虑业务的暴露,而不用为每个service单独考虑。
举个例子,现在集群有api、文件存储、前端3个service,可以通过一个ingress对象来实现图中的请求转发:
ingress规则是很灵活的,可以根据不同域名、不同path转发请求到不同的service,并且支持https/http。
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为例。
ingress
ingress是一个API对象,和其他对象一样,通过yaml文件来配置。ingress通过http或https暴露集群内部service,给service提供外部URL、负载均衡、SSL/TLS能力以及基于host的方向代理。ingress要依靠ingress-controller来具体实现以上功能。前一小节的图如果用ingress来表示,大概就是如下配置:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: abc-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
tls:
- hosts:
- api.abc.com
secretName: abc-tls
rules:
- host: api.abc.com
http:
paths:
- backend:
serviceName: apiserver
servicePort: 80
- host: www.abc.com
http:
paths:
- path: /image/*
backend:
serviceName: fileserver
servicePort: 80
- host: www.abc.com
http:
paths:
- backend:
serviceName: feserver
servicePort: 8080
与其他k8s对象一样,ingress配置也包含了apiVersion、kind、metadata、spec等关键字段。有几个关注的在spec字段中,tls用于定义https密钥、证书。rule用于指定请求路由规则。这里值得关注的是metadata.annotations字段。在ingress配置中,annotations很重要。前面有说ingress-controller有很多不同的实现,而不同的ingress-controller就可以根据"kubernetes.io/ingress.class:"来判断要使用哪些ingress配置,同时,不同的ingress-controller也有对应的annotations配置,用于自定义一些参数。列如上面配置的'nginx.ingress.kubernetes.io/use-regex: "true"',最终是在生成nginx配置中,会采用location ~来表示正则匹配。
ingress的部署
ingress的部署,需要考虑两个方面:
- ingress-controller是作为pod来运行的,以什么方式部署比较好
- ingress解决了把如何请求路由到集群内部,那它自己怎么暴露给外部比较好
下面列举一些目前常见的部署和暴露方式,具体使用哪种方式还是得根据实际需求来考虑决定。
Deployment+LoadBalancer模式的Service
如果要把ingress部署在公有云,那用这种方式比较合适。用Deployment部署ingress-controller,创建一个type为LoadBalancer的service关联这组pod。大部分公有云,都会为LoadBalancer的service自动创建一个负载均衡器,通常还绑定了公网地址。只要把域名解析指向该地址,就实现了集群服务的对外暴露。
Deployment+NodePort模式的Service
同样用deployment模式部署ingress-controller,并创建对应的服务,但是type为NodePort。这样,ingress就会暴露在集群节点ip的特定端口上。由于nodeport暴露的端口是随机端口,一般会在前面再搭建一套负载均衡器来转发请求。该方式一般用于宿主机是相对固定的环境ip地址不变的场景。
NodePort方式暴露ingress虽然简单方便,但是NodePort多了一层NAT,在请求量级很大时可能对性能会有一定影响。
DaemonSet+HostNetwork+nodeSelector
用DaemonSet结合nodeselector来部署ingress-controller到特定的node上,然后使用HostNetwork直接把该pod与宿主机node的网络打通,直接使用宿主机的80/433端口就能访问服务。这时,ingress-controller所在的node机器就很类似传统架构的边缘节点,比如机房入口的nginx服务器。该方式整个请求链路最简单,性能相对NodePort模式更好。缺点是由于直接利用宿主机节点的网络和端口,一个node只能部署一个ingress-controller pod。比较适合大并发的生产环境使用。
ingress测试
我们来实际部署和简单测试一下ingress。测试集群中已经部署有2个服务gowebhost与gowebip,每次请求能返回容器hostname与ip。测试搭建一个ingress来实现通过域名的不同path来访问这两个服务:
测试ingress使用k8s社区的ingress-nginx,部署方式用DaemonSet+HostNetwork。
部署ingress-controller
部署ingress-controller pod及相关资源
官方文档中,部署只要简单的执行一个yaml
https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
mandatory.yaml这一个yaml中包含了很多资源的创建,包括namespace、ConfigMap、role,ServiceAccount等等所有部署ingress-controller需要的资源,配置太多就不粘出来了,我们重点看下deployment部分:
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:
serviceAccountName: nginx-ingress-serviceaccount
containers:
- name: nginx-ingress-controller
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.25.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 -> 33
runAsUser: 33
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
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
可以看到主要使用了“quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.25.0”这个镜像,指定了一些启动参数。同时开放了80与443两个端口,并在10254端口做了健康检查。
我们需要使用daemonset部署到特定node,需要修改部分配置:先给要部署nginx-ingress的node打上特定标签,这里测试部署在"node-1"这个节点。
$ kubectl label node node-1 isIngress="true"
然后修改上面mandatory.yaml的deployment部分配置为:
# 修改api版本及kind
# apiVersion: apps/v1
# kind: Deployment
apiVersion: extensions/v1beta1
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
# 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:
serviceAccountName: nginx-ingress-serviceaccount
# 选择对应标签的node
nodeSelector:
isIngress: "true"
# 使用hostNetwork暴露服务
hostNetwork: true
containers:
- name: nginx-ingress-controller
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.25.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 -> 33
runAsUser: 33
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
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
修改完后执行apply,并检查服务
$ kubectl apply -f mandatory.yaml
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
daemonset.extensions/nginx-ingress-controller created
# 检查部署情况
$ kubectl get daemonset -n ingress-nginx
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
nginx-ingress-controller 1 1 1 1 1 isIngress=true 101s
$ kubectl get po -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-ingress-controller-fxx68 1/1 Running 0 117s 172.16.201.108 node-1 <none> <none>
可以看到,nginx-controller的pod已经部署在在node-1上了。
暴露nginx-controller
到node-1上看下本地端口:
[root@node-1 ~]# netstat -lntup | grep nginx
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 2654/nginx: master
tcp 0 0 0.0.0.0:8181 0.0.0.0:* LISTEN 2654/nginx: master
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 2654/nginx: master
tcp6 0 0 :::10254 :::* LISTEN 2632/nginx-ingress-
tcp6 0 0 :::80 :::* LISTEN 2654/nginx: master
tcp6 0 0 :::8181 :::* LISTEN 2654/nginx: master
tcp6 0 0 :::443 :::* LISTEN 2654/nginx: master
由于配置了hostnetwork,nginx已经在node主机本地监听80/443/8181端口。其中8181是nginx-controller默认配置的一个default backend。这样,只要访问node主机有公网IP,就可以直接映射域名来对外网暴露服务了。如果要nginx高可用的话,可以在多个node
上部署,并在前面再搭建一套LVS+keepalive做负载均衡。用hostnetwork的另一个好处是,如果lvs用DR模式的话,是不支持端口映射的,这时候如果用nodeport,暴露非标准的端口,管理起来会很麻烦。
配置ingress资源
部署完ingress-controller,接下来就按照测试的需求来创建ingress资源。
# ingresstest.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-test
annotations:
kubernetes.io/ingress.class: "nginx"
# 开启use-regex,启用path的正则匹配
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
rules:
# 定义域名
- host: test.ingress.com
http:
paths:
# 不同path转发到不同端口
- path: /ip
backend:
serviceName: gowebip-svc
servicePort: 80
- path: /host
backend:
serviceName: gowebhost-svc
servicePort: 80
部署资源
$ kubectl apply -f ingresstest.yaml
测试访问
部署好以后,做一条本地host来模拟解析test.ingress.com到node的ip地址。测试访问
可以看到,请求不同的path已经按照需求请求到不同服务了。
由于没有配置默认后端,所以访问其他path会提示404:
关于ingress-nginx
关于ingress-nginx多说几句,上面测试的例子是非常简单的,实际ingress-nginx的有非常多的配置,都可以单独开几篇文章来讨论了。但本文主要想说明ingress,所以不过多涉及。具体可以参考ingress-nginx的官方文档。同时,在生产环境使用ingress-nginx还有很多要考虑的地方,这篇文章写得很好,总结了不少最佳实践,值得参考。
最后
- ingress是k8s集群的请求入口,可以理解为对多个service的再次抽象
- 通常说的ingress一般包括ingress资源对象及ingress-controller两部分组成
- ingress-controller有多种实现,社区原生的是ingress-nginx,根据具体需求选择
- ingress自身的暴露有多种方式,需要根据基础环境及业务类型选择合适的方式
参考
Kubernetes Document
NGINX Ingress Controller Document
Kubernetes Ingress Controller的使用介绍及高可用落地
通俗理解Kubernetes中Service、Ingress与Ingress Controller的作用与关系
posted on 2021-08-15 16:44 luzhouxiaoshuai 阅读(4186) 评论(0) 编辑 收藏 举报