前面讲过 Service 对象可以通过 NodePort 的方式将单个服务暴露到 Kubernetes 集群的外部,而 Ingress 则是暴露服务的另一种方式,它更复杂、也更强大。
下面是 Ingress 工作示例图,可以看出它所扮演的角色和 Spring Cloud Gateway 是类似的。

Kubernetes Ingress 也是一个 API 对象,通过 Ingress 对象可以制定请求转发的规则,把外部的请求路由到集群中的 Service 服务中。不同的是,Service 的暴露方式针对的是单个服务,而 Ingress 则是为整个集群的服务提供访问入口。
下面就将前面通过 Docker Compose 部署的微服务示例项目部署到 Kubernetes 平台中,关于 Kubernetes 平台的快速搭建,可以参看其它章节《一键部署利器 Kubeadm 搭建 Kubernetes》章节。我这里使用了两台 2 核 8G 的 ECS 搭建的。

示例中各个微服务的 API 资源描述文件均放置在各个模块中,内容较长,请 clone 项目后查看。

我们将各个模块的 YML 文件 copy 至 ECS 中 /opt/cloud 目录下。
- kubectl apply -f /opt/cloud/cloud-namespace.yml
- kubectl apply -f /opt/cloud/eureka-server.yml
- kubectl apply -f /opt/cloud/actuator-admin.yml
- kubectl apply -f /opt/cloud/api-gateway.yml
- kubectl apply -f /opt/cloud/auth-server.yml
- kubectl apply -f /opt/cloud/user-server.yml
- kubectl apply -f /opt/cloud/order-server.yml
通过 kubectl apply -f 命令依次部署上述 YML 文件,注意先部署第一个 cloud-namespace.yml,因为要先创建好自定义的 namespace 对象。
apiVersion: v1
kind: Namespace
metadata:
name: cloud
全部执行完成后,登录 kubernetes dashboard 查看工作负载信息。

下面这几个服务的 Service 对象都通过 NodePort 的形式暴露到了集群外部,可以在浏览器中访问(注意要添加ECS 的安全组规则)。
暴露服务 | 访问地址 | 用户密码 |
---|---|---|
eureka-server | http://ip:31000/login | aAuHAd/aAuHAd |
spring boot admin | http://ip:32700/login | cloud/cloud@monitor |
api gateway swagger | http://ip:32000/swagger-ui.html | swagger 聚合入口 |
api gateway | http://ip:32000 | 网关入口 |
在 Dashboard 上可以进行很多操作,例如扩容、缩容,查看日志,进入/删除 Pod,编辑 YML 文件等等。留给你去探索,这里不在详细说明。

由于部署的时候允许 Master 参与调度(taint 污点标签实现),所以会看到注册上来的 Pod 网段有两个。

在 Service 列表,可以看到 type 有两种: ClusterIP(集群内通信 IP) 和 NodePort(暴露外网端口),网关 api-gateway 服务已经通过 NodePort 方式暴露到了公网 32000 端口,所以你还是可以使用 Spring Cloud Gateway 作为微服务入口测试的。

另外,我在项目中提供的每个微服务的 Kubernetes YML 描述文件都定义如下了四个对象:
- Service 暴露服务,负载均衡,服务发现
(注意:NodePort 端口范围是 30000-32767)
- Deployment 控制循环,滚动更新
- ReplicaSet 副本个数,应用版本,版本回滚
- Pod 存活探针,就绪探针,最小调度单位
这些对象也是在我们引入 Istio 服务网格时所必须满足的前提条件,对于 Kubernetes 中 Pod、Service、ReplicaSet、Deployment 这些基础常用概念一定要了然于心,对其 YML 描述字段要非常熟悉,对它们之间的协作关系、实现原理也要有所了解。
下面介绍并部署 Ingress 对象来作为集群服务的访问入口。
为了让 Ingress 对象工作,集群必须有一个正在运行的 Ingress Controller。它有很多的第三方实现,本节选用的是 Nginx 提供的实现 Nginx Ingress Controller 来演示
- HAProxy Ingress Controller for Kubernetes
- Istio Ingress is an Istio based ingress controller
- Kong Ingress Controller for Kubernetes
- NGINX Ingress Controller for Kubernetes
Ingress 和 Ingress Controller 的区别:
-
Ingress
它是 Kubernetes 中的一个 API 对象,定义请求如何转发到 Service 的规则。
-
Ingress Controller
它是反向代理的程序,会根据 Ingress 对象制定的规则实现请求转发。
部署 Nginx Ingress Controller。
我们将官方提供的 ingress-nginx YML 文件下载到本地,因为其中 ingress-nginx-controller Pod 的镜像名称有点问题,需要手动修改。(我在项目的根目录下也放置了一份 ingress-nginx.yml
,你可以直接用)
curl -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.44.0/deploy/static/provider/cloud/deploy.yaml >> /opt/cloud/ingress-nginx.yml
将:
image: k8s.gcr.io/ingress-nginx/controller:v0.44.0@sha256:3dd0fac48073beaca2d67a78c746c7593f9c575168a17139a9955a82c63c4b9a
修改为:
image: registry.cn-shanghai.aliyuncs.com/11060/ingress-nginx-controller:v0.44.0
部署命令:kubectl apply -f /opt/cloud/ingress-nginx.yml
,执行成功后登录 Dashboard 可以看见 ingress-nginx 这个 namespace 下的所有资源。

