ingress流量控制与灰度金丝雀发布
一、ingress
1、ingress是什么
ingress是一种七层流量转发机制,即七层负载均衡,请求抵达ingress后,ingress会匹配url的路径部分,将不同的路径分发不同的后端svc(一个svc代理一个微服务的多副本)来处理
请求到了svc之后,svc依据自己标签选中的微服务pod以及负载均衡策略(例如ipvs)来将请求转发给指定pod
注意:svc拥有负载均衡能力的前提是它有clusterIP
2、为何要用ingress
为了用引入七层负载均衡把微服务重新汇聚成一个整体,然后对外暴漏
二、引入ingress之后完整的访问流程
见图 第五章
三、ingress相关概念
1. ingress的控制器
ingress controller-----> 负载均衡软件,跑在pod里-----> k8s的控制器来对pod进行管理自愈
为了解决两点问题:
1、配置中转发给某个svc最好用其fqdn域名而不是ip-》默认使用k8s的coredns
2、ingress的软件需要能够被管理起来能够自愈----》引入k8s的控制器资源来管理
需要把ingress的软件部署到pod里,并且用k8s的控制器资源来管理
ingress的七层负载均衡软件 + 负责管理维护其配置的守护进程===》合在一起部署在同一个pod中===》有一个专门的称呼叫ingress controller
2. ingress对象
是一种往ingress的软件中注入配置的一种非常方便的方式----》用yaml清单的方式注入配置
四、ingress有3种部署方案(到底用k8s中的哪种控制器资源来进行管理有何区别)
1. 按照是否需要为ingress的pod创建svc来区分,可以分为两大方案
pod是通过物理节点的IP端口暴露出去的,对接的下游还有一个物理的负载均衡器(软件的也可以),这就需要每个物理节点都暴露ip+端口,能访问到k8s里的pod;————svc会在每个物理节点添加ipvs转发规则;还有一种方案deamenset就是在每个节点上都部署一个pod,他的网络模式为hostnetwork,这样就能通过每个物理节点访问到ingress了。
1、需要创建ingress的svc(非hostNetwork网络模式)
depoyment来部署ingress的pod(pod的网络不是hostNetwork) + svc(type为LoadBalancer)
depoyment来部署ingress的pod(pod的网络不是hostNetwork) + svc(type为NodePort)
2、不需要创建ingress的svc(用hostNetwork网络模式)转发路径更短,效率更高
Daemonset来部署ingress的pod(pod的网络就是hostNetwork)
五、部署ingress、测试使用
注入匹配规则:ingress controller ---------ingressclass--------ingress对象
物理节点的ip:32568
curl http://test.ingress.com:34780/host/test.html
wget --no-check-certificate https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.1/deploy/static/provider/baremetal/deploy.yaml # 最新下载地址,需要换镜像地址 https://github.com/kubernetes/ingress-nginx/blob/main/deploy/static/provider/baremetal/deploy.yaml # 里面包含了代理的nodeport的svccat > microservices.yaml << EOF apiVersion: apps/v1 kind: Deployment metadata: labels: app: gowebhost name: gowebhost spec: replicas: 2 selector: matchLabels: app: gowebhost strategy: {} template: metadata: labels: app: gowebhost spec: containers: - image: nginx:1.18 name: nginx --- apiVersion: v1 kind: Service metadata: creationTimestamp: null labels: app: gowebhost name: gowebhost spec: ports: - port: 9999 protocol: TCP targetPort: 80 selector: app: gowebhost type: ClusterIP status: loadBalancer: {} --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: gowebip name: gowebip spec: replicas: 2 selector: matchLabels: app: gowebip strategy: {} template: metadata: labels: app: gowebip spec: containers: - image: nginx:1.18 name: nginx --- apiVersion: v1 kind: Service metadata: creationTimestamp: null labels: app: gowebip name: gowebip spec: ports: - port: 8888 protocol: TCP targetPort: 80 selector: app: gowebip type: ClusterIP status: loadBalancer: {} EOFcat > ingress.yaml << EOF apiVersion: networking.k8s.io/v1 # kubectl explain ingress.apiVersion kind: Ingress metadata: name: ingress-test namespace: default annotations: #kubernetes.io/ingress.class: "nginx" # 开启use-regex,启用path的正则匹配 nginx.ingress.kubernetes.io/use-regex: "true" spec: ingressClassName: nginx rules: # 定义域名 - host: test.ingress.com http: paths: # 不同path转发到不同端口 - path: /ip pathType: Prefix backend: service: name: gowebip port: number: 8888 - path: /host pathType: Prefix backend: service: name: gowebhost port: number: 9999 EOF六、 ingress对象资源详解
(一) 核心字段介绍
ingress是一个API对象,和其他对象一样,通过yaml文件来配置,为负载均衡程序注入配置(一条 ingress就是写入nginx.conf中的一段配置)
1. 以如下ingress对象yaml为示例展开介绍
apiVersion: networking.k8s.io/v1 # 可以查看详情kubectl explain ingress kind: Ingress metadata: name: ingress-test namespace: default annotations: # 注解 kubernetes.io/ingress.class: "nginx" #老版本,选择ingress controller nginx.ingress.kubernetes.io/use-regex: "true" # 开启use-regex,启用path的正则匹配, spec: tls: - hosts: - test.ingress.com secretName: ingress-tls ingressClassName: nginx # 选择ingress controller rules: # 定义域名 - host: test.ingress.com # 外部访问的域名 http: paths: # 不同path转发到不同端口 - path: /ip pathType: Prefix # 前缀匹配 backend: service: name: gowebip #svc的fqnd名 port: number: 8888 #svc的端口 - path: /host pathType: Prefix backend: service: name: gowebhost port: number: 9999与其他k8s对象一样,ingress配置有几个重要的属性:
1、metadata.annotations(详细用法:第八章节)
在ingress配置中,annotations很重要,可以用来控制启用何种功能,如下use-regex启用正则匹配:
如上案例nginx.ingress.kubernetes.io/use-regex: "true"最终是在生成nginx配置中,会采用location ~来表示正则匹配。
kubectl get ingressclasses类跨名称空间的,他在所有名称空间下都有,会关联一个控制器
创建一个ingress controller都会创建一个ingressclasses资源相关联,等于是他的唯一id,注入配置是靠ingresscalsses找到控制器的
2、tls
tls用于定义https密钥、证书,详见第七章节
3、ingressClassName:见下一小节
4、rules,rules中的pathType、backend以及`defaultBackend`:见下下小节
2. ingressClass.Name字段
yaml [root@k8s-master-01 ~]# kubectl get ingressclass -o yaml # 可以查看到名为nginx的控制器 apiVersion: v1 items: - apiVersion: networking.k8s.io/v1 kind: IngressClass metadata: ...... name: nginx # 这个名字就是你在创建ingress对象时引用的ingressClassName名 spec: controller: k8s.io/ingress-nginx # 这个名字是在ingress-controller控制器启动args里指定的 kind: List metadata: resourceVersion: ""注意:如果你的k8s中安装了多个ingress控制器,在创建ingress对象时,你就需要用ingressClassName来选择你想要的ingress控制器
由于一个集群中可能有多个 Ingress 控制器,所以我们还可以将一个特定的IngressClass对象标记为集群默认是Ingress类。只需要将一个 IngressClass 资源的 `ingressclass.kubernetes.io/is-default-class` 注解设置为true即可,这样未指定 `ingressClassName` 字段的 Ingress 就会使用这个默认的 IngressClass。
apiVersion: networking.k8s.io/v1 kind: IngressClass metadata: annotations: ingressclass.kubernetes.io/is-default-class: "true"如果集群中有多个 `IngressClass` 被标记为默认,准入控制器将阻止创建新的未指定 `ingressClassName` 的 Ingress 对象。最好的方式还是确保集群中最多只能有一个 `IngressClass` 被标记为默认。
3. rules字段
rules字段用于指定请求路由转发规则。
一、host:
提供了 host 域名,则 rules 则会匹配该域名的相关请求,此外 host 主机名可以是精确匹配(例如 foo.bar.com)或者使用通配符来匹配(例如 *.foo.com)。
二、http.paths:定义访问的路径列表
比如上面定义的 /testpath,每个路径都有一个由 backend.service.name 和 backend.service.port.number 定义关联的 Service 后端,在控制器将流量路由到引用的服务之前,host 和 path 都必须匹配传入的请求才行。
三、backend:该字段其实就是用来定义后端的 Service 服务的
与路由规则中 host 和 path 匹配的流量会将发送到对应的 backend 后端去。
了解:Resource
backend 后端除了可以引用一个 Service 服务之外,还可以通过一个 resource 资源进行关联,
Resource 是当前 Ingress 对象命名空间下引用的另外一个 Kubernetes 资源对象,Resource 后端的一种常见用法是将所有入站数据导向带有静态资产的对象存储后端,
但是需要注意的是 Resource 与 Service 配置是互斥的,只能配置一个,
如下所示:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-resource-backend spec: rules: - http: paths: - path: /icons pathType: ImplementationSpecific backend: resource: apiGroup: k8s.example.com kind: StorageBucket name: icon-assets该 Ingress 资源对象描述了所有的 /icons 请求会被路由到同命名空间下的名为 icon-assets 的 StorageBucket 资源中去进行处理。
四、pathType字段
事实上每个路径都需要有对应的路径类型,当前支持的`pathType` 路径类型有三种:
kubectl explain ingress.spec.rules.http.paths.pathType FIELD: pathType <string> ENUM: Exact ImplementationSpecific PrefixExact(精确/完全): 请求必须精确地匹配指定的路径、且区分大小写。例如,如果路径设置为/foo,则仅/foo会被匹配,而/foo/或/foo/bar不会匹配。
Prefix(前缀): 基于以 `/` 分隔的 URL 路径前缀匹配,匹配区分大小写。如果设置为/foo,则任何以这个前缀开始的路径(比如/foo、/foo/、/foo/bar)都会被匹配。它不要求完全精确匹配,只要求请求的路径以指定的path开头。
ImplementationSpecific(交给特定控制器实现): 当指定 pathType 为 ImplementationSpecific 时,意味着匹配路径的具体行为将由所选的 Ingress 控制器来决定,比如 nginx 或 traefik,每个控制器可能会有它自己对路径匹配的解释和实现方式。
在nginx的情况下,这通常涉及到更多细微或复杂的匹配条件,可能包括正则表达式或特定于nginx的行为。
示例
# 使用 ImplementationSpecific 类型的路径匹配方式,具体行为由 Ingress Controller 决定 - path: /prefix-path pathType: Prefix backend: service: name: prefix-service port: number: 80 apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: example-ingress namespace: default spec: rules: - host: example.com http: paths: # 使用 Exact 类型的路径匹配方式,路径必须与 /exact-path 完全一致 - path: /ip pathType: Exact backend: service: name: exact-service port: number: 80 --- # 使用 Prefix 类型的路径匹配方式,任何以 /prefix-path 为前缀的路径都会匹配 - path: /prefix-path pathType: Prefix backend: service: name: prefix-service port: number: 80 --- # 使用 ImplementationSpecific 类型的路径匹配方式,具体行为由 Ingress Controller 决定 - path: /regex-path pathType: ImplementationSpecific backend: service: name: regex-service port: number: 804. ingress-nginx的优化
其实就是一个nginx内核有优化
pstree -p <uid> 看一个ingressnginx的子进程,5. 构建TLS站点(deamser管理的ingress访问加上证书443)
https协议ssl证书
#生成secret,不需要挂载,直接用ingress对象添加 kind: ingress spec: tls: - hosts: - test.ingress.com secretName: ingress-tls1、# 准备证书 openssl genrsa -out tls.key 2048 # 生成一个私钥 openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=ShangHai/L=ShangHai/O=Ingress/CN=test.ingress.com # 自签一个证书 2、# 生成secret,不需要挂载,直接用ingress对象添加 kubectl -n default create secret tls ingress-tls --cert=tls.crt --key=tls.key你提供的这两条命令用于生成 RSA 私钥和自签名的 X.509 证书,通常用于测试 HTTPS、Ingress 等场景,具体解释如下: 第一条命令:生成 RSA 私钥 openssl genrsa -out tls.key 2048 genrsa:指定生成 RSA 算法的私钥。 -out tls.key:将生成的私钥保存到tls.key文件中。 2048:指定私钥长度为 2048 位(属于安全的长度,兼顾安全性和性能)。 执行后,会在当前目录生成tls.key文件,包含 2048 位的 RSA 私钥(需妥善保管,不可泄露)。 第二条命令:生成自签名证书 openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=ShangHai/L=ShangHai/O=Ingress/CN=test.ingress.com req:处理证书请求(Certificate Request)的命令。 -new:生成新的证书请求。 -x509:跳过 “生成证书请求(CSR)” 步骤,直接生成自签名的 X.509 证书(无需 CA 机构签名)。 -key tls.key:指定使用前面生成的tls.key私钥来签名证书。 -out tls.crt:将生成的证书保存到tls.crt文件中。 -subj:指定证书的 “主题信息”(避免交互式输入),各字段含义: C=CN:国家(Country),CN 代表中国。 ST=ShangHai:省份(State),这里是上海。 L=ShangHai:城市(Locality),这里是上海。 O=Ingress:组织(Organization),这里自定义为 “Ingress”。 CN=test.ingress.com:通用名称(Common Name),通常是证书对应的域名(后续访问该域名时,证书会被匹配)6. annotation
一、域名重定向
metadata: annotations: nginx.ingress.kubernetes.io/rewrite-target: https://www.baidu.com/s?wd=egon二、设置白名单
允许客户端的IP访问
三、正则匹配
七、发布策略
什么是发布:
部署启用新代码
发布过程中会遇到的问题:
1、发布过程中服务会暂时中断
2、新版本遇到问题,如何快速回滚
总结为一个目标:确保服务中断断时间不要过长
于是诞生多种发布策略
1. 滚动发布
就一套环境,在升级过程中,并不是一下子启用所有新版本,而是先启动一个新的,再停一个老版本,一点点向新版本滚动,直到完成全部升级。
如果环境中有10台机器,只需要新增1台机器,就可以滚动起来了
优点:
1、节省机器、最小化停机时间、平滑过渡
缺点:
1、新老版本共存,在整个升级过程中极不稳定
一旦访问出问题,无法确定是新版本的问题还是老版本的问题
关键是缺少对流量的控制
2. 蓝绿发布(蓝老绿新):环境维度,以整套环境基本单位来进行流量分发
核心是部署两套环境,两套环境的机器配置都一样
老环境部署老版本,新环境部署新版本
在两套环境的基础上做流量的分配,旧80%,新20%,然后逐步增加新环境的流量
如果原环境中有10台机器,新环境也需要有10台机器
优点:随时切换,快速切回老环境,也能抗住压力,因为老环境原封不动的放着呢
缺点:耗费资源
3. 金丝雀发布(有时候会与灰度发布代表一个意思,总体来说都是小范围尝试,然后逐步扩大,站在这个维度很多人会将金丝雀发布与灰度当成一个意思,但细说的话有用法层面的区别)流量维度,站在整体流量的维度进行分配,没有细分用户特征
蓝绿有两套一样配置的环境,流量分分配是以一个整个环境为单位分发的
金丝雀,先部署少数几台新版本,然后采用流量的控制的方式,逐步严重
让一点一点扩大范围,适用于迭代版本,而不是大版本更新
4. 灰度发布:用户群体特征,从所有用户中选出一些充当小白鼠
从已经注册的用户中选出一部分,给一点优惠,让大家尝试新功能给,你反馈,
发布方式,先灰度验证,再发正式环境
关键区别:金丝雀发布的流量分配不区分用户
总结:金丝雀发布可以被视为灰度发布的一种实现方式,但灰度发布的范围更广,涵盖了更多逐步发布的策略。
(一) ingress-金丝雀发布
四种Canary规则
金丝雀发布:小范围流量尝试,然后逐步扩大
控制流量的两大类方式:
1、基于权重
canary-weight
2、基于用户请求
canary-by-header、 canary-by-header-value、canary-by-cookie
