DEV Community

Kahiro Okina
Kahiro Okina

Posted on

Shadow Service Pattern

Shadow Service Pattern

The Shadow Service pattern is a mechanism for communication using a Service on Kubernetes that has "no actual destination." This guide explains the specific method of creating a Service with an assigned ClusterIP (Shadow Service) and the EndpointSlice that the Service references. The key feature is that it can be completed using only standard Kubernetes features, without needing to change kube-proxy settings.


What is a Shadow Service?

  • A Service that is linked to an arbitrary IP rather than referencing Pods running on Nodes
  • Utilizes the Kubernetes Service object mechanism as-is, and ClusterIP can be automatically assigned
  • Can be implemented without modifying default Kubernetes components like kube-proxy

By creating what is essentially a "dummy" Service and defining the endpoint information (such as IP and port) that becomes the actual backing for that Service yourself using EndpointSlice, you can make "external resources" accessible via ClusterIP within Kubernetes.


Implementation Flow

  1. Create the Shadow Service
  2. Create the EndpointSlice
  3. Associate the Service name with the EndpointSlice label
  4. Access external resources via the ClusterIP

1. Creating the Shadow Service

Since the Shadow Service doesn't have Pods as a backend, you don't specify or disable the selector and type (NodePort, LoadBalancer, etc.) in a typical Service definition. In the following example, the name is set to "dummy" and HTTPS (443) port is defined.

apiVersion: v1
kind: Service
metadata:
  name: dummy
  namespace: default
spec:
  ports:
    - port: 443
      protocol: TCP
      targetPort: 443
      name: https
Enter fullscreen mode Exit fullscreen mode

At this stage, when you execute kubectl apply -f shadow-service.yaml, a ClusterIP for the Service will be automatically assigned.

2. Creating the EndpointSlice

Next, define an EndpointSlice as the endpoint linked to the Shadow Service.

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: dummy
  namespace: default
  labels:
    kubernetes.io/service-name: dummy
addressType: IPv4
ports:
- name: https
  protocol: TCP
  port: 443
endpoints:
- addresses:
  - "93.184.215.14" # Example: IP of example.com, specify external endpoint
  conditions:
    ready: true
  zone: zone-a
  nodeName: node-a
Enter fullscreen mode Exit fullscreen mode

In the above, "93.184.215.14" is linked to the endpoint as an external resource. By specifying dummy in the kubernetes.io/service-name label, it is associated with the Service dummy created earlier.

3. Association

If the Shadow Service's metadata.name and the EndpointSlice's labels.kubernetes.io/service-name are the same, they are automatically associated. This connects the Service entry point (ClusterIP and port 443) with the actual external endpoint ("93.184.215.14").

4. Access Overview

Once complete, requests to the ClusterIP (e.g., 10.96.0.X) will be forwarded to the external IP specified in the EndpointSlice. From the application or user's perspective, it appears as if they are accessing a Service called "dummy," but the actual backing is an external address.


Testing

You can test access using curl as follows:

curl https://dummy --insecure -H "Host: www.example.com"
Enter fullscreen mode Exit fullscreen mode

Benefits and Considerations

Benefits

  1. Completed within the scope of existing Kubernetes components
  2. Can obtain a ClusterIP even without having Pods

Considerations

  1. Manage the availability and validity of the IP addresses specified in the EndpointSlice
  2. Verify whether other integrated Ingress Controllers or Gateway Controllers support such Shadow Services

References

Services without selectors | Kubernetes

Top comments (0)