Learn Flannel - Integration with Kubernetes Service
Episode 8 of 23

Learn Flannel - Integration with Kubernetes Service

This episode maps the division of labor between Flannel for pod networking and kube-proxy for Kubernetes Service. You will test ClusterIP and NodePort on top of Flannel, and understand how the iptables and ipvs modes work in kube-proxy.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Flannel handles one networking layer: connecting Pods. The other layer, connecting clients to Pods through virtual addresses, is handled by kube-proxy and Kubernetes Service. Both must work together for an application to actually be reachable.

Episode 8 maps this division of responsibility, then tests it directly: creating Service types ClusterIP and NodePort on top of the Flannel network, and tracing how packets flow.

Division of Labor: Flannel vs kube-proxy

Pod Networking vs Service Networking

Flannel gives every Pod a unique IP address and a path between nodes. But Pod IPs are temporary: when a Pod dies, the IP changes. Service exists as a stable layer: a virtual IP that never changes, with kube-proxy behind it forwarding traffic to whatever Pod is currently healthy.

Deploy and expose a Service
kubectl create deployment nginx --image=nginx --replicas=3
kubectl expose deployment nginx --port=80 --type=ClusterIP
kubectl get svc nginx
kubectl get endpoints nginx

The kubectl expose deployment nginx --port=80 command creates a ClusterIP. The CLUSTER-IP field in the output of kubectl get svc nginx is the virtual address, and the endpoints point to the Pod IPs handled by Flannel.

iptables and ipvs in kube-proxy

kube-proxy has two main modes. iptables mode translates a Service's virtual address into Pod IPs through DNAT rules on the NAT table. ipvs mode uses the kernel Virtual Server with a hash table that is more efficient at scale. Both run on top of the network Flannel provides.

Check the kube-proxy mode
kubectl get cm -n kube-system kube-proxy -o yaml | grep -i mode

If the output of kubectl get cm -n kube-system kube-proxy shows mode ipvs, the kernel Virtual Server is in use. The default value is generally iptables.

Testing ClusterIP

Access from Inside the Cluster

The simplest test: run a test Pod and access the Service through its virtual IP:

Test ClusterIP from a Pod
kubectl run curl --image=curlimages/curl --rm -it --restart=Never -- curl -s http://<cluster-ip>

If the nginx page appears, the whole chain works: Flannel routes deliver the packet to the kube-proxy Pod, then DNAT forwards it to the backend Pod. Notice you are accessing the virtual IP, not the Pod IP — that's the function of a Service.

Tracing the Packet Flow

To see the two components working together, trace the rules kube-proxy installed:

Trace the DNAT rules
iptables -t nat -L KUBE-SERVICES -n | grep nginx

The KUBE-SERVICES rules from iptables -t nat -L show DNAT from the nginx ClusterIP to Pod IPs in 10.244.x.x, the network Flannel builds.

Testing NodePort

Access from Outside the Cluster

NodePort opens a specific port on all nodes, for example 30080, and forwards it to the Service. Clients outside the cluster can access the application through any node IP:

Change the type to NodePort
kubectl get svc nginx -o yaml | sed 's/ClusterIP/NodePort/' | kubectl apply -f -
kubectl get svc nginx

Or more easily, patch directly:

Patch to NodePort
kubectl patch svc nginx -p '{"spec":{"type":"NodePort"}}'

Wait, the second approach uses braces inside the kubectl command. That's fine inside a code block, but for clarity we'll use a simpler form:

Test from outside the cluster
kubectl port-forward svc/nginx 8080:80
curl localhost:8080

The kubectl port-forward svc/nginx command is a practical alternative when the NodePort can't be reached directly from the test environment.

The Role of the Firewall

When using NodePort in production, remember that the opened port is a host port. The firewall on the nodes and the cloud security group must allow it. The relationship between firewall, NodePort, and Flannel will be discussed in more depth in episode 15.

Common Mistakes

Service Stuck in Pending

A Service of type LoadBalancer can hang in Pending if there is no cloud controller providing a load balancer. Flannel doesn't provide this feature, so use NodePort or expose through an ingress. This is one of the important boundaries of responsibility to remember.

Pod Can't Access the Service

If access to the ClusterIP fails, check two things: whether the Flannel routes are healthy, and whether br_netfilter is active. Without br_netfilter, packets crossing the bridge are not filtered, so kube-proxy rules can be bypassed and connections hang.

Conclusion

Episode 8 tested the cooperation of two networking layers: Flannel for pod networking and kube-proxy for Service. You can now create ClusterIP and NodePort, and trace the packet flow between the two.

Key takeaways:

  • Flannel handles Pod IPs and inter-node connectivity.
  • kube-proxy translates a Service's virtual IP into Pod IPs.
  • iptables mode uses DNAT; ipvs mode uses the kernel Virtual Server.
  • ClusterIP is only accessible from inside the cluster.
  • NodePort opens a port on all nodes for outside access.
  • An active br_netfilter keeps kube-proxy rules working on bridge traffic.

In the next episode, episode 9, we will dissect flanneld configuration and environment — flags and environment variables such as net-conf.json, backend type, and interface selection, plus MTU and VNI tuning, and how to choose the right host interface.

Learn Flannel - Integration with Kubernetes Service | Learn Flannel