2017-07-31 11:31:13 +08:00
|
|
|
|
# 服务发现与负载均衡
|
2017-05-20 21:03:25 +08:00
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
Kubernetes 在设计之初就充分考虑了针对容器的服务发现与负载均衡机制,提供了 Service 资源,并通过 kube-proxy 配合 cloud provider 来适应不同的应用场景。随着 kubernetes 用户的激增,用户场景的不断丰富,又产生了一些新的负载均衡机制。目前,kubernetes 中的负载均衡大致可以分为以下几种机制,每种机制都有其特定的应用场景:
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
- Service:直接用 Service 提供 cluster 内部的负载均衡,并借助 cloud provider 提供的 LB 提供外部访问
|
|
|
|
|
- Ingress Controller:还是用 Service 提供 cluster 内部的负载均衡,但是通过自定义 LB 提供外部访问
|
|
|
|
|
- Service Load Balancer:把 load balancer 直接跑在容器中,实现 Bare Metal 的 Service Load Balancer
|
|
|
|
|
- Custom Load Balancer:自定义负载均衡,并替代 kube-proxy,一般在物理部署 Kubernetes 时使用,方便接入公司已有的外部服务
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
|
|
|
|
## Service
|
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
Service 是对一组提供相同功能的 Pods 的抽象,并为它们提供一个统一的入口。借助 Service,应用可以方便的实现服务发现与负载均衡,并实现应用的零宕机升级。Service 通过标签来选取服务后端,一般配合 Replication Controller 或者 Deployment 来保证后端容器的正常运行。
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
Service 有三种类型:
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
- ClusterIP:默认类型,自动分配一个仅 cluster 内部可以访问的虚拟 IP
|
|
|
|
|
- NodePort:在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过`<NodeIP>:NodePort` 来访问该服务
|
|
|
|
|
- LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部的负载均衡器,并将请求转发到`<NodeIP>:NodePort`
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
另外,也可以将已有的服务以 Service 的形式加入到 Kubernetes 集群中来,只需要在创建 Service 的时候不指定 Label selector,而是在 Service 创建好后手动为其添加 endpoint。
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
|
|
|
|
## Ingress Controller
|
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
Service 虽然解决了服务发现和负载均衡的问题,但它在使用上还是有一些限制,比如
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
- 对外访问的时候,NodePort 类型需要在外部搭建额外的负载均衡,而 LoadBalancer 要求 kubernetes 必须跑在支持的 cloud provider 上面
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
Ingress 就是为了解决这些限制而引入的新资源,主要用来将服务暴露到 cluster 外面,并且可以自定义服务的访问策略。比如想要通过负载均衡器实现不同子域名到不同服务的访问:
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
foo.bar.com --| |-> foo.bar.com s1:80
|
|
|
|
|
| 178.91.123.132 |
|
|
|
|
|
bar.foo.com --| |-> bar.foo.com s2:80
|
|
|
|
|
```
|
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
可以这样来定义 Ingress:
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
apiVersion: extensions/v1beta1
|
|
|
|
|
kind: Ingress
|
|
|
|
|
metadata:
|
|
|
|
|
name: test
|
|
|
|
|
spec:
|
|
|
|
|
rules:
|
|
|
|
|
- host: foo.bar.com
|
|
|
|
|
http:
|
|
|
|
|
paths:
|
|
|
|
|
- backend:
|
|
|
|
|
serviceName: s1
|
|
|
|
|
servicePort: 80
|
|
|
|
|
- host: bar.foo.com
|
|
|
|
|
http:
|
|
|
|
|
paths:
|
|
|
|
|
- backend:
|
|
|
|
|
serviceName: s2
|
|
|
|
|
servicePort: 80
|
|
|
|
|
```
|
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
**注意:** Ingress 本身并不会自动创建负载均衡器,cluster 中需要运行一个 ingress controller 来根据 Ingress 的定义来管理负载均衡器。目前社区提供了 nginx 和 gce 的参考实现。
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
|
|
|
|
## Service Load Balancer
|
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
在 Ingress 出现以前,Service Load Balancer 是推荐的解决 Service 局限性的方式。Service Load Balancer 将 haproxy 跑在容器中,并监控 service 和 endpoint 的变化,通过容器 IP 对外提供 4 层和 7 层负载均衡服务。
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
社区提供的 Service Load Balancer 支持四种负载均衡协议:TCP、HTTP、HTTPS 和 SSL TERMINATION,并支持 ACL 访问控制。
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
|
|
|
|
## Custom Load Balancer
|
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
虽然 Kubernetes 提供了丰富的负载均衡机制,但在实际使用的时候,还是会碰到一些复杂的场景是它不能支持的,比如:
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
|
|
|
|
- 接入已有的负载均衡设备
|
2021-12-25 21:42:34 +08:00
|
|
|
|
- 多租户网络情况下,容器网络和主机网络是隔离的,这样 `kube-proxy` 就不能正常工作
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
这个时候就可以自定义组件,并代替 kube-proxy 来做负载均衡。基本的思路是监控 kubernetes 中 service 和 endpoints 的变化,并根据这些变化来配置负载均衡器。比如 weave flux、nginx plus、kube2haproxy 等。
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
|
|
|
|
## Endpoints
|
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
有几种情况下需要用到没有 selector 的 service。
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
- 使用 kubernetes 集群外部的数据库时
|
|
|
|
|
- service 中用到了其他 namespace 或 kubernetes 集群中的 service
|
|
|
|
|
- 在 kubernetes 的工作负载与集群外的后端之间互相迁移
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
可以这样定义一个没有 selector 的 service。
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
kind: Service
|
|
|
|
|
apiVersion: v1
|
|
|
|
|
metadata:
|
|
|
|
|
name: my-service
|
|
|
|
|
spec:
|
|
|
|
|
ports:
|
|
|
|
|
- protocol: TCP
|
|
|
|
|
port: 80
|
|
|
|
|
targetPort: 9376
|
|
|
|
|
```
|
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
定义一个 Endpoints 来对应该 service。
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
kind: Endpoints
|
|
|
|
|
apiVersion: v1
|
|
|
|
|
metadata:
|
|
|
|
|
name: my-service
|
|
|
|
|
subsets:
|
|
|
|
|
- addresses:
|
|
|
|
|
- ip: 1.2.3.4
|
|
|
|
|
ports:
|
|
|
|
|
- port: 9376
|
|
|
|
|
```
|
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
访问没有 selector 的 service 跟访问有 selector 的 service 时没有任何区别。
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
使用 kubernetes 时有一个很常见的需求,就是当数据库部署在 kubernetes 集群之外的时候,集群内的 service 如何访问数据库呢?当然你可以直接使用数据库的 IP 地址和端口号来直接访问,有没有什么优雅的方式呢?你需要用到 `ExternalName Service`。
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
kind: Service
|
|
|
|
|
apiVersion: v1
|
|
|
|
|
metadata:
|
|
|
|
|
name: my-service
|
|
|
|
|
namespace: prod
|
|
|
|
|
spec:
|
|
|
|
|
type: ExternalName
|
|
|
|
|
externalName: my.database.example.com
|
|
|
|
|
ports:
|
|
|
|
|
- port: 12345
|
|
|
|
|
```
|
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
这个例子中,在 kubernetes 集群内访问 `my-service` 实际上会重定向到 `my.database.example.com:12345` 这个地址。
|
2017-07-31 11:31:13 +08:00
|
|
|
|
|
|
|
|
|
## 参考资料
|
|
|
|
|
|
2021-12-25 21:42:34 +08:00
|
|
|
|
- [Service - kubernetes.io](https://kubernetes.io/docs/concepts/services-networking/service/)
|
|
|
|
|
- [Ingress - kubernetes.io](http://kubernetes.io/docs/user-guide/ingress/)
|
|
|
|
|
- [service Loadbalancer - github.com](https://github.com/kubernetes/contrib/tree/master/service-loadbalancer)
|
|
|
|
|
- [Load Balancing Kubernetes Services with NGINX Plus - nginx.com](https://www.nginx.com/blog/load-balancing-kubernetes-services-nginx-plus/)
|
|
|
|
|
- [Flux - github.com](https://github.com/weaveworks/flux)
|
|
|
|
|
- [kube2haproxy - github.com](https://github.com/adohe-zz/kube2haproxy)
|