Applications within a cluster sometimes need to invoke external services, and we know that internal service invocations within the cluster are accessed through Service, so is it possible to keep using Service uniformly for external services as well? The answer is yes, accessing external services through Service can bring other benefits besides the unified way. For example, if the same application in different environments (spaces) accesses the external database in different environments, the configuration of both sides can be unified through Service mapping, so that different applications in different spaces can access different external databases through the same Service Name. For example, the two spaces test-1 and test-2 are two different business environments, through service mapping, the same Service in different spaces accesses the corresponding external databases in different environments.

different spaces

In addition, you can also ensure minimal changes, if the external database IP or other changes, you only need to modify the Service corresponding mapping, the service itself does not need to change the configuration. The specific scenario is as follows.

1. External domain name mapping to internal Service -> ExternalName

1
2
3
4
5
6
7
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  externalName: mysql.example.com
  type: ExternalName

Once created, the same space Pod can access external MySQL services via mysql:3306.

Note that while externalName also supports IP, it is not resolved by Ingress and CoreDNS (supported by KubeDNS). If you have IP-related requirements, you can use Headless Service -> Type ExternalName . Another thing to note is that because of the CNAME, if the external service goes through another layer of proxy forwarding, such as Nginx, the mapping will not be valid unless the corresponding server_name is configured.

2. External IP Mapping to Internal Service

2.1. IP Mapping

As mentioned before, although the externalName field can be configured as an IP address, Ingress and CoreDNS do not resolve it. If the external service is provided as an IP, then Headless Service can be used to implement the mapping.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  clusterIP: None
  type: ClusterIP

---

apiVersion: v1
kind: Endpoints
metadata:
 name: mysql
subsets:
 - addresses:
     - ip: 192.168.1.10

service does not specify a selector, manually maintain the creation of endpoint, after creation you can access 192.168.1.10:3306 service purpose through mysql:3306. Headless Service can not modify the port-related, if you want to modify the access port, you need to operate further.

2.2. IP + Port Mapping

If the external port is not a standard port and you want to use the standard port when accessing through Service, e.g. external MySQL provides port 3307 and internal wants to access through Service 3306, then you can achieve this by the following way.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: v1
kind: Service
metadata:
 name: mysql
spec:
 type: ClusterIP
 ports:
 - port: 3306
   targetPort: 3307

---

apiVersion: v1
kind: Endpoints
metadata:
 name: mysql
subsets:
 - addresses:
     - ip: 192.168.1.10
   ports:
     - port: 3307

service without specifying a selector, manually maintain the creation endpoint, and then you can access the external 192.168.1.10:3307 service via mysql:3306 after creation.

3. Summary

We can see that the above external service mapping, externalName and Headless Service methods map external services without intermediate proxies and are implemented through DNS hijacking. When there is a need for port changes, they have to be forwarded through the internal kube-proxy layer. Under normal circumstances, it is better to introduce as few middle-tier layers as possible, especially for database applications, because introducing middle-tier layers brings convenience but also means performance loss, especially for those services that are sensitive to latency.