01. 10. 2026 Daniel Vedovato DevOps, Kubernetes, NetEye, Uncategorized

Planning Kubernetes Networking for a NetEye 4.49 Upgrade: The Service LoadBalancer CIDR

Upgrading an existing NetEye cluster to 4.49 introduces a networking question that is easy to underestimate.

The existing environment may already have everything we normally associate with a NetEye cluster: a corporate network for frontend access and integrations, a private trusted network for internal cluster communication, and the corresponding virtual IPs. With Kubernetes entering the architecture in NetEye 4.49, three Kubernetes CIDRs have to be planned: pod_cidr, svc_cidr, and service_loadbalancer_cidr.

At first sight, that can look like a straightforward IP address planning exercise. It isn’t quite that simple.

During the preparation of a real three-node upgrade, the main question gradually became much more specific: what does the new service_loadbalancer_cidr actually require from the datacenter network, and can that requirement be validated before Kubernetes is installed?

That distinction turned out to be much more useful than treating all three CIDRs as equivalent.

Why NetEye 4.49 Changes the Network Planning

The first assumption was that the three Kubernetes CIDRs could be handled in roughly the same way: find three unused private ranges, size them generously enough, and keep them away from existing addresses.

That approach quickly raised practical questions.

The existing NetEye frontend already had its own corporate subnet and virtual IP. The cluster also had a separate trusted network used for node-to-node communication and internal cluster services. Where should the new LoadBalancer range go?

Should it be carved out of the corporate network because LoadBalancer services are meant to be reachable?

Should it use the private network instead?

Would another VLAN be required? Or even another network interface on every node?

There was also a more fundamental concern around the other two CIDRs. Using address ranges that already existed elsewhere in the organization could create routing conflicts, even though those addresses would only be used internally by Kubernetes.

The useful way to approach the problem was therefore not simply to ask, “Which three subnets should we choose?”

The better questions were:

  • Which CIDRs stay entirely inside Kubernetes?
  • Which one interacts with the datacenter Layer 2 network?
  • What must remain unique?
  • What can share existing infrastructure?
  • What can realistically be validated before the upgrade?

Once those questions were separated, the design became much clearer.

Three CIDRs, but Only One Reaches the Underlay

The three Kubernetes CIDRs have different responsibilities. The NetEye 4.49 Kubernetes Networking requirements describe the three address spaces and their different roles.

pod_cidr provides the address space from which Pod IP addresses are allocated. In NetEye 4.49, this is an internal Kubernetes network managed by the platform.

svc_cidr provides virtual IP addresses for Kubernetes Services. This is also an internal cluster address space.

Neither of these networks needs a corresponding datacenter VLAN, DHCP scope, gateway, or physical subnet simply because the CIDR exists.

They are logical networks.

That does not mean their values can be chosen without considering the surrounding infrastructure. If NetEye must communicate with an address that overlaps one of these ranges, the routing installed for Kubernetes can take precedence over the route that would otherwise reach that external system.

This matters particularly in environments with many internal networks, remote sites, overlapping RFC1918 space, or VPN connections.

service_loadbalancer_cidr is different.

It contains the addresses assigned to Kubernetes Services of type LoadBalancer. Those addresses need to be reachable from the trusted network, and NetEye uses Cilium to announce them on the selected Layer 2 network, as described in the NetEye Kubernetes architecture and Cilium Layer 2 announcements.

That makes the LoadBalancer CIDR the point where Kubernetes address planning meets the actual datacenter underlay.

CIDRPurposeInteraction with the datacenter network
pod_cidrPod addressesInternal to Kubernetes
svc_cidrKubernetes Service addressesInternal to Kubernetes
service_loadbalancer_cidrLoadBalancer service addressesAnnounced on the selected trusted Layer 2

This was the key architectural clarification in the investigation.

The new requirement was not simply “Kubernetes needs another /24“. It was that a dedicated LoadBalancer address space had to be usable on the Layer 2 network available to the cluster nodes.

Designing the Service LoadBalancer Network

An early question was whether the LoadBalancer addresses had to be taken from the existing corporate subnet.

They did not.

The existing NetEye frontend addresses and corporate virtual IP could remain unchanged. The new LoadBalancer pool serves a different purpose and can use its own dedicated IP subnet on the trusted side of the architecture.

“Dedicated”, however, is important wording here.

A dedicated service_loadbalancer_cidr means a separate IP address space. It does not automatically mean:

  • another physical NIC;
  • another virtual NIC;
  • another VLAN;
  • or another switching infrastructure.

