前言
我们知道,k8s 有丰富的生态,例如可以自动签发证书的 cert-manager 等;同时,声明式的设计带来的易于实现 IaC 的特性。但是我们有很多应用并没有做 k8s 的适配,还是传统的部署方式。因此,就在想,能不能通过 k8s 来做一个大号的反向代理,使得集群成为统一的服务访问端点,让传统的服务也可以享受到 k8s 的各种便利。
本篇,我们聚焦于,如何让 k8s 代理外部的服务。
引入
我们知道,传统的 k8s 服务暴露主要是 Ingress、Service、Deployment 三个部分组成,大致可以用以下图来展示
graph LR
Web --> Ingress --> Service --> Deployment
图中的箭头代表请求的方向,其中 Ingress 由集群的 ingressclass 来实现,service 则是由集群内部实现,deployment 是我们部署的应用。
- Web 端是网络流量入口,我们要用集群作为流量的统一入口,自然必须设置为集群的地址
- Ingress 是集群的反代具体实现,可以选择不同的实现
- Service 是集群内部组件,用来给具体的服务提供一个统一的入口
- Deployment 是我们在集群上面部署的具体应用
下面来一个个分析,我们应该在上述流程的哪一步进行修改,来达到代理外部服务的目的
Ingress
参阅 官方文档,似乎没有发现可以配置外部地址的地方。
Service
参阅 官方文档,Service 比 ingress 复杂的多。
看到有个 ExternalName 类型,似乎是可以使用外部的地址的。
于是乎,就尝试创建 ExternalName 类型的 Service,然后再用 ingress 引用这个 service。
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
|
apiVersion: v1
kind: Service
metadata:
name: external-service
namespace: default
spec:
externalName: suyiiyii.top
sessionAffinity: None
type: ExternalName
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
name: test-ingress
namespace: default
spec:
ingressClassName: traefik
rules:
- host: test.k.suyiiyii.top
http:
paths:
- backend:
service:
name: external-service
port:
number: 80
path: /
pathType: Prefix
|
但是很遗憾,我的 ingressclass traefik 报错了
Cannot create service: externalName services not allowed: default/external-service" providerName=kubernetes serviceName=external-service servicePort="&ServiceBackendPort{Name:,Number:80,}" ingress=test-ingress namespace=default
似乎是 traefik 不支持 externalName 类型的 service,所以只能作罢。
Deployment
大不了我自己写一个应用,就只做代理的事情。配置一个地址,运行起来就把所有到应用的请求转发到配置的地址。
但是,先不说自己写一个有多麻烦,运行之前要配置代理的地址,运行时还会占用额外的资源。
所以只能作为下下策。
Service + Endpoints
最后还得在 Service 上寻找解决方法。
Service 在实现上,是通过 Endpoints,找到对应的后端服务的,例如
flowchart LR
Service --> Endpoints
Endpoints --> Deployment
其中,endpoints 是集群会自动配置的,所以我们平时使用的时候不需要关心。
不过,我们也可以手动配置 endpoint,来指向我们自己的外部服务。
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
|
apiVersion: v1
kind: Endpoints
metadata:
name: minio # 端点名称,可以根据需要修改
subsets:
- addresses:
- ip: 10.21.22.24 # 外部服务的 IP 地址
ports:
- port: 9002 # 外部服务的端口
protocol: TCP # 协议类型
name: console
- port: 9000 # 外部服务的端口
protocol: TCP # 协议类型
name: api
---
apiVersion: v1
kind: Service
metadata:
name: minio
spec:
ports:
- port: 9002
protocol: TCP
name: console
targetPort: 9002
- port: 9000
protocol: TCP
name: api
targetPort: 9000
type: ClusterIP
|
这样子,当访问 minio Service 时,就会自动反代到外部的服务啦。
最后,再和以前一样,搭配上 ingress,就实现了自动管理的 https 了
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
37
38
39
40
41
|
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minio-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- secretName: minio-tls
rules:
- host: minio.kl.suyiiyii.top
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: minio
port:
name: api
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minio-console-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- secretName: minio-console-tls
rules:
- host: minio-console.kl.suyiiyii.top
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: minio
port:
name: console
|
总结
这下子就把集群当做成了一个大号的反代了,并且可以使用集群的工作流,manifest 都上传到仓库,然后用 argo 自动更新,又把一个组件 IaC 了。🥰🥰🥰