Nginx Ingress
在K8S的中, Service 暴露给外界的三种方法。其中有一个叫作 LoadBalancer 类型的 Service,它会为你在 Cloud Provider(比如:Google Cloud 或者 OpenStack)里创建一个与该 Service 对应的负载均衡服务。
但是,由于每个 Service 都要有一个负载均衡服务,所以这个做法实际上既浪费成本又高。作为用户,我其实更希望看到 Kubernetes 为我内置一个全局的负载均衡器。然后,通过我访问的 URL,把请求转发给不同的后端 Service。
这种全局的、为了代理不同后端 Service 而设置的负载均衡服务,就是 Kubernetes 里的 Ingress 服务。
简介
Kubernetes 内置一个全局的负载均衡器。然后,通过访问 URL,把请求转发给不同的后端 Service。这就是这种全局的、为了代理不同后端 Service 而设置的负载均衡服务,就是 Kubernetes 里的 Ingress 服务。所以,Ingress 的功能其实很容易理解:所谓 Ingress,就是 Service 的“Service”。
安装 nginx-ingress
- 创建
Nginx Controller
- 创建
Namespace
与账号
- 创建角色并绑定账号
- 创建 default server 的秘钥
- 创建存放
nginx.conf
的Config Map
- 创建
ingress-class
- 创建
Nginx Controller Pod
- 暴露
Nginx Controller
服务 - 创建
Ingress
规则
Host
精准与通配符匹配Path
前缀或精确匹配Backend
第一步:创建 Nginx Controller
|
|
Namespace 与 账号
|
|
default server 秘钥证书 与 Config Map
|
|
创建 Nginx-Ingress
当一个新的 Ingress 对象由用户创建后,nginx-ingress-controller 就会根据 Ingress 对象里定义的内容,生成一份对应的 Nginx 配置文件(/etc/nginx/nginx.conf),并使用这个配置文件启动一个 Nginx 服务。
|
|
为了让用户能够用到这个 Nginx,我们就需要创建一个 Service 来把 Nginx Ingress Controller 管理的 Nginx 服务暴露出去。创建 Node Port
, 暴露服务。Kubernetes将在集群的每个节点上随机分配两个端口。可以使用 任意节点 + 分配的特殊端口 即可访问服务。
|
|
这个 Service 的唯一工作,就是将所有携带 ingress-nginx 标签的 Pod 的 80 和 433 端口暴露出去。
测试
Nginx 官方 ingress 提供了 cafe 、 tea 的例子,参考: https://github.com/nginxinc/kubernetes-ingress/tree/master/examples/complete-example
|
|
部署
|
|
验证:
|
|
配置
每次文件变化后,执行 kubectl apply -f cafe-ingress.yaml
,实际会对Nginx进行一次reload。
|
|
执行上述命令后,会生成一个 ingress 规则。
|
|
而这个ingress 规则实质上是在 ingress controller
的 deployment pod 中的 /etc/nginx/conf.d
中生成一个规则。
|
|
nginx.conf
相关配置遵从 configmap 模板配置, 同样更改会reload。
详见:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
k8s 官方的 ingress-nginx 是利用 balance by lua 的方式进行负载均衡。nginx 官方是利用 nginx reload 实现。
ingress 工作原理
K8S 调度 Nginx Ingress Controller Pod
, Go 语言基于Nginx 模板生成的 nginx.conf
- 模板语法
import "text/template"
- 模板位置 Nginx 官方:
/nginx.ingress.tmpl
和nginx.tmpl
- 填充模板的数据:
ConfigMap
,Ingress
,Service
和Secrets
配置文件改变后,**Nginx 官方的 Ingress (https://github.com/nginxinc/kubernetes-ingress) ** 的做法是每次 reload。而 **kubernetes 官方的 Ingress **是基于 lua 实现的类似openresty 的 balance by lua
来实现配置重载。
而配置文件本身是全部存在的 ETCD 中的。ETCD 基于 raft 协议实现高可用的一致性。具体可以参考我之前的文章 etcd 的基本入门
Nginx 官方的Ingress 和 K8S 官方的Ingress 性能对比。
- 静态部署:即 Nginx 配置文件不变, 可以看到开源的Nginx(蓝线)在压力逐渐增加时,时延变高的最慢。
- 动态部署: 即 Nginx 配置总是变,如 upstream 变化导致需要配置变化。官方Nginx的性能就拉垮了,压力到90多就时延上升一个台阶,到99.9时时延已经1分钟以上了。
参考:K8S Ingress Controller技术细节探讨
Ingress Controller
Ingress Controller 完成了包含 负载均衡/会话保持
、协议转换
、TLS 卸载、认证
、文本压缩
、请求认证
、限流限速
、Waf
、全链路跟踪
、日志监控
等等功能。
第三方模块启用
Nginx 有大量的第三方模块,Ingress 复用 Nginx 时这些大量的第三方模块是用 annotations
的方式加载这些第三方模块。详见 K8S官方文档 Annotations 和 Nginx 官方文档
|
|
- opentrace 全链路追踪
Nginx 本身可以遵从全链路追踪 opentracing
架构规范实现(https://opentracing.io/)。通过为流行的平台提供一致的,富有表现力的,供应商中立的API,OpenTracing使开发人员可以轻松地通过O(1)配置更改添加(或切换)跟踪实现。OpenTracing还为OSS检测和特定于平台的跟踪帮助程序库提供了通用语言。
比如全链路追踪的 jaeger trace
。jaeger 本身搭建比较简单,但是其数据源需要 ingress Nginx 按照 opentracing 规范导入到 jaeger 中最使用 UI 查看。
nginx ingress
中的nginx 支持如 https://github.com/opentracing-contrib/nginx-opentracing.git
等模块。
详见: 采用 NGINX Ingress Controller for Kubernetes 支持 OpenTracing
nginx.conf 配置加载
nginx 的 config 配置文件是通过 ConfigMap
搭配 go 语言的 template 模板来更新 nginx.conf
。
|
|
如下是进入到 nginx ingress controller
pod 里看到的内容,ConfigMap
里data中的内容,worker-processes: "2"
会对应到 pod 里的 nginx.tmpl
的 {{.WorkerProcesses}}
|
|
k8s与Nginx 官方 Ingres 区别
进程架构
K8S 官方
- /usr/bin/dumb-init
- nginx-ingress-controller
- /usr/local/nginx/sbin/nginx -c /etc/nginx/nginx.conf
Nginx 官方
- nginx-ingress
- /usr/sbin/nginx
K8S 官方优势
可以看出 K8S 官方是对容器的理解非常深,容器是单进程架构,这并不意味着容器里面只能跑一个进程,而是指容器内只能管理一个进程。K8S 的这一个进程就是 /usr/bin/dumb-init
仿照了操作系统中的 systemd
进程对这个POD容器进行管理。
而Nginx官方的Ingress 是 nginx-ingress
进程。
另一个就是K8S官方的负载均衡配置变更是用的 Balance By Lua
,这个在配置频繁变更时性能会很高。
- Nginx 官方优势
但是 Nginx 官方的 Ingress 明显是对 nginx
的理解更加深刻的。Ingress 默认是不支持正则匹配,Nginx 官方则对此有优化,这个就是 VirtualServer
、VirtualServerRoute
。
另外,Nginx 官方还提供了 snippets
。支持更高级的匹配模式,但其实也是一种全局的匹配。 具体参考 Advanced Configuration with Snippets
支持添加 302 跳转,支持全局加 Header 。
|
|
另外Nginx官方支持自定义模板。具体参考 Custom Annotations