In the environment being prepared for upgrade, the trusted network was already available on the same interface of all three nodes. The design that emerged was therefore to keep the existing trusted/heartbeat subnet unchanged and make an additional LoadBalancer subnet available on the same Layer 2 infrastructure.

Conceptually, the layout looked like this:

The two trusted-side subnets have different purposes even though they share the same Layer 2 domain.

This became an important point in the investigation. Separating the LoadBalancer address space from the heartbeat subnet does not mean that the underlying network infrastructure must also be separated.

The same applies to network interfaces. Adding another interface could be an architectural choice in a different environment, but it is not inherently required just because a service_loadbalancer_cidr exists.

What matters is that the selected trusted Layer 2 network is available to the cluster nodes that may need to announce those addresses.

In this three-node environment, all three nodes were on that network. That is why the later validation tested the proposed subnet in every node-to-node direction.

Sizing Without Applying the Same Rule Three Times

The sizing discussion exposed another easy mistake: using the Pod CIDR sizing rule for all three networks.

For pod_cidr, NetEye 4.49 allocates a /24 Pod range per node.

That gives a straightforward cluster-level sizing relationship:

pod_cidr/24 blocks availableMaximum nodes
/2411
/2322
/2244
/2188

For a three-node cluster, /22 is therefore the smallest aggregate range that provides one /24 per node.

During the investigation, a /25-per-node design was considered as a way to reduce address consumption. It did not match the supported NetEye 4.49 design, which uses /24 Pod ranges per node, so it was discarded.

svc_cidr follows a different rule.

Its size depends on the number of Kubernetes Services that need addresses, not on the number of cluster nodes. The node-based calculation used for pod_cidr therefore should not be reused here.

service_loadbalancer_cidr is different again. Its capacity needs to cover the LoadBalancer services that will receive addresses from that pool. A /24 is a practical size for most NetEye installations, but this is not the same /24-per-node rule used for Pods.

In the environment used for this investigation, additional address space eventually became available, so the final design kept more headroom for Pods than the three-node minimum:

pod_cidr:                  172.22.0.0/21
svc_cidr:                  172.22.8.0/24
service_loadbalancer_cidr: 172.22.9.0/24

These ranges are illustrative, but the sizing relationship reflects the real design decision.

Lifecycle also matters here. pod_cidr and svc_cidr need careful planning before Kubernetes is created because changing them later requires recreating the Kubernetes cluster.

service_loadbalancer_cidr is different: it can be changed later, but not through a standard NetEye command. Doing so requires a manually planned procedure.

Choosing CIDRs Without Creating Routing Conflicts

Once the sizing was understood, the next problem was finding actual address ranges.

For pod_cidr and svc_cidr, the fact that the networks are internal does not make overlap irrelevant.

Imagine that NetEye needs to monitor a server reachable through a VPN, and that server has an address falling inside the configured pod_cidr.

When Kubernetes installs routing for the Pod network, traffic destined for that address may be treated as traffic for the Kubernetes network rather than being sent toward the VPN.

The same type of problem can occur with svc_cidr.

So the pre-upgrade address inventory needs to cover more than directly connected datacenter networks. It should also include the address spaces NetEye needs to reach through routed networks, remote sites and VPNs.

This does not mean that a Pod or Service CIDR must be globally unique throughout an organization. Those internal ranges can be reused in isolated Kubernetes clusters when there is no need for direct communication with the overlapping addresses.

The practical question is whether that NetEye installation needs to reach them.

service_loadbalancer_cidr needs stricter treatment. Its addresses participate in the real trusted Layer 2 network, so the pool must be available there and must not collide with addresses already in use.

Before performing any live test, we therefore checked the proposed address plan itself.

The three candidate CIDRs were validated for correct alignment and mutual non-overlap. We then inspected all three nodes to make sure that no addresses from the proposed ranges were already configured and that no explicit routes conflicted with them.

Only after those checks did we move on to the LoadBalancer network itself.

Testing the LoadBalancer Network Before the Upgrade

At this point Kubernetes was not yet present: the cluster was still running NetEye 4.48.

That was useful rather than limiting, because it forced us to define exactly what we wanted to validate.

We could not test Kubernetes LoadBalancer behavior.

We could test whether the datacenter network would support the Layer 2 assumptions required by the future LoadBalancer network.

The test was performed on all three nodes and was deliberately temporary.

First, we inspected the trusted interface and the routing configuration on each node. We also checked that the proposed ranges were not already present.

The routing tables were then inspected for overlapping routes. The test used the existing system routing data rather than assuming that an apparently unused RFC1918 range was actually free.

For example, the check included:

ip -4 route show table all

