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
- Create the Shadow Service
- Create the EndpointSlice
- Associate the Service name with the EndpointSlice label
- 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
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
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"
Benefits and Considerations
Benefits
- Completed within the scope of existing Kubernetes components
- Can obtain a ClusterIP even without having Pods
Considerations
- Manage the availability and validity of the IP addresses specified in the EndpointSlice
- Verify whether other integrated Ingress Controllers or Gateway Controllers support such Shadow Services
Top comments (0)