背景
有时候需要多域名指向同一个 ingress 路由规则,比如 a.com a.cn 指向同一个 server
问题
通过查阅nginx-ingress
的官方文档,可以知道有一个annotations 叫 server alias
https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#server-alias 可以帮助我们完成上述需求,
eg如下:
代码语言:javascript复制apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: aaa-ingress
annotations:
nginx.ingress.kubernetes.io/server-alias: "a.cn"
labels:
name: aaa
spec:
rules:
- host: a.com
http:
paths:
- path: /
backend:
serviceName: aaa
servicePort: 80
这里有个问题,我们知道 在一个域名时,我们配证书一般是这样配置的
根据密钥生成证书secret
代码语言:javascript复制kubectl create secret tls a-com-https --key a-com.key --cert a-com.crt
代码语言:javascript复制apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: aaa-ingress
annotations:
nginx.ingress.kubernetes.io/server-alias: "a.cn"
labels:
name: aaa
spec:
rules:
- host: a.com
http:
paths:
- path: /
backend:
serviceName: aaa
servicePort: 80
tls:
- hosts:
- a.com
secretName: a-com-https
很简单的就配置好了
自然而然,在多域名时候仿照上述配置就有了如下配置
代码语言:javascript复制kubectl create secret tls a-cn-https --key a-cn.key --cert a-cn.crt
代码语言:javascript复制apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: aaa-ingress
annotations:
nginx.ingress.kubernetes.io/server-alias: "a.cn"
labels:
name: aaa
spec:
rules:
- host: a.com
http:
paths:
- path: /
backend:
serviceName: aaa
servicePort: 80
tls:
- hosts:
- a.com
secretName: a-com-https
- hosts:
- a.cn
secretName: a-cn-https
然后我们分别访问一下 a.com
和 a.cn
此时 a.com 可以正常访问,但是 a.cn 会提示证书错误
这是为什么呢?
我们可以进入到 nginx-ingress-controller 的容器内看下生成的 nginx.conf,看看他到底帮我们做了些什么?
这是生成后的nginx.conf
我们可以看到,实际上,nginx-ingress-controller 把设置的 alias 全部配置到了 server_name 中,此时证书加载的其实是 a.com (tls 下的第一个证书),自然而且第二个域名访问时出现证书错误也是合理的。
解决
知道了问题所在,那可以怎么解决一下呢?
不用 server alias 就好了,每一个域名转发规则单独配置
。
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: aaa-ingress
labels:
name: aaa
spec:
rules:
- host: a.cn
http:
paths:
- path: /
backend:
serviceName: aaa
servicePort: 80
- host: a.com
http:
paths:
- path: /
backend:
serviceName: aaa
servicePort: 80
tls:
- hosts:
- a.com
secretName: a-com-https
- hosts:
- a.cn
secretName: a-cn-https
上述配置就可以完成,但是同样也带来了一个问题
就是每个规则都需要配置多遍
,但如果后期改动没有同时修改,就会导致出错。但目前没有找到合适的解决方案
结论
上述的解决方案还是有问题的,同时在生产环境上,一般也不是 ingress 的 lb 直接提供服务,一般外层还会有一层 cdn,我觉得将 tls 证书绑定在云厂商的 cdn 上比较合适,cdn 到 lb 直接使用 http 进行转发,同时还可以享受云厂商提供的证书的动态更新功能,自己在 ingress 管理证书在每年换证书时还需要手动更新一次。