使用Ingress来负载分发微服务
NodePort Service存在太多缺陷,不适合生产环境。LoadBlancer Service则不太灵活,比如针对微服务架构,那么不同服务是否需要多个负载均衡服务呢?那么,我们还有其他选择么?那就是Ingress。
Ingress将集群外部的HTTP和HTTPS路由暴露给集群中的Service,相当于集群的入口,而入口规则则由Ingress定义的规则来控制。在使用Ingress之前,我们先需要有一个Ingress Controller(入口控制器),例如ingress-nginx。Ingress负责定义抽象的规则,而Ingress Controller负责具体实现。通常情况下,Ingress搭配负载均衡一起使用。接下来,笔者结合一个简单的微服务Demo来使用Ingress进行负载分发。由于需要使用到负载均衡服务,本教程使用腾讯云容器服务进行讲解。
为了便于大家理解,我们先做一个简单的规划。整体规划图如下所示:
如图所示,整体步骤如下所示:
如上所述,接下来我们进入开发环节。
为了完成我们上述的目标,我们需要提供以下两个demo(不限编程语言):
如下图所示,apidemo1的访问路径为https://{hostname}:{port}/api/demo1,输出JSON“["value1","value2"]”。
注意:apidemo1和apidemo2均需支持80端口和443端口访问。
如下图所示,apidemo2的访问路径为https://{hostname}:{port}/api/demo2,输出JSON“["value3","value4"]”。
由于Demo比较简单,这里我们就不贴代码了。Demo准备完成后,我们需要推送docker镜像到目标仓储,然后创建部署(Deployment)以及服务(Service)。
整个过程在前面的章节我们均有详细讲述,因此这里就不赘述了,这里我们仅提供参考的YAML定义文件:
apiVersion: apps/v1beta2 #api版本
kind: Deployment #使用部署对象
metadata:
labels: #标签列表
app: apidemo1
name: apidemo1 #部署名称
namespace: default #命名空间
spec:
replicas: 1 #副本数
selector: #选择器
matchLabels:
app: apidemo1
template: #Pod模板
metadata:
labels:
app: apidemo1
spec:
containers: #容器列表
- env: #环境变量设置
- name: PATH
value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- name: ASPNETCORE_URLS
value: http://+:80
- name: DOTNET_RUNNING_IN_CONTAINER
value: "true"
- name: ASPNETCORE_VERSION
value: 2.2.6
image: ccr.ccs.tencentyun.com/magicodes/apidemo1:latest #镜像地址
imagePullPolicy: Always #镜像拉取策略,Always表示总是拉取最新镜像,IfNotPresent表示如果本地存在则不拉取,Never则表示只使用本地镜像
name: apidemo1 #容器名称
resources: #资源限制
limits: #最高限制
cpu: 500m
memory: 256Mi
requests: #预分配
cpu: 250m
memory: 64Mi
workingDir: /app #工作目录
dnsPolicy: ClusterFirst #DNS策略
restartPolicy: Always #重启策略
terminationGracePeriodSeconds: 30 #删除需要时间
镜像是公开的,基于以上YAML定义,各位可以直接基于腾讯云的容器服务的【YAML创建资源】进行创建,步骤如下:
4.接下来,需要确保创建成功。我们使用上述参考的YAML分别创建Deployment“apidemo1”和“apidemo2”如下图所示:
接下来,我们来分别创建“apidemo1”和“apidemo2”Service资源。参考YAML如下所示:
apiVersion: v1
kind: Service #资源类型
metadata:
name: apidemo1 #服务名称
namespace: default
spec:
ports: #端口列表
- name: tcp-80-80
nodePort: 31010 #节点端口
port: 80 #当前端口
protocol: TCP #协议
targetPort: 80 #目标端口
selector: #标签选择器
app: apidemo1
type: NodePort #NodePort 类型的Service
注意:因为Ingress不会暴露任意端口或协议,因此用于外部访问时,Service类型必须为NodePort或者LoadBalancer类型。
使用上述类似的“YAML创建资源”的步骤创建Service如下图所示:
我们创建的Service类型为NodePort,因此可以通过节点公网IP和上述定义的nodePort访问,如下图所示:
接下来我们需要创建Ingress并配置好转发规则达成如下目标:
根据以上目标,我们定义YAML如下所示:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: qcloud #注释,不同的Ingress控制器支持不同的注释
name: demo-ip
namespace: default
spec:
rules: #规则列表
- http: #HTTP规则
paths: #路径列表
- backend: #后端配置
serviceName: apidemo1 #后端服务名称
servicePort: 80 #服务端口
path: /api/demo1 #路径,同一个域名路径需不同
- http:
paths:
- backend:
serviceName: apidemo2 #后端服务名称
servicePort: 80 #服务端口
path: /api/demo2 #路径,同一个域名路径需不同
使用以上YAML创建资源,腾讯云会自动创建负载均衡服务并且提供负载均衡IP,如下图所示:
我们来验证下通过此IP访问是否能够达到预期结果,测试分别如下图所示:
虽然我们达成了目标,但是通过IP访问体验并不友好,如何通过域名访问呢?YAML定义定义如下所示:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: qcloud #注释,不同的Ingress控制器支持不同的注释
kubernetes.io/ingress.http-rules: '[{"host":"demo.xin-lai.com","path":"/api/demo1","backend":{"serviceName":"apidemo1","servicePort":80}},{"host":"demo.xin-lai.com","path":"/api/demo2","backend":{"serviceName":"apidemo2","servicePort":80}}]' #HTTP转发规则
kubernetes.io/ingress.https-rules: "null"
kubernetes.io/ingress.rule-mix: "true"
random: "7778255514276773869"
name: demo
namespace: default
spec:
rules: #规则列表
- host: demo.xin-lai.com #主机名,可选。如不填写,则使用IP地址。
http: #HTTP规则
paths: #路径列表
- backend: #后端配置
serviceName: apidemo1 #后端服务名称
servicePort: 80 #服务端口
path: /api/demo1 #路径,同一个域名路径需不同
- host: demo.xin-lai.com #主机名,可选。如不填写,则使用IP地址。
http:
paths:
- backend:
serviceName: apidemo2 #后端服务名称
servicePort: 80 #服务端口
path: /api/demo2 #路径,同一个域名路径需不同
值得注意的是,不同的Ingress控制器支持不同的注释,因此注释的编写请参阅所使用的Ingress控制器的说明。转发规则中,host为空则使用IP。
创建完成之后,腾讯云同样会自动创建负载均衡服务并且提供负载均衡IP,如下图所示,接下来我们需要将域名“demo.xin-lai.com”解析到该负载均衡IP“193.112.232.48”:
解析完成后,我们同样进行验证:
如上图所示,我们使用域名完成了以下目标:
至此,一个简单的使用Ingress来负载分发微服务的Demo完成。当然这仅仅是微服务架构的万里长征第一步,毕竟Nginx Ingress控制器仅仅解决了服务的分发,并不具备完整的接口网关功能,对于这块,笔者推荐大家使用Kong+Kong Ingress Controller,架构如下图所示:
接下来,我们再谈谈微服务应用服务的管理问题。微服务往往有许多小服务,每个微服务都能够独立进行部署和扩展,那么必然提高了应用管理的复杂度,它们的配置、分发、版本管理等等都是一个管理的难题。在这块,有什么更好的解决方案吗?那就Helm。