Kubernetes Nginx-ingress

主机 Nginx

一般 nginx 做主机反向代理(网关)有以下配置

  1. upstream order{
  2. server 192.168.1.10:5001;
  3. server 192.168.1.11:5001;
  4. }
  5. server {
  6. listen 80;
  7. server_name order.example.com;
  8. access_log /var/log/nginx/order.example.com-access.log;
  9. error_log /var/log/nginx/order.example.com-error.log;
  10. location / {
  11. proxy_pass_header Server;
  12. proxy_set_header Host $http_host;
  13. proxy_set_header X-Real-IP $remote_addr;
  14. proxy_set_header X-Scheme $scheme;
  15. proxy_pass http://order;
  16. }
  17. }

其中 192.168.1.10:5001,192.168.1.10:5001 把他们称为 Endpoint,就是所谓的具体的服务,比如 order 订单服务。

pod nginx-ingress

nginx-ingress也是一种代理,是一个pod,外部的数据统一经过(必经)这个pod,然后通过该pod内部的nginx方向代理到各各服务(Endpoint)。nginx-ingress是ingress控制器插件的一种,这些插件有很多,比如istio-ingressgateway。

1、Pod

nginx-ingress pod有两个功能,controller 和 nginx:

controller:和kubernetes api通讯实时更新nginx配置(就是ingress yaml资源了) nginx:正常的反向代理
与主机nginx的区别是,该pod nginx-ingress是运行在pod里。主机在定义反向代理配置文件时,需要监听一个对外开放的端口,比如上边的80端口。那么pod中的nginx端口是如何配置的呢?
在github上找到了nginx-ingress的deployment.yaml
https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
其中一段

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: nginx-ingress-controller
  5. namespace: ingress-nginx
  6. labels:
  7. app.kubernetes.io/name: ingress-nginx
  8. app.kubernetes.io/part-of: ingress-nginx
  9. spec:
  10. replicas: 1
  11. selector:
  12. matchLabels:
  13. app.kubernetes.io/name: ingress-nginx
  14. app.kubernetes.io/part-of: ingress-nginx
  15. template:
  16. metadata:
  17. labels:
  18. app.kubernetes.io/name: ingress-nginx
  19. app.kubernetes.io/part-of: ingress-nginx
  20. annotations:
  21. prometheus.io/port: "10254"
  22. prometheus.io/scrape: "true"
  23. spec:
  24. # wait up to five minutes for the drain of connections
  25. terminationGracePeriodSeconds: 300
  26. serviceAccountName: nginx-ingress-serviceaccount
  27. containers:
  28. - name: nginx-ingress-controller
  29. image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.26.1
  30. ...
  31. ...
  32. ...
  33. ports:
  34. - name: http
  35. containerPort: 80
  36. - name: https
  37. containerPort: 443

可以看到

  1. - name: http
  2. containerPort: 80
  3. - name: https
  4. containerPort: 443

默认对外监听了两个端口80和443,也就是说,有这两个端口对外就可以web服务了。

2、ingress 资源

ingress 资源通过yaml进行管理的,比如以下:

  1. apiVersion: extensions/v1beta1
  2. kind: Ingress
  3. metadata:
  4. name: order
  5. spec:
  6. rules:
  7. - host: order.example.com
  8. http:
  9. paths: /
  10. backend:
  11. serviceName: order
  12. servicePort: 80

以上定义了一个单一规则的ingress,该pod(nginx-ingress)接收到外部所有的请求,将被发送到内部order服务的80端口上。接下来看pod(nginx-ingress)如何把ingress资源转化为该pod中的nginx反向代理配置文件

  1. upstream order{
  2. server order:80;
  3. }
  4. server {
  5. listen 80;
  6. server_name order.example.com;
  7. ...
  8. ...
  9. location / {
  10. proxy_pass_header Server;
  11. proxy_set_header Host $http_host;
  12. proxy_set_header X-Real-IP $remote_addr;
  13. proxy_set_header X-Scheme $scheme;
  14. proxy_pass http://order; # 对应ingress 资源 name: order
  15. }
  16. }

当然ingress如果包含https,那么会转化nginx对应的443端口及证书的配置文件内容,这里就不写了。
那么,单一个规则的ingress资源代理多个服务(比如order服务,product服务)或者多个ingress资源文件如何转化为nginx配置?猜测,其实就是转化成了多个。

  1. upstream order{
  2. server order:80;
  3. }

当然,被转化的nginx配置文件要比这些复杂的多,据说还是用lua脚本写的,灵活如openresty。

3、nginx-ingress对外提供服务

一般来讲,pod直接对外提供服务就只有两种方式:

  • create一个service,该service暴漏nodePort
  • forward 映射

一般采用第一种。
nginx-ingress也是一个pod,所以,为了能使外部通过该pod代理访问,还需要nginx-ingress对外提供一个nodePort的service。这个service这里也不再写了。

4、nginx-ingress工作流程

Nginx-ingress 控制器实现原理 - 图1
可以看到,因为 nginx-ingress 这个pod做了所有service的代理,在高并发情况下将承受巨大压力,可以增加多个pod实例。