K8S集群服务器
IP | Hostname |
---|---|
10.20.1.139 | k8s-master01 |
10.20.1.140 | k8s-node01 |
10.20.1.141 | k8s-node02 |
一、负载均衡器
负载均衡器有两类,区别在于 四层网络 和 七层网络 的支持,传输层在第四层,这层协议有 TCP/UDP/TCP SSL 等,而七层有 HTTP/HTTPS。
1. 基于 LVS 的 HTTPS 负载均衡
基于 LVS 的 HTTPS 负载均衡 是 典型的四层代理架构。客户端发出请求,经过LVS直接转发到服务器,然后服务器返回结果,从请求的发出到结果的响应,中间仅仅产生一次完整的TCP连接。
2. 基于 Nginx 的 HTTPS 负载均衡
基于 Nginx 的 HTTPS 负载均衡是一种基于七层网络代理架构的实现。客户端发出 https 请求,请求到达nginx服务器,nginx 重新生成一个新的 http 请求发到真实的服务器,服务器计算结果后发往 nginx,nginx再将结果以 https 的方式返回给客户端。从请求的发出到结果的响应,中间产生了两次请求。
二、Ingress简介
1. Ingress 介绍
Ingress 是从 Kubernetes 集群外部访问集群内部服务的入口,同时为集群内的 Service 提供七层负载均衡能力。它提供了 HTTP 和 HTTPS 路由功能,使外部流量能够访问集群内部的服务。通过定义 Ingress 资源,可以控制哪些外部请求能够访问集群中的哪些服务,以及如何路由这些请求。
具体架构图如下:
我们做网站时,使用 Nginx 做 Web 服务器,会使用一个子域名绑定一个网站,a.xxx.com
绑定 A 网站,b.xxx.com
绑定 B 网站,这样在一个域名的不同子域名可以访问不同的站点,对于现在的大多数互联网网站,依然会使用这种方法划分。
在微服务架构中,多个模块部署在不同的服务器上,则但是我们希望都通过 xxx.com
这个域名直接访问,就好像所有模块都在一起,让用户感觉只有一个网站。则可能会使用目录路径对模块进行划分,例如如果我们要实现 xxx.com/a
访问 A 模块,xxx.com/b
访问 B 模块,但对用户来说,一直在访问 xxx.com
这个域名。
这种需求,我们可以使用 nginx 进行反向代理,而在 Kubernetes 中,这种需求也是一模一样的。
首先,我们可以为 A、B、C 等应用,创建多个 Service,每个 Service 访问一个应用,然后使用 Ingress 配置路由规则,决定 URL 可以访问哪个 Service。
Ingress 公开了从集群外部到集群内服务的 HTTP 和 HTTPS 路由,Ingress 资源上定义的规则控制了路由。
Ingress 可以让集群中的多个 Service 能够从集群外访问,Ingress 还提供负载均衡、SSL/TLS 和基于名称的虚拟服务器等,Ingress 可以配置边缘路由器或其他前端工具来帮助处理网络流量,但是一般都是通自己的负载均衡器来实现。
Ingress 有两部分,一部分是 LoadBalancer ,提供统一入口,代理请求;另一部分是 Ingress 控制器,复制定义路由规则等。
如果不使用公有云平台的 LoadBalancer ,那么就自己搭建一个服务器,这台服务器加入到 Kubernetes 集群中,做流量入口,这台服务器网络接口必须够大,抗得住流量。
2. Ingress 与 Service
在前面,我们已经学习到了 Service,通过 Service 我们可以暴露一个端口到外网中,通过这个端口可以访问应用。
其中,有两种方法可以暴露 Service,可以让其被集群外部访问:
- 使用
Service.Type=LoadBalancer
- 使用
Service.Type=NodePort
Service 的访问方式是 IP,每次要将服务公开给外界时,都必须创建一个新的 LoadBalancer 并向云服务商获取一个公网 IP 地址。或者使用 NodePort
,但是只能在一台服务器上被访问,而且 Service 只能为一种 Pod 服务,暴露一个或多个端口,那么 N 个服务,就需要创建 N 个 Service。Service 虽然能够公开端口到外部网络中,但是无法将这些服务合并到一个 example.com/{服务}
中访问,Service 需要通过不同的端口访问。
如果你有一个 example.com
域名,你部署了多个 Web 服务,其中有两个子模块分别为课程(course)、考试(exam) 两个微服务,这些模块构成了一个培训网站。此时我们希望访问 example.com/api/course
能够访问课程学习模块,访问 example.com/api/exam
能够访问考试模块。显然,Service 是无法做到的。
使用 Ingress ,可以轻松设置路由规则,而且无需创建一堆 LoadBalancers/Nodes 公开每个服务,并且 Ingress 本身具有很多功能。
Ingress 也需要 Service 。
三、 安装 Ingress 控制器
Ingress 控制器有多种实现,其中 Kubernetes 官方有一个名为 Ingress-nginx 的实现,其它实现还有 Kong Ingress、Traefik、HAProxy Ingress 等。这里演示 使用 Helm 安装 Ingress-nginx 。
官方文档:https://kubernetes.github.io/ingress-nginx/deploy/#using-helm
1. 下载 Ingress-nginx 安装包
需要首先安装helm管理工具:https://georgechan95.github.io/blog/d8e3c7b3.html
ingress-nginx 的仓库在国外,国内下载需要vpn支持,参考:https://georgechan95.github.io/blog/7f174b3e.html
# 添加 ingress-nginx仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
# 下载 ingress-nginx 安装包
helm pull ingress-nginx/ingress-nginx --version=4.8.3
2. 导入 Ingress-nginx 镜像
这些镜像是 ingress-nginx 启动时所需的镜像,由于国内的网络无法从国外下载镜像,因此需要提前把这些镜像下载好,导入到服务器中。
关于如何使用 Docker 拉取谷歌镜像,参考这篇博客:https://georgechan95.github.io/blog/b01d5c62.html
# 下载 ingress-nginx 需要的镜像
# 所有节点都需要导入这些镜像
docker pull registry.k8s.io/ingress-nginx/controller:v1.9.4
docker pull registry.k8s.io/defaultbackend-amd64:1.5
docker pull registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231011-8b53cabe0
docker pull registry.k8s.io/ingress-nginx/opentelemetry:v20230721-3e2062ee5
3. 安装 Ingress-nginx
3.1 解压 Ingress-nginx 压缩包
# 安装包解压
$ tar -zxvf ingress-nginx-4.8.3.tgz
# 进入 ingress-nginx 解压后的目录
$ cd ingress-nginx
# 当前所在目录
$ pwd
/opt/k8s/10/ingress-nginx
# 查看 ingress-nginx 目录结构
$ tree .
.
├── CHANGELOG.md
├── Chart.yaml
├── .....
├── README.md.gotmpl
├── changelog
│ ├── Changelog-4.5.2.md
│ ├── .....
│ └── Changelog-4.8.3.md
├── changelog.md.gotmpl
├── ci
│ ├── controller-admission-tls-cert-manager-values.yaml
........
│ └── deployment-webhook-values.yaml
├── templates
│ ├── NOTES.txt
│ ├── admission-webhooks
│ │ ├── cert-manager.yaml
│ │ ├── job-patch
│ │ │ ├── clusterrole.yaml
│ │ │ ├── ......
│ │ │ └── serviceaccount.yaml
│ │ └── validating-webhook.yaml
│ ├── clusterrole.yaml
│ ├── .....
│ └── default-backend-serviceaccount.yaml
└── values.yaml
3.2 编辑 values.yaml
# 修改 values.yaml 文件
$ vim values.yaml
# 修改1:
# 修改如下内容:
controller
hostNetwork: true # 使用主机网路
dnsPolicy: ClusterFirstWithHostNet # Pod 的网络命名空间与主机共享,Pod 使用主机的网络栈
kind: DaemonSet # 每个节点部署一个 ingress-nginx-controller
ingressClassResource:
default: true # 使用默认的Inginx类,默认是 nginx
# 修改2:
#注释 digest 相关内容
controller
image:
#digest: sha256:xxxxx
#digestChroot: sha256:xxxxx
admissionWebhooks:
patch:
image:
#digest: sha256:xxxxx
将解压后的 ingress-nginx 目录内 values.yaml 文件中的 digest: sha256xxxx 所在的所有的行注释掉,避免因为下载镜像的指纹与文件要求不一致,无法运行
3.3 关于 dnsPolicy
ClusterFirstWithHostNet:
- 当 Pod 的
hostNetwork
设置为 true 时,使用该 DNS 策略。 - 这意味着 Pod 的网络命名空间与主机共享,Pod 使用主机的网络栈。
- 在此配置下,Pod 将首先尝试通过主机上的 DNS 解析 DNS 请求。如果主机上没有找到,则会将请求发送到 kube-dns 服务,由 kube-dns 服务进行处理。
- 这种策略适用于需要与主机网络共享的特殊情况,但它不会为 Pod 提供专用的 DNS 解析功能。
ClusterFirst:
- 这是 Kubernetes 中默认的 DNS 策略。
- 当 Pod 的
hostNetwork
设置为 false 或未设置时,使用该策略。 - 在此策略下,Pod 首先尝试通过 kube-dns 服务解析 DNS 请求。如果 kube-dns 无法解析,则会向上级 DNS 服务器继续发起请求。
- 这种策略适用于大多数情况,其中 Pod 需要使用 Kubernetes 集群的 DNS 服务解析其他 Pod 或服务的主机名。
3.4 安装 ingress-nginx
# 使用 Helm 安装 ingress-nginx
$ helm install ingress-nginx --namespace ingress-nginx --create-namespace .
# 查看 ingress-nginx release
$ helm list -n ingress-nginx
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
ingress-nginx ingress-nginx 1 2025-06-26 18:35:32.209570796 +0800 CST deployed ingress-nginx-4.8.3 1.9.4
# 查看 IngressClass
$ kubectl get ingressclass
NAME CONTROLLER PARAMETERS AGE
nginx k8s.io/ingress-nginx <none> 153m
# 查看 Service
$ kubectl get service -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.105.7.64 <pending> 80:32570/TCP,443:31991/TCP 117m
ingress-nginx-controller-admission ClusterIP 10.102.42.201 <none> 443/TCP 117m
# 查看 Pod
$ kubectl get pod -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-controller-pf6sb 1/1 Running 0 117m 192.168.6.141 k8s-node02 <none> <none>
ingress-nginx-controller-qmb7h 1/1 Running 0 117m 192.168.6.140 k8s-node01 <none> <none>
# 查看 DaemonSet
$ kubectl get daemonset -n ingress-nginx -o wide
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR
ingress-nginx-controller 2 2 2 2 2 kubernetes.io/os=linux 118m controller registry.k8s.io/ingress-nginx/controller:v1.9.4 app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
4. 测试 Ingress-nginx
4.1 创建 Service 和 Deployment
httpproxy-dep-svc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: my-nginx
image: nginx:1.29.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: nginx
执行资源清单
$ kubectl apply -f httpproxy-dep-svc.yaml
查看资源
$ kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 59d <none>
nginx-svc ClusterIP 10.111.16.251 <none> 80/TCP 8s app=nginx
$ kubectl get deployment -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx-deploy 2/2 2 2 16s my-nginx nginx:1.29.0 app=nginx
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-6fc4ff86dc-n76xc 1/1 Running 0 22s 172.16.58.249 k8s-node02 <none> <none>
nginx-deploy-6fc4ff86dc-nlmw5 1/1 Running 0 22s 172.16.85.206 k8s-node01 <none> <none>
4.2 创建 Ingress
ingress.yaml
apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
name: ingress-httpproxy
namespace: default
spec:
ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
- host: www.test-http-proxy.com # 指定此规则适用于请求的 HTTP 主机头(Host Header)为 www.test-http-proxy.com 的流量。客户端必须通过该域名访问, 如果省略 host,Ingress 会匹配所有域名(即通配规则)。
http: # 定义了 HTTP 协议的路由规则
paths: # 用于指定路径匹配规则
- path: / # 指定匹配的 URL 路径为 /,即根路径,这是最常见的路径,表示匹配所有以 / 开头的请求
pathType: Prefix # 定义路径匹配的类型为 Prefix,表示匹配以指定路径(/) 开头的所有请求
backend: # 定义请求的转发目标,即后端服务
service:
name: nginx-svc # 指定后端服务的名称为 nginx-svc.(必须存在于同一命名空间,或通过 <namespace>/<service-name> 跨命名空间引用)
port:
number: 80 # 指定目标 Service 的端口为 80
执行资源清单
$ curl http://www.test-http-proxy.com
查看资源
$ kubectl get ingress -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-httpproxy nginx www.test-http-proxy.com 80 18
4.3 修改主机 host 文件
修改host文件,将其中一台集群节点的IP,映射域名:www.test-http-proxy.com
$ cat /etc/hosts
10.20.1.140 www.test-http-proxy.com
10.20.1.140 是 node节点的Ip,部署了 Ingress 控制器。这里通过 Ingress 控制器 将请求转发到 SVC。
4.4 浏览器访问域名
打开浏览器,访问 http://www.test-http-proxy.com, 通过访问 Ingress Controller ,访问到 Nginx Svc
$ kubectl get service -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.105.7.64 <pending> 80:32570/TCP,443:31991/TCP 117m
ingress-nginx-controller-admission ClusterIP 10.102.42.201 <none> 443/TCP 117m
至此可以了解到通过使用 Ingress-Nginx 让外部流量能够访问集群内部的服务。
四、Ingress Nginx 使用
ingress的api版本历经过多次变化他们的配置项也不太一样分别是:
- extensions/v1beta1:1.16版本之前使用
- networking.k8s.io/v1beta1:1.19版本之前使用
- networking.k8s.io/v1:1.19版本之后使用
1. Ingress-nginx HTTP 代理
资源清单:ingress-nginx-http-proxy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: my-nginx
image: nginx:1.29.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80 # 指定容器监听的端口
protocol: TCP # 指定端口使用的协议,TCP 表示端口处理 TCP 流量,适合 nginx 的 HTTP 服务
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
ports:
- port: 80 # Service 对外暴露的端口号
targetPort: 80 # Service 将流量转发到的目标 Pod 的端口号
protocol: TCP
selector:
app: nginx # Service 将流量路由到带有标签 app=nginx 的 Pod
apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
name: ingress-httpproxy
namespace: default
spec:
ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
- host: www.test-http-proxy.com # 指定此规则适用于请求的 HTTP 主机头(Host Header)为 www.test-http-proxy.com 的流量。客户端必须通过该域名访问, 如果省略 host,Ingress 会匹配所有域名(即通配规则)。
http: # 定义了 HTTP 协议的路由规则
paths: # 用于指定路径匹配规则
- path: / # 指定匹配的 URL 路径为 /,即根路径,这是最常见的路径,表示匹配所有以 / 开头的请求
pathType: Prefix # 定义路径匹配的类型为 Prefix,表示匹配以指定路径(/) 开头的所有请求
backend: # 定义请求的转发目标,即后端服务
service:
name: nginx-svc # 指定后端服务的名称为 nginx-svc.(必须存在于同一命名空间,或通过 <namespace>/<service-name> 跨命名空间引用)
port:
number: 80 # 指定目标 Service 的端口为 80
执行资源清单
$ kubectl apply -f ingress-nginx-http-proxy.yaml
deployment.apps/nginx-deploy created
service/nginx-svc created
ingress.networking.k8s.io/ingress-httpproxy created
查看部署资源
$ kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 59d <none>
nginx-svc ClusterIP 10.111.16.251 <none> 80/TCP 8s app=nginx
$ kubectl get deployment -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx-deploy 2/2 2 2 16s my-nginx nginx:1.29.0 app=nginx
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-6fc4ff86dc-n76xc 1/1 Running 0 22s 172.16.58.249 k8s-node02 <none> <none>
nginx-deploy-6fc4ff86dc-nlmw5 1/1 Running 0 22s 172.16.85.206 k8s-node01 <none> <none>
$ kubectl get ingress -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-httpproxy nginx www.test-http-proxy.com 80 18
修改主机 Host 文件
IP 可以是集群内部署了 Ingress-Controler 的任意一台服务器 IP
10.20.1.140 www.test-http-proxy.com
测试访问 HTTP
$ curl http://www.test-http-proxy.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
2. Ingress-nginx HTTPS 代理
2.1 生成证书和私钥
# 1. 创建证书扩展文件
$ vim http.ext
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = www.https-proxy.com
IP.1 = 127.0.0.1
# 2. 创建证书
# 生成证书步骤1 : 生成 CSR(证书签名请求) 和 私钥文件 tls.key
openssl req -new -newkey rsa:2048 -sha256 -nodes -out tls.csr -keyout tls.key -subj "/C=CN/ST=Beijing/L=Beijing/O=Super Inc./OU=Web Security/CN=www.https-proxy.com"
# 生成证书步骤2 : 生成证书tls.crt,并指定证书扩展文件
openssl x509 -req -days 365 -in tls.csr -signkey tls.key -out tls.crt -extfile http.ext -extensions v3_req
# 查看生成的证书文件
$ ls
http.ext tls.crt tls.csr tls.key
# 3. 将证书和私钥存储到 Secret
$ kubectl create secret tls ingress-nginx-tls --key tls.key --cert tls.crt
查看证书 Secret
# 查看 Secret $ kubectl get secret ingress-nginx-tls -n default NAME TYPE DATA AGE ingress-nginx-tls kubernetes.io/tls 2 22s # 查看 Secret 详情 $ kubectl describe secret ingress-nginx-tls -n default Name: ingress-nginx-tls Namespace: default Labels: <none> Annotations: <none> Type: kubernetes.io/tls Data ==== tls.crt: 1436 bytes tls.key: 1708 bytes # 查看 Secret 数据 $ kubectl get secret ingress-nginx-tls -n default -o yaml apiVersion: v1 data: tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQrRENDQXVDZ0F3SUJBZ0lVWk9iZ3V4cUR5bTlVWk1XUDROMEdnR3pTZkw4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2V6RUxNQWtHQTFVRUJoTUNRMDR4RURBT0JnTlZCQWdNQjBKbGFXcHBibWN4RURBT0JnTlZCQWNNQjBKbAphV3BwYm1jeEV6QVJCZ05WQkFvTUNsTjFjR1Z5SUVsdVl5NHhGVEFUQmdOVkJBc01ERmRsWWlCVFpXTjFjbWwwCmVURWNNQm9HQTFVRUF3d1RkM2QzTG1oMGRIQnpMWEJ5YjNoNUxtTnZiVEFlRncweU5UQTJNamN3TXpBeE1qWmEKRncweU5qQTJNamN3TXpBeE1qWmFNSHN4Q3pBSkJnTlZCQVlUQWtOT01SQXdEZ1lEVlFRSURBZENaV2xxYVc1bgpNUkF3RGdZRFZRUUhEQWRDWldscWFXNW5NUk13RVFZRFZRUUtEQXBUZFhCbGNpQkpibU11TVJVd0V3WURWUVFMCkRBeFhaV0lnVTJWamRYSnBkSGt4SERBYUJnTlZCQU1NRTNkM2R5NW9kSFJ3Y3kxd2NtOTRlUzVqYjIwd2dnRWkKTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDUVJkTE1TZGpNdHQ2NzVPclVhbmNRNTN5eQpTZitEYVZ2Q2xPdjlGNDRkbG1GSFlrVVZXRW9VQkNIRzdCM1pBb0pRWGFpaEJRbUl5UTNJV0o2ODhsWVpEOU1XClgzU212MGp3Q1A0SVcxaTYyVHBwb0JVRHhlNlI3SHhBQXJXeG9pMzV6Q1lFVVRoZzY3OExhWDRma04xR0pYY3AKaERqZ1FFZ3NqTmVwdGNGRVBLaUxicTNhNVlkRWdpTmpVTnh3dWpKY1RFYllkMXgwUFh5V1lYVDNDV29Fd3JUZQozcU0zWUxTdThjRXdIT21VUW13Rzhvc1p4c2lLeXZjN2MwK3JWWUpqeXR1MFJDRVRjY3Njb2hhSWpqT25xaTN0ClVhd0tKbG9Fa3M5Y2dCb05BSzFodXRDRk9UbzJMY3VZSjA1akhSdy84VXI4RG4rc0w4cGFFSWNqZ2VqOUFnTUIKQUFHamREQnlNQWtHQTFVZEV3UUNNQUF3Q3dZRFZSMFBCQVFEQWdYZ01CTUdBMVVkSlFRTU1Bb0dDQ3NHQVFVRgpCd01CTUNRR0ExVWRFUVFkTUJ1Q0UzZDNkeTVvZEhSd2N5MXdjbTk0ZVM1amIyMkhCSDhBQUFFd0hRWURWUjBPCkJCWUVGTU9jdUNxSTVpL3kwazBtSDVWeFFNaEdhRTA0TUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFBeHZ5LzUKWGE1TjRxc3B4WS9rN0NPSTZoT2VBTitqaGF1SWVMeUkrb1UvczkzVnVLTkRrQ0ErakEyRHRWQmhtQ0xrVUdnbQo1enN5MkJHTndZZW4zV05mTXZZUmQ1ZFhjK3ZzUVNaV2VROWwwZ3FKaTdTeEQwaDJZa3BOUlJVcy84RXRSOUJFCmFKSmNkYTV1dlVwT2VFQ3JrWVhGRnIvK09yZW9Mdi9MV3dtK3VLRytLd204YUU1V3Z6czM0SUlqM1pOMlk1ZVQKVDh3dVhhOVJqbU1mRldaaDA4UHJUd3RXT1R1cW5TQUZ3Z2tpeTBab0RtNFd5amlUNmluZWpzTlpSa2ZCcW5ieQpwQVN0eGlmUWk4S2hRNVUzOEhkUVMzYnpNdnFiS2g3ZlZoamh4Si8wNVBQVHE0NGU3eG56dnlEazFUaC9vWnZ0CjJLdUZuVVkxLzlMayt1U1cKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2d0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktrd2dnU2xBZ0VBQW9JQkFRQ1FSZExNU2RqTXR0NjcKNU9yVWFuY1E1M3l5U2YrRGFWdkNsT3Y5RjQ0ZGxtRkhZa1VWV0VvVUJDSEc3QjNaQW9KUVhhaWhCUW1JeVEzSQpXSjY4OGxZWkQ5TVdYM1NtdjBqd0NQNElXMWk2MlRwcG9CVUR4ZTZSN0h4QUFyV3hvaTM1ekNZRVVUaGc2NzhMCmFYNGZrTjFHSlhjcGhEamdRRWdzak5lcHRjRkVQS2lMYnEzYTVZZEVnaU5qVU54d3VqSmNURWJZZDF4MFBYeVcKWVhUM0NXb0V3clRlM3FNM1lMU3U4Y0V3SE9tVVFtd0c4b3NaeHNpS3l2YzdjMCtyVllKanl0dTBSQ0VUY2NzYwpvaGFJampPbnFpM3RVYXdLSmxvRWtzOWNnQm9OQUsxaHV0Q0ZPVG8yTGN1WUowNWpIUncvOFVyOERuK3NMOHBhCkVJY2pnZWo5QWdNQkFBRUNnZ0VBQm1OOUpldzRPWS9OMWFxdSs3M2FMTDYweVhnQzVLTm4rNDl1S0NIZ3BSbEUKRUszcFFCSE40cUhiTldIcElYTmR2aExPVlR1eDlDTnVaT1V6RHZhNU9YaTNWaVNKelJvbjJwbnFBVE02L3VLQQpnUmhrWXl0NE9NWFhnUVhOc2hmQkt2QmFGNTRFSGR0RlNyWCt3OXJvU0MzL3RKcmFZajNKSkdYajVVRTdRQnI4CkxZemUvaXp0TVAyeENMSytwL3hJa1JpRVRaVmRubmtaM2FEY3JtcGlmOGRUcGZMbDVYUlRTNWtvbitXMmdybkUKdFd3L3lsWUVzcHo2c1BPRWV0bDNWK3VNYVlsOW9sTEZtQ1M1NUJxQjRid05zSHQyMDdzRmQ2SmdmRFdpZE9yUwpOSWdqRXMxOVphSU9VZitRN254VkQrNGNWaVFJbHhJc21CVGNONjRlOFFLQmdRRERSQmJzdWs3aHQ4MDRwR2wzCnN3M2Q5NndDZHZyOEVtdU41ZDdScEtudG5RdkQvaVJjTS9nNGZlU2czQ1lTbUpCSFNwUDFmZE0wODZBTXBIbzMKcmw2RGtZZ2diUGM4QndHZGp2NDJUdmFYUkQ1T2tnSjlPcDUreHZLMFpmZWJVeERlT3k2SmhNNFFJck5GZVF1dgpCZ0lJSUlSRTJzOTdlak1FclNPQ21CSlNjUUtCZ1FDOUpXOTYwVjIxdkk2L2lBUzZ5eitlSytJaVRxYjh3TUxwCjZjTWR0UEhTdy9URkJ0RVFpSGJvYTUwZER5YVh5TXR4dUpvamNLUXN5ZzdZWlFxQnpheEkwZEIvR0dqRzNlM1oKNjYwQXVXZ0pSN0VOYit3N2pDdjVGa0NWTEg1MEcxbXM2RjlBRXk0ajlOOStuSDlOTEtzbHZmcmNYbFIvY09HeQp6Q29adjdWdFRRS0JnUUNaYkJWckdSUERqQ3dsOWlDY0dVYXJBZC9YNis1V1FvN1paaVRGcWRDT1R4ZWdmajNKCmFGZis0d1BSVkVoaDBoZUN2RmsyeVE4N0NyVFZXaUpoUDVNcFl4NkhBN2JhSmxNaG5lbWxlRE9PTk9PVHptdEEKUTkrbWt1QzkxMlJPV1Z6bWo2K0lBNTM0MVpydjJpVFE5ekovZWpVUytLMlBRanQxMENnWGd5N2FNUUtCZ1FDMQpFdVdLV215djB2ZUZmSjJxaFhFOTV4enhZd0tSN2FlcmIxS1BXZTQzcThqajVnYTNJUzFVaTlFNVJJdlp1eXlvCmplVmlFQy9iZ1FSOVBSMjE3a1FFNG5nTGRENjZRek8wNzk0TFYzTzFqcUI5RUt6Q3hRcER4MzNFVVhndGh4RnUKYW5ibFRIZGJqTTE0MURFNm5JeXI4UmY3WjRMVkRpZkRsNWltVmRWRjhRS0JnUUNnTlB6enkrQUJtVHFLVytXbAoxb0lzUlJlQjdDd1pxUjNUZ0FBaXdKOEpRTFdoREdiQzdJQ0FLVlZkNGZjeUtXVlovRWIrK3RZdUc5ZUpWUkY4CldzU2J1Y0phcktBN1k4UDUydDVtWUp6ZkZjb0hLNXVSVFlOVElFM2w4YmhnSmxqaVJPTER1a2N6cEhVdkJLZkYKYVg4UjNtR3hhZFJ4U25TZUhiN2QvNUFaVlE9PQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg== kind: Secret metadata: creationTimestamp: "2025-06-27T03:10:37Z" name: ingress-nginx-tls namespace: default resourceVersion: "13338253" uid: fffb5d77-97c4-4237-8be9-a487d96dbf34 type: kubernetes.io/tls
2.2 创建资源清单
资源清单:ingress-nginx-https-proxy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx-https
template:
metadata:
labels:
app: nginx-https
spec:
containers:
- name: my-nginx
image: nginx:1.29.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80 # 指定容器监听的端口
protocol: TCP # 指定端口使用的协议,TCP 表示端口处理 TCP 流量,适合 nginx 的 HTTP 服务
apiVersion: v1
kind: Service
metadata:
name: nginx-https-svc
namespace: default
spec:
ports:
- port: 80 # Service 对外暴露的端口号
targetPort: 80 # Service 将流量转发到的目标 Pod 的端口号
protocol: TCP
selector:
app: nginx-https # Service 将流量路由到带有标签 app=nginx-https 的 Pod
apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
name: ingress-https-proxy
namespace: default
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true" # HTTP 重定向为HTTPS, true表示强制重定向
spec:
ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
- host: www.https-proxy.com # 指定此规则适用于请求的 HTTP 主机头(Host Header)为 www.www.https-proxy.com 的流量。客户端必须通过该域名访问, 如果省略 host,Ingress 会匹配所有域名(即通配规则)。
http: # 定义了 HTTP 协议的路由规则
paths: # 用于指定路径匹配规则
- path: / # 指定匹配的 URL 路径为 /,即根路径,这是最常见的路径,表示匹配所有以 / 开头的请求
pathType: Prefix # 定义路径匹配的类型为 Prefix,表示匹配以指定路径(/) 开头的所有请求
backend: # 定义请求的转发目标,即后端服务
service:
name: nginx-https-svc # 指定后端服务的名称为 nginx-https-svc.(必须存在于同一命名空间,或通过 <namespace>/<service-name> 跨命名空间引用)
port:
number: 80 # 指定目标 Service 的端口为 80
tls:
- hosts:
- www.https-proxy.com # 指定域名
secretName: ingress-nginx-tls # 证书和私钥保存的 Secret
可以看到Ingress添加TLS配置也非常简单,只需要在 spec下添加一个 tls 字段即可:
- hosts:证书所授权的域名列表
- secretName:证书的 Secret 名字
- ingressClassName: ingress class 的名字,1.22+需要配置
执行资源清单
$ kubectl apply -f ingress-nginx-https-proxy.yaml
deployment.apps/nginx-deploy created
service/nginx-https-svc created
ingress.networking.k8s.io/ingress-https-proxy created
查看部署资源
$ kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 59d <none>
nginx-https-svc ClusterIP 10.99.219.148 <none> 80/TCP 96s app=nginx-https
$ kubectl get deployment -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx-deploy 2/2 2 2 8s my-nginx nginx:1.29.0 app=nginx-https
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-7d6bd7f587-47kqv 1/1 Running 0 21s 172.16.85.213 k8s-node01 <none> <none>
nginx-deploy-7d6bd7f587-92hhz 1/1 Running 0 21s 172.16.58.233 k8s-node02 <none> <none>
$ kubectl get ingress -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-https-proxy nginx www.https-proxy.com 80, 443 2m57s
修改主机 Host 文件
IP 可以是集群内部署了 Ingress-Controler 的任意一台服务器 IP
10.20.1.140 www.https-proxy.com
测试访问 HTTPS访问
端口号通过命令:kubectl get svc -n ingress-nginx 查看 443 映射端口
# 用命令行测试 https 请求,其中 -k 表示忽略自签名证书警告
$ curl -k https://www.https-proxy.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
需要将自签发的 tls.crt 证书导入到浏览器中,否则会有 “不安全” 的告警提示
如果在ingress中设置tls,即默认的http会被强制重定向到https,http即不可访问,如果需要http与https同时可以使用可以设置
- nginx.ingress.kubernetes.io/ssl-redirect: “false” :禁用强制重定向,这样可以同时使用http与https
3. Ingress-nginx BasicAuth 代理
有些网站可能需要通过密码来访问,对于这类网站可以使用 Nginx 的 basic-auth 设置密码访 问,具体方法如下,由于需要使用 htpasswd 工具,所以需要安装httpd。
# 安装 htpasswd 工具
$ dnf -y install httpd-tools
# 使用 htpasswd 命令创建一个新的基本认证密码文件 auth,并为用户 george 设置密码。
$ htpasswd -c auth george
New password:
Re-type new password:
Adding password for user george
# 创建一个 Kubernetes Secret 资源,类型为 generic,用于存储基本认证的密码文件 auth,以便在 Ingress 或 Nginx 中启用 HTTP 基本认证。
$ kubectl create secret generic ingress-basic-auth --from-file=auth
查看 Secret
$ kubectl get secret ingress-basic-auth -o yaml apiVersion: v1 data: auth: Z2VvcmdlOiRhcHIxJEpoZFB6aVNPJDVXcjhqTDYyQll5Nm5aa3ZHWlB3ejAK kind: Secret metadata: creationTimestamp: "2025-06-27T06:12:07Z" name: ingress-basic-auth namespace: default resourceVersion: "13361989" uid: 9550e4af-4a83-48d7-9b40-fc207303a192 type: Opaque
创建包含密码认证的Ingress:
- nginx.ingress.kubernetes.io/auth-type:认证类型,可以是 basic 和 digest
- nginx.ingress.kubernetes.io/auth-secret:密码文件的 Secret 名称
- nginx.ingress.kubernetes.io/auth-realm:需要密码认证的消息提醒
资源清单
ingress-nginx-basic-auth.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: my-nginx
image: nginx:1.29.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80 # 指定容器监听的端口
protocol: TCP # 指定端口使用的协议,TCP 表示端口处理 TCP 流量,适合 nginx 的 HTTP 服务
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
ports:
- port: 80 # Service 对外暴露的端口号
targetPort: 80 # Service 将流量转发到的目标 Pod 的端口号
protocol: TCP
selector:
app: nginx # Service 将流量路由到带有标签 app=nginx 的 Pod
apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
name: ingress-basic-auth
namespace: default
annotations:
nginx.ingress.kubernetes.io/auth-type: basic # 认证类型
nginx.ingress.kubernetes.io/auth-secret: ingress-basic-auth # 密码文件的 Secret 名称
nginx.ingress.kubernetes.io/auth-realm: '请输入用户名和密码:' # 需要密码认证的消息提醒
spec:
ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
- host: auth.basic.com # 指定此规则适用于请求的 HTTP 主机头(Host Header)为 auth.basic.com 的流量。
http: # 定义了 HTTP 协议的路由规则
paths: # 用于指定路径匹配规则
- path: / # 指定匹配的 URL 路径为 /,即根路径,这是最常见的路径,表示匹配所有以 / 开头的请求
pathType: ImplementationSpecific # 表示路径匹配行为由 Ingress 控制器定义,对于 nginx Ingress 控制器,ImplementationSpecific 通常等同于 Prefix,即匹配以指定路径开头的请求。
backend: # 定义请求的转发目标,即后端服务
service:
name: nginx-svc # 指定后端服务的名称为 nginx-svc.(必须存在于同一命名空间,或通过 <namespace>/<service-name> 跨命名空间引用)
port:
number: 80 # 指定目标 Service 的端口为 80
执行资源清单
$ kubectl apply -f ingress-nginx-basic-auth.yaml
修改主机 Host 文件
IP 可以是集群内部署了 Ingress-Controler 的任意一台服务器 IP
10.20.1.140 auth.basic.com
浏览器访问测试
4. Ingress-nginx 域名重定向
在 Nginx 作为代理服务器时,Redirect 可用于域名的重定向,比如访问 old.com 被重定向到 new.com。Ingress 可以更简单的实现 Redirect 功能,接下来用 ingress-redirect.com 作为旧域名, www.baidu.com 作为新域名进行演示:
相关配置项:
- permanent-redirect:重定向到的域名
- permanent-redirect-code:重定向代码,不配置默认301(永久重定向,如有其他原因可自行配置)
资源清单:ingress-nginx-redirect.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: my-nginx
image: nginx:1.29.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80 # 指定容器监听的端口
protocol: TCP # 指定端口使用的协议,TCP 表示端口处理 TCP 流量,适合 nginx 的 HTTP 服务
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
ports:
- port: 80 # Service 对外暴露的端口号
targetPort: 80 # Service 将流量转发到的目标 Pod 的端口号
protocol: TCP
selector:
app: nginx # Service 将流量路由到带有标签 app=nginx-https 的 Pod
apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
name: ingress-redirect
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx" # 指定使用的Ingress控制器类名,与 ingressClassName 作用相同
nginx.ingress.kubernetes.io/permanent-redirect: https://www.baidu.com # 永久重定向网址
nginx.ingress.kubernetes.io/permanent-redirect-code: '301' # 永久重定向状态码
spec:
ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
- host: ingress-redirect.com # 指定此规则适用于请求的 HTTP 主机头(Host Header)为 ingress-redirect.com 的流量。客户端必须通过该域名访问, 如果省略 host,Ingress 会匹配所有域名(即通配规则)。
执行资源清单
$ kubectl apply -f ingress-nginx-redirect.yaml
修改主机host文件,添加域名映射
IP 可以是集群内部署了 Ingress-Controler 的任意一台服务器 IP
10.20.1.140 ingress-redirect.com
浏览器访问测试
5. Ingress-nginx Rewrite
官方示例:https://kubernetes.github.io/ingress-nginx/examples/rewrite/
相关配置项:
- nginx.ingress.kubernetes.io/rewrite-target: 重定向配置
5.1 案例
资源清单:ingress-nginx-rewrite.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: my-nginx
image: nginx:1.29.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80 # 指定容器监听的端口
protocol: TCP # 指定端口使用的协议,TCP 表示端口处理 TCP 流量,适合 nginx 的 HTTP 服务
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
ports:
- port: 80 # Service 对外暴露的端口号
targetPort: 80 # Service 将流量转发到的目标 Pod 的端口号
protocol: TCP
selector:
app: nginx # Service 将流量路由到带有标签 app=nginx-https 的 Pod
apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
name: ingress-rewrite
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2 # 对匹配的 URL 路径进行重写。$2 引用正则表达式捕获组
spec:
ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
- host: ingress-rewrite.com # 定义流量路由规则,基于主机名(host)。这里指定只处理发送到 ingress-rewrite.com 的请求
http:
paths:
- path: /api(/|$)(.*) # 匹配以 /api 开头的路径,后面可以跟 / 或直接结束(|$ 表示路径结束),并捕获剩余部分 (.*) 作为捕获组 $2, 例如:/api、/api/、/api/anything 都会匹配
pathType: ImplementationSpecific # 路径匹配的具体行为由 Ingress 控制器(NGINX)定义。通常与正则表达式结合使用,允许更灵活的匹配逻辑
backend:
service:
name: nginx-svc
port:
number: 80
执行资源清单
$ kubectl apply -f ingress-nginx-rewrite.yaml
修改主机host文件,添加域名映射
IP 可以是集群内部署了 Ingress-Controler 的任意一台服务器 IP
10.20.1.140 ingress-rewrite.com
访问域名,不加 /api 前缀:404
访问域名,添加 /api 前缀:成功访问到 nginx-svc Service 的默认页面
访问域名,添加路径 /api/index.html 成功访问到 nginx-svc Service 的 /index.html 页面
5.1 rewrite 和 redirect
在 Ingress 控制器中,rewrite 和 redirect 是两种不同的操作,它们的作用和行为有所不同:
Rewrite(重写)
- 作用:重写是指修改请求的路径,但是客户端不会察觉到这个变化,它仅在服务器内部发生。在 Kubernetes 中,可以通过 Ingress 的注解来配置重写规则
- 示例:比如你有一个服务部署在 /v1 路径下,但是你希望用户访问时不需要输入 /v1,那么你可以使用重写将请求从根路径 / 重写到 /v1
Redirect(重定向)
- 作用:重定向是指服务器向客户端发出一个新的 URL,让客户端进行新的请求。客户端会收到一个 HTTP 3xx 状态码,然后根据其中的重定向地址进行新的请求。这意味着客户端会知道发生了重定向,它会发起新的请求
- 示例:比如你有一个网站的旧地址是 http://example.com,但是你希望所有的请求都转发到 https://example.com,这时你就可以使用重定向将所有的 HTTP 请求重定向到 HTTPS
区别:
- 影响范围:Rewrite 只在服务器内部修改请求路径,不会影响到客户端,而 Redirect 则会向客户端发送一个新的 URL,让客户端发起新的请求
- 状态码:Rewrite 不涉及状态码的改变,而 Redirect 会向客户端发送一个重定向的 HTTP 状态码(例如 301 永久重定向、302 临时重定向等)
- 可见性:Rewrite 对于客户端来说是透明的,而 Redirect 则会告知客户端发生了重定向
在选择使用 Rewrite 还是 Redirect 时,需要根据具体的需求来决定。如果你希望在不修改客户端请求的情况下修改路径,那么使用 Rewrite;如果你希望客户端知道发生了重定向,并且根据新的 URL 进行新的请求,那么使用 Redirect。
6. Ingress-nginx 错误代码重定向
这里的错误代码重定向分为全局设置与某个ingress设置
6.1 默认错误后端(全局)
错误代码重定向功能需要使用 helm 重新部署 ingress-nginx 控制器部署步骤如下:
6.1.1 修改 values.yaml
# 修改 ingress-nginx 目录内 valume.yml 文件
defaultBackend:
enabled: true # 开启全局错误码重定向
name: defaultbackend
image:
registry: registry.k8s.io
image: defaultbackend-amd64
tag: "1.5"
pullPolicy: IfNotPresent
这里的镜像是 ingress-nginx 的默认镜像,需要提前下载并导入到服务器中
6.1.2 更新 Ingress Nginx
# 更新 Ingress Nginx
$ helm upgrade ingress-nginx . -n ingress-nginx
# 查看 Pod 是否更新,如果是则为刚创建的
$ kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-cpbcd 1/1 Terminating 0 31h
ingress-nginx-controller-szlfb 1/1 Running 0 25s
ingress-nginx-defaultbackend-f7797494f-t77x4 1/1 Running 0 39s
# 旧的 controller 正在关闭,新创建的在运行中,Ingress Nginx 更新成功
6.1.3 测试资源清单
ingress-nginx-global-errorcode.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: my-nginx
image: nginx:1.29.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: nginx
apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
name: ingress-global-errorcode
namespace: default
spec:
ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
- host: global.errorcode.com # 指定此规则适用于请求的 HTTP 主机头(Host Header)为 global.errorcode.com 的流量。
http: # 定义了 HTTP 协议的路由规则
paths: # 用于指定路径匹配规则
- path: / # 指定匹配的 URL 路径为 /,即根路径,这是最常见的路径,表示匹配所有以 / 开头的请求
pathType: Prefix # 定义路径匹配的类型为 Prefix,表示匹配以指定路径(/) 开头的所有请求
backend: # 定义请求的转发目标,即后端服务
service:
name: nginx-svc # 指定后端服务的名称为 nginx-svc.(必须存在于同一命名空间,或通过 <namespace>/<service-name> 跨命名空间引用)
port:
number: 80 # 指定目标 Service 的端口为 80
执行资源清单
$ kubectl apply -f ingress-nginx-global-errorcode.yaml
修改主机host文件,添加域名映射
IP 可以是集群内部署了 Ingress-Controler 的任意一台服务器 IP
10.20.1.140 global.errorcode.com
当开启 Ingress Nginx 全局错误码重定向时,此时请求不存在的路径,服务端会返回默认的内容
例如请求 http://ingress-rewrite.com/123.html
6.2 单独声明错误后端
设置某个ingress的错误重定向会覆盖全局设置,示例如下
- nginx.ingress.kubernetes.io/default-backend: 默认后端service名称
- nginx.ingress.kubernetes.io/custom-http-errors: 那些错误代理重定向到默认后端svc
资源清单
ingress-nginx-single-errorcode.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: error-code-deploy # 用于当请求出现规定的错误码时,返回默认内容
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: error
template:
metadata:
labels:
app: error
spec:
containers:
- name: error-web
image: registry.k8s.io/defaultbackend-amd64:1.5
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
apiVersion: v1
kind: Service
metadata:
name: error-code-svc # 当请求异常,接收到规定的错误码时,请求会重定向到这个service,用来处理错误请求,返回默认内容
namespace: default
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: error
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: my-nginx
image: nginx:1.29.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: nginx
apiVersion: networking.k8s.io/v1 # 指定 API 版本
kind: Ingress # 指定资源类型为 Ingress,表示这是一个用于管理 HTTP/HTTPS 流量的 Kubernetes 资源
metadata:
name: ingress-single-errorcode
namespace: default
annotations:
nginx.ingress.kubernetes.io/default-backend: 'error-code-svc' # 指定请求异常时,重定向到哪个SVC处理
nginx.ingress.kubernetes.io/custom-http-errors: "404,415" # 哪些错误代理重定向到默认后端svc
spec:
ingressClassName: nginx # 指定此 Ingress 资源由名称为 nginx 的 IngressClass 处理,定义在 values.yaml 中 controller.ingressClassResource.name
rules: # 定义了流量路由的规则,即如何根据域名(host)和路径(path)将请求转发到后端服务。
- host: single.errorcode.com # 指定此规则适用于请求的 HTTP 主机头(Host Header)为 single.errorcode.com 的流量。
http: # 定义了 HTTP 协议的路由规则
paths: # 用于指定路径匹配规则
- path: / # 指定匹配的 URL 路径为 /,即根路径,这是最常见的路径,表示匹配所有以 / 开头的请求
pathType: Prefix # 定义路径匹配的类型为 Prefix,表示匹配以指定路径(/) 开头的所有请求
backend: # 定义请求的转发目标,即后端服务
service:
name: nginx-svc # 指定后端服务的名称为 nginx-svc.(必须存在于同一命名空间,或通过 <namespace>/<service-name> 跨命名空间引用)
port:
number: 80 # 指定目标 Service 的端口为 80
为了体现出单独为 Ingress 声明错误码的处理效果,这里先将 ingress-nginx 的全局错误码处理关闭
# 修改 values.yaml
defaultBackend:
enabled: false # 关闭全局错误码重定向
name: defaultbackend
image:
registry: registry.k8s.io
image: defaultbackend-amd64
tag: "1.5"
pullPolicy: IfNotPresent
# 更新 Ingress Nginx
$ helm upgrade ingress-nginx . -n ingress-nginx
执行资源清单
$ kubectl apply -f ingress-nginx-single-errorcode.yaml
修改主机host文件,添加域名映射
IP 可以是集群内部署了 Ingress-Controler 的任意一台服务器 IP
10.20.1.140 single.errorcode.com
测试:
使用浏览器访问一个不存在的路径,在没有错误码重定向时会返回 404, 如今为 Ingress 单独配置了错误码,会返回配置的 Service 的数据。
http://single.errorcode.com/api/index1.html
7. Ingress-nginx 匹配请求头
使用 ingress-nginx 实现根据不同的请求头,将请求转发到不同的服务。需要先开启 ingress-nginx 的 snippet 功能。
7.1 开启 Snippet
# 编辑 ingress-nginx-controller ConfigMap
$ kubectl edit cm ingress-nginx-controller -n ingress-nginx
# 开启 snippet
apiVersion: v1
data:
allow-snippet-annotations: "true"
7.2 编辑资源清单
ingress-nginx-match-request-header.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: snippet
name: snippet-dep
spec:
replicas: 1
selector:
matchLabels:
app: snippet
template:
metadata:
labels:
app: snippet
spec:
containers:
- name: snippet-deploy
image: nginx:1.29.0
imagePullPolicy: IfNotPresent
apiVersion: v1
kind: Service
metadata:
labels:
app: snippet
name: snippet-svc
spec:
ports:
- name: 80-80
port: 80
targetPort: 80
protocol: TCP
selector:
app: snippet
type: ClusterIP
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: snippet-igs
namespace: default
annotations:
nginx.ingress.kubernetes.io/server-snippet: |
set $agentflag 0;
if ($http_user_agent ~* "(Android|IPhone)") { # 如果是Android或IPhone访问会重定向到 www.baidu.com 的新网站
set $agentflag 1;
}
if ($agentflag = 1) {
return 302 http://www.baidu.com;
}
spec:
rules:
- host: snippet.request.com
http:
paths:
- path: /
pathType: Prefix # 定义路径匹配的类型为 Prefix,表示匹配以指定路径(/) 开头的所有请求
backend:
service:
name: snippet-svc
port:
number: 80
执行资源清单
$ kubectl apply -f ingress-nginx-match-request-header.yaml
编辑Host文件
$ cat /etc/hosts 10.20.1.140 snippet.request.com
10.20.1.140 是 node 节点,部署了 Ingress 控制器
测试访问:默认请求头
$ curl http://snippet.request.com <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style>
成功访问到 Nginx
测试访问:添加请求头
$ curl http://snippet.request.com -H 'User-Agent: Android' -I HTTP/1.1 302 Moved Temporarily Date: Fri, 04 Jul 2025 07:08:56 GMT Content-Type: text/html Content-Length: 138 Connection: keep-alive Location: http://www.baidu.com
请求重定向到了 www.baidu.com
8. Ingress-nginx 配置黑白名单
8.1. 配置方案
Ingress-nginx 配置黑白名单有两种方式:
- Annotations:只对指定的ingress生效
- ConfigMap:全局生效
configmap官方配置文档说明:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
若是同时配置了 Annotations 和 configmap,一般都是 annotations 生效,configmap 不生效,因为 annotations 优先级比 configmap 高
8.2 黑白名单的区别
- 白名单是默认是拒绝所有,只允许一个地址去访问
- 黑名单是不允许该地址去访问所有
黑白名单配置使用 configmap 还是 annotations
- 黑名单建议使用 ConfigMap 去配置
- 白名单建议使用 Annotations 去配置
8.3 ConfigMap 添加黑名单
配置黑名单禁止某一个或某一段 IP,需要在 Nginx Ingress 的 ConfigMap 中配置,比如将 10.20.1.141(多个配置逗号分隔)添加至黑名单。
configmap官方配置文档说明:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
8.3.1 编辑 Ingress-Nginx ConfigMap
$ kubectl edit cm ingress-nginx-controller -n ingress-nginx
apiVersion: v1
data:
allow-snippet-annotations: "true"
block-cidrs: 10.20.1.141,10.20.1.149
编辑后保存!
8.3.2 测试资源清单
ingress-nginx-black-block.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: test
name: test-deploy
spec:
replicas: 1
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
containers:
- image: nginx:1.29.0
name: myapp
apiVersion: v1
kind: Service
metadata:
labels:
app: test
name: test-svc
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
selector:
app: test
type: ClusterIP
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: global.black.com
spec:
rules:
- host: global.black.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: test-svc
port:
number: 80
执行资源清单
$ kubectl apply -f ingress-nginx-global-black.yaml
修改Host文件
# 在 10.20.1.140 服务器添加 Host 配置
echo "10.20.1.140 global.black.com" >> /etc/hosts
# 在 10.20.1.141 服务器添加 Host 配置
echo "10.20.1.141 global.black.com" >> /etc/hosts
访问测试
# 在 10.20.1.140 服务器上测试,可以成功访问 Ingress
$ curl global.block.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# 在 10.20.1.141 服务器上测试,访问被禁止,全局配置生效
$ curl global.block.com
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>
8.4 Annotations 添加黑名单
资源清单: ingress-nginx-annotations-black.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: black
name: black-deploy
spec:
replicas: 1
selector:
matchLabels:
app: black
template:
metadata:
labels:
app: black
spec:
containers:
- image: nginx:1.29.0
name: myapp
apiVersion: v1
kind: Service
metadata:
labels:
app: black
name: black-svc
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
selector:
app: black
type: ClusterIP
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/server-snippet: |
deny 10.20.1.141; # 拒绝特定 IP
deny 192.168.6.0/24; # 拒绝特定网段
allow all; # 允许其他 IP
name: annotaions.black.com
spec:
rules:
- host: annotaions.black.com
http:
paths:
- pathType: Prefix
backend:
service:
name: black-svc
port:
number: 80
path: /
执行资源清单
$ kubectl apply -f ingress-nginx-annotations-black.yaml
修改Host文件
# 在 10.20.1.140 服务器添加 Host 配置
echo "10.20.1.140 annotaions.black.com" >> /etc/hosts
# 在 10.20.1.141 服务器添加 Host 配置
echo "10.20.1.141 annotaions.black.com" >> /etc/hosts
访问测试
# 在 10.20.1.140 服务器上测试,可以成功访问 Ingress
$ curl annotaions.black.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# 在 10.20.1.141 服务器上测试,访问被禁止,全局配置生效
$ curl annotaions.black.com
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>
8.5 ConfigMap 设置白名单
白名单表示只允许某个IP可以访问
8.5.1 编辑 Ingress-Nginx ConfigMap
添加 whitelist-source-range
配置
$ kubectl edit cm ingress-nginx-controller -n ingress-nginx
apiVersion: v1
data:
allow-snippet-annotations: "true"
block-cidrs: 10.20.1.141,10.20.1.149
whitelist-source-range: 10.20.1.139,10.20.1.88
编辑后保存!
8.5.2 测试资源清单
ingress-nginx-global-white.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: test
name: test-deploy
spec:
replicas: 1
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
containers:
- image: nginx:1.29.0
name: myapp
apiVersion: v1
kind: Service
metadata:
labels:
app: test
name: test-svc
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
selector:
app: test
type: ClusterIP
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: global.white.com
spec:
rules:
- host: global.white.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: test-svc
port:
number: 80
执行资源清单
$ kubectl apply -f ingress-nginx-global-white.yaml
修改Host文件
# 在 10.20.1.140 服务器添加 Host 配置
echo "10.20.1.140 global.white.com" >> /etc/hosts
# 在 10.20.1.139 服务器添加 Host 配置
echo "10.20.1.140 global.white.com" >> /etc/hosts
访问测试
# 在 10.20.1.139 服务器上测试,可以成功访问 Ingress
$ curl global.white.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# 在 10.20.1.140 服务器上测试,访问被禁止,全局配置生效
$ curl global.white.com
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>
8.6 Annotations 添加白名单
资源清单: ingress-nginx-annotations-white.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: white
name: white-deploy
spec:
replicas: 1
selector:
matchLabels:
app: white
template:
metadata:
labels:
app: white
spec:
containers:
- image: nginx:1.29.0
name: myapp
apiVersion: v1
kind: Service
metadata:
labels:
app: white
name: white-svc
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
selector:
app: white
type: ClusterIP
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/whitelist-source-range: "10.20.1.140"
name: annotations.white.com
spec:
rules:
- host: annotations.white.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: white-svc
port:
number: 80
执行资源清单
$ kubectl apply -f ingress-nginx-annotations-white.yaml
修改Host文件
# 在 10.20.1.140 服务器添加 Host 配置
echo "10.20.1.140 annotations.white.com" >> /etc/hosts
# 在 10.20.1.141 服务器添加 Host 配置
echo "10.20.1.141 annotations.white.com" >> /etc/hosts
访问测试
# 在 10.20.1.140 服务器上测试,可以成功访问 Ingress
$ curl annotations.white.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# 在 10.20.1.141 服务器上测试,访问被禁止,全局配置生效
$ curl annotations.white.com
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>
9. Ingress-nginx 速率限制
有时候可能需要限制速率以降低后端压力,或者限制单个IP每秒的访问速率防止攻击。此时可以使用 Nginx 的 rate limit 进行配置
9.1 速率限制设置
#限制每秒的连接,单个 IP:
nginx.ingress.kubernetes.io/limit-rps
#限制每分钟的连接,单个 IP:
nginx.ingress.kubernetes.io/limit-rpm
#限制客户端每秒传输的字节数,单位为 K,需要开启 proxy-buffering:
nginx.ingress.kubernetes.io/limit-rate
#速率限制白名单
nginx.ingress.kubernetes.io/limit-whitelist
9.2 测试案例:无速率限制
资源清单 :ingress-nginx-rate-limit-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: speed-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: speed
template:
metadata:
labels:
app: speed
spec:
containers:
- name: myapp
image: nginx:1.29.0
imagePullPolicy: IfNotPresent
apiVersion: v1
kind: Service
metadata:
namespace: default
name: speed-svc
spec:
selector:
app: speed
type: ClusterIP
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
执行资源清单
$ kubectl apply -f ingress-nginx-rate-limit-pod.yaml
编辑Host文件
# 在 10.20.1.140 服务器写入
echo "10.20.1.140 rate.limit.com" >> /etc/hosts
# 在 10.20.1.141 服务器写入
echo "10.20.1.141 rate.limit.com" >> /etc/hosts
测试在无Ingress 限制速率的情况下, 发起100次请求
# 安装 ab 工具
$ sudo yum install -y httpd-tools
# 测试发起100个请求,并发数是 10
$ ab -c 10 -n 100 http://rate.limit.com/ | grep requests
Complete requests: 100
Failed requests: 0
Time per request: 0.188 [ms] (mean, across all concurrent requests)
Percentage of the requests served within a certain time (ms)
结论:在没有速率限制的情况下,100个请求全部成功。
9.3 测试案例:使用 Ingress 限制请求速率
资源清单:ingress-nginx-rate-limit-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: speed-ingress
namespace: default
annotations:
nginx.ingress.kubernetes.io/limit-rps: "10" # 每秒最多 10 个请求
nginx.ingress.kubernetes.io/limit-whitelist: "10.20.1.140,192.168.6.0/24" # 这些 IP 范围免于速率限制
spec:
rules:
- host: rate.limit.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: speed-svc
port:
number: 80
执行资源清单
$ kubectl apply -f ingress-nginx-rate-limit-ingress.yaml
测试速率限制
# 在 10.20.1.141 服务器上使用 ab 同时发起100个请求
$ ab -c 10 -n 100 http://rate.limit.com/ | grep requests
Complete requests: 100
Failed requests: 49
Time per request: 0.205 [ms] (mean, across all concurrent requests)
Percentage of the requests served within a certain time (ms)
###
由于 Ingress 做了请求速率的限制,发起100个请求,有49个失败了
###
# 在 10.20.1.140 服务器上使用 ab 同时发起100个请求
$ ab -c 10 -n 100 http://rate.limit.com/ | grep requests
Complete requests: 100
Failed requests: 0
Time per request: 0.137 [ms] (mean, across all concurrent requests)
Percentage of the requests served within a certain time (ms)
###
虽然Ingress对请求做了速率限制,由于 10.20.1.140 服务器ip在ingress 速率限制的白名单中,因此请求速率不受限制,100个请求全部成功
###
10. Ingress-nginx 灰度或者金丝雀发布
10.1 概述
灰度发布(也称金丝雀发布,Canary Release)是一种软件部署策略,旨在降低新版本上线带来的风险。它通过将新版本逐步推送给一小部分用户或系统(称为“金丝雀”),观察其表现、稳定性及用户反馈,再决定是否推广到全部用户。以下是详细解释:
核心概念
- 逐步推广:新版本不会一次性部署到所有用户,而是先部署到小规模用户群(如1%的用户或特定区域)。
- 监控与验证:在灰度发布期间,开发团队会密切监控新版本的性能、错误率、用户体验等指标。
- 快速回滚:如果发现问题,可以迅速回滚到旧版本,减少对用户的影响。
- 金丝雀的由来:名称源于煤矿工人使用金丝雀鸟来检测矿井中有毒气体。如果鸟儿出现异常,工人会立即撤离。类似地,灰度发布通过小范围测试来“预警”潜在问题。
实施步骤
- 选择目标群体:确定一小部分用户或服务器作为“金丝雀”,可以基于地理位置、用户ID、设备类型等条件。
- 部署新版本:将新版本部署到选定群体,同时旧版本继续服务其他用户。
- 监控表现:使用监控工具(如日志分析、性能指标、用户反馈)评估新版本的稳定性。
- 逐步扩展:如果表现良好,逐步增加新版本的覆盖范围(如从1%到10%、50%直至100%)。
- 回滚或全量发布:若发现问题,回滚到旧版本;若一切正常,完成全量发布。
10.2 创建 V1 版本的 Ingress
资源清单: ingress-nginx-canary-release-v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: default
name: canary-deploy-v1
labels:
app: v1
spec:
replicas: 10
selector:
matchLabels:
app: v1
template:
metadata:
labels:
app: v1
spec:
containers:
- name: deploy-v1
image: wangyanglinux/myapp:v1.0
imagePullPolicy: IfNotPresent
apiVersion: v1
kind: Service
metadata:
labels:
app: v1
name: canary-svc-v1
namespace: default
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
selector:
app: v1
type: ClusterIP
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: default
name: ingress-v1
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
ingressClassName: "nginx"
rules:
- host: canary.release.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: canary-svc-v1
port:
number: 80
执行资源清单
$ kubectl apply -f ingress-nginx-canary-release-v1.yaml
编辑Hosts文件
$ echo "10.20.1.140 canary.release.com" >> /etc/hosts
测试请求
$ curl http://canary.release.com
www.xinxianghf.com | hello MyAPP | version v1.0
10.3 创建 V2 版本的 Ingress
资源清单:ingress-nginx-canary-release-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: default
name: canary-deploy-v2
labels:
app: v2
spec:
replicas: 10
selector:
matchLabels:
app: v2
template:
metadata:
labels:
app: v2
spec:
containers:
- name: deploy-v2
image: wangyanglinux/myapp:v2.0
imagePullPolicy: IfNotPresent
apiVersion: v1
kind: Service
metadata:
labels:
app: v2
name: canary-svc-v2
namespace: default
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
selector:
app: v2
type: ClusterIP
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: default
name: ingress-v2
annotations:
nginx.ingress.kubernetes.io/canary: "true" # 启用金丝雀发布模式
nginx.ingress.kubernetes.io/canary-weight: "10" # 定义金丝雀服务的流量权重,单位为百分比
spec:
ingressClassName: "nginx"
rules:
- host: canary.release.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: canary-svc-v2
port:
number: 80
执行资源清单
$ kubectl apply -f ingress-nginx-canary-release-v2.yaml
编辑Hosts文件
$ echo "10.20.1.140 canary.release.com" >> /etc/hosts
测试请求
测试请求 100次, 查看请求汇总信息
# 做100次请求
$ for i in {1..100};do curl http://canary.release.com >> sum;done
# 查看请求汇总信息
$ cat sum | sort | uniq -c
92 www.xinxianghf.com | hello MyAPP | version v1.0
8 www.xinxianghf.com | hello MyAPP | version v2.0
结论:请求了100次,其中 92次请求到了 v1.0 版本, 8次请求到 v2.0版本。v2.0 大约占了 10%
11. Ingress-nginx 代理后端 https 协议
如果后端服务是 https 协议,需要使用 nginx.ingress.kubernetes.io/backend-protocols
声明后端服务是 https
。这里代理K8s的web控制台作为示例。代理后访问默认会强制跳转到 https 协议,返回的证书也是服务本身的证书。
资源清单:ingress-nginx-proxy-https-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: proxyhttps
name: proxyhttps-deploy
spec:
replicas: 1
selector:
matchLabels:
app: proxyhttps
template:
metadata:
labels:
app: proxyhttps
spec:
containers:
- image: wangyanglinux/tools:httpsv1
name: myapp
apiVersion: v1
kind: Service
metadata:
labels:
app: proxyhttps
name: proxyhttps-svc
spec:
ports:
- name: 443-443
port: 443
protocol: TCP
targetPort: 443
selector:
app: proxyhttps
type: ClusterIP
执行资源清单
$ kubectl apply -f ingress-nginx-proxy-https-pod.yaml
访问Service
# 查看 Service 资源
$ kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
proxyhttps-svc ClusterIP 10.103.15.21 <none> 443/TCP 3m25s app=proxyhttps
# 访问Service
$ curl -k https://10.103.15.21
Hello, HTTPS!
$ curl http://10.103.15.21:443
Client sent an HTTP request to an HTTPS server.
当前Service只能使用 HTTPS 访问
只用 Ingress 代理后端 HTTPS 服务
资源清单:ingress-nginx-proxy-https-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
name: ingress.https.com
namespace: default
spec:
rules:
- host: ingress.https.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: proxyhttps-svc
port:
number: 443
执行资源清单
$ kubectl apply -f ingress-nginx-proxy-https-ingress.yaml
编辑Host文件
$ echo "10.20.1.140 ingress.https.com" >> /etc/hosts
请求测试
$ curl http://ingress.https.com
Hello, HTTPS!
结论:使用 Ingress 代理了后端HTTPS请求
12. Ingress-nginx 四层代理
在新版本的nginx也引入了四层代理的概念,可直接代理TCP与UDP协议,在ingress-nginx也可以通过四层代理实现service的代理,实现方式如下:
官方文档:https://kubernetes.github.io/ingress-nginx/user-guide/exposing-tcp-udp-services/
首先在使用 helm 部署 ingress-nginx 之后,需修改 nginx 启动资源的启动参数添加--tcp-services-configmap
、--udp-services-configmap
的配置启用四层代理,通过修改配置 configmap 资源进行四层代理的配置。
12.1TCP代理
修改 ingress-nginx 控制器
在 ingress-nginx-controller 中添加 --tcp-services-configmap
启动参数
$ kubectl edit ds -n ingress-nginx ingress-nginx-controller
spec:
containers:
- args:
- /nginx-ingress-controller
- --tcp-services-configmap=$(POD_NAMESPACE)/nginx-ingress-tcp-configmap
#参数说明如下
--tcp-services-configmap=$(POD_NAMESPACE)/ 这里为固定,表示tcp配置选择ingress-nginx安装的命名空间的configmap资源
nginx-ingress-tcp-configmap 为configmap资源的名称
编辑 ConfigMap
nginx-ingress-tcp-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-ingress-tcp-configmap
namespace: ingress-nginx # ingress-nginx 所在的命名空间
data:
"9000": "default/proxyhttps-svc:443"
$ kubectl apply -f nginx-ingress-tcp-configmap.yaml
Pod资源清单
ingress-nginx-tcp-proxy-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: proxyhttps
name: proxyhttps-deploy
spec:
replicas: 1
selector:
matchLabels:
app: proxyhttps
template:
metadata:
labels:
app: proxyhttps
spec:
containers:
- image: wangyanglinux/tools:httpsv1
name: myapp
apiVersion: v1
kind: Service
metadata:
labels:
app: proxyhttps
name: proxyhttps-svc
spec:
ports:
- name: 443-443
port: 443
protocol: TCP
targetPort: 443
selector:
app: proxyhttps
type: ClusterIP
执行资源清单
$ kubectl apply -f ingress-nginx-tcp-proxy-pod.yaml
测试四层代理访问
$ kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
proxyhttps-svc ClusterIP 10.96.172.123 <none> 443/TCP 63s app=proxyhttps
# 首先直接访问 SVC,确认服务可用
$ curl -k https://10.96.172.123:443
Hello, HTTPS!
# 测试通过ingress 4层代理访问
$ curl -k https://10.20.1.140:9000
Hello, HTTPS!
12.2 UDP代理
修改 ingress-nginx 控制器
在 ingress-nginx-controller 中添加 --tcp-services-configmap
启动参数
$ kubectl edit ds -n ingress-nginx ingress-nginx-controller
spec:
containers:
- args:
- /nginx-ingress-controller
- --udp-services-configmap=$(POD_NAMESPACE)/nginx-ingress-udp-configmap
#参数说明如下
--tcp-services-configmap=$(POD_NAMESPACE)/ 这里为固定,表示tcp配置选择ingress-nginx安装的命名空间的configmap资源
nginx-ingress-tcp-configmap 为configmap资源的名称
编辑 ConfigMap
nginx-ingress-udp-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-ingress-udp-configmap
namespace: ingress
data:
"53": "kube-system/kube-dns:53"
13. Ingress-nginx 链路追踪
官方文档:https://kubernetes.github.io/ingress-nginx/user-guide/third-party-addons/opentracing/#jaeger
官方推荐的链路追踪插件为 Zipkin 或者 Jaeger。这里我们选用 Jaeger。
13.1 部署 Jaeger
# 下载部署资源清单
wget https://raw.githubusercontent.com/jaegertracing/jaeger-kubernetes/master/all-in-one/jaeger-all-in-one-template.yml
修改 jaeger 资源清单
apiVersion: v1
kind: List
items:
- apiVersion: apps/v1 # 将版本修改为 apps/v1
kind: Deployment
metadata:
name: jaeger
labels:
app: jaeger
app.kubernetes.io/name: jaeger
app.kubernetes.io/component: all-in-one
spec:
replicas: 1
selector: # 添加选择器, apps/v1版本需要
matchLabels:
app: jaeger
strategy:
type: Recreate
template:
metadata:
labels:
app: jaeger
app.kubernetes.io/name: jaeger
app.kubernetes.io/component: all-in-one
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "16686"
spec:
containers:
- env:
- name: COLLECTOR_ZIPKIN_HTTP_PORT
value: "9411"
image: jaegertracing/all-in-one
imagePullPolicy: IfNotPresent # 修改镜像下载策略,提前将镜像下载好
name: jaeger
ports:
- containerPort: 5775
protocol: UDP
- containerPort: 6831
protocol: UDP
- containerPort: 6832
protocol: UDP
- containerPort: 5778
protocol: TCP
- containerPort: 16686
protocol: TCP
- containerPort: 9411
protocol: TCP
readinessProbe:
httpGet:
path: "/"
port: 14269
initialDelaySeconds: 5
- apiVersion: v1
kind: Service
metadata:
name: jaeger-query
labels:
app: jaeger
app.kubernetes.io/name: jaeger
app.kubernetes.io/component: query
spec:
ports:
- name: query-http
port: 80
protocol: TCP
targetPort: 16686
selector:
app.kubernetes.io/name: jaeger
app.kubernetes.io/component: all-in-one
type: LoadBalancer
- apiVersion: v1
kind: Service
metadata:
name: jaeger-collector
labels:
app: jaeger
app.kubernetes.io/name: jaeger
app.kubernetes.io/component: collector
spec:
ports:
- name: jaeger-collector-tchannel
port: 14267
protocol: TCP
targetPort: 14267
- name: jaeger-collector-http
port: 14268
protocol: TCP
targetPort: 14268
- name: jaeger-collector-zipkin
port: 9411
protocol: TCP
targetPort: 9411
selector:
app.kubernetes.io/name: jaeger
app.kubernetes.io/component: all-in-one
type: ClusterIP
- apiVersion: v1
kind: Service
metadata:
name: jaeger-agent
labels:
app: jaeger
app.kubernetes.io/name: jaeger
app.kubernetes.io/component: agent
spec:
ports:
- name: agent-zipkin-thrift
port: 5775
protocol: UDP
targetPort: 5775
- name: agent-compact
port: 6831
protocol: UDP
targetPort: 6831
- name: agent-binary
port: 6832
protocol: UDP
targetPort: 6832
- name: agent-configs
port: 5778
protocol: TCP
targetPort: 5778
clusterIP: None
selector:
app.kubernetes.io/name: jaeger
app.kubernetes.io/component: all-in-one
- apiVersion: v1
kind: Service
metadata:
name: zipkin
labels:
app: jaeger
app.kubernetes.io/name: jaeger
app.kubernetes.io/component: zipkin
spec:
ports:
- name: jaeger-collector-zipkin
port: 9411
protocol: TCP
targetPort: 9411
clusterIP: None
selector:
app.kubernetes.io/name: jaeger
app.kubernetes.io/component: all-in-one
可以将所有的 SVC、Deployment 都放到单独的命名空间中,这样就不会被误删除
执行 Jaeger 资源清单
$ kubectl apply -f jaeger-all-in-one-template.yml
# 查看 SVC, !!! 注意:浏览器访问 jaeger 是通过 jaeger-query, 这里的 31272 就是对外暴露的端口
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jaeger-agent ClusterIP None <none> 5775/UDP,6831/UDP,6832/UDP,5778/TCP 12m
jaeger-collector ClusterIP 10.99.111.240 <none> 14267/TCP,14268/TCP,9411/TCP 12m
jaeger-query LoadBalancer 10.100.53.251 <pending> 80:31272/TCP 12m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d5h
zipkin ClusterIP None <none> 9411/TCP 12m
# 查看 Deployment
$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
jaeger 1/1 1 1 20s
# 查看 Pod
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
jaeger-cbfbf99b4-cxgq6 1/1 Running 0 22s
到此 Jaeger 就部署好了
注意:浏览器访问 jaeger 是通过 jaeger-query, 这里的 31272 就是对外暴露的端口,可以通过:http://物理机ip:31035 访问 Jaeger
13.2 ingress 设置
需要修改 ingress 的 configmap 文件,添加相应参数,开启 Ingress 链路追踪
$ kubectl edit cm -n ingress-nginx ingress-nginx-controller
apiVersion: v1
data:
allow-snippet-annotations: "true"
enable-opentracing: "true" #开启链路追踪
jaeger-collector-host: jaeger-agent.default.svc.cluster.local #链路追踪的svc名称
重建 Ingress-Nginx Pod
# 查看Pod
$ kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-25wk6 1/1 Running 0 150m
ingress-nginx-controller-qcbp2 1/1 Running 0 151m
# 删除Pod,等待重建
$ kubectl delete pod ingress-nginx-controller-25wk6 ingress-nginx-controller-qcbp2 -n ingress-nginx
浏览器访问Jaeger
参考链接
https://zhangzhuo.ltd/articles/2022/03/20/1647773666928.html
https://www.cnblogs.com/tencent-cloud-native/p/13865502.html
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 george_95@126.com