With the VPC CNI, a Pod can hold an address from the VPC, and a VPN user with the right route can reach it directly. That makes direct Pod access feel like the simplest option, and it is, until the Pod is replaced. The address a user remembers should belong to the application, not to a replica. Comparing the three entries comes down to which object owns the address and what must keep working when the workload moves.

Pick by lifecycle first, then by what the network has to do to make the entry reachable.

Three entries, three lifetimes

A Pod IP is owned by a Pod: allocated with it and released when it ends. A ClusterIP is owned by a Service and is virtual, meaningful only where the cluster's service routing exists. An internal load balancer is owned by a cloud resource that the cluster's controller programs with backends. Those ownership models predict the failure you get: a stale address, an unreachable name, or a backend set that is out of date.

Write the comparison down before choosing. Once the owner and the failure are named, the choice usually makes itself.

EntryOwnerFailure when the workload moves
Pod IPThe PodAddress changes and saved links break
ClusterIPThe ServiceVirtual address with no meaning outside cluster routing
Internal balancerCloud resource plus controllerBackends update, but the DNS view is yours to maintain

Direct Pod access: useful, temporary

Direct access is genuinely useful for a controlled check: one administrator, one short session, one specific port. It is a poor contract for users because the address is an implementation detail that changes on every rollout. Recording one in a wiki is how a working service turns into a rumour.

It also invites wide rules. Permission for one administrator to reach one Pod is not permission for every address in the node subnet, and the second is what usually gets written.

ClusterIP: cluster-scoped by design

A ClusterIP works because the cluster's dataplane programs routing for it inside the cluster. From a laptop on the VPN the address means nothing unless something deliberately exposes it. A name ending in svc.cluster.local belongs to cluster DNS, so copying it to a client with a different resolver produces a name that does not exist rather than a routing error.

ClusterIP remains the right entry for in-cluster callers, including other workloads. It is simply not a publication mechanism for users outside the cluster's routing domain.

Internal load balancer: the published path

An internal load balancer gives you a stable private address and a name your own zone can point at, while the controller keeps the backend set current, as the EKS load-balancing guide describes. That is the entry that survives an ordinary Pod replacement without anyone editing a document. It costs a cloud resource, a controller configuration and a route from the VPN, and those are the parts people underestimate.

Use the controller model the cluster actually runs. Annotations written for one integration do not apply to another.

Who the source address is

Security groups see the source that arrives at their boundary, which may be the connected client or a translated address depending on the VPN and load-balancing path. On EC2-backed nodes, ordinary VPC CNI Pods inherit the node ENI's groups by default, while supported configurations can attach Pod-specific groups. Write rules for the documented path instead of for a guessed laptop address.

Keep the application's own listener and authentication as separate controls. A network rule that permits the flow is not an authorization decision and should not be treated as one.

What to hand users

Give users a service name, not an address. Publish the name in the private zone, point it at the internal entry, then test by replacing a backend Pod while a client keeps the same name open. That exercise tests the property that matters: reaching the same application after a routine deployment.

Keep direct Pod access as a documented operational exception with its own scope, well away from the user-facing instructions.

Amanqephe ahlobene