我们这个系列的文章一直都在学习和掌握K8S各种组成部分在集群里的角色、作用和使用场景,那么针对今天这个主题任务「给K8S上的Web服务做域名解析」你觉得应该使用什么组件来完成呢?
如果你看过我上一篇文章你知道K8S暴露服务的方式有哪些吗? 应该能猜到是使用Ingress
,那么有人会问为啥不能用NodePort
这种方式呢?今天的文章我们就来详细探讨一下这些相关的问题:
NodePort
这种暴露服务的方式不适合用来给服务做域名解析。Ingress
暴露Web服务(会给大家做一个Demo进行演示)。Ingress
怎么做高可用。NodePort
类型的Service
是向集群外暴露服务的最原始方式,也是最好让人理解的。NodePort
,顾名思义,会在所有节点(宿主机或者是VM)上打开一个特定的端口,发送到这个端口的任何流量都会转发给Service
。
NodePort
Service 的原理可以用下面这个图表示:
NodePort Service的原理图
上图我们顺着流量的流向箭头从下往上看,流量通过NodeIP+NodePort
的方式进入集群,上图三个节点的30001上的流量都会转发给Service,再由Service给到后端端点Pod
。
NodePort Service的优点是简单,好理解,通过IP+端口的方式就能访问,但是它的缺点也很明显,比如:
在K8S的这些组件中Ingress
不是一种Service
。相反,它位于多个Service
的前端,给这些Service
充当“智能路由代理”或集群的入口点(entrypoint)。
在Service
前面加上Ingress
,集群中需要有Ingress-Controller
才行。如果是自建K8S集群,通常使用nginx-ingress
作为控制器,它使用NGINX
服务器作为反向代理来把流量路由给后面的Service
。
通过Ingress
可以对后端Service
进行基于域名和URL路径的路由。例如,您可以将 foo.yourdomain.com 上的所有内容发送到 foo Service,将 yourdomain.com/bar/ 路径下的所有内容发送到 bar Service。
Ingress运行原理
我们可以把这张图和上面NodePort原理图做一个比较,看看两者的区别。上面这个示意图对应的Ingress资源声明文件差不多应该长这个样子:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
spec:
backend: // 哪个都不匹配时,走这个兜底的Service
serviceName: other
servicePort: 8080
rules:
- host: foo.mydomain.com
http:
paths:
- backend:
serviceName: foo
servicePort: 8080
- host: mydomain.com
http:
paths:
- path: /bar/
backend:
serviceName: bar
servicePort: 8080
上面说了很多理论,下面我们可以通过一个简单的Demo进行演示,我本地使用的是Docker Desktop
自带的K8S集群,至于为啥用它,没别的就是简单。
要使用Ingress
,那么集群里就得先有个Ingress-Controller
,我们先来安装一个Nginx-Ingress-Controller
(其本质上就是一个Nginx Server):
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.0/deploy/static/provider/cloud/deploy.yaml
执行上述命令后,其实会在本地集群的ingress-nginx
命名空间里,安装三个创建nginx-controller
的Pod
:
? ~ kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-n59dn 0/1 Completed 2 49d
ingress-nginx-admission-patch-hft52 0/1 Completed 3 49d
ingress-nginx-controller-68649d49b8-nlch7 1/1 Running 77 49d
前两个admission
相关的Pod
是给nignx controller
做配置用的,执行完就退出,第三个才是运行着nginx-controlelr
的Pod
。
我之前几次在本地试验Ingress
没有成功,就是因为这个nignx-controller
没有正常启动起来。一个常见的错误是nginx controller
这个Pod
拉取镜像k8s.gcr.io/ingress-nginx/controller:v0.46.0@sha256:....
的速度非常慢,所以我们最好是在安装控制器前先通过docker pull
命令把这个镜像拉到本地。
在本地安装完Ingress控制器后,为了演示方便,之前本地搭建Nacos
时做过一个Service
,Nacos
是阿里巴巴出的一个可以做自动配置和服务注册的组件,自带Web管理界面,正好可以拿它来演示。
下面我想能通过dev.nacos.com
访问nacos-service
,最终让nacos-service
把流量路由给后端安装了Nacos
服务的Pod
,这个Ingress
可以这么声明
//ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: nacos-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: dev.nacos.com
http:
paths:
- path: /
backend:
serviceName: nacos-service
servicePort: 8848
在集群里应用这个Ingress
后
# 执行下面两个命令
# kubectl apply -f nacos-ingress.yaml
# kubectl get ingress
? ~ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
nacos-ingress <none> dev.nacos.com localhost 80 54d
再在本地hosts文件里绑定上
127.0.0.1 dev.nacos.com # 本地K8S集群的IP是127.0.0.1
就能通过域名访问到Nacos
服务的管理界面
Nacos的Web界面
为了不影响阅读,Service、Deployment这些声明文件,我放在了GitHub 仓库里,链接如下:
https://github.com/kevinyan815/LearningKubernetes
如果有啥疑问可以通过留言或者加微信号fsg1233210与我讨论。
Ingress
怎么做高可用上面我们聊了Ingress
怎么暴露服务,以及在本地怎么实践演练用Ingress
暴露服务,那么有的人肯定会好奇,在生产集群里Ingress
是怎么做高可用的呢?域名解析应该怎么绑定呢?
正常的生产环境,因为Ingress
是公网的流量入口,所以压力比较大肯定需要多机部署。一般会在集群里单独出几台Node
,只用来跑Ingress-Controller
,可以使用deamonSet
的让节点创建时就安装上Ingress-Controller
,在这些Node上层再做一层负载均衡,把域名的DNS解析到负载均衡IP上。
考虑到多业务线服务相互不影响的话,还需要让不同的业务线的转发规则注入到不同的Ingress
里,这个通过我们上面声明Ingress时的注解annotations:kubernetes.io/ingress.class
就能实现。
其实每家公司的方案肯定不一样,尤其是解析链路里加上高防Waf的话,会更复杂,由于我不是专业运维,也只是知道一些大概的思路,如果有专业的大佬欢迎留言,让我们共同进步一下。
其实这个主题我一直想写,之前断断续续尝试了两三次才在本地把Ingress
这套跑通,搞明白。希望今天的文章能帮大家进行一下Ingress
知识的分析,如果想自己掌握、想明白,还是需要把文章好好看看,亲自实践一下演示的例子,以及多复习复习前面关于Service的知识才行。