有时候需要在集群中使用外部集群的服务。
通过类型为ExternalName的Service 或 手动设置Endpoints便可实现。

什么是Endpoints
在Service和Pod之间实际上还存在一种资源Endpoints。可以通过 kubectl describe 来查看到

$ kubectl describe svc/nginx
Name:              nginx
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=nginx
Type:              ClusterIP
IP:                10.96.27.104
Port:              web-8080  8080/TCP
TargetPort:        80/TCP
Endpoints:         172.32.0.6:80,172.40.0.6:80
Session Affinity:  None
Events:            <none>
$ kubectl get endpoints nginx
NAME    ENDPOINTS                                                     AGE
nginx   172.32.0.6:80,172.40.0.6:80

在客户端连接到服务时,服务代理选择Endpoints中存储的IP:PORT中的一个,然后将链接重定向到该位置。
作为Service与Pod中间的关联层,当Service未定义Pod选择器时,就不会自动创建Endpoints资源,需要手动创建。
Endpoints配置结构

type Endpoints struct {
    metav1.TypeMeta `json:",inline"`
    metav1.ObjectMeta `json:"metadata,omitempty"`

    // 组成服务的Address的集合。
    // 每个地址对应多个端口,其中有部分已经就绪,有部分未就绪。就绪与未就绪的放入不同的Addresses集合中。
    // 不存在某个地址同时存在于Addresses与NotReadyAddreses中。
    Subsets []EndpointSubset `json:"subsets,omitempty"`
}

type EndpointSubset struct {
    // 已经就绪的地址集。这些终端可以被负载均衡器和客户端正常发现和使用
    Addresses []EndpointAddress `json:"addresses,omitempty"`

    // 未就绪的地址集,可能由于未启动完成、就绪检查失败或者最近的存活检查失败。
    NotReadyAddresses []EndpointAddress `json:"notReadyAddresses,omitempty"`

    // 在地址上可用的端口集
    Ports []EndpointPort `json:"ports,omitempty"`
}

type EndpointAddress struct {
    // Endpoint的IP地址
    IP  string `json:"ip"`

    // Endpoint的主机名
    Hostname string `json:"hostname,omitempty"`

    // 节点主机名,可以使得改Endpoints被部署到指定的节点上
    NodeName *string `json:"nodeName,omitempty"`

    // 引用某个对象来提供Endpoint能力,暂不了解
    TargetRef *ObjectReference `json:"targetRef,omitempty"`
}

type EndpointPort struct {
    // 端口名,必须与Service中定义的ServicePort一致
    // 在只有一个端口时为可选项,多个端口则必填
    Name string `json:"name,omitempty"`

    // Endpoint的端口
    Port int32 `json:"port"`

    // IP协议,支持TCP(默认)、UDP和SCTP
    Protocol Protocol `json:"protocol,omitempty"`
}

type Protocol string
const (
    ProtocolTCP Protocol = "TCP"
    ProtocolUDP Protocol = "UDP"
    ProtocolSCTP Protocol = "SCTP"
)

两种方案实现将外部服务引入集群

手动配置一个Endpoints并将外部服务加入
配置外部服务的别名给服务

手动配置服务的Endpoint
某些情况下,应用系统需要将一个非本集群的服务作为后端服务进行连接,这时候可以通过创建一个无LabelSelector的Service来实现

创建一个没有选择器的Service
为该服务创建Endpoints资源

apiVersion: v1
kind: Service
metadata:
  name: external-svc
spec:
  ports:
  - port: 80
---
apiVersion: v1
kind: Endpoints
metadata:
  name: external-svc
subsets:
  - addresses:
    - ip: 47.95.148.6
    ports:
    - port: 80
$ kubectl run -it --rm --generator=run-pod/v1 busybox --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget external-svc
Connecting to external-svc (10.96.138.102:80)
saving to 'index.html'
index.html           100% |*******************************|   613  0:00:00 ETA
'index.html' saved

创建一个类型为ExternalName的服务,并配置externalName字段,即可实现。
此类服务仅在DNS级别为服务创建了简单的CNAME记录。因此连接此服务将会直接连接到外部的服务,完全绕过代理。
所以此类服务也不会有集群IP。

apiVersion: v1
kind: Service
metadata:
  name: external-name-svc
spec:
  type: ExternalName
  externalName: ali.cdnnnn.com
  ports:
  - port: 80

$ kubectl run -it --rm --generator=run-pod/v1 busybox --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget external-name-svc
Connecting to external-name-svc (47.95.148.6:80)
saving to 'index.html'
index.html           100% |***********************************************|   613  0:00:00 ETA
'index.html' saved