参考来源:
- Ingress-Nginx 官方文档地址: NGINX Configuration
- 课程随堂笔记: Kubernetes全栈架构师:基于世界500强的k8s实战课程
Ingress Nginx 常用配置
以下是自定义配置 Ingress Nginx 的三种方式:
- ConfigMap: 使用 Configmap 在 NGINX 中设置全局配置;
- Annotations: 使用 Annotations 配置指定 Ingress 的规则;
- Custom template: 当需要更具体的设置时,使用此方法。例如 open_file_cache,将监听选项调整为 rcvbuf,或者当无法通过 ConfigMap 更改配置时。
以上3中方法,第一二种已经能够满足 90% 以上的需求了。以下示例是常用的几种配置需求。
Ingress Nginx 入门使用
创建一个用于学习 Ingress 的 Namespace,之后所有的操作都在此 Namespace 进行
1
2# kubectl create ns study-ingress
namespace/study-ingress created创建一个简单的 Nginx 模拟 Web 服务
1
2# kubectl create deploy nginx --image=registry.cn-beijing.aliyuncs.com/dotbalo/nginx:1.15.12 -n study-ingress
deployment.apps/nginx created创建该 Web 容器的 Service
1
2# kubectl expose deployment nginx --port 80 -n study-ingress
service/nginx exposed创建 Ingress 指向上面创建的 Service(web-ingress.yaml)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
namespace: study-ingress
spec:
ingressClassName: nginx # 如果浏览器访问报 404,需要加上这个配置
rules:
- host: nginx.test.com
http:
paths:
- backend:
service:
name: nginx
port:
number: 80
path: /
pathType: ImplementationSpecific如果 apiVersion 是
networking.k8s.io/v1beta1
,则对应的配置如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: nginx-ingress
namespace: study-ingress
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: nginx.test.com
http:
paths:
- backend:
serviceName: nginx
servicePort: 80
path: /
pathType: ImplementationSpecific这里的内容采用的均是
networking.k8s.io/v1
版本创建 Ingress 资源,如果 Kubernetes 版本低于 1.19,可以用使用networking.k8s.io/v1beta1
替代,配置可以参上上面的networking.k8s.io/v1beta1
,两种配置的差异只有 backend 的配置不一样。创建该 Ingress
1
2# kubectl create -f web-ingress.yaml
ingress.networking.k8s.io/nginx-ingress created由于是测试环境,所以需要先修改主机 hosts 文件,将 Ingress Controller 所安装节点的 IP 配置解析。然后浏览器测试访问 nginx.test.com,如下
Ingress Nginx 域名重定向(Redirect)
在 Nginx 作为代理服务器时,Redirect 可用于域名的重定向,比如访问 old.com 被重定向到 new.com。Ingress 可以更简单的实现 Redirect 功能,接下来使用 nginx.redirect.com 作为旧域名,www.59izt.com 作为新域名进行演示:
创建 web-redirect.yaml 文件,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-redirect
namespace: study-ingress
annotations:
nginx.ingress.kubernetes.io/permanent-redirect: https://www.59izt.com # 这里填写新域名
spec:
ingressClassName: nginx
rules:
- host: nginx.redirect.com # 这里填写旧域名
http:
paths:
- backend:
service:
name: nginx
port:
number: 80
path: /
pathType: ImplementationSpecific创建该资源
1
2# kubectl create -f web-redirect.yaml
ingress.networking.k8s.io/nginx-redirect created使用浏览器访问域名 nginx.redirect.com,同时打开开发者工具,可以看到 301 状态码:
或者使用 curl 命令查看
1
2
3
4
5
6
7
8# curl -H "Host:nginx.redirect.com" 192.168.55.114
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
Ingress Nginx 前后端分离(Rewrite)
首先创建一个应用,模拟后端服务
1
2# kubectl create deployment backend-api --image=registry.cn-beijing.aliyuncs.com/dotbalo/nginx:backend-api -n study-ingress
deployment.apps/backend-api created创建 Service 暴露应用
1
2# kubectl expose deployment backend-api --port 80 -n study-ingress
service/backend-api exposed查看该 Service 的地址,并通过 /api-a 访问测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22# kubectl get svc -n study-ingress
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
backend-api ClusterIP 10.104.229.110 <none> 80/TCP 64s
nginx ClusterIP 10.108.14.135 <none> 80/TCP 71m
# curl 10.104.229.110/api-a # 访问 /api-a 接口显示 404
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.15.12</center>
</body>
</html>
# 直接访问后端根路径是可以的
# curl 10.104.229.110
<h1> backend for ingress rewrite </h1>
<h2> Path: /api-a </h2>
<a href="http://gaoxin.kubeasy.com"> Kubeasy </a>通过 Ingress Nginx 的 Rewrite 功能,将 /api-a 重写为 “/“,如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-rewrite
namespace: study-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: nginx.test.com
http:
paths:
- backend:
service:
name: backend-api
port:
number: 80
path: /api-a(/|$)(.*)
pathType: ImplementationSpecific创建该资源
1
2# kubectl create -f web-rewrite.yaml
ingress.networking.k8s.io/nginx-rewrite created再次访问 nginx.test.com/api-a 既可访问到后端服务
Ingress Nginx 错误代码重定向
通过 Helm 修改默认后端镜像地址,以及更新 ConfigMap 配置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36## nginx configuration
## Ref: https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/index.md
##
## Overrides for generated resource names
# See templates/_helpers.tpl
# nameOverride:
# fullnameOverride:
# 更新 configMap
controller:
name: controller
image:
... 省略 N 行 ...
# Will add custom configuration options to Nginx https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
config: # 默认值为 config: {}
apiVersion: v1
client_max_body_size: 20m
custom-http-errors: "404,415,503"
# 修改 默认 后端镜像地址
## Default 404 backend
##
defaultBackend:
##
enabled: true # 默认为 false,需要修改为 true
name: defaultbackend
image:
registry: registry.cn-beijing.aliyuncs.com # 修改仓库地址以及镜像地址
image: dotbalo/defaultbackend-amd64
# for backwards compatibility consider setting the full image url via the repository value below
# use *either* current default registry/image or repository format or installing chart by providing the values.yaml will fail
# repository:
tag: "1.5" # 注意镜像版本号
...使用以下命令更新 Release
1
# helm upgrade ingress-nginx -n ingress-nginx .
更新后 Pod 会自动重启,并且会创建一个 defaultbackend
1
2
3
4# kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-tmvcv 1/1 Running 0 27s
ingress-nginx-defaultbackend-754c754f77-kvznw 1/1 Running 0 50s更新完成以后访问一个不存在的页面时,比如之前定义的 nginx.test.com。访问一个不存在的页面 123,就会跳转到 Error Server 中的页面
Ingress Nginx 配置 SSL 证书
生产对外的服务一般需要配置 https 协议,使用 Ingress 也可以非常方便的添加 https 的证书。
由于这里是学习环境,并没有申请权威的证书,所以使用 OpenSSL 生成一个测试证书。如果是生产环境,证书应该在权威的第三方公司购买,无需自行生成。
使用 OpenSSL 生成证书
1
2
3
4
5
6# openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginx.test.com"
Generating a 2048 bit RSA private key
........................+++
..................+++
writing new private key to 'tls.key'
-----使用以下命令创建 Secret,加载证书
1
2# kubectl create secret tls ca-secret --cert=tls.crt --key=tls.key -n study-ingress
secret/ca-secret created修改 web-ingress.yaml 文件,配置 Ingress 添加 TLS 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
namespace: study-ingress
spec:
ingressClassName: nginx
rules:
- host: nginx.test.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: nginx
port:
number: 80
tls:
- hosts: # 证书所授权的域名列表
- nginx.test.com
secretName: ca-secret # 证书的 Secret 名字可以看到 Ingress 添加 TLS 配置也非常简单,只需要再 spec 下添加一个 tls 字段既可.
更新该资源
1
2# kubectl apply -f web-ingress.yaml
ingress.networking.k8s.io/nginx-ingress configured现在使用 curl 进行测试,域名已经被重定向到了 https
1
2
3
4
5
6
7# curl -H "Host:nginx.test.com" 192.168.55.114 -I
HTTP/1.1 308 Permanent Redirect
Date: Mon, 18 Oct 2021 03:09:16 GMT
Content-Type: text/html
Content-Length: 164
Connection: keep-alive
Location: https://nginx.test.com使用浏览器访问,会自动跳转到 https,如下
Ingress Nginx 匹配请求头
首先部署移动端应用
1
2
3
4
5# kubectl create deployment phone --image=registry.cn-beijing.aliyuncs.com/dotbalo/nginx:phone -n study-ingress
deployment.apps/phone created
# kubectl expose deployment phone --port 80 -n study-ingress # 暴露服务
service/phone exposed创建 Ingress 实例,Ingress 实例也可以使用 kubectl 创建,只需要一条命令即可,如下
1
2# kubectl create ingress phone --class=nginx --rule=m.test.com/*=phone:80 -n study-ingress
ingress.networking.k8s.io/phone created部署电脑端应用
1
2
3
4
5# kubectl create deployment laptop --image=registry.cn-beijing.aliyuncs.com/dotbalo/nginx:laptop -n study-ingress
deployment.apps/laptop created
# kubectl expose deployment laptop --port 80 -n study-ingress
service/laptop exposed查看服务部署状态
1
2
3
4# kubectl get pods -n study-ingress -l 'app in (phone,laptop)'
NAME READY STATUS RESTARTS AGE
laptop-664b565969-8shdv 1/1 Running 0 3m55s
phone-567dbf74b5-hgghn 1/1 Running 0 7m42s创建电脑端的 Ingress,注意 Ingress annotations 的 nginx.ingress.kubernetes.io/server-snippet 配置。Snippet 配置是专门用于一些复杂的 Nginx 配置的,和 Nginx 配置通用。匹配移动端实例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-laptop
namespace: study-ingress
annotations:
nginx.ingress.kubernetes.io/server-snippet: |
set $agentflag 0;
if ($http_user_agent ~* "(Android|iPhone|Windows Phone|UC|Kindle)" ){
set $agentflag 1;
}
if ( $agentflag = 1 ) {
return 301 http://m.test.com;
}
spec:
ingressClassName: nginx
rules:
- host: test.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: laptop
port:
number: 80创建该 Ingress 资源
1
2# kubectl create -f web-laptop.yaml
ingress.networking.k8s.io/nginx-laptop created首先通过浏览器访问 test.com,可以看到页面是 Laptop
接下来打开浏览器开发者工具,将终端类型改为 iPhone,或者直接使用 iPhone 收集访问(线上业务一般配置的都有 DNS,可以直接解析域名,测试环境可能需要自己单独配置),如下图所示:
刷新页面,浏览器会自动跳转到 m.test.com,如下
Ingress Nginx 基本认证
有些网站可能需要通过密码来访问,对于这类网站可以使用 Nginx 的 basic-auth 设置密码访问,具体方法如下
由于需要使用 htpasswd 工具,所以需要安装 httpd-tools:
1
yum install -y httpd-tools
使用 htpasswd 创建 foo 用户的密码
1
2
3
4# htpasswd -c auth foo
New password:
Re-type new password:
Adding password for user foo以上命令会在当前目录下生成一个 auth 文件,内容如下
1
2# cat auth
foo:$apr1$HfhgS.D2$GFDUa0iyVZ.cFzfYRn8Gi/基于之前创建的密码文件创建 Secret
1
2# kubectl create secret generic basic-auth --from-file=auth -n study-ingress
secret/basic-auth created创建包含密码认证的 Ingress(web-with-auth.yaml)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/auth-realm: Please Input Your Username and Password.
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-type: basic
name: ingress-with-auth
namespace: study-ingress
spec:
ingressClassName: nginx # for k8s >= 1.22+
rules:
- host: auth.test.com
http:
paths:
- backend:
service:
name: nginx
port:
number: 80
path: /
pathType: ImplementationSpecific- nginx.ingress.kubernetes.io/auth-realm: 需要认证的消息提醒内容
- nginx.ingress.kubernetes.io/auth-secret: 密码文件的 Secret 名称
- nginx.ingress.kubernetes.io/auth-type: 认证类型,可以是 basic 或者 digest
创建该资源
1
2# kubectl create -f web-with-auth.yaml
ingress.networking.k8s.io/ingress-with-auth created浏览器访问测试,输入用户名和密码,既可访问到正常的页面
Ingress Nginx 黑白名单
配置黑名单
配置黑名单禁止某一个或者某一段 IP,需要在 Ingress Nginx 的 ConfigMap 中配置,比如将 192.168.55.112(多个配置用逗号分隔)添加至黑名单.
1
2
3
4
5
6# Will add custom configuration options to Nginx https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
config:
apiVersion: v1
client_max_body_size: 20m
custom-http-errors: "404,415,503"
block-cidrs: 192.168.55.112 # 多个配置使用逗号分隔滚动更新 Ingress Nginx
1
# helm upgrade ingress-nginx -n ingress-nginx .
使用
192.168.55.112
主机测试访问m.test.com
,发现该 IP 已经被禁止访问1
2
3
4
5
6$ curl -H "Host:m.test.com" 192.168.55.114 -I
HTTP/1.1 403 Forbidden
Date: Mon, 18 Oct 2021 05:38:58 GMT
Content-Type: text/html
Content-Length: 146
Connection: keep-alive测试使用其他主机测试访问 m.test.com,状态码为正常的 200,说明黑名单配置已经生效了。
1
2
3
4
5
6
7
8
9# curl -H "Host:m.test.com" 192.168.55.114 -I
HTTP/1.1 200 OK
Date: Mon, 18 Oct 2021 05:39:34 GMT
Content-Type: text/html
Content-Length: 62
Connection: keep-alive
Last-Modified: Thu, 12 Aug 2021 08:23:47 GMT
ETag: "6114da93-3e"
Accept-Ranges: bytes
配置白名单
白名单表示只允许某个 IP 可以访问,白名单可以直接在 ingress 的资源清单文件中配置既可(也可以通过 ConfigMap 配置),只需要添加一个 nginx.ingress.kubernetes.io/whitelist-source-range
注释既可。
修改 web-with-auth.yaml 文件,将 IP
192.168.55.113
添加到白名单,如下所示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/auth-realm: Please Input Your Username and Password
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/whitelist-source-range: 192.168.55.113
name: ingress-with-auth
namespace: study-ingress
spec:
ingressClassName: "nginx"
rules:
- host: auth.test.com
http:
paths:
- backend:
service:
name: nginx
port:
number: 80
path: /
pathType: ImplementationSpecific应用更新该 Ingress 实例
1
2# kubectl replace -f web-with-auth.yaml
ingress.networking.k8s.io/ingress-with-auth replaced此时只有 192.168.55.113 是可以访问 auth.test.com,其他 IP 地址是被禁止访问
1
2
3
4
5
6
7# curl -H "Host:auth.test.com" 192.168.55.114 -I
HTTP/1.1 401 Unauthorized
Date: Mon, 18 Oct 2021 05:54:08 GMT
Content-Type: text/html
Content-Length: 172
Connection: keep-alive
WWW-Authenticate: Basic realm="Please Input Your Username and Password."其他主机访问 auth.test.com 显示拒绝访问,如下
1
2
3
4
5
6# curl -H "Host:auth.test.com" 192.168.55.114 -I
HTTP/1.1 403 Forbidden
Date: Mon, 18 Oct 2021 05:53:46 GMT
Content-Type: text/html
Content-Length: 146
Connection: keep-alive
Ingress Nginx 速率限制
有时候可能需要限制速率以降低后端压力,或者限制单个 IP 每秒的访问速率以防止攻击。此时可以使用 Nginx 的 rate limit 进行配置。
首先没有加速率限制时,使用 ab 进行访问,Failed 为 0
1
2
3
4
5# ab -c 10 -n 100 http://auth.test.com/ |grep requests
Complete requests: 100
Failed requests: 0
Time per request: 1.466 [ms] (mean, across all concurrent requests)
Percentage of the requests served within a certain time (ms)添加速率限制,限制只能由一个连接,只需要添加 nginx.ingress.kubernetes.io/limit-connections 为 1 即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/auth-realm: Please Input Your Username and Password.
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-type: basic
# nginx.ingress.kubernetes.io/whitelist-source-range: 192.168.55.113
nginx.ingress.kubernetes.io/limit-connections: "1"
name: ingress-with-auth
namespace: study-ingress
spec:
ingressClassName: nginx # for k8s >= 1.22+
rules:
- host: auth.test.com
http:
paths:
- backend:
service:
name: nginx
port:
number: 80
path: /
pathType: ImplementationSpecific更新该资源,再次使用 ab 测试,Failed 为 21.
1
2
3
4
5# ab -c 10 -n 100 http://auth.test.com/ |grep requests
Complete requests: 100
Failed requests: 21
Time per request: 1.679 [ms] (mean, across all concurrent requests)
Percentage of the requests served within a certain time (ms)还有很多其他方面的限制,常用的有:
1
2
3
4
5
6
7
8
9
10
11# 限制每秒的连接,单个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官方说明地址 : Rate Limiting
Ingress Nginx 灰度/金丝雀发布
首先创建模拟生产环境的 Namespace 和服务(这里为了方便区分,创建了2个 namespace,其实生产环境可以不用创建)
1
2
3
4
5
6
7
8
9
10
11# kubectl create ns production
namespace/production created
# kubectl create deployment canary-v1 --image=registry.cn-beijing.aliyuncs.com/dotbalo/canary:v1 -n production
deployment.apps/canary-v1 created
# kubectl expose deployment canary-v1 --port 8080 -n production
service/canary-v1 exposed
# kubectl create ingress canary-v1 --class=nginx --rule=canary.com/*=canary-v1:8080 -n production
ingress.networking.k8s.io/canary-v1 created使用浏览器访问该服务,可以看到 Canary v1 的页面
接下来创建 v2 版本,充当灰度环境
1
2
3
4
5
6
7
8# kubectl create ns canary
namespace/canary created
# kubectl create deployment canary-v2 --image=registry.cn-beijing.aliyuncs.com/dotbalo/canary:v2 -n production
deployment.apps/canary-v2 created
# kubectl expose deployment canary-v2 --port 8080 -n production
service/canary-v2 exposed待程序启动完成后,通过 Service 访问该服务,会返回 Canary v2:
1
2# curl 10.103.78.201:8080
<h1>Canary v2</h1>接下来,通过 Ingress 控制流量,创建 v2 版本的 Ingress 时,需要添加两个 Annotations,分别是:
nginx.ingress.kubernetes.io/canary
,表明是灰度环境,nginx.ingress.kubernetes.io/canary-weight
, 表明切换多少流量到该环境.
创建 canary-v2.yaml,此时
nginx.ingress.kubernetes.io/canary-weight
的值设置为 10,即 v1:v1 为 9:11
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
name: canary-v2
namespace: production
spec:
ingressClassName: nginx # for k8s >= 1.22+
rules:
- host: canary.com
http:
paths:
- backend:
service:
name: canary-v2
port:
number: 8080
path: /
pathType: ImplementationSpecific- 创建该资源
1
2# kubectl create -f canary-v2.yaml
ingress.networking.k8s.io/canary-v2 created测试灰度发布,接下来使用脚本进行测试,脚本会输出 v1 和 v2 的访问次数比值。脚本内容如下
1
2
3
4
5
6
7
8
9vim test-canary.rb
counts = Hash.new(0)
100.times do
output = `curl -s canary.com | grep 'Canary' | awk '{print $2}' | awk -F "<" '{print $1}'`
counts[output.strip.split.last] += 1
end
puts counts由于是 ruby 脚本,所以需要先安装 ruby
1
yum install -y ruby
使用脚本进行测试
1
2# ruby test-canary.rb
{"v1"=>90, "v2"=>10}