nginx-ingress 介绍
Ingress 是一种 Kubernetes 资源,也是将 Kubernetes 集群内服务暴露到外部的一种方式。
Nginx Ingress Controller 是 Kubernetes Ingress Controller 的一种实现,作为反向代理将外部流量导入集群内部,实现将 Kubernetes 内部的 Service 暴露给外部,这样我们就能通过公网或内网直接访问集群内部的服务。
目前helm仓库中已经有了nginx-ingress的资源。
项目地址: https://kubernetes.github.io/ingress-nginx
github地址: https://github.com/kubernetes/ingress-nginx/
流量导入方式
要想暴露内部流量,就需要让 Ingress Controller 自身能够对外提供服务,我们可以选择一下方式:
Ingress Controller 使用 Deployment 部署,Service 类型指定为 LoadBalancer
- 可以通过 Cloud Provider 提供loadbalancer
- 可以通过指定external ip 设置vip方式
Ingress Controller 使用 DeamonSet 部署,Pod 指定 hostnetwork或hostPort 来暴露端口
- 没有高可用保证,需要自己实现
- 需要占用宿主机端口
Ingress Controller 使用 NodePort方式
- 没有高可用保证,需要自己实现
- 需要占用宿主机端口
LoadBalancer 方式导入流量
云厂商 Cloud Provider
这种方式部署 Nginx Ingress Controller 最简单,只要保证上面说的前提:集群有 Cloud Provider 并且支持 LoadBalancer,如果你是使用云厂商的 Kubernetes 集群,保证你集群所使用的云厂商的账号有足够的余额,执行下面的命令一键安装:
1 | helm install --name nginx-ingress --namespace kube-system stable/nginx-ingress |
因为 stable/nginx-ingress 这个 helm 的 chart 包默认就是使用的这种方式部署。
部署完了我们可以查看 LoadBalancer 给我们分配的 IP 地址:
1 | $ kubectl get svc -n kube-system |
EXTERNAL-IP 就是我们需要的外部 IP 地址,通过访问它就可以访问到集群内部的服务了,我们可以将想要的域名配置这个IP的DNS记录,这样就可以直接通过域名来访问了。具体访问哪个 Service, 这个就是我们创建的 Ingress 里面所配置规则的了,可以通过匹配请求的 Host 和 路径这些来转发到不同的后端 Service.
Bare Metal 环境下流量导入
barematal可以参考官方文档:
https://kubernetes.github.io/ingress-nginx/deploy/#bare-metal
https://kubernetes.github.io/ingress-nginx/deploy/baremetal/
我这里简单罗列了集中方式,仅供参考:
在使用 Bare Metal 的时候可以有几种方式:
- A pure software solution: MetalLB
- Over a NodePort Service
- Via the host network
- Using a self-provisioned edge
- External IPs
MetalLB
待补充…
EXTERNAL-IP
kube-proxy ipvs
在我们的环境中,kube-proxy开启了ipvs模式,ingress controller采用externalIp的Service,externalIp指定的就是VIP,vip会由kube-proxy ipvs接管。
实验环境:
1 | [root@lab1 ingeress]# kubectl get node -owide |
此时我们部署:
1 | helm install --name nginx-ingress --set "rbac.create=true,controller.service.externalIPs[0]=10.7.12.210" stable/nginx-ingress |
这种方式提供了一种,基于 IPVS 的 Bare metal环境下Kubernetes Ingress边缘节点的高可用。
如果这里不使用的ipvs,那么需要使用keepalived代替 提供vip支持。
亦或是:这里提供多组ip:
1 | spec: |
然后将域名同时解析到externalIPs里。
这里提到了externalIP在ingress中的几种使用方式:
- ipvs(k8s 1.11 后可直接切换为ipvs)
- keepalived(自建)
- 多组externalIPs
这时我们去任意节点查看:
1 | [root@lab1 ingeress]# ip a sh kube-ipvs0 |
可以看到 10,7.12.210这个ip绑定到了 kube-ipvs0 上了
在几台节点宿主机上查看,我们可以看到 ExternalIP 的 Service 是通过 Kube-Proxy对外暴露的,这里的 10.7.12.210是内网 IP。 实际生产应用中是需要通过边缘路由器或全局统一接入层的负载均衡器将到达公网 IP 的外网流量转发到这个内网 IP 上,外部用户再通过域名访问集群中以 Ingress 暴露的所有服务。
1 | [root@lab1 ingeress]# sudo netstat -tlunp|grep kube-proxy|grep -E '80|443' |
这时我们访问:
1 | [root@lab1 deploy]# curl http://10.7.12.210 |
创建测试
1 | [root@lab1 ingeress]# cat my-nginx.yaml |
访问:
1 | [root@lab1 ingeress]# curl my-nginx |
查看相关信息
1 | [root@lab1 ingeress]# kubectl get svc |
kube-proxy iptables
这种方式需要外部提供vip高可用
这里我们指定controller.service.externalIPs[0]为vip地址,如下方式部署:
1 | helm install --name nginx-ingress --set "rbac.create=true,controller.service.externalIPs[0]=10.7.12.210,controller.service.externalIPs[1]=10.7.12.201,controller.service.externalIPs[2]=10.7.12.202" stable/nginx-ingress |
部署之后,我们这里只是指定了vip地址,但是环境中并未真实提供vip地址,
那么之后可以通过keepalived方式提供vip。
hostnetwork/hostport
这种方式实际是使用集群内的某些节点来暴露流量,使用 DeamonSet 部署,保证让符合我们要求的节点都会启动一个 Nginx 的 Ingress Controller 来监听端口,这些节点我们叫它 边缘节点,因为它们才是真正监听端口,让外界流量进入集群内部的节点,这里我使用集群内部的一个节点来暴露流量,并且 80 和 443 端口没有被其它占用。
nodeport 则是在所有集群节点启动监听端口。
接下来的实现方式是 hostNetwork:
挑选边缘节点
首先,查看集群节点:
1 | ➜ ~ kubectl get node |
我想要 lab4 这个节点作为 边缘节点 来暴露流量,我来给它加个 label,以便后面我们用 DeamonSet 部署 Nginx Ingress Controller 时能绑到这个节点上,我这里就加个名为 node:edge 的 label :
1 | $ kubectl label node lab4 node=edge |
如果 label 加错了可以这样删掉:
1 | $ kubectl label node lab4 node- |
部署ingress
我们可以这样查看版本:
1 | [root@lab1 ~]# helm search nginx-ingress |
注意: 目前有的k8s版本使用hostport不生效,这里我是使用的hostnetwork方式。
接下来我们覆盖一些默认配置来安装,我们选择stable的0.9.5,注意这里集群开启了rbac,所以这里也要开启rbac支持,否则会导致controller无法启动。
同时我们这里选择了hostNetwork的方式:
1 | helm install stable/nginx-ingress \ |
这里指定的参数具体可以在github主页查看:
可以看下是否成功启动:
1 | [root@lab1 ~]# kubectl get pods -owide -n kube-system | grep nginx-ingress |
如果状态不是 Running 可以查看下详情:
1 | $ kubectl describe -n kube-system po/nginx-ingress-controller-9nxsw |
这里我们可以在lab4节点上查看:
1 |
|
[root@lab1 deploy]# curl http://10.7.12.204
default backend - 404
[root@lab1 deploy]# curl -k https://10.7.12.204
default backend - 404
1 | LISTEN 0 128 :::443 :::* users:(("nginx",pid=28179,fd=16),("nginx",pid=28175,fd=16),("nginx",pid=27967,fd=16)) |
这时会在lab4上启动进程监听80和443:
可以通过浏览器访问 lab4或ip:
1 | [root@lab1 deploy]# curl http://10.7.12.204 |
运行成功我们就可以创建 Ingress 来将外部流量导入集群内部啦,外部 IP 是我们的 边缘节点 的 IP,公网和内网 IP 都算,我用的 lab4 这个节点,并且它有公网 IP,我就可以通过公网 IP 来访问了,如果再给这个公网 IP 添加 DNS 记录,我就可以用域名访问了。
这里一点要注意:
hostnetwork下pod会继承宿主机的网络协议,也就是使用了主机的dns,会导致svc的请求直接走宿主机的上到公网的dns服务器而非集群里的dns server,需要设置pod的dnsPolicy: ClusterFirstWithHostNet即可
高可用
此时部署成功之后,这里同样需要通过keepalived或外部LB提供高可用
示例:
1 | [root@k8s-m1 deploy]# kubectl get nodes --show-labels |
edge节点keepalived(这里同时兼master高可用)配置:
1 | [root@k8s-m1 deploy]# cat /etc/keepalived/keepalived.conf |
1 | [root@k8s-m1 deploy]# cat /etc/keepalived/check_haproxy.sh |
这时访问vip即可
1 | [root@k8s-m1 deploy]# curl 10.7.12.200 |
测试
我们来创建一个服务测试一下,先创建一个 my-nginx.yaml
1 | vi my-nginx.yaml |
创建:
1 | kubectl apply -f my-nginx.yaml |
查看状态:
1 | [root@lab1 ingeress]# kubectl get pod |
没有dns,那么可以通过配置/etc/hsots 方式解析。
然后浏览器通过域名访问,可以看到 Welcome to nginx! 这个 nginx 默认的主页。
注意:定义 Ingress 的时候最好加上 kubernetes.io/ingress.class 这个 annotation,在有多个 Ingress Controller 的情况下让请求能够被我们安装的这个处理(云厂商托管的 Kubernetes 集群一般会有默认的 Ingress Controller)
nodeport
这里我们使用官方yaml文件方式部署
github地址: https://github.com/kubernetes/ingress-nginx/
官方部署文档:
https://github.com/kubernetes/ingress-nginx/blob/nginx-0.20.0/docs/deploy/index.md
我们可以如下方式直接部署:
1 | git clone https://github.com/kubernetes/ingress-nginx.git |
部署完成之后,可以访问nodePort,同样会返回;
default backend - 404
参考
https://imroc.io/posts/kubernetes/use-nginx-ingress-controller-to-expose-service/