kubernetes-handbook/practice/service-discovery-and-loadb...

139 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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