Ingress**也是Kubernetes项目里的一种 API 对象,它公开了从集群外部到集群内Service
的 HTTP 和 HTTPS 路由,这些路由由 Ingress 资源上定义的规则控制。
internet
|
[ Ingress ]
--|-----|--
[ Services ]
如果用一句话概况Ingress
的话就是:Ingress
是Service
们的反向代理。通过看Ingress
对象的定义你会感觉自己在看Nginx
的配置文件一样。
Ingress
资源对象的YAML
定义。与大多数Kubernetes资源一样,也需要apiVersion
,Kind
,Metadata
和Spec
这些组成部分。
一个典型的Ingress
对象的定义如下所示:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: app-ingress
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
backend:
serviceName: app-service
servicePort: 80
- path: /v2
backend:
serviceName: app-service-v2
servicePort: 80
在上面这个Ingress
的YAML
定义中,最值得我们关注的,是spec.rules 字段。在 Kubernetes 里,这个字段叫作:IngressRule。
IngressRule
里面 host 字段定义的值,就是这个Ingress
的入口。当访问 app.example.com
的时候,实际上访问到的是这个 Ingress
对象。这样就能使用 IngressRule 来对请求进行下一步转发。
IngressRule
的定义,主要依赖于path
字段。可以简单地理解为,这里的每一个path
都对应一个后端 Service
。上面的例子里,定义了两个path
,它们分别对应:app-service和app-service-v2 两个后端Service
。通过Service
,流量最终会到达Service
后面的Pod
。
servicePort字段指定的端口值就是在Service
的定义里port
字段的值,上一篇讲Service的文章里已经科普了一下Service
定义里的nodePort
,port
和targetPort
都是什么意思,感觉到懵圈(我自己都有点懵)的读者大大可以翻阅一下文章《学练结合,快速掌握Kubernetes Service》里的这部分内容。
所以 Ingress
对象,其实就是 Kubernetes
项目对**"反向代理"**的一种抽象。一个 Ingress
对象的主要内容,实际上就是一个"反向代理"服务的配置文件的描述。而这个代理服务对应的转发规则,就是 IngressRule
。这就是为什么在每条 IngressRule
里,需要有一个 host 字段来作为这条 IngressRule
的入口,然后还需要有一系列 path
字段来声明具体的转发策略。
有了Ingress
后我们还需要Ingress Controller
,它会根据你定义的Ingress
对象,提供对应的代理能力。目前,业界常用的各种反向代理项目,比如 Nginx、Envoy 等,都已经为 Kubernetes 专门维护了对应的 Ingress Controller。
下面我就用最常用的Nginx Ingress Controller给这个系列教程一直以来用的Demo实践应用一下Ingress
安装Ingress Controller
因为Minikube
里边内置了Nginx Ingress Controller这个插件, 默认没有启用,所以如果是在Minikube
这个单节点集群里实践的话只需要执行下面的命令:
minikube addons enable ingress
检查验证 Nginx Ingress 控制器处于运行状态:
kubectl get pods -n kube-system --filed-selector=Running
有下图红框里的Pod
就证明已经安装成功了:
因为这个Pod用的官方镜像是在红帽软件的镜像库里,所以安装时间可能会有点长,也可能会失败,如果网络条件允许的话可以在准备阶段先执行 docker pull http://quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.32.0 把镜像下载到本地。
此外还有不少安装Nginx Ingress Controller
的方式,比如用Kubernetes的包管理工具Helm安装,这些安装方式可以参考官方的部署指南[1]。
创建Ingress
因为我们之前给应用Pod
创建的Service
名字叫app-service,port
字段指定的是端口80
➜ ~ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
app-service NodePort 10.108.26.155 <none> 80:30080/TCP 6d16h
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 96d
➜ ~ kubectl describe svc app-service
Name: app-service
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=go-app
Type: NodePort
IP: 10.108.26.155
Port: http 80/TCP
TargetPort: 3000/TCP
NodePort: http 30080/TCP
Endpoints: 10.1.0.24:3000,10.1.0.25:3000
这就确定了我们要创建建的Ingress
对象,第一个path
里要设置的backend.serviceName和backend.servicePort字段的值,Ingress对象的YAML
定义如下:
# app-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: app-ingress
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
backend:
serviceName: app-service
servicePort: 80
说明:因为目前为止我们只创建了一个Service,所以在Ingress里也只能设置一个path。
这个Ingress定义里设置的IngressRules
是把所有对app.example.com入口的请求都路由到app-service
这个Service
的80端口。
定义好Ingress
对象后,也是执行kubectl apply -f创建对象,可以看到所有的对象的创建和更新都可以用apply操作搞定,这就是Kubernetes
项目声明式定义的好处。
kubectl apply -f app-ingress.yaml --record
# 执行后的输出
ingress.networking.k8s.io/app-ingress created
验证Ingress
查询Ingress是否创建成功,使用通用的kubectl get命令:
➜ ~ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
app-ingress <none> app.example.com 192.168.64.4 80 20s
有可能需要在提交创建操作几分钟后才能在集群里查询到Ingress
在集群里查询到Ingress后,就可以通过kubctl describe ingress命令查看Ingress
对象是否按照我们的定义成功代理了app-service
这个Service
:
➜ ~ kubectl describe ingress app-ingress
Name: app-ingress
Namespace: default
Address: 192.168.64.4
Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
Host Path Backends
---- ---- --------
app.example.com
/ app-service:80 (10.1.0.24:3000,10.1.0.25:3000)
Annotations: kubernetes.io/change-cause: kubectl apply --filename=app-ingress.yaml --record=true
Events: <none>
上面输出里的Rlues
部分可以清楚的看到,把Host: app.example.com所有请求(定义了Path是/)都代理到了后端app-service
的80端口,Service后面的Pod
正是它的Endpoints
,与上面的kubctl describe svc app-service命令输出里的Endpoints
信息一致。
接下来在/etc/hosts
文件里追加下面的内容,就能通过域名访问我们的服务了:
192.168.64.4 app.example.com
你们在练习的时候,可以自己尝试新增一个Service
,然后更新Ingress,再指定一个/v2
之类的Path,让所有匹配这个规则的请求都能路由给新的Service。
接下来
Ingress
还有很多其他的配置,想要简单的讲完,还是挺难的。最常用的比如怎么设置TLS私钥和证书这些配置在Kubernetes官方文档-Ingress[2] 部分都有提到,后面自己练习的时候可以试试给Ingress
启用HTTPs
访问的功能。