Before assigning any test address, Duplicate Address Detection was performed on one candidate IP per node using arping.

The test followed the same pattern as:

arping -D -q -c 3 -w 3 -I TRUSTED_INTERFACE TEST_IP

Only after no duplicate use was detected for the candidate addresses during the test were temporary addresses from the proposed service_loadbalancer_cidr added to the trusted interface.

Using anonymized addresses, the setup was equivalent to:

node-a: 172.22.9.11/24
node-b: 172.22.9.12/24
node-c: 172.22.9.13/24

All three addresses were placed on the same existing trusted interface that already carried the cluster’s private network.

Linux then installed the expected directly connected route for the new subnet on every node.

The important part came next: full-mesh communication.

The test did not only check node A to node B. Every source/destination combination was exercised:

A to B
A to C
B to A
B to C
C to A
C to B

For each direction we checked routing, ICMP connectivity and ARP neighbor resolution.

All ping tests completed with 0% packet loss, and ARP resolution showed the expected MAC address of the destination node.

This was important because successful routed IP communication alone would not have answered the architectural question. The LoadBalancer design depends on the nodes sharing the required Layer 2 environment, so direct ARP behavior was the more relevant evidence.

After the test, all temporary addresses were removed and the nodes were checked again to make sure that no test configuration remained.

The result was not a permanent network change. It was a controlled pre-upgrade validation of the existing infrastructure.

What We Proved and What We Deliberately Did Not

The test answered the question that had started the investigation.

The proposed LoadBalancer subnet could be made available on the existing trusted Layer 2 infrastructure of all three nodes. Each node could use an address from that subnet on the same trusted interface already in use, the nodes could communicate directly at Layer 2, and no additional operating-system network interface was required in this environment.

It also showed that no duplicate use was detected for the candidate addresses during the test and that the proposed CIDRs did not conflict with routes configured on the nodes.

That was enough to confirm that the datacenter assumptions behind the planned service_loadbalancer_cidr were sound.

But there is an equally important list of things that the test did not prove.

The cluster was still running NetEye 4.48, so there was no Kubernetes environment in which to test actual Pod or Service allocation.

The test did not validate:

  • allocation of real LoadBalancer IPs by Kubernetes;
  • the actual Cilium LoadBalancer IP pool;
  • Cilium Layer 2 announcement policies;
  • failover of a LoadBalancer VIP between nodes;
  • Kubernetes Service behavior;
  • Pod networking;
  • or the success of the NetEye 4.49 upgrade itself.

For pod_cidr and svc_cidr, the pre-upgrade checks could verify that the proposed ranges were correctly formed, mutually consistent and free from visible operating-system routing conflicts. They could not simulate the address allocation that would occur once Kubernetes was installed.

That boundary is worth keeping explicit.

We did not test Kubernetes before Kubernetes existed.

We validated the datacenter conditions that the future Kubernetes LoadBalancer network would depend on.

That distinction is the main lesson I would carry into similar NetEye 4.49 upgrade planning.

The three Kubernetes CIDRs should not be treated as three interchangeable network requests. Two of them primarily require careful logical address planning. The third, service_loadbalancer_cidr, creates a concrete dependency on the trusted Layer 2 infrastructure.

Once that difference is understood, the preparation becomes much more precise: size each range according to its actual role, eliminate routing conflicts, determine where the LoadBalancer subnet will live, and validate that Layer 2 design before the upgrade window begins.

Daniel Vedovato

Daniel Vedovato

I'm a NOC Engineer at Würth IT Italy, where I work on critical infrastructure monitoring and automation. Before joining Würth IT, I spent nearly seven years managing ICT infrastructure at an international airport. This experience gave me a solid grounding in high-availability systems and the kind of monitoring that actually matters when things go wrong at 3 AM. My day-to-day revolves around Icinga, NetEye, and making monitoring pipelines smarter and less noisy. I'm also deeply interested in the practical side of running AI infrastructure on-premises and integrating it into existing observability stacks.

Author

Daniel Vedovato

I'm a NOC Engineer at Würth IT Italy, where I work on critical infrastructure monitoring and automation. Before joining Würth IT, I spent nearly seven years managing ICT infrastructure at an international airport. This experience gave me a solid grounding in high-availability systems and the kind of monitoring that actually matters when things go wrong at 3 AM. My day-to-day revolves around Icinga, NetEye, and making monitoring pipelines smarter and less noisy. I'm also deeply interested in the practical side of running AI infrastructure on-premises and integrating it into existing observability stacks.

Leave a Reply

Your email address will not be published. Required fields are marked *

Archive