Service Exposure Guide ¶
This guide explains how to expose services in Kube-DC projects. The method you use depends on your project's network type and your requirements.
Quick Reference ¶
| Network Type | Default EIP Source | Best For | Recommended Method |
|---|---|---|---|
| Cloud | ext-cloud subnet |
Web apps, APIs | Gateway Routes (expose-route) |
| Public | ext-public subnet |
VMs, custom protocols | EIP + LoadBalancer |
Note: Both network types support EIPs and LoadBalancers. The difference is where EIPs are allocated from.
Understanding Project Network Types ¶
When creating a project, you choose an egressNetworkType:
apiVersion: kube-dc.com/v1
kind: Project
metadata:
name: my-project
namespace: my-org
spec:
egressNetworkType: cloud # or "public"
Cloud Network (egressNetworkType: cloud) ¶
- Default EIPs allocated from
ext-cloudsubnet (shared/NAT IPs) - Outbound traffic goes through a shared NAT gateway
- Can create public EIPs by specifying
externalNetworkType: public - Gateway Routes provide easy HTTPS exposure with auto-certificates
- Supports VMs, pods, and all workload types
- Best for: Web applications, APIs, microservices, cost-optimized workloads
- Cost: Lower (shared infrastructure, cloud IPs often included)
Public Network (egressNetworkType: public) ¶
- Default EIPs allocated from
ext-publicsubnet (dedicated public IPs) - Direct internet connectivity without NAT
- Each EIP is a dedicated public IP address
- Supports any TCP/UDP protocol
- Supports VMs, pods, and all workload types
- Best for: Game servers, custom protocols, direct IP requirements
- Cost: Higher (dedicated public IPs)
Feature Comparison ¶
| Feature | Cloud Project | Public Project |
|---|---|---|
| Default EIP source | ext-cloud |
ext-public |
| Can get public EIPs | Would be supported (specify externalNetworkType: public) |
✅ Yes (default) |
| Can use Gateway Routes | ✅ Yes | ✅ Yes |
| Can use EIP + LB | ✅ Yes | ✅ Yes |
| Can run VMs | ✅ Yes | ✅ Yes |
| Can run Pods | ✅ Yes | ✅ Yes |
Part 1: Cloud Network Projects ¶
For projects with egressNetworkType: cloud, use Gateway Routes to expose services.
All Service Annotations Reference ¶
Gateway Route Annotations ¶
| Annotation | Description | Example Values |
|---|---|---|
expose-route |
Enable Gateway route | http, https, tls-passthrough |
route-hostname |
Custom hostname (optional) | api.example.com |
route-port |
Target port (optional) | 8080, 50051 |
tls-issuer |
cert-manager Issuer name | letsencrypt (default) |
tls-secret |
User-provided TLS secret | my-tls-secret |
EIP/LoadBalancer Annotations ¶
| Annotation | Description | Example Values |
|---|---|---|
bind-on-default-gw-eip |
Use project's default EIP | "true" |
bind-on-eip |
Use a specific EIP by name | my-eip |
autodelete |
Auto-delete EIP when service deleted | "true" |
create-gateway-backend |
Create Envoy Gateway backend | "true" |
Note: Prefix is
service.nlb.kube-dc.com/
Network Type Annotation ¶
| Annotation | Description | Example Values |
|---|---|---|
network.kube-dc.com/external-network-type |
EIP type for auto-created EIP | cloud, public |
Tip: Use this on a LoadBalancer service to get a public EIP in a cloud project:
Status Annotations (Read-Only) ¶
| Annotation | Description |
|---|---|
route-hostname-status |
Assigned hostname (set by controller) |
Note: All annotations use prefix
service.nlb.kube-dc.com/
Gateway Route Annotations (Details) ¶
Add these annotations to your LoadBalancer Service:
Route Type Comparison ¶
| Route Type | Port | TLS | App Serves | Use Case |
|---|---|---|---|---|
http |
80 | None | HTTP | Plain HTTP traffic |
https |
443 | Gateway terminates | HTTP | ⭐ Recommended - Auto TLS certs |
tls-passthrough |
443 | App terminates | HTTPS | End-to-end encryption |
Example: HTTPS Web Application (Recommended) ¶
The simplest way to expose a web app with automatic TLS:
Step 1: Create the Issuer (once per namespace) ¶
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt
namespace: my-project
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: your-email@example.com # Replace with valid email
privateKeySecretRef:
name: letsencrypt-account-key
solvers:
- http01:
gatewayHTTPRoute:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: eg
namespace: envoy-gateway-system
Step 2: Deploy your application ¶
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: my-project
spec:
replicas: 2
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: nginx:alpine
ports:
- containerPort: 80
Step 3: Create LoadBalancer Service with HTTPS route ¶
apiVersion: v1
kind: Service
metadata:
name: my-app
namespace: my-project
annotations:
# Expose via HTTPS with auto-provisioned certificate
service.nlb.kube-dc.com/expose-route: "https"
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 80
Step 4: Verify and access ¶
# Check assigned hostname
kubectl get svc my-app -n my-project -o jsonpath='{.metadata.annotations.service\.nlb\.kube-dc\.com/route-hostname-status}'
# Output: my-app-my-project.stage.kube-dc.com
# Check certificate status
kubectl get certificate -n my-project
# Test access
curl https://my-app-my-project.stage.kube-dc.com
Example: Plain HTTP ¶
For non-TLS HTTP traffic:
apiVersion: v1
kind: Service
metadata:
name: my-app
namespace: my-project
annotations:
service.nlb.kube-dc.com/expose-route: "http"
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 80
Access via: http://my-app-my-project.stage.kube-dc.com
Example: TLS Passthrough (Kubernetes API) ¶
For services that handle their own TLS (like Kubernetes control planes):
apiVersion: v1
kind: Service
metadata:
name: cluster-api
namespace: my-project
annotations:
service.nlb.kube-dc.com/expose-route: "tls-passthrough"
spec:
type: LoadBalancer
selector:
app: kube-apiserver
ports:
- port: 6443
targetPort: 6443
Access via: https://cluster-api-my-project.stage.kube-dc.com:6443
Example: Custom Hostname ¶
Override the auto-generated hostname:
apiVersion: v1
kind: Service
metadata:
name: my-app
namespace: my-project
annotations:
service.nlb.kube-dc.com/expose-route: "https"
service.nlb.kube-dc.com/route-hostname: "api.mycompany.com"
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 80
Note: You must configure DNS to point api.mycompany.com to the Gateway IP.
Example: User-Provided Certificate ¶
Use your own TLS certificate instead of auto-provisioning:
# First, create your TLS secret
kubectl create secret tls my-tls-secret \
--cert=path/to/tls.crt \
--key=path/to/tls.key \
-n my-project
---
apiVersion: v1
kind: Service
metadata:
name: my-app
namespace: my-project
annotations:
service.nlb.kube-dc.com/expose-route: "https"
service.nlb.kube-dc.com/tls-secret: "my-tls-secret"
service.nlb.kube-dc.com/route-hostname: "secure.mycompany.com"
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 80
Example: gRPC Service ¶
gRPC services work with HTTPS routes (HTTP/2):
apiVersion: v1
kind: Service
metadata:
name: grpc-api
namespace: my-project
annotations:
service.nlb.kube-dc.com/expose-route: "https"
service.nlb.kube-dc.com/route-port: "50051"
spec:
type: LoadBalancer
selector:
app: grpc-server
ports:
- name: grpc
port: 50051
targetPort: 50051
Part 2: EIP-Based Exposure (Both Project Types) ¶
Both cloud and public projects can use EIPs and LoadBalancer services.
Default EIP Allocation ¶
| Project Type | Default EIP Source | Can Request |
|---|---|---|
| Cloud | ext-cloud subnet |
Both cloud and public EIPs |
| Public | ext-public subnet |
Both cloud and public EIPs |
When to use EIPs vs Gateway Routes: - Use Gateway Routes for HTTP/HTTPS/gRPC (simpler, auto-TLS) - Use EIPs for TCP/UDP protocols, VMs, or when you need a dedicated IP
Understanding EIPs ¶
External IPs (EIPs) provide IP addresses for your project from the configured external network.
Default Gateway EIP ¶
Every project automatically gets a default EIP (default-gw) that acts as:
- NAT gateway for outbound traffic
- Default endpoint for LoadBalancer services
Creating Additional EIPs ¶
For services that need dedicated IPs:
apiVersion: kube-dc.com/v1
kind: EIp
metadata:
name: web-server-eip
namespace: my-project
spec:
externalNetworkType: public # or "cloud"
EIP Types:
externalNetworkType |
Description | Use Case |
|---|---|---|
cloud |
Shared/NAT pool IP | Cost-effective, outbound NAT |
public |
Dedicated public IP | Direct access, static IP, VMs |
Tip: Cloud projects can request public EIPs for services that need dedicated IPs (e.g., game servers, VMs with direct access).
LoadBalancer Service Annotations ¶
| Annotation | Description |
|---|---|
service.nlb.kube-dc.com/bind-on-default-gw-eip: "true" |
Use project's default EIP |
service.nlb.kube-dc.com/bind-on-eip: "eip-name" |
Use a specific EIP |
Example: Web Server on Default EIP ¶
apiVersion: v1
kind: Service
metadata:
name: nginx-lb
namespace: my-project
annotations:
service.nlb.kube-dc.com/bind-on-default-gw-eip: "true"
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- name: http
port: 80
targetPort: 80
- name: https
port: 443
targetPort: 443
Example: Service on Dedicated EIP ¶
# Step 1: Create dedicated EIP
apiVersion: kube-dc.com/v1
kind: EIp
metadata:
name: api-eip
namespace: my-project
spec:
externalNetworkType: public
---
# Step 2: Bind service to the EIP
apiVersion: v1
kind: Service
metadata:
name: api-lb
namespace: my-project
annotations:
service.nlb.kube-dc.com/bind-on-eip: "api-eip"
spec:
type: LoadBalancer
selector:
app: api-server
ports:
- port: 443
targetPort: 443
Example: VM SSH Access ¶
Expose SSH access to a virtual machine:
apiVersion: v1
kind: Service
metadata:
name: vm-ssh
namespace: my-project
annotations:
service.nlb.kube-dc.com/bind-on-default-gw-eip: "true"
spec:
type: LoadBalancer
selector:
vm.kubevirt.io/name: my-vm # Target VM name
ports:
- name: ssh
port: 2222 # External port
targetPort: 22 # Internal SSH port
Floating IPs (FIPs) ¶
Floating IPs map an internal IP directly to an EIP, providing 1:1 NAT.
When to Use FIPs ¶
- Direct IP mapping for VMs
- Services that need to see their public IP
- Protocols that don't work behind NAT
Creating a FIP ¶
apiVersion: kube-dc.com/v1
kind: FIp
metadata:
name: vm-fip
namespace: my-project
spec:
ipAddress: 10.0.10.5 # Internal IP of VM or pod
eip: my-eip # Name of existing EIP
Part 3: Choosing the Right Approach ¶
Decision Tree ¶
┌─────────────────────────────────────────────────────────────┐
│ What are you exposing? │
└─────────────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
Web App/API VM Direct Custom Protocol
│ Access │
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌───────────┐ ┌───────────────┐
│Cloud Project│ │ Public │ │ Public │
│expose-route │ │ Project │ │ Project │
│ : https │ │ EIP+FIP │ │ EIP + LB │
└─────────────┘ └───────────┘ └───────────────┘
Comparison Table ¶
| Feature | Gateway Routes (Cloud) | EIP + LoadBalancer (Public) |
|---|---|---|
| IP Address | Shared Gateway IP | Dedicated per EIP |
| Protocols | HTTP, HTTPS, gRPC | Any TCP/UDP |
| TLS Termination | Gateway (auto-cert) | Application |
| Cost | Lower | Higher |
| Setup | Simple annotation | EIP + Service config |
| DNS | Auto hostname | Manual |
| Best For | Web apps, APIs | VMs, game servers |
Part 4: Advanced Topics ¶
Envoy Gateway Backend ¶
Use the create-gateway-backend annotation to register a service as an Envoy Gateway Backend for advanced routing scenarios:
apiVersion: v1
kind: Service
metadata:
name: my-backend
namespace: my-project
annotations:
service.nlb.kube-dc.com/create-gateway-backend: "true"
spec:
type: ClusterIP
selector:
app: my-app
ports:
- port: 8080
targetPort: 8080
This creates an Envoy Gateway Backend resource, enabling:
- Cross-namespace routing from Gateway
- Custom backend policies
- Advanced load balancing configurations
Automatic External Endpoints ¶
For every LoadBalancer service, Kube-DC creates external endpoints for cross-VPC DNS access:
- External Service:
<service-name>-ext - DNS:
<service>-ext.<namespace>.svc.cluster.local
Namespace-Scoped Ingress Controller ¶
For advanced HTTP routing beyond Gateway capabilities, deploy a dedicated ingress-nginx:
# ingress-values.yaml
controller:
ingressClassResource:
enabled: false
scope:
enabled: true
namespace: my-project
admissionWebhooks:
enabled: false
service:
annotations:
service.nlb.kube-dc.com/bind-on-default-gw-eip: "true"
rbac:
create: true
scope: true
defaultBackend:
enabled: false
helm install ingress ingress-nginx/ingress-nginx \
--namespace my-project \
--values ingress-values.yaml
Troubleshooting ¶
Gateway Routes (Cloud Projects) ¶
# Check route hostname was assigned
kubectl get svc my-app -o yaml | grep route-hostname-status
# Check certificate status
kubectl get certificate -n my-project
kubectl describe certificate my-app-tls -n my-project
# Check HTTPRoute created
kubectl get httproute -n my-project
# Check Gateway listener
kubectl get gateway eg -n envoy-gateway-system -o yaml | grep -A5 "https-my-app"
# Controller logs
kubectl logs -n kube-dc deployment/kube-dc-manager | grep my-app
EIP/LoadBalancer (Public Projects) ¶
# Check EIP status
kubectl get eip -n my-project
kubectl describe eip my-eip -n my-project
# Check LoadBalancer external IP
kubectl get svc -n my-project
# Check service events
kubectl describe svc my-lb -n my-project
Common Issues ¶
| Issue | Cause | Solution |
|---|---|---|
| No hostname assigned | Missing expose-route annotation |
Add annotation |
| Certificate not ready | Issuer not created | Create Issuer first |
| 503 error | Backend not ready | Check pod status |
| EIP pending | No available IPs | Check subnet capacity |
| Connection timeout | DNS not configured | Point DNS to Gateway/EIP |
Summary ¶
| Project Type | Service Type | Annotation | Result |
|---|---|---|---|
| Cloud | LoadBalancer | expose-route: https |
Auto HTTPS with cert |
| Cloud | LoadBalancer | expose-route: http |
HTTP only |
| Cloud | LoadBalancer | expose-route: tls-passthrough |
App handles TLS |
| Public | LoadBalancer | bind-on-default-gw-eip: "true" |
Use default EIP |
| Public | LoadBalancer | bind-on-eip: "name" |
Use specific EIP |
| Public | FIp | N/A | 1:1 NAT mapping |