I0221 11:26:17.7630407 flags.go:208] "Watching for Ingress" class="nginx"
W0221 11:26:17.7630767 flags.go:213] Ingresses with an empty class will also be processed by this Ingress controller
-------------------------------------------------------------------------------
NGINX Ingress controller
Release: v0.44.0
Build: f802554ccfadf828f7eb6d3f9a9333686706d613
Repository: https://github.com/kubernetes/ingress-nginx
nginx version: nginx/1.19.6
-------------------------------------------------------------------------------
上面这个是 ingress-nginx-controller
Pod 启动的部分日志,看下第一行的输出,默认配置下它会监视所有命名空间下的 Ingress 对象的创建和修改,可以通过 --watch-namespace
参数将作用域限制到特定的命名空间。配置入口在 Deployment 对象中:https://kubernetes.github.io/ingress-nginx/user-guide/cli-arguments/
args:
- /nginx-ingress-controller
- --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
- --election-id=ingress-controller-leader
- --ingress-class=nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
- --watch-namespace=cloud
下面是 ingress-nginx.yml 中定义的 Service 对象,这个 Service 的类型为 LoadBalancer,它会将所有携带 ingress-nginx 标签的 Pod 通过 80 和 433 端口暴露出去,这样我们就可以在集群外部访问到这个 Nginx 了。
# Source: ingress-nginx/templates/controller-service.yaml
apiVersion: v1
kind: Service
metadata:
annotations:
labels:
helm.sh/chart: ingress-nginx-3.23.0
......
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
type: LoadBalancer
ports:
- name: http
port: 80
protocol: TCP
targetPort: http
- name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller
查看下 Service 向外部暴露的端口 HTTP:32475 HTTPS:31729
[root@k8s001 ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.99.90.115 <pending> 80:32475/TCP,443:31729/TCP 20m
部署成功后可以在浏览器中测试下这两个端口,注意先在阿里云控制台添加这两个端口的安全组规则。

下面部署 Ingress 对象,它是用来制定请求转发的规则,指定需要暴露到集群外的服务,这个文件我也在项目的根目录下:cloud-ingress.yml
。其中 rules 属性在 Kubernetes 里叫作 IngressRule,它的 Key 是 host,要注意 host 的值必须是一个全限定域名(FQDN),不能是 IP 地址,所以如果要测试的话,你需要有一个域名,并且确保已经正确解析到了你的 ECS 上。
https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-rules
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: cloud
name: cloud-ingress
spec:
rules:
- host: viewhub.cn
http:
paths:
- path: /user
pathType: Prefix
backend:
service:
name: user-server
port:
number: 9097
- path: /auth
pathType: Prefix
backend:
service:
name: auth-server
port:
number: 9096
- path: /order
pathType: Prefix
backend:
service:
name: order-server
port:
number: 9099
当我们访问 viewhub.cn 域名的时候,实际上访问到的就是这个 Ingress 对象,然后 Kubernetes 会根据 path 字段的规则来对请求进行下一步转发。这里你可以把一个 Ingress 对象理解为 Nginx 反向代理的配置文件 nginx.conf,把 ingress-controller 理解为 Nginx。
执行 kubectl apply -f /opt/cloud/cloud-ingress.yml
命令部署,Nginx Ingress Controller 会 watch 到 Ingress 对象的创建,然后根据 ingress 对象中的规则来修改 nginx.conf 文件,提供对应的代理能力。
在 Dashboard 界面可以清晰的看到 cloud-ingress 所代理的路径,要转发到的服务及服务端口。

这个 /
规则会匹配所有路径,我将它路由到了 eureka 服务,你可以通过 http://viewhub.cn:32475 访问进入 eureka 页面。如果 Ingress 中的多条路径会匹配到同一个请求,最长的匹配路径优先。

再调用一个接口测试下,可以看到 /user/init 路径正确转发到了 user-server 服务。

你还可以通过 Dashboard 或者 kubectl exec 命令进入 ingress-nginx-controller 这个 Pod,去看下的它的 nginx.conf 配置文件,你就会非常清晰的认识到它到底在做些什么。

通过上面的测试,可以看到 Nginx Ingress Controller 创建的 Nginx 负载均衡器,已经成功的根据 Ingress 对象制定的规则将请求转发到了对应的后端 Service。
你应该可以感受到,Ingress 的功能还是比较弱的, 它工作在七层仅适用于 HTTP 路由,而且用法相对简单,只能通过匹配有限的字段 host、path、port 来路由流量。下一节我们将演示在 Istio 体系如何统一管理入口流量,你会发现它更能胜任云服务网关这个角色。
~ 终 ~
网友评论