Nginx在Kubernetes中的应用
-
- [2、Nginx Ingress](#2、Nginx Ingress)
-
- [2.1、Nginx Ingress原理](#2.1、Nginx Ingress原理)
- 2.2、集成的第三方模块
- 2.3、安装部署
-
- [2.3.1、Nginx Ingress部署](#2.3.1、Nginx Ingress部署)
- 2.3.2、管理工具
- 2.4、日志管理
- 2.5、监控管理
2、Nginx Ingress
Kubernetes通过kube-proxy服务实现了Service的对外发布及负载均衡,它的各种方式都是基于传输层实现的。在实际的互联网应用场景中,不仅要实现单纯的转发,还有更加细致的策略需求,如果使用真正的负载均衡器更会增加操作的灵活性和转发性能。基于以上需求,Kubernetes引入了资源对象Ingress, Ingress为Service提供了可直接被集群外部访问的虚拟主机、负载均衡、SSL代理、HTTP路由等应用层转发功能。Kubernetes官方发布了基于GCE和Nginx的Ingress控制器,Nginx Ingress控制器能根据Service中Pod的变化动态地调整配置,结合Nginx的高稳定性、高性能、高并发处理能力等特点,使Kubernetes对集群中运行于容器的应用程序具有了更加灵活的应用层管理能力。
Nginx Ingress因使用Nginx的不同版本,分为Nginx官方版本和Kubernetes社区版。Nginx官方版本提供其基于Go语言开发的Ingress控制器,并与Nginx集成分为Nginx开源版和Nginx Plus版;开源版仅基于Nginx的原始功能,提供了Nginx原生配置指令的支持,相较于Nginx Plus版功能简单且不支持Pod变化的动态变更。Nginx Plus版则提供了诸多完善的商业功能,其支持Nginx原生配置指令、JWT验证、Pod变化的动态配置及主动健康检查等功能。Kubernetes社区版是基于Nginx的扩展版OpenResty及诸多第三方模块构建的,其基于OpenResty的Lua嵌入式编程能力,扩展了Nginx的功能,并基于balancer_by_lua模块实现了Pod变化的动态变更功能。本章将基于Kubernetes社区版的Nginx Ingress进行介绍。
2.1、Nginx Ingress原理
Nginx Ingress由资源对象Ingress、Ingress控制器、Nginx三部分组成,Ingress控制器用以将Ingress资源实例组装成Nginx配置文件(nginx.conf),并重新加载Nginx使变更的配置生效。当它监听到Service中Pod变化时通过动态变更的方式实现Nginx上游服务器组配置的变更,无须重新加载Nginx进程。工作原理如图所示。

- Ingress,一组基于域名或URL把请求转发到指定Service实例的访问规则,是Kubernetes的一种资源对象,Ingress实例被存储在对象存储服务etcd中,通过接口服务被实现增、删、改、查的操作。
- Ingress控制器(Ingress controller),用以实时监控资源对象Ingress、Service、End-point、Secret(主要是TLS证书和Key)、Node、ConfigMap的变化,自动对Nginx进行相应的操作。
- Nginx,实现具体的应用层负载均衡及访问控制。
Ingress控制器通过同步循环机制实时监控接口服务Ingress等资源对象的变化,当相关Service对应的端点列表有变化时,会通过HTTP POST请求将变化信息发送到Nginx内部运行的Lua程序进行处理,实现对NginxUpstream中后端Pod IP变化的动态修改。每个后端Pod的 IP及targetPort信息都存储在Nginx的共享内存区域,Nginx对每个获取的请求将使用配置的负载均衡算法进行转发,Nginx的配置中应用Lua模块的balancer_by_lua功能实现upstream指令域的动态操作,Pod IP变化及资源对象Ingress对upstream指令域相关注解(annotation)的变化无须执行Nginx的reload操作。
当Ingress控制器监控的其他资源对象变化时,会对当前变化的内容创建Nginx配置模型,如果新的配置模型与当前运行的Nginx配置模型不一致,则将新的配置模型按照模板生成新的Nginx配置,并对Nginx执行reload操作。Nginx配置模型避免了Nginx的无效reload操作。为避免因Nginx配置语法错误导致意外中断,Ingress控制器为Nginx的配置内容提供了冲突检测及合并机制,Ingress控制器使用了准入控制插件(Validating AdmissionWebhook)做验证Ingress配置语法的准入控制,验证通过 的Ingress资源对象才会被保存在存储服务etcd中,并被Ingress控制器生成确保没有语法错误的Nginx配置文件。
2.2、集成的第三方模块
Kubernetes的Nginx Ingress当前版本是0.25.1,其集成了Nginx的扩展版本Open-Resty的1.15.8.1版本,OpenResty的最大特点是集成了Lua脚本的嵌入式编程功能,基于Nginx的优化,使Nginx具有更强的扩展能力。Nginx Ingress通过Lua脚本编程,利用OpenResty的balancer_by_lua模块,可通过nginx-ingress控制器动态地修改Nginx上游服务器组的配置,无须Nginx进程的热加载,有效地解决了因Pod调度带来的Pod IP变化的问题。Kubernetes的Nginx Ingress在OpenResty基础上还集成了诸多的第三方模块,模块功能介绍如下。
-
(1)Ajp协议模块(nginx_ajp_module)
Ajp协议模块是一个使Nginx实现Ajp协议代理的模块,该模块可以使Nginx通过Ajp协议连接到被代理的Tomcat服务。
-
(2)InfluxDB输出模块(nginx-influxdb-module)
InfluxDB输出模块可以使Nginx的每次请求记录以InfluxDB作为后端进行存储,其以非阻塞的方式对每个请求进行过滤,并使用UDP协议将处理后的数据发送到InfluxDB服务器。可以通过该模块实时监控Nginx的所有请求,获得每个请求的连接类型、请求状态,并通过InfluxDB实现相关故障状态的报警。
-
(3)GeoIP2数据库模块(ngx_http_geoip2)
MaxMind的GeoIP数据库已经升级到第二代,GeoIP2数据库提供了准确的IP信息,包括IP地址的位置(国家、城市、经纬度)等数据。该模块增加了GeoIP2数据的支持。
模块网址:https://github.com/nginx-modules/ngx_http_geoip2_module
-
(4)摘要认证模块(nginx-http-auth-digest)
摘要认证模块使Nginx的基本认证功能增加了摘要认证(Digest Authentication)的支持,这是一种简单的身份验证机制,是对基本认证的一种安全改进,仅通过服务端及客户端根据用户名和密码计算的摘要信息进行验证,避免了密码的明文传递,增加了认证过程的安全性。
模块网址:https://github.com/nginx-modules/nginx-http-auth-digest
-
(5)内容过滤模块(ngx_http_substitutions_filter_module)
内容过滤模块是一个内容过滤功能的模块,其相对于Nginx自带的内容过滤模块(ngx_http_sub_module,参见4.3.4节)增加了正则匹配的替换方式。
模块网址:https://github.com/nginx-modules/ngx_http_substitutions_filter_module
-
(6)分布式跟踪模块(nginx-opentracing)
OpenTracing由API规范、实现该规范的框架和库以及项目文档组成,是一个轻量级的标准化规范,其位于应用程序和跟踪分析程序之间,解决了不同分布式追踪系统API不兼容的问题。OpenTracing允许开发人员使用API向应用程序代码中添加工具,实现业务应用中的分布式请求跟踪。分布式请求跟踪,也称分布式跟踪,是一种用于分析和监视应用程序的方法,特别是那些使用微服务体系结构构建的应用程序。分布式跟踪有助于查明故障发生的位置以及导致性能低下的原因。该模块是将Nginx的请求提供给OpenTracing项目的分布式跟踪系统用于应用的请求分析和监控。Nginx Ingress中集成了jaeger和zipkin两种分布式跟踪系统的OpenTracing项目插件,用户可根据实际情况进行选择使用。
模块网址:https://github.com/opentracing-contrib/nginx-opentracing
-
(7)Brotli压缩模块(ngx_brotli)
Brotli是Google推出的侧重于HTTP压缩的一种开源压缩算法,它使用lz77算法的现代变体、Huffman编码和基于上下文的二阶建模的组合来压缩数据。在与Deflate相似的压缩与解压缩速度下,增加了20%的压缩密度。在与gzip的测试下,因压缩密度高其消耗的压缩时间要比gzip多,但在客户端解压的时间则相当。
-
(8)ModSecurity连接器模块(ModSecurity-nginx)
ModSecurity是一个开源的Web应用防火墙,其主要作用是增强Web应用的安全性并保护Web应用免受攻击。模块ModSecurity-nginx是一个Nginx的ModSecurity连接器,其提供了Nginx和libmodsecurity(ModSecurity v3)之间的通信通道。Nignx Ingress中已经集成了ModSecurity和OWASP规则集,在Nginx配置文件目录可以查看相关配置。
-
(9)lua-resty-waf模块
lua-resty-waf是一个基于OpenResty的高性能Web应用防火墙,它使用Nginx Lua API及灵活的规则架构分析和处理HTTP请求信息,并不断开发和测试一些自定义的规则补丁来应对不断出现的新的安全威胁。lua-resty-waf提供了ModSecurity兼容的规则语法,支持ModSecurity现有规则的自动转换,用户无须学习新的语法规则就可以扩展lua-resty-waf的规则。
2.3、安装部署
Helm是一个非常方便的Kubernetes应用部署工具,支持Nginx Ingress的快速部署和卸载。通过Helm可快速将Nginx Ingress部署在Kubernetes集群中,Helm中NginxIngress的1.19.1版本Chart部分参数如表所示。


Nginx Ingress的默认部署方式是Deployment,只会部署一个副本,Service对外发布类型是LoadBalancer,安装参数如下:
bash
helm install --name nginx-ingress stable/nginx-ingress --set rbac.create=true
- Helm安装的应用名称为nginx-ingress。
- rbac.create参数用以为nginx-ingress创建RBAC资源,获取与接口服务的访问授权。
2.3.1、Nginx Ingress部署
Nginx Ingress以Pod形式运行在Kubernetes集群中,用户可根据Kubernetes的网络通信特点以及实际场景选择灵活的部署方式进行Nginx Ingress的部署,此处分别以基于资源对象Service的NodePort方式和Pod的hostNetwork方式举例介绍。
-
(1)Service的NodePort方式
以NodePort类型部署Nginx Ingress,需要使用参数进行指定controller.service.type为NodePort。为便于管理,可以为Nginx Ingress创建单独使用的命名空间nginx-ingress,部署拓扑如图所示。

部署命令如下:
bash# 安装nginx-ingress helm install --name nginx-ingress \ --namespace nginx-ingress \ stable/nginx-ingress \ --set "rbac.create=true,controller.autoscaling.enabled=true,controller. autoscaling.minReplicas=2,controller.service.type=NodePort,con-troller.service.externalTrafficPolicy=Local" # 也可以在创建后调整副本数 kubectl scale --replicas=3 deployment/nginx-ingress- Helm安装的应用名称为nginx-ingress,命名空间为nginx-ingress。
- 以默认的Deployment方式部署,设置Pod副本数为2,并以Service的NodePort方式对外发布服务,设置流量调度策略为Local。
- Kubernetes将为nginx-ingress Service随机创建范围在30000~32767之间的Node-Port端口。
- 用户将Kubernetes中节点IP和NodePort手动添加到传输层负载均衡中的虚拟服务器集群中。
- 外部请求发送到传输层负载均衡虚拟服务器,传输层负载将请求数据转发到Kubernetes集群节点的NodePort。
- NodePort类型的Service将请求负载到对应的NginxPod。
- Nginx将用户请求进行应用层负载转发到配置的应用Pod。
- 在该部署方式下,Nginx Pod需要使用Local的流量调度策略,获取客户端的真实IP。
-
(2)Pod的hostNetwork方式
主机网络(hostNetwork)方式可以使Pod与宿主机共享网络命名空间,外网传输效率最高。因Pod直接暴露外网,虽然存在一定的安全问题,但不存在客户端源IP隐藏的问题,部署拓扑如图所示。

部署命令如下:
bash# 以Deployment方式部署 helm install --name nginx-ingress \ --namespace nginx-ingress \ stable/nginx-ingress \ --set "rbac.create=true,controller.service.type=ClusterIP,controller. hostNetwork=true"- Deployment方式部署时,Nginx Ingress的Service设置类型为ClusterIP,仅提供内部服务端口。
- 用户将Kubernetes中节点IP及80、443端口手动添加到传输层负载均衡中的虚拟服务器集群中。
- 用户请求经传输层负载均衡设备转发到Nginx, Nginx将用户请求负载到Kubernetes集群内的Pod应用。
也可以使用DaemonSet部署方式,在集群中的每个节点自动创建并运行一个Nginx Ingress Pod,实现NginxIngress的自动扩展。
bash# 以DaemonSet方式部署nginx-ingress并成为集群唯一入口 helm install --name nginx-ingress \ --namespace nginx-ingress \ stable/nginx-ingress \ --set "rbac.create=true,controller.kind=DaemonSet,controller.service.type=ClusterIP,controller.hostNetwork=true" -
** (3)SSL终止(SSL Termination)和SSL透传(SSLPassthrough)**
SSL终止模式下,客户端的TLS数据会在代理服务器Nginx中解密,解密的数据由代理服务器直接或再次TLS加密后传递给被代理服务器,这种模式下,相对增加代理服务器的计算负担,但方便了SSL证书的统一管理。
SSL透传模式下,Nginx不会对客户端的HTTPS请求进行解密,加密的请求会被直接转发到后端的被代理服务器,这种方式常被应用到后端的HTTPS服务器需要对客户端进行客户端证书验证的场景,相对也会降低Nginx对TLS证书加解密的负担。由于请求数据是保持加密传输的,HTTP消息头将无法修改,所以消息头字段X-forwarded-*的客户端IP无法被添加。Nginx Ingress默认部署方式没有开启SSL透传的支持,需要在部署时使用参数--enable-ssl- passthrough进行开启。
bash# 修改部署资源对象nginx-ingress-controller kubectl edit Deployment/nginx-ingress-controller -n nginx-ingress # 在规范部分添加容器启动参数--enable-ssl-passthrough spec: containers: - args: - /nginx-ingress-controller - --default-backend-service=nginx-ingress/nginx-ingress-default-backend - --election-id=ingress-controller-leader - --ingress-class=nginx - --configmap=nginx-ingress/nginx-ingress-controller - --enable-ssl-passthrough -
(4)卸载Nginx Ingress
Nginx的配置是以资源对象ConfigMap和Ingress方式存储在etcd服务中的,所以即便删除或重新部署Nginx Ingress也不会影响之前的配置。
bashhelm delete --purge nginx-ingress
2.3.2、管理工具
Nginx Ingress提供了基于kubectl工具的管理插件ingress-nginx,用于Nginx Ingress的日常维护。插件ingress-nginx安装方法如下:
bash
# 安装插件ingress-nginx
kubectl krew install ingress-nginx
常见命令参数如下:
bash
# 显示所有的Ingress实例摘要
kubectl ingress-nginx ingresses
# 查看所有的后端Service配置
kubectl ingress-nginx backends -n nginx-ingress
# 查看Nginx的所有配置
kubectl ingress-nginx conf -n nginx-ingress
# 查看指定主机名的Nginx配置
kubectl ingress-nginx conf -n nginx-ingress --host auth.nginxbar.org
# 查看Nginx服务器的配置目录
kubectl ingress-nginx exec -i -n nginx-ingress -- ls /etc/nginx
# 查看Nginx服务器的日志
kubectl ingress-nginx logs -n nginx-ingress
2.4、日志管理
Nginx Ingress是以Pod方式运行的,在默认配置下,Nginx的日志输出到stdout及stderr。Kubernetes下有很多日志收集解决方案,此处推荐使用Filebeat进行容器日志收集,并将容器日志实时发送到ELK集群,ELK环境部署可参见9.2节,日志收集方案逻辑如图所示。

- Docker的默认日志驱动是json-driver,每个容器的日志输出到stdout及stderr中时,Docker的日志驱动会将容器日志以*-json.log的命名方式保存在/var/lib/docker/containers/目录下。
- 在Kubernetes集群中以DaemonSet方式部署Filebeat应用,会在每个Node节点运行一个Filebeat应用Pod,进行每个Node节点的容器日志采集。
- Filebeat采集的日志可以直接发送给Logstash服务器,也可以发送给Kafka后由Logstash服务器进行异步获取。
- 所有日志被Logstash转到Elasticsearch集群进行存储。
- 使用者通过Kibana进行日志查看和分析。
-
(1)部署Filebeat
bash# 获取官方的Filebeat资源配置文件 curl -L -O https://raw.githubusercontent.com/elastic/beats/7.3/deploy/kubernetes/filebeat-kubernetes.yaml # 修改filebeat输出目标为Logstash sed -i "s/ cloud.id/ #cloud.id/g" filebeat-kubernetes.yaml sed -i "s/ cloud.auth/ #cloud.auth/g" filebeat-kubernetes.yaml sed -i "s/ output.elasticsearch:/ output.logstash:/g" filebeat-kubernetes.yaml sed -i 's/ hosts:.*/ hosts: ["10\.10\.4\.37:5045"]/g' filebeat-kubernetes.yaml sed -i "s/ username/ #username/g" filebeat-kubernetes.yaml sed -i "s/ password/ #password/g" filebeat-kubernetes.yaml kubectl create -f filebeat-kubernetes.yaml -
(2)配置Logstash
按照kubernetes.labels.app创建容器日志在Elasticsearch中的索引,配置文件内容如下:bashcat>logstash/pipeline/k8s.conf<<EOF input { beats { port => 5045 codec =>"json" } } filter { mutate { # 添加字段kubernetes_apps默认值为kubernetes_noapps add_field => { "kubernetes_apps" => "kubernetes_noapps" } } if [kubernetes][labels][app] { mutate { # 当存在kubernetes.labels.app时,将该字段复制为字段kubernetes_apps copy => { "[kubernetes][labels][app]" => "kubernetes_apps" } } } } output { elasticsearch { # 将log输出到ES服务器 hosts => ["http://10.10.4.37:9200"] # 根据字段kubernetes_apps的值创建ES索引 index => "k8slog-%{kubernetes_apps}-%{[@metadata][version]}-%{+YYYY.MM.dd}" } } EOFHelm默认会为安装的应用添加app标签,通过Helm安装Nginx Ingress的app标签值为nginx-ingress,因此Elasticsearch中自动创建的索引名前缀为k8slog-nginx-ingress-*。
2.5、监控管理
Nginx Ingress中已经集成了Nginx的PrometheusExporter,可以直接使用Prometheus或Zabbix获取监控数据。Nginx监控支持可以在部署的时候使用部署参数controller.metrics.enabled=true启用。Prometheus及Zabbix的部署和使用可参见10.4节。
bash
# 启用监控
helm install --name nginx-ingress \
--namespace nginx-ingress \
stable/nginx-ingress \
--set "rbac.create=true,controller.kind=DaemonSet,controller.service.type=ClusterIP,controller.hostNetwork=true,controller.metrics.enabled=true"
curl http://节点IP:9913/metrics