HCN

Ok, now lets finally look at the Kubernetes networking bastion: HCN. HCN has a few core objects that we use for the windows kube proxy.

Host Compute Network

An HCN Network is an entity that's used to represent a host compute network and its associated system resources and policies. An HCN network typically can include:

  • A set of metadata (ID, name, type)
  • A virtual switch
  • A host virtual network adapter (acting as a default gateway for the network)
  • A NAT instance (if required by the network type)
  • A set of subnet and MAC pools
  • Any network-wide policies to be applied (for example, ACLs)

Example: Setup of a Network for Pods

Add-HcnNetwork -Network @{
    Name = "calico-network";
    Type = "Overlay";
    NetworkAdapterName = "Ethernet";
    Subnets = @(@{
        IPAddressPrefix = "192.168.0.0/16";
        Policies = @(@{
            Type = "VSID";
            VSID = 4096;
        })
    })
}

Host Compute Endpoint

An HCN Endpoint is an entity that's used to represent an IP endpoint on an HCN network and its associated system resources and policies. An HCN endpoint typically consists of:

  • A set of metadata (ID, name, parent network ID)
  • Its network identity (IP address, MAC address)
  • Any endpoint specific policies to be applied (ACLs, routes)

Lets look at how, hypothetically, you could create a pod network via an HCN Endpoint call:

Example: POD

Add-HcnEndpoint -Endpoint @{
    Name = "calico-endpoint";
    VirtualNetwork = "calico-network";
    IPAddress = "192.168.0.2";
    PrefixLength = 24;
    Policies = @(@{
        Type = "ACL";
        Settings = @{
            Rules = @( @{
                Protocol = 256;
                Action = "Allow";
                Direction = "Out";
                LocalAddresses = "0.0.0.0/0";
                RemoteAddresses = "0.0.0.0/0";
            })
        }
    })
}

Host Compute LoadBalancer

The Kube Proxy uses a custom Loadbalancer API that the HCN defines. You can see that it gets activated if a service has session affinity

353   if flags.isIPv6 {
354     lbFlags |= LoadBalancerFlagsIPv6
355   }
356
357   lbDistributionType := hcn.LoadBalancerDistributionNone
358

Next, we check the sessionAffinity flag below... and CHANGE the lbDistributionType... to distribute VIA source IP. This routes the incoming IP address consistently to the same backend.

359   if flags.sessionAffinity {
360     lbDistributionType = hcn.LoadBalancerDistributionSourceIP
361   }
362
363   loadBalancer := &hcn.HostComputeLoadBalancer{
364     SourceVIP: sourceVip,
365     PortMappings: []hcn.LoadBalancerPortMapping{
366       {
367         Protocol:         uint32(protocol),
368         InternalPort:     internalPort,
369         ExternalPort:     externalPort,
370         DistributionType: lbDistributionType,
371         Flags:            lbPortMappingFlags,
372       },
373     },

An HCN load balancer is an entity that's used to represent a host compute network load balancer. Load balancers allow you to have load balanced host compute network endpoints. So, lets now look at an example of how this would work in a kube proxy. Note the other examples showed how to make pods / networks, which is more of a CNI thing - but the kube proxy, focuses on the loadbalancing part:

# Define the VIP (Virtual IP) of the service and the destination IP of the Pod
$VIP = "10.96.0.10"
$destinationIP = "100.1.2.3"

# Fetch the network 
$network = Get-HnsNetwork | Where-Object { $_.Name -eq "YourNetworkName" } 

# Create a load balancing policy
$policy = @{
    "Type" = "LOAD_BALANCING"
    "IP" = $VIP
    "Protocol" = "TCP"
    "InternalPort" = "YourServicePort"
    "ExternalPort" = "YourServicePort"
    "LoadBalancerDistribution" = "SourceIP"
    "Destinations" = @($destinationIP)
}

# Convert policy to JSON
$policyJSON = $policy | ConvertTo-Json

# Add the policy to the network
Add-HnsLoadBalancer $network.Id $policyJSON

Customizing the loadbalancer: Affinity

Open question... can you program probabilities on the HCN loadbalancers ? Not sure. But, there are some customizations you can do.

Theres a LoadBalancerPortMapping struct in the HNS Api, that allopws you to , via the DistributionType choosed to have biases in loadbalancing, i.e. - have all client IPs go to the same IP (2) - have all traffic of protocol X on client IP Y go to the same IP (1)

The HostComputeLoadBalancer points to a LoadBalancerPortMapping object which has customizabliity.

// LoadBalancerPortMapping is associated with HostComputeLoadBalancer
type *LoadBalancerPortMapping** struct {
    Protocol         uint32                       `json:",omitempty"` // EX: TCP = 6, UDP = 17
    InternalPort     uint16                       `json:",omitempty"`
    ExternalPort     uint16                       `json:",omitempty"`
    DistributionType LoadBalancerDistribution     `json:",omitempty"` // EX: Distribute per connection = 0, distribute traffic of the same protocol per client IP = 1, distribute per client IP = 2
    Flags            LoadBalancerPortMappingFlags `json:",omitempty"`
}

// HostComputeLoadBalancer represents software load balancer.
type HostComputeLoadBalancer struct {
    Id                   string                    `json:"ID,omitempty"`
    HostComputeEndpoints []string                  `json:",omitempty"`
    SourceVIP            string                    `json:",omitempty"`
    FrontendVIPs         []string                  `json:",omitempty"`
    PortMappings         []LoadBalancerPortMapping `json:",omitempty"`
    SchemaVersion        SchemaVersion             `json:",omitempty"`
    Flags                LoadBalancerFlags         `json:",omitempty"` // 0: None, 1: EnableDirectServerReturn
}
// LoadBalancerPortMapping is associated with HostComputeLoadBalancer
type LoadBalancerPortMapping struct {
    Protocol     uint32                       `json:",omitempty"` // EX: TCP = 6, UDP = 17
    InternalPort uint16                       `json:",omitempty"`
    ExternalPort uint16                       `json:",omitempty"`
    Flags        LoadBalancerPortMappingFlags `json:",omitempty"`
    Protocol         uint32                       `json:",omitempty"` // EX: TCP = 6, UDP = 17
    InternalPort     uint16                       `json:",omitempty"`
    ExternalPort     uint16                       `json:",omitempty"`
    DistributionType LoadBalancerDistribution     `json:",omitempty"` // EX: Distribute per connection = 0, distribute traffic of the same protocol per client IP = 1, distribute per client IP = 2
    Flags            LoadBalancerPortMappingFlags `json:",omitempty"`
}