This commit is contained in:
huanqing.shao
2019-09-19 23:38:00 +08:00
parent 462610661e
commit 7c2a1e8abd
2 changed files with 168 additions and 3 deletions

View File

@ -307,6 +307,73 @@ DNS 的配置方式取决于该 Service 是否配置了 selector
* 对 ExternalName 类型的 Service返回 CNAME 记录
* 对于其他类型的 Service返回与 Service 同名的 `Endpoints` 的 A 记录
## 虚拟 IP 的实现
如果只是想要正确使用 Service不急于理解 Service 的实现细节,您无需阅读本章节。
### 避免冲突
Kubernetes 的一个设计哲学是:尽量避免非人为错误产生的可能性。就设计 Service 而言Kubernetes 应该将您选择的端口号与其他人选择的端口号隔离开。为此Kubernetes 为每一个 Service 分配一个该 Service 专属的 IP 地址。
为了确保每个 Service 都有一个唯一的 IP 地址kubernetes 在创建 Service 之前,先更新 etcd 中的一个全局分配表,如果更新失败(例如 IP 地址已被其他 Service 占用),则 Service 不能成功创建。
Kubernetes 使用一个后台控制器检查该全局分配表中的 IP 地址的分配是否仍然有效,并且自动清理不再被 Service 使用的 IP 地址。
### Service 的 IP 地址
Pod 的 IP 地址路由到一个确定的目标,然而 Service 的 IP 地址则不同,通常背后并不对应一个唯一的目标。 kube-proxy 使用 iptables Linux 中的报文处理逻辑)来定义虚拟 IP 地址。当客户端连接到该虚拟 IP 地址时,它们的网络请求将自动发送到一个合适的 Endpoint。Service 对应的环境变量和 DNS 实际上反应的是 Service 的虚拟 IP 地址(和端口)。
#### Userspace
以上面提到的图像处理程序为例。当后端 Service 被创建时Kubernetes master 为其分配一个虚拟 IP 地址(假设是 10.0.0.1),并假设 Service 的端口是 1234。集群中所有的 kube-proxy 都实时监听者 Service 的创建和删除。Service 创建后kube-proxy 将打开一个新的随机端口,并设定 iptables 的转发规则(以便将该 Service 虚拟 IP 的网络请求全都转发到这个新的随机端口上),并且 kube-proxy 将开始接受该端口上的连接。
当一个客户端连接到该 Service 的虚拟 IP 地址时iptables 的规则被触发,并且将网络报文重定向到 kube-proxy 自己的随机端口上。kube-proxy 接收到请求后,选择一个后端 Pod再将请求以代理的形式转发到该后端 Pod。
这意味着 Service 可以选择任意端口号,而无需担心端口冲突。客户端可以直接连接到一个 IP:port无需关心最终在使用哪个 Pod 提供服务。
#### iptables
仍然以上面提到的图像处理程序为例。当后端 Service 被创建时Kubernetes master 为其分配一个虚拟 IP 地址(假设是 10.0.0.1),并假设 Service 的端口是 1234。集群中所有的 kube-proxy 都实时监听者 Service 的创建和删除。Service 创建后kube-proxy 设定了一系列的 iptables 规则(这些规则可将虚拟 IP 地址映射到 per-Service 的规则。per-Service 规则进一步链接到 per-Endpoint 规则,并最终将网络请求重定向(使用 destination-NAT到后端 Pod。
当一个客户端连接到该 Service 的虚拟 IP 地址时iptables 的规则被触发。一个后端 Pod 将被选中(基于 session affinity 或者随机选择),且网络报文被重定向到该后端 Pod。与 userspace proxy 不同,网络报文不再被复制到 userspacekube-proxy 也无需处理这些报文,且报文被直接转发到后端 Pod。
在使用 node-port 或 load-balancer 类型的 Service 时,以上的代理处理过程是相同的。
#### IPVS <Badge text="Kuboard 已支持" type="success"/>
在一个大型集群中(例如,存在 10000 个 Serviceiptables 的操作将显著变慢。IPVS 的设计是基于 in-kernel hash table 执行负载均衡。因此,使用 IPVS 的 kube-proxy 在 Service 数量较多的情况下仍然能够保持好的性能。同时,基于 IPVS 的 kube-proxy 可以使用更复杂的负载均衡算法(最少连接数、基于地址的、基于权重的等)
## 支持的传输协议
未完待续【2019年9月18日 22:33】
#### TCP <Badge text="Kuboard 已支持" type="success"/>
默认值。任何类型的 Service 都支持 TCP 协议。
#### UDP
大多数 Service 都支持 UDP 协议。对于 LoadBalancer 类型的 Service是否支持 UDP 取决于云供应商是否支持该特性。
#### HTTP <Badge text="Kuboard 不支持" type="error"/>
如果您的云服务商支持,您可以使用 LoadBalancer 类型的 Service 设定一个 Kubernetes 外部的 HTTP/HTTPS 反向代理,将请求转发到 Service 的 Endpoints。
::: tip
使用 Ingress
:::
#### Proxy Protocol <Badge text="Kuboard 不支持" type="error"/>
如果您的云服务上支持(例如 AWS您可以使用 LoadBalancer 类型的 Service 设定一个 Kubernetes 外部的负载均衡器,并将连接已 PROXY 协议转发到 Service 的 Endpoints。
负载均衡器将先发送描述该 incoming 连接的字节串,如下所示:
```
PROXY TCP4 192.0.2.202 10.0.42.7 12345 7\r\n
```
然后在发送来自于客户端的数据
#### SCTP <Badge text="Kuboard 不支持" type="error"/>
尚处于 `alpha` 阶段,暂不推荐使用。如需了解,请参考 [SCTP](https://kubernetes.io/docs/concepts/services-networking/service/#sctp)

View File

@ -3,7 +3,11 @@ layout: LearningLayout
description: Kubernetes 中发布 Service 的方式ServiceType
---
# Service 类型
# 发布 Service
Kubernetes Service 支持的不同访问方式。
## Service 类型
Kubernetes 中可以通过不同方式发布 Service通过 `ServiceType` 字段指定,该字段的默认值是 `ClusterIP`,可选值有:
@ -31,10 +35,104 @@ Kubernetes 中可以通过不同方式发布 Service通过 `ServiceType` 字
## ClusterIP
未完待续【2019年9月18日 22:56】
ClusterIP 是 ServiceType 的默认值。在 [Iptables 代理模式](service-details.html#iptables-代理模式) 中,详细讲述了 ClusterIP 类型 Service 的工作原理。
## NodePort
对于 `NodePort` 类型的 ServiceKubernetes 为其分配一个节点端口(对于同一 Service在每个节点上的节点端口都相同该端口的范围在初始化 apiserver 时可通过参数 `--service-node-port-range` 指定默认是30000-32767。节点将该端口上的网络请求转发到对应的 Service 上。可通过 Service 的 `.spec.ports[*].nodePort` 字段查看该 Service 分配到的节点端口号。
在启动 kube-proxy 时使用参数 `--nodeport-address` 可指定阶段端口可以绑定的 IP 地址段。该参数接收以逗号分隔的 CIDR 作为参数值例如10.0.0.0/8,192.0.2.0/25kube-proxy 将查找本机符合该 CIDR 的 IP 地址,并将节点端口绑定到符合的 IP 地址上。
例如,
* 如果启动 kube-proxy 时指定了参数 `--nodeport-address=127.0.0.0/8`,则 kube-proxy 只将阶段端口绑定到 loopback 地址上。
* `--nodeport-address` 的默认值是一个空列表。则 kube-proxy 将节点端口绑定到该节点所有的网络 IP 地址上。
您可以通过 `nodePort` 字段指定节点端口号(必须在 `--service-node-port-range` 指定的范围内。Kubernetes 在创建 Service 时将使用该节点端口,如果该端口已被占用,则创建 Service 将不能成功。在这种情况下,您必须自己规划好端口使用,以避免端口冲突。
使用 NodePort您可以
* 根据自己的需要配置负载均衡器
* 配置 Kubernetes / 非 Kubernetes 的混合环境
* 直接暴露一到多个节点的 IP 地址,以便客户端可访问 Kubernetes 中的 Service
NodePort 类型的 Service 可通过如下方式访问:
* 在集群内部通过 $(ClusterIP): $(Port) 访问
* 在集群外部通过 $(NodeIP): $(NodePort) 访问
## LoadBalancer
在支持外部负载均衡器的云环境中(例如 GCE、AWS、Azure 等),将 `.spec.type` 字段设置为 `LoadBalancer`Kubernetes 将为该Service 自动创建一个负载均衡器。负载均衡器的创建操作异步完成,您可能要稍等片刻才能真正完成创建,负载均衡器的信息将被回写到 Service 的 `.status.loadBalancer` 字段。如下所示:
``` yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
loadBalancerIP: 78.11.24.19
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 146.148.47.155
```
发送到外部负载均衡器的网络请求就像被转发到 Kubernetes 中的后端 Pod 上。负载均衡的实现细节由各云服务上确定。
由于 Kuboard 不限定 Kubernetes 是运行在裸机上、私有云上或者是公有云上,因此 Kuboard 暂不支持 LoadBalancer 类型的 Service。关于更多 LoadBalancer Service 相关的描述,请参考 [Type LoadBalancer](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer) 和您所使用的云供应商的文档
## ExternalName
ExternalName 类型的 Service 映射到一个外部的 DNS name而不是一个 pod label selector。可通过 `spec.externalName` 字段指定外部 DNS name。
下面的例子中,名称空间 `prod` 中的 Service `my-service` 将映射到 `my.database.example.com`
``` yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
```
执行 `nslookup my-service.prod.svc.cluster.local` 指令时,集群的 DNS 服务将返回一个 `CNAME` 记录,其对应的值为 `my.database.example.com`。访问 `my-service` 与访问其他类型的 Service 相比,网络请求的转发发生在 DNS level而不是使用 proxy。如果您在后续想要将 `my.database.example.com` 对应的数据库迁移到集群内部来,您可以按如下步骤进行:
1. 在 Kubernetes 中部署数据库(并启动数据库的 Pod
2. 为 Service 添加合适的 selector 和 endpoint
3. 修改 Service 的类型
::: tip 注意事项
* ExternalName 可以接受一个 IPv4 地址型的字符串作为 `.spec.externalName` 的值,但是这个字符串将被认为是一个由数字组成的 DNS name而不是一个 IP 地址。
* 如果要 hardcode 一个 IP 地址,请考虑使用 [headless Service](./service-details.html#headless-services)
:::
## External IP
如果有外部 IP 路由到 Kubernetes 集群的一个或多个节点Kubernetes Service 可以通过这些 `externalIPs` 进行访问。`externalIP` 需要由集群管理员在 Kubernetes 之外配置。
在 Service 的定义中, `externalIPs` 可以和任何类型的 `.spec.type` 一通使用。在下面的例子中,客户端可通过 `80.11.12.10:80` externalIP:port 访问`my-service`
``` yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
externalIPs:
- 80.11.12.10
```