| name | kubernetes-network |
| description | Manage Zeabur Kubernetes networking directly with kubectl: create Service or NodePort exposure, route a domain through Ingress and TLS, or diagnose zeabur.internal service communication. Use whenever a service needs internal or external network reachability without the Zeabur backend. |
Read ../../references/kubernetes.md before changing network resources. It defines the kubectl-only boundary, identity labels, name defaults, and ownership loop.
Resolve the traffic contract
Collect the protocol, target container port, requested public hostname or NodePort, path behavior, and TLS requirement. Inventory the controller, Service, selected Pods, EndpointSlices, and Ingresses before choosing a name or selector:
kubectl -n "$NS" get svc,ingress -l "zeabur_service_id=$ZEABUR_SERVICE_ID"
kubectl -n "$NS" get endpointslice -l "kubernetes.io/service-name=$SERVICE_NAME" -o wide
kubectl -n "$NS" get pods -l "zeabur_service_id=$ZEABUR_SERVICE_ID" -o wide
A Service selector is a traffic contract. Copy the selected workload's stable labels, normally zeabur_type=user-service,zeabur_service_id=<service-id>, and avoid deployment-specific labels when the Service must survive a rollout. Name the service service-<service-id> unless an existing resource supplies the canonical name.
Complete this step only when at least one Ready endpoint is known, or the user has explicitly requested creation before the workload is healthy.
Internal Service
Create or update a ClusterIP Service with named ports. A named port avoids silently coupling the Service to a container port number.
apiVersion: v1
kind: Service
metadata:
name: service-<service-id>
namespace: environment-<environment-id>
labels:
zeabur_type: user-service
zeabur_project_id: <project-id>
zeabur_service_id: <service-id>
zeabur_environment_id: <environment-id>
spec:
type: ClusterIP
selector:
zeabur_type: user-service
zeabur_service_id: <service-id>
ports:
- name: http
protocol: TCP
port: 8080
targetPort: http
Kubernetes-native DNS is service-<service-id>.$NS.svc.cluster.local. The backend configures Pods with the search domain $NS.zeabur.internal, so service-<service-id>.zeabur.internal is a compatibility alias only when that custom DNS zone resolves in the target cluster. Verify both names from an existing service Pod; use the Kubernetes-native name when the alias is absent.
kubectl -n "$NS" exec "$POD" -- getent hosts "$SERVICE_NAME.$NS.svc.cluster.local"
kubectl -n "$NS" exec "$POD" -- getent hosts "$SERVICE_NAME.zeabur.internal"
NodePort
Use NodePort only for direct node-address reachability. It does not create a hostname, provide TLS termination, or bypass node firewalls. Change an existing Service with a declarative fragment that preserves all ports and selectors; for a new Service set type: NodePort and omit nodePort so Kubernetes allocates a valid port.
apiVersion: v1
kind: Service
metadata:
name: service-<service-id>
namespace: environment-<environment-id>
spec:
type: NodePort
ports:
- name: tcp
protocol: TCP
port: 5432
targetPort: 5432
After applying, obtain the allocated port and routable node address from cluster state. Test with the requested protocol from an authorized client; kubectl port-forward proves the Service/endpoints but not node firewall or load-balancer reachability.
kubectl -n "$NS" get service "$SERVICE_NAME" \
-o custom-columns=NAME:.metadata.name,TYPE:.spec.type,PORT:.spec.ports[*].port,NODEPORT:.spec.ports[*].nodePort
kubectl get nodes -o wide
Domain, Ingress, and TLS
A domain route is an Ingress rule: host, prefix path /, backend service-<service-id>, and the requested Service port. Select an existing ingress class or require the user to choose one; an Ingress without a controller has no external effect.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: domain-<domain-id>
namespace: environment-<environment-id>
labels:
zeabur_type: user-service
zeabur_service_id: <service-id>
zeabur_environment_id: <environment-id>
spec:
ingressClassName: <class>
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service-<service-id>
port:
number: 8080
For TLS, reference an existing Secret or, only after confirming the cert-manager.io API exists, create a Certificate whose secretName is referenced by spec.tls. Wait for Certificate.status.conditions before declaring HTTPS ready.
Ingress establishes cluster routing. Public DNS is complete only when the authoritative zone points to the ingress controller address. Detect a configured external-dns controller before using its annotations; otherwise report the exact status.loadBalancer.ingress hostname/IP and the required A, AAAA, or CNAME record for the DNS owner to create.
kubectl get ingressclass
kubectl -n "$NS" get ingress "$INGRESS_NAME" -o wide
kubectl -n "$NS" describe ingress "$INGRESS_NAME"
kubectl -n "$NS" get certificate "$CERTIFICATE_NAME" 2>/dev/null
Completion
Verify the full traffic chain in order: Ready Pod, EndpointSlice target, Service port, Ingress address, then DNS and HTTPS from an external client when requested. Report the canonical Service DNS name, custom zeabur.internal lookup result, exposed ports, ingress class/address, and outstanding DNS or certificate prerequisite. Do not equate an admitted Ingress with a live DNS record or a working TLS certificate.