Kubernetes Ingress 作为云服务的 API 网关

前面讲过 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 描述文件都定义如下了四个对象:

  1. Service 暴露服务,负载均衡,服务发现(注意:NodePort 端口范围是 30000-32767)
  2. Deployment 控制循环,滚动更新
  3. ReplicaSet 副本个数,应用版本,版本回滚
  4. 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 体系如何统一管理入口流量,你会发现它更能胜任云服务网关这个角色。

~ 终 ~

©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容