Kubernetes微服务架构的演进与优化

Kubernetes微服务架构的演进与优化——从Ingress到Istio

 💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。

推荐:Linux运维老纪的首页,持续学习,不断总结,共同进步,活到老学到老
导航剑指大厂系列:全面总结 运维核心技术:系统基础、数据库、网路技术、系统安全、自动化运维、容器技术、监控工具、脚本编程、云服务等。
常用运维工具系列:常用的运维开发工具, zabbix、nagios、docker、k8s、puppet、ansible等
数据库系列:详细总结了常用数据库 mysql、Redis、MongoDB、oracle 技术点,以及工作中遇到的 mysql 问题等
懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

1、简介

在现代云原生应用中,服务网格和Ingress控制器都是常用的组件。服务网格(如Istio、Linkerd)提供了服务间的通信、监控、安全等功能,而Ingress控制器则帮助我们从外部访问集群内部的服务。

对于Kubernetes的Service,无论是Cluster-Ip和NodePort均是四层的负载,集群内的服务如何实现七层的负载均衡,这就需要借助于Ingress,Ingress控制器的实现方式有很多,比如nginx, Contour, Haproxy, trafik, Istio。几种常用的ingress功能对比和选型可以参考这里。

2、常用组件

Ingress-nginx是7层的负载均衡器 ,负责统一管理外部对k8s cluster中Service的请求。主要包含:

  • ingress-nginx-controller:根据用户编写的ingress规则(创建的ingress的yaml文件),动态的去更改nginx服务的配置文件,并且reload重载使其生效(是自动化的,通过lua脚本来实现)。

  • Ingress资源对象:将Nginx的配置抽象成一个Ingress对象。

3、原理

ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化。

  • 然后读取ingress规则(规则就是写明了哪个域名对应哪个service),按照自定义的规则,生成一段nginx配置。

  • 再写到nginx-ingress-controller的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器把生成的nginx配置写入/etc/nginx/nginx.conf文件中。

  • 然后reload一下使配置生效。以此达到域名分别配置和动态更新的问题。

4、安装Ingress控制器

[root@mast01 istio]# kubectl apply -f ingress-nginx.yaml

[root@mast01 istio]# kubectl get pod -n ingress-nginx -o wide
NAME                                   READY   STATUS     RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
ingress-nginx-admission-create-nrfz9   0/1     Completed   0         86m   10.244.205.195   work01   <none>           <none>
ingress-nginx-admission-patch-6pjjv    0/1     Completed   1         86m   10.244.75.85     work02   <none>           <none>
ingress-nginx-controller-b7qf6         1/1     Running     0         86m   192.168.58.117   work01   <none>           <none>
ingress-nginx-controller-szc5z         1/1     Running     0         86m   192.168.58.118   work02   <none>           <none>

5、使用ingress访问网格服务

[root@mast01 istio]# vim front-tomcat-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: front-tomcat
namespace: istio-demo
spec:
rules:
 - host: tomcat.istio-demo.com
  http:
    paths:
     - backend:
        serviceName: front-tomcat
        servicePort: 8080
      path: /
status:
loadBalancer: {}
 
[root@mast01 ~]# kubectl exec -it ingress-nginx-controller-szc5z -n ingress-nginx bash
bash-5.1$ ps -ef
PID   USER     TIME COMMAND
   1 www-data  0:00 /usr/bin/dumb-init -- /nginx-ingress-controller --election-id=ingress-controller-leader --controller-class=k8s.io/ingress-nginx --configmap=ingress-nginx/ing
   7 www-data  0:10 /nginx-ingress-controller --election-id=ingress-controller-leader --controller-class=k8s.io/ingress-nginx --configmap=ingress-nginx/ingress-nginx-controller
  26 www-data  0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /etc/nginx/nginx.conf
  31 www-data  0:02 nginx: worker process
  32 www-data  0:02 nginx: worker process
  33 www-data  0:00 nginx: cache manager process
 108 www-data  0:00 bash
 114 www-data  0:00 ps -ef
 
bash-5.1$ cat /etc/nginx/nginx.conf
...
server_name tomcat.istio-demo.com ;

listen 80 ;
listen [::]:80 ;
listen 443 ssl http2 ;
listen [::]:443 ssl http2 ;

set $proxy_upstream_name "-";

ssl_certificate_by_lua_block {
certificate.call()
}

