Ingress Controller 是一个统称,并不只有一个,例如:
现实生活中,大部分流量都是 http ,而通常情况下 K8S 的 Overlay 网络是 K8S 节点才能访问的,例如 PodIP 是 10.224.1.198,非 K8S worker 访问这个 IP 路由到自己网关,然后网关路由出去,也就是无法访问到 PodIP,这个和 vmware workstation 的 nat 网络虚拟机一样,你局域网内其他机器无法访问你 vmware 上的虚机。
假设有两个 Service 需要映射出去:
你第一时间想到的是 node 上跑个 nginx 反向代理 Service
nginx 写配置文件, resolver 写 coredns SVC_IP:
http { resolver 10.96.0.10 valid=5s; server { listen 80; location /userInfo { proxy_pass http://account-user.prod.svc.cluster.local; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /bookList { proxy_pass http://book-server.prod.svc.cluster.local; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } } |
后面你意识到这样每次都是走 Service,能否 proxy_pass 写的是 service 名字,lua 去请求 https://kubernetes.default.svc.cluster.local 把 PodIP 维护在 upstream 列表里。
再后面,你意识到写文件非常繁琐,不知道哪些 Service 被代理了,你意识到 k8s 有 annotation 这个东西,能够在这里写注释自己 nginx + lua 读取,你可能写到 svc 的 annotation 上。也就是下面类似:
apiVersion: v1 kind: Service metadata: annotations: conf:| more_set_headers "Request-Id: $req_id"; ... ... |
nginx + lua 连接 kube-apiserver,获取所有 Service 的 annotation 生成配置文件。
随着你对 k8s 的 api 越来越熟悉,意识到写 svc 上似乎太繁琐,这样不方便 kubectl 增删改查,可不可以创建自己的资源对象,类似 Kind: Pod 那样有 kind: Proxy,实际上这就是 Kind: ingress 由来。把反向代理配置文件抽象成 K8S 的 yaml 配置:
# 这里是举例,不保证时效性 apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-ingress annotations: nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/proxy-read-timeout: "600" nginx.ingress.kubernetes.io/proxy-send-timeout: "600" spec: ingressClassName: nginx rules: - host: api.domain.com http: paths: - backend: serviceName: api servicePort: 80 - host: test.domain.com http: paths: - path: /web/* backend: serviceName: web servicePort: 8080 - host: backoffice.domain.com http: paths: - backend: serviceName: backoffice servicePort: 8080 |
例如访问到 Ingress Controller 的 http 流量:
也就是和 nginx 反向代理类似,如果你进入到 ingress nginx 内,会发现上面的 Ingress 最终还是在容器内生成 nginx 配置文件:
$ kubectl -n ingress-nginx exec nginx-ingress-controller-6cdcfd8ff9-t5sxl -- cat /etc/nginx/nginx.conf ... ## start server nginx.testdomain.com server { server_name nginx.testdomain.com ; listen 80; set $proxy_upstream_name "-"; location / { set $namespace "default"; set $ingress_name "nginx-ingress"; set $service_name "nginx"; set $service_port "80"; set $location_path "/"; ........ ## end server nginx.testdomain.com ... |
要注意的一点是虽然写的是反向代理 service 名字,但是实际是直接反向代理到 service 的 endpoint 上的。
+-------+ | | -+---------->+ | / +-------+ node1 / / / +-------+ +--------+ / | | | client +-----------> SLB -------------->+ | +--------+ \ +-------+ node2 \ \ \ +-------+ ------------->+ | | | +-------+ node3 |
部署方式:
多个 Ingres Controller(注意 ingress yaml 的 ingressClassName)
+---------------------------+ | | -+---------->+ hostNetwork的ingress nginx| / +---------------------------+ node1 / / / +---------------------------+ +--------+ / | | | client +-----------> F5 -------------->+ hostNetwork的ingress nginx| +--------+ \ +---------------------------+ node1 \ \ \ +---------------------------+ ------------->+hostNetwork的ingress nginx | | | +---------------------------+ node3 +---------------------------+ | | -+---------->+ hostNetwork的Higress | / +---------------------------+ node4 / / / +---------------------------+ +--------+ / | | | client +-----------> SLB(or VIP) -------->+ hostNetwork的Higress | +--------+ \ +---------------------------+ node5 \ \ \ +---------------------------+ ------------->+ hostNetwork的Higress | | | +---------------------------+ node6 |