背景:
由于域名和公网费用昂贵。通常是只有一个域名,但是有多个应用需要上线。通常都会域名+应用名称(www.ecloud.com/app
)。原本应用已经开发好的了,访问是在 /
。那就需要改写上下文来实现。
原应用演示
$ kubectl get svc app demo
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
app ClusterIP 10.183.0.36 <none> 8001/TCP 6m13s
demo ClusterIP 10.183.0.37 <none> 8002/TCP 2m47s
$ curl 10.183.0.36:8001
app
$ curl 10.183.0.37:8002/test/demo/
demo
现在有两个应用分别是
app
、demo
。分别的访问路径为:/
、/test/demo
。现在只有一个域名是www.ecloud.com
且需要把两个网页都放在同一个域名访问。
添加上下文路径
现在的目标是把 app
应用,可以通过 www.ecloud.com/app/
来展示
创建ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: app
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2 # 真实到服务的上下文
spec:
ingressClassName: nginx
rules:
- host: www.ecloud.com
http:
paths:
- path: /app(/|)(.*) # 浏览器访问上下文
backend:
serviceName: app
servicePort: 8001
验证
$ curl www.ecloud.com/app/
app
$ curl www.ecloud.com/app/index.html
app
减少上下文路径
现在的目标是把 demo
应用,可以通过 www.ecloud.com/demo/
来展示
创建ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: demo
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /test/demo/$2 # 真实到服务的上下文
spec:
ingressClassName: nginx
rules:
- host: www.ecloud.com
http:
paths:
- path: /demo(/|)(.*) # 浏览器访问上下文
backend:
serviceName: demo
servicePort: 8002
验证
$ curl www.ecloud.com/demo
demo
$ curl www.ecloud.com/demo/
demo
$ curl www.ecloud.com/demo/index.html
demo
修改主域名跳转
应该给应用设置一个 app-root
的注解,这样当我们访问主域名的时候会自动跳转到我们指定的 app-root
目录下面。如下所示:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: demo
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /test/demo/$2 # 真实到服务的上下文
nginx.ingress.kubernetes.io/app-root: /demo/ # 这里写浏览器访问的路径
spec:
ingressClassName: nginx
rules:
- host: www.ecloud.com
http:
paths:
- path: /demo(/|)(.*) # 浏览器访问上下文
backend:
serviceName: demo
servicePort: 8002
验证
$ curl www.ecloud.com
<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
# nginx-ingress-controller 的日志
192.168.32.134 - - [16/Sep/2021:08:22:39 +0000] "GET / HTTP/1.1" 302 138 "-" "curl/7.29.0" 78 0.000 [-] [] - - - - 5ba35f028edbd48ff316bd544ae60746
$ curl www.ecloud.com -L
demo
# nginx-ingress-controller 的日志
192.168.32.134 - - [16/Sep/2021:08:22:56 +0000] "GET / HTTP/1.1" 302 138 "-" "curl/7.29.0" 78 0.000 [-] [] - - - - 4ffa0129b9fab80b9e904ad9716bd8ca
192.168.32.134 - - [16/Sep/2021:08:22:56 +0000] "GET /demo/ HTTP/1.1" 200 5 "-" "curl/7.29.0" 83 0.003 [default-demo-8002] [] 20.0.32.159:8002 5 0.002 200 3d17d7cb25f3eacc7eb848955a28675f
注意事项
不能定义默认的
ingress.spec.backend
字段。否则会发生不符合预期的跳转。
模拟定义 ingress.spec.backend
字段
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: app
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
backend: # 设置默认的backend
serviceName: app
servicePort: 8001
rules:
- host: www.ecloud.com
http:
paths:
- path: /app(/|$)(.*)
backend:
serviceName: app
servicePort: 8001
查看ingress资源情况
$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
app nginx www.ecloud.com 192.168.32.138 80 20m
$ kubectl describe ingress app
Name: app
Namespace: default
Address: 192.168.32.138
Default backend: app:8001 (20.0.32.157:8001)
Rules:
Host Path Backends
---- ---- --------
www.ecloud.com
/app(/|$)(.*) app:8001 (20.0.32.157:8001)
Annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 7m52s (x5 over 21m) nginx-ingress-controller Scheduled for sync
测试访问
$ curl www.ecloud.com
app
$ curl www.ecloud.com/fskl/fskf/ajfk
app
发现不符合
/app
的上下文也可以匹配到/
的页面,这个是不符合我们的预期的。
查看nginx的配置文件
$ kubectl -n ingress-nginx exec -it ingress-nginx-controller-6c979c5b47-bpwf6 -- bash
$ vi /etc/nginx/nginx.conf
# 找到 `server_name` 为设置的域名,找到为 `location ~* "^/"`
# 没有匹配到 `/app` 的上下文,则进入该location。
# 该location读取app应用的 `/` 。所以访问 `/fskl/fskf/ajfk` 都可以访问到 `/` 的页面
# 原本我们的预期是访问错了上下文,应该是报 `404` 的,而不是访问主域名页面
location ~* "^/" {
set $namespace "default";
set $ingress_name "app";
set $service_name "app";
set $service_port "8001";
set $location_path "/"
...
}
虽然没有定义默认的 ingress.spec.backend
字段。在 kubectl describe ingress
查看ingress详情时,会有 Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
提示,但是影响正常使用。