location / {

set $namespace      "istio-demo";
set $ingress_name   "front-tomcat";
set $service_name   "front-tomcat";
set $service_port   "8080";
set $location_path  "/";
set $global_rate_limit_exceeding n;
...
查看效果

只有网格内部访问会遵从virtualservice的规则,在宿主机中直接访问Service的ClusterIP还是按照默认的规则转发。流量比例1:1

多路径转发
myblog.luffy.com -> 172.21.51.67 -> /foo   service1:4200
                                    /bar   service2:8080
                                    / myblog:80

myblog.luffy.com/foo ----> myblog.luffy.com/service1:4200
myblog.luffy.com/bar ----> myblog.luffy.com/service2:8080
myblog.luffy.com/ ----> myblog.luffy.com/myblog:80
实现
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: simple-fanout-example
namespace: luffy
spec:
rules:
- host: myblog.luffy.com
  http:
    paths:
    - path: /foo
      backend:
        serviceName: service1
        servicePort: 4200
    - path: /bar
      backend:
        serviceName: service2
        servicePort: 8080
    - path: /
      backend:
        serviceName: myblog
        servicePort: 80
nginx的URL重写
myblog.luffy.com -> 172.21.51.67 -> /foo/   myblog:80/admin/

myblog.luffy.com/foo/ ----> myblog.luffy.com/admin/
实现
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: rewrite-path
namespace: luffy
annotations:
  nginx.ingress.kubernetes.io/rewrite-target: /admin/$1
spec:
rules:
- host: myblog.luffy.com
  http:
    paths:
    - path: /foo/(.*)
      backend:
        serviceName: myblog
        servicePort: 80

6、使用ingressgateway访问网格服务

Ingress本身无法实现流量权重转发,主要因为其设计初衷是用于在集群外部暴露HTTP和HTTPS路由,并基于路径和主机名分发请求,而不是高级流量管理,其设计并不是为了实现高级流量管理和控制。Ingress缺乏细粒度流量控制和动态调整能力,依赖于静态配置和简单的路由规则,无法根据权重进行复杂的流量分配。

对于入口流量管理,您可能会问:为什么不直接使用 Kubernetes Ingress API ?原因是 Ingress API 无法表达 Istio 的路由需求。Ingress 试图在不同的 HTTP 代理之间取一个公共的交集,因此只能支持最基本的 HTTP 路由,最终导致需要将代理的其他高级功能放入到注解(annotation)中,而注解的方式在多个代理之间是不兼容的,无法移植。

Istio Gateway 通过将 L4-L6 配置与 L7 配置分离的方式克服了 Ingress 的这些缺点。Gateway 只用于配置 L4-L6 功能(例如,对外公开的端口,TLS 配置),所有主流的L7代理均以统一的方式实现了这些功能。然后,通过在 Gateway 上绑定 VirtualService 的方式,可以使用标准的 Istio 规则来控制进入 Gateway 的 HTTP 和 TCP 流量。

[root@mast01 istio]# vim front-tomcat-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: front-tomcat-gateway
namespace: istio-demo
spec:
selector:
  istio: ingressgateway # use istio default controller
servers:
 - port:
    number: 80
    name: http
    protocol: HTTP
  hosts:
   - tomcat.istio-demo.com
   
[root@mast01 istio]# kubectl apply -f front-tomcat-gateway-virtualservice.yaml

效果是在Istio的ingress网关上加了一条规则,允许`tomcat.istio-demo.com 的外部http流量进入到网格中,但是只是接受访问和流量输入,当流量到达这个网关时,它还不知道发送到哪里去。

网关已准备好接收流量,我们必须告知它将收到的流量发往何处,这就用到了前面使用过的VirtualService

要为进入上面的 Gateway 的流量配置相应的路由,必须为同一个 host 定义一个 VirtualService,并使用配置中的 gateways 字段绑定到前面定义的 Gateway 上 。

[root@mast01 istio]# vim front-tomcat-gateway-virtualservice.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: gateway-front-tomcat
namespace: istio-demo
spec:
gateways:
 - front-tomcat-gateway
hosts:
 - tomcat.istio-demo.com
http:
 - name: front-tomcat-route
  route:
   - destination:
      host: front-tomcat
      subset: v1
    weight: 90
   - destination:
      host: front-tomcat
      subset: v2
    weight: 10
     
[root@mast01 istio]# kubectl apply -f front-tomcat-gateway.yaml

该网关列表指定,只有通过我们指定的网关 front-tomcat-gateway 的流量是允许的。所有其他外部请求将被拒绝,并返回 404 响应。

请注意,在此配置中,来自网格中其他服务的内部请求不受这些规则约束

模拟访问

端口 31927 是通过 Kubernetes 中的 Service 类型为 NodePort 来公开服务的一种方式。在 Kubernetes 中,NodePort 允许将服务的端口映射到每个节点的某个固定端口上,从而可以从集群外部访问该服务。

在 Istio 中,istio-ingressgateway 是负责接收外部流量并进入 Istio 网格的组件。通过将 istio-ingressgateway 配置为 NodePort 类型,Kubernetes 将会把这个服务公开在集群的所有节点上,使用固定的端口号 31927。这样,外部用户可以通过访问任何一个集群节点的 IP 地址和端口 31927,来访问和使用 Istio 网格中的服务。

[root@mast01 istio]# kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}'
31927

[root@mast01 istio]# curl -HHost:tomcat.istio-demo.com 192.168.58.117:31927/
去除端口
​​​​​​​# 在一台80端口未被占用的机器中,如ip为172.21.51.69
$ docker run -d --restart=always -p 80:80 --name istio-nginx nginx:alpine

# 在容器的/etc/nginx/conf.d/目录中,新增配置文件
$ cat front-tomcat.conf
upstream front-tomcat {
 server 192.168.58.117:31927;
}
server {
   listen       80;
   listen  [::]:80;
   server_name  tomcat.istio-demo.com;

   location / {
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_http_version 1.1;
       proxy_pass http://front-tomcat;
   }
}

$ nginx -s reload
本地配置hosts
192.168.58.117 tomcat.istio-demo.com
查看效果

直接访问http://tomcat.istio-demo.com 即可实现外部域名访问到网格内部服务

7、使用服务网格访问网格服务

使用 Istio 的主要优势之一是它提供了更高级别的服务网格功能,包括流量管理、安全性、监控和可观察性等方面的解决方案。尽管 Kubernetes 的 Ingress 可以用于简单的 HTTP(S) 流量路由和负载均衡,但它在灵活性和功能上远不及 Istio 的服务网格。Istio 提供了诸如智能路由、故障恢复、流量调节、策略执行等功能,使得在微服务架构中管理和保护服务更加方便和强大。相比之下,服务网格(如Istio)专门设计用于微服务间通信管理,提供细粒度的流量控制、动态调整和全面的可观察性,因此能够实现流量权重转发等高级功能。

流程图

资源清单
[root@mast01 istio]# vim front-tomcat-service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
  app: front-tomcat
name: front-tomcat
namespace: istio-demo
spec:
ports:
 - name: http
  port: 8080
  protocol: TCP
  targetPort: 8080
selector:
  app: front-tomcat
type: ClusterIP
 
[root@mast01 istio]# kubectl apply -f front-tomcat-service.yaml
[root@mast01 istio]# vim front-tomcat-v2-dpl.yam
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
  app: front-tomcat
  version: v2
name: front-tomcat-v2
namespace: istio-demo
spec:
replicas: 1
selector:
  matchLabels:
    app: front-tomcat
    version: v2
template:
  metadata:
    labels:
      app: front-tomcat
      version: v2
  spec:
    containers:
     - image: consol/tomcat-7.0:latest
      name: front-tomcat
      command: ["/bin/sh", "-c", "echo 'hello tomcat version2'>/opt/tomcat/webapps/ROOT/index.html;/opt/tomcat/bin/deploy-and-run.sh;"]
       
[root@mast01 istio]# kubectl apply -f <(istioctl kube-inject -f front-tomcat-v2-dpl.yaml)
创建服务网格
[root@mast01 istio]# vim front-tomcat-virtualservice.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: front-tomcat
namespace: istio-demo
spec:
hosts:
 - front-tomcat
http:
 - name: front-tomcat-route
  route:
   - destination:
      host: front-tomcat
      subset: v1
    weight: 90
   - destination:
      host: front-tomcat
      subset: v2
    weight: 10
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: front-tomcat
namespace: istio-demo
spec:
host: front-tomcat
subsets:
 - name: v1
  labels:
    version: v1
 - name: v2
  labels:
    version: v2
     
[root@mast01 istio]# kubectl apply -f front-tomcat-virtualservice.yaml

[root@mast01 istio]# kubectl get pod -n istio-demo
NAME                               READY   STATUS   RESTARTS         AGE
bill-service-v1-7bc6d7b575-tbgrs   2/2     Running   22 (2d23h ago)   15d
bill-service-v2-6755bb6b6d-tkrzm   2/2     Running   22 (2d23h ago)   15d
front-tomcat-v1-57bc6c5d9f-sfn52   2/2     Running   21 (2d23h ago)   15d
front-tomcat-v2-876c9bffd-8ss6r    2/2     Running   0               3h19m

# 多次请求,可以看到流量分摊9比1
[root@mast01 istio]# kubectl -n istio-demo exec -ti bill-service-v1-7bc6d7b575-tbgrs -c bill-service sh
/ # curl front-tomcat:8080
hello tomcat version2

8、总结

Ingress:对接ingress controller,实现外部流量进入集群内部,只适用于 HTTP 流量,使用方式也很简单,只能对 service、port、HTTP 路径等有限字段匹配来路由流量,这导致它无法路由如 MySQL、Redis 和各种私有 RPC 等 TCP 流量。要想直接路由南北向的流量,只能使用 Service 的 LoadBalancer 或 NodePort,前者需要云厂商支持,后者需要进行额外的端口管理。有些 Ingress controller 支持暴露 TCP 和 UDP 服务,但是只能使用 Service 来暴露,Ingress 本身是不支持的,例如 nginx ingress controller,服务暴露的端口是通过创建 ConfigMap 的方式来配置的。

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux运维老纪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值