# 与集群外部服务映射

将Service与集群外部服务映射，即用于令集群内部的资源，如Pod，可以借助Service对象访问外部的服务。

共有两种实现方式：

1. 外部服务只提供IP地址，则**使用Endpoint资源**匹配外部服务的IP地址和端口信息，再交由Service对象；
2. 外部服务提供了完全限定域名（FQDN），则**使用`spec.type=ExternalName`的Service**；

## Endpoint映射外部服务

在[**Service介绍**](https://yangsijie151104.gitbook.io/k8s-note/service/6.-fu-wu-service)一节中，提到过在Service与Pod之间，有一层Endpoint来负责选择将流量转发至哪些Pod，而默认情况下，Endpoint是由Service的**标签选择器**负责创建的，它会自动为标签匹配的Pod创建Endpoint资源，并将所有的这些Pod的IP地址和端口信息都记录其中。

因此，若想通过Endpoint实现与外部服务的映射，仅需如下两步即可：

1. 将Service对象的`spec.selector`置为空，令该Service对象不会自动创建Endpoint；
2. 创建**与Service对象同名的**Endpoint对象，并且将外部服务的IP地址和端口记录其中；

在下图中，集群内部的Pod可以通过访问Service（ClusterIP: 10.108.226.39:80）直接与4个被映射的外部服务进行通信：

![使用Endpoint映射外部服务架构](https://2906552408-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M6Ub8CloS5kJszh6xSR%2Fsync%2F337ec79d4439f3028d30e7a47ca20d78ed4d2d1a.png?generation=1588594608623245\&alt=media)

### 创建无标签选择器的Service

创建的Service的`spec.selector`为空，令其不会自动创建Endpoint对象。最简单的配置文件案例格式如下，该Service对象的名字为external-service：

```yaml
apiVersion: v1
kind: Service
metadata:
  name: external-service
spec:
  ports:
  - port: 80
```

### 创建Endpoint对象

创建的Endpoint对象需要与Service对象同名，并将外部服务的IP地址和端口记录其中。配置文件案例格式如下，该Endpoint对象与Service对象同名，均为external-service：

```yaml
apiVersion: v1
kind: Endpoints
metadata:
  name: external-service
subsets:    # 包含了相关的外部服务的IP地址和端口信息
  - addresses:
    - ip: 11.11.11.11
    - ip: 22.22.22.22
    ports:
    - port: 8000
    - port: 8001
```

{% hint style="info" %}
**Tips:** 上面这种配置文件的含义是，可以访问的地址集为：11.11.11.11:8000, 11.11.11.11:8001, 22.22.22.22:8000, 22.22.22.22:8001
{% endhint %}

## ExternalName类型的Service映射外部服务

通过使用`spec.type=ExternalName`类型的Service对象，可以省去手动创建Endpoint对象的过程，这种Service对象**不具备ClusterIP**，**不创建Endpoint资源对象**。相当于为服务创建了CNAME记录，在DNS级别进行重定向，将访问服务的FQDN转换为外部服务的FQDN。

使用这种方式的前提是，外部服务有自己的FQDN，`spec.externalName`中即使填写IP地址，也会被Kubernetes识别为FQDN去进行解析。

如下图，在名为default的命名空间中有如下资源，因此Pod可以通过访问`external-service.default.svc.cluster.local`（甚至是`external-service`，至于为什么可以参考[Pod发现Service章节中的通过FQDN发现Service](https://yangsijie151104.gitbook.io/k8s-note/service/6.-fu-wu-service/nei-bu-pod-fa-xian-service)）来与`someapi.somecompany.com`进行通信：

![ExternalName类型的Service映射外部服务架构](https://2906552408-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M6Ub8CloS5kJszh6xSR%2Fsync%2Fbdfb54be224d6f73e002ad85afbb0cf644ab21bc.png?generation=1588594608277460\&alt=media)

给出下面这个案例，Service名为external-service：

```yaml
apiVersion: v1
kind: Service
metadata: 
  name: external-service
spec:
  type: ExternalName    # 修改类型为ExternalName，用来将连接重定向至外部的dns域名
  externalName: someapi.somecompany.com    # 外部的域名
  ports:
  - port: 80
```

{% hint style="warning" %}
在测试过程中，`spec.externalName`被设置为百度、当当，测试均不成功，猜测可能是WEB端有一些安全设置吧。
{% endhint %}
