<aside> ⏰ 本文我们将通过 golang 来实现一个简单的自定义的 Ingress 控制器。
</aside>
在 Kubernetes 中通过 Ingress 来暴露服务到集群外部,这个已经是一个很普遍的方式了,而真正扮演请求转发的角色是背后的 Ingress Controller,比如我们经常使用的 traefik、ingress-nginx 等就是一个 Ingress Controller。本文我们将通过 golang 来实现一个简单的自定义的 Ingress Controller,可以加深我们对 Ingress 的理解。
我们在 Kubernetes 集群上往往会运行很多无状态的 Web 应用,一般来说这些应用是通过一个 Deployment 和一个对应的 Service 组成,比如我们在集群上运行一个 whoami 的应用,对应的资源清单如下所示:
# whoami.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami
labels:
app: whoami
spec:
replicas: 1
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: cnych/whoami
ports:
- containerPort: 80
---
kind: Service
apiVersion: v1
metadata:
name: whoami
spec:
selector:
app: whoami
ports:
- protocol: TCP
port: 80
targetPort: 80
可以直接使用上面的资源清单部署该应用:
$ kubectl apply -f whoami.yaml
通过部署该应用,在 Kubernetes 集群内部我们可以通过地址 whoami.default.svc.cluster.local
来访问该 Web 应用,但是在集群外部的用户应该如何来访问呢?当然我们可以使用 NodePort 类型的 Service 来进行访问,但是当我们应用越来越多的时候端口的管理也是一个很大的问题,所以一般情况下不采用该方式,之前我们的方法是用 DaemonSet 在每个边缘节点上运行一个 Nginx 应用:
spec:
hostNetwork: true
containers:
- image: nginx:1.15.3-alpine
name: nginx
ports:
- name: http
containerPort: 80
hostPort: 80
通过设置 hostNetwork:true
,容器将绑定节点的80端口,而不仅仅是容器,这样我们就可以通过节点的公共 IP 地址的 80 端口访问到 Nginx 应用了。这种方法理论上肯定是有效的,但是有一个最大的问题就是需要创建一个 Nginx 配置文件,如果应用有变更,还需要手动修改配置,不能自动发现和热更新,这对于大量的应用维护的成本显然太大。这个时候我们就可以用另外一个 Kubernetes 提供的方案了:Ingress
。
Kubernetes 内置就支持通过 Ingress 对象将外部的域名映射到集群内部服务,我们可以通过如下的 Ingress 对象来对外暴露服务:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: whoami
spec:
tls:
- hosts:
- "*.qikqiak.com"
secretName: qikqiak-tls
rules:
- host: who.qikqiak.com
http:
paths:
- path: /
backend:
serviceName: whoami
servicePort: 80
该资源清单声明了如何将 HTTP 请求路由到后端服务:
who.qikqiak.com
的请求都将被路由到 whoami
服务后面的 Pod 列表中去。.qikqiak.com
,则对请求使用 qikqiak-tls
这个证书。这个配置显然比我们取手动维护 Nginx 的配置要方便太多了,完全就是自动化的。