This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Networking Guide

Network layout, firewall and ports

Overview

deploy configures each machine’s network for the cluster: its firewall, its routing rules for cluster traffic, and the kernel network settings. The site setting backplane_network chooses the layout. A second setting, manage_firewall, chooses whether deploy manages the firewall or you do.

LayoutGuideRecommended for
Segregated: a backplane network for traffic between the machines, separate from the public network for clientsConfiguring Segregated NetworksProduction. Cluster traffic is kept off the public network.
Shared: one network for everythingShared Interface SetupMachines with a single network interface.

A backplane is optional, but we recommend one wherever the machines can have a second network. The backplane is the network the cluster machines use to reach each other (east-west traffic). Every machine must be reachable on it, and it should be a separate network from the public one. Setting it to the public network’s range works, but then every host on the public network is trusted for all traffic. It does not have to be reserved for the cluster: other hosts may also be on it, but with the firewall managed they can reach every port on the machines, including the cluster datastore (etcd, 2379-2380/tcp), the Kubernetes API (6443/tcp) and the kubelet (10250/tcp).

Interfaces and Addresses

Every machine needs an IPv4 default route on its public interface, the interface that clients reach it on. The route does not need to lead to the internet: on an isolated network, use your site’s router or any gateway address on that subnet. deploy uses this route to find each machine’s public interface and address, and stops with [ACD-NO-DEFAULT-ROUTE] without one.

From that route, deploy works out each machine’s two addresses:

  • The public interface is the one holding the default route. Its address is the machine’s public address, which clients reach.
  • The cluster address is the address other machines reach it on: its address inside backplane_network when that is set, and otherwise its public address.

Interfaces that are neither the public interface nor the backplane are left as they are.

The cluster also uses two internal address ranges, which must not be in use anywhere on your network:

NetworkDefaultSetting
Pods10.42.0.0/16cluster_pod_cidr
Services10.43.0.0/16cluster_svc_cidr

Firewall

With manage_firewall: true, the default, deploy starts and enables firewalld on every machine and keeps two things as its own:

  • The acd-cluster zone, with target ACCEPT, which trusts all traffic from the cluster: the backplane interface (or, without a backplane, the other machines’ addresses), and the pod and service networks.
  • The acd-public policy, from the public zone to the machine, which opens the ports clients need:
    PortPurpose
    80/tcpHTTP ingress
    443/tcpHTTPS ingress: the GUI, the API, Zitadel and Grafana
    8086/tcpMetrics pushed by the CDN Directors (Vector)

It also places each machine’s public interface in the public zone, on its NetworkManager connection. Before the first run, make sure the public zone allows everything else you need on that interface, SSH included. To check, run firewall-cmd --zone=public --list-all on each machine: ssh should be listed under services, or port 22 under ports.

deploy removes anything in acd-cluster and acd-public that it did not put there. Add your own rules to other zones, such as public: deploy never changes their rules.

Ports Between the Machines

Within the cluster, the machines trust each other for all traffic. When you manage the firewall yourself, the ports the cluster needs between machines are:

PortBetweenPurpose
6443/tcpall machinesKubernetes API, also used by the image registry mirror on every machine
2379-2380/tcpserversCluster datastore (etcd)
8472/udpall machinesPod network (Flannel VXLAN)
10250/tcpall machinesKubelet
5001/tcpall machinesImage registry mirror (Spegel)
9100/tcpall machinesHost metrics (node-exporter)

The pod and service networks must also be in a zone with target ACCEPT.

Kafka Ports

The CDN Directors reach Kafka on these ports, on every machine:

PortPurpose
9092/tcpKafka bootstrap
30000/tcpKafka bootstrap, external
30001/tcp and upOne port per Kafka broker, numbered consecutively: 30001 for the first broker, 30002 for the second, and so on

With the default three brokers, the broker ports are 30001-30003, so the full range is 30000-30003. With more brokers, the range grows by one port per broker: six brokers use 30000-30006. In the rest of this documentation, “30000-30003” means this range for the default three brokers. Widen it if your cluster runs more.

deploy neither opens nor checks these ports, and the host firewall does not filter them: as on any host running containers, traffic that Kubernetes forwards to its services passes before the firewall’s zone rules apply. These ports are reachable from every network that can reach the machines.

Important: Restrict 9092/tcp and the whole 30000 range (30000-30003 with three brokers) to your CDN Directors on your network’s own firewall. The same applies to any other port a Kubernetes service publishes on the machines.

Ingress NodePorts

The ingress service (Traefik) also publishes two NodePorts on every machine, which forward to its HTTP and HTTPS ports, 80 and 443. Kubernetes picks them at installation from 30000-32767, so they differ from one cluster to another, and the host firewall does not filter them, as for the Kafka ports. Find them on a server:

kubectl get service traefik -n kube-system
NAME      TYPE           CLUSTER-IP    EXTERNAL-IP                          PORT(S)                      AGE
traefik   LoadBalancer   10.43.12.34   192.0.2.11,192.0.2.12,192.0.2.13     80:31873/TCP,443:30306/TCP   3d

Here they are 31873 (HTTP) and 30306 (HTTPS). Clients need only 80 and 443: block the two NodePorts on your network’s own firewall.

Managing the Firewall Yourself

Set manage_firewall: false to configure firewalld yourself. deploy then only checks that the ports between the machines and the ports clients need are open in the zone their traffic arrives in, and that the pod and service networks are in a zone with target ACCEPT. It stops before changing anything, and shows the firewall-cmd commands to run, if they are not. Only firewalld is checked: if it is not running, the check is skipped, and your own firewall must allow the same traffic.

To hand the firewall of a running cluster over to yourself, on each machine:

  1. Move the pod and service networks to a zone with target ACCEPT, such as firewalld’s own trusted. For the default ranges:

    for network in 10.42.0.0/16 10.43.0.0/16; do
        firewall-cmd --permanent --zone=acd-cluster --remove-source="$network"
        firewall-cmd --permanent --zone=trusted --add-source="$network"
        firewall-cmd --zone=trusted --change-source="$network"
    done
    
  2. Open the ports in the zone their traffic arrives in, with firewall-cmd --zone=<zone> --add-port=<port>, once with --permanent and once without.

  3. On a machine with a backplane, put the backplane interface in the zone you want: nmcli connection modify <its connection> connection.zone <zone>.

  4. Set manage_firewall: false in group_vars/all.yaml and run deploy.

deploy then empties the acd-cluster zone and the acd-public policy, and moves any interface still in acd-cluster to firewalld’s default zone, with a warning.

Routing

With manage_routes: true, the default, deploy adds lookup main routing rules at priority 50, so that cluster traffic always uses the main routing table, even on machines that use policy routing. On a machine with a backplane, ip rule then shows:

0:	from all lookup local
50:	from 10.42.0.0/16 lookup main proto static
50:	from all to 10.42.0.0/16 lookup main proto static
50:	from 10.43.0.0/16 lookup main proto static
50:	from all to 10.43.0.0/16 lookup main proto static
50:	from all to 10.10.0.0/24 lookup main proto static
32766:	from all lookup main
32767:	from all lookup default

Keep your own rules at other priorities. See manage_routes for how these rules interact with your own.

Managing Routing Yourself

If your own policy routing rules must sit at priority 50 or below, set manage_routes: false and add the cluster’s rules yourself. Add them before you change the setting on a running cluster: deploy then removes every priority-50 rule from the connections it manages.

Every machine needs five lookup main rules:

RuleDefault value
from <cluster_pod_cidr>from 10.42.0.0/16
to <cluster_pod_cidr>to 10.42.0.0/16
from <cluster_svc_cidr>from 10.43.0.0/16
to <cluster_svc_cidr>to 10.43.0.0/16
to <cluster network>backplane_network if set, such as to 10.10.0.0/24. Without a backplane, the subnet of the machine’s public interface, such as to 192.0.2.0/24.

Give them a priority other than 50, and a lower number than any of your own rules that send traffic to another table, such as your from <address> lookup <table> source rules. Store them on the NetworkManager connection of the interface the machines reach each other on: the backplane interface, or the public interface without a backplane. For example, at priority 40 on a backplane connection named eth1 (table 254 is main):

nmcli connection modify eth1 +ipv4.routing-rules "priority 40 from 10.42.0.0/16 table 254"
nmcli connection modify eth1 +ipv4.routing-rules "priority 40 to 10.42.0.0/16 table 254"
nmcli connection modify eth1 +ipv4.routing-rules "priority 40 from 10.43.0.0/16 table 254"
nmcli connection modify eth1 +ipv4.routing-rules "priority 40 to 10.43.0.0/16 table 254"
nmcli connection modify eth1 +ipv4.routing-rules "priority 40 to 10.10.0.0/24 table 254"

Stored rules take effect when the connection is next activated. To activate it now, run nmcli connection up eth1 in a maintenance window: it re-applies the whole connection, and briefly interrupts traffic on that interface. Then check the rules with ip rule show.

Whichever way the rules are managed, deploy checks before changing anything that cluster traffic resolves through the main routing table, and stops with [ACD-ROUTING-CONFLICT], naming the rule in the way, if it does not.

Changes Are Checked

After changing a machine’s network, deploy compares the live state with what it planned: the interface zones, the firewall, the routing rules and the kernel settings. It stops before installing anything on the cluster if they differ. This check cannot be skipped. See the [ACD-VERIFY-...] codes in Installation Troubleshooting.

Boot-Time Network Tools

deploy stores its interface zones and routing rules on the machines’ NetworkManager connections. Tools that rewrite those connections at boot, such as cloud-init or a virtualization platform’s contextualization, can undo them after a reboot: an interface back in the wrong zone, or the priority-50 rules gone. Nothing checks for this between deploy runs.

Disable such regeneration of the network connections on the cluster machines. Where you cannot, run deploy again after a reboot: it puts the settings back, prints Host network changed on <machine>: ... naming what it changed, and carries on.

1 - Shared Interface Setup

One network interface for both cluster and client traffic

Overview

In a shared layout, each machine has a single network: the cluster’s own traffic and client traffic both use the interface holding the default route. This is the simplest layout, for machines with one network interface.

Security note: Cluster traffic shares the public network, so it is not isolated from clients. For production, a segregated backplane is recommended.

Configuration

Leave backplane_network empty in /etc/acd/deploy/group_vars/all.yaml. This is the default:

backplane_network: ""

Each machine’s cluster address is then its public address. The machines may be on one subnet or on routed subnets, as long as each can reach the others’ addresses.

What deploy Sets Up

On each machine, with manage_firewall: true:

  • The public interface is placed in firewalld’s public zone, with the ports clients need opened through the acd-public policy.
  • The other machines’ addresses, and the pod and service networks, are trusted in the acd-cluster zone, which accepts all traffic. Hosts other than the cluster machines get only the ports open in public.
  • Routing rules keep traffic to the pod and service networks, and to the machine’s own subnet, on the main routing table. If your machines are on different subnets and use policy routing, make sure traffic to the other machines’ subnets also uses the main table.

Verification

After deploy, on any machine:

firewall-cmd --get-active-zones
firewall-cmd --zone=acd-cluster --list-sources

The acd-cluster zone lists the pod and service networks (10.42.0.0/16 and 10.43.0.0/16 by default) and the other cluster machines’ addresses, and the public interface is in the public zone.

For the ports the cluster uses, and for managing the firewall yourself, see the Networking Guide.

2 - Configuring Segregated Networks

A private backplane for cluster traffic, separate from the public network

Overview

In a segregated layout, each machine has two networks:

  • A public network, holding the default route, which clients and CDN Directors use to reach the manager.
  • A backplane network, separate from the public network, which carries all traffic between the machines (east-west traffic): the Kubernetes API, the cluster datastore, the pod network and storage replication.

This keeps cluster traffic off the public network, and lets the firewall trust the backplane completely while the public interface opens only the ports clients need. A backplane is optional, but it is the recommended layout for production.

The backplane does not have to be reserved for the cluster machines. Other hosts may be on it too, such as your CDN Directors: it is simply the network the cluster machines use to reach each other.

flowchart LR
    clients[Users and CDN Directors] -->|public network| eth0
    subgraph machine[Each cluster machine]
        eth0[eth0: public zone]
        eth1[eth1: acd-cluster zone]
    end
    eth1 <-->|backplane network| peers[Other cluster machines]

Requirements

  • The backplane is a separate network from the public network.
  • Every machine has exactly one interface with an address in the backplane network, and every machine is reachable from the others on it.
  • The default route is on the public interface, not the backplane.
  • Only hosts you trust are on the backplane. With manage_firewall: true, every host on the backplane can reach every port on every cluster machine, including the cluster datastore (etcd, 2379-2380/tcp), the Kubernetes API (6443/tcp) and the kubelet (10250/tcp), so connect only hosts you trust to it.
  • Both interfaces are managed by NetworkManager, with an active connection.

Configuration

Give the backplane’s address range in /etc/acd/deploy/group_vars/all.yaml, before the first deploy:

backplane_network: "10.10.0.0/24"

Nothing else is needed: no per-machine settings and no firewall commands. deploy finds each machine’s interface in that range and sets up the rest.

Important: backplane_network is locked at the first installation. A cluster cannot be moved on to or off a backplane later without reinstalling it.

What deploy Sets Up

On each machine, with manage_firewall: true:

  • Kubernetes uses the backplane: each machine’s cluster address is its backplane address, the pod network (Flannel) runs over the backplane interface, and the public address is advertised as the machine’s external address.
  • The backplane interface is placed in the acd-cluster zone, which accepts all traffic, together with the pod and service networks.
  • The public interface is placed in firewalld’s public zone, with the ports clients need opened through the acd-public policy.
  • Routing rules keep traffic to the pod, service and backplane networks on the main routing table.

Other interfaces are left as they are.

Verification

After deploy, on any machine:

firewall-cmd --get-active-zones

Expected output:

acd-cluster
  interfaces: eth1
  sources: 10.42.0.0/16 10.43.0.0/16
public
  interfaces: eth0

Check the cluster addresses Kubernetes uses:

grep -E 'node-ip|external|flannel' /etc/rancher/k3s/config.yaml.d/20-acd-node.yaml

Expected output, on manager-1:

node-ip: "10.10.0.11"
node-external-ip: "192.0.2.11"
flannel-iface: "eth1"

And on a server:

kubectl get nodes -o wide

INTERNAL-IP shows each machine’s backplane address, and EXTERNAL-IP its public address.

Problems

CodeCauseFix
[ACD-BACKPLANE-NO-MATCH]No interface on a machine has an address in backplane_network.Fix backplane_network, or the machine’s addresses. Every machine needs an address in it.
[ACD-BACKPLANE-AMBIGUOUS]More than one interface on a machine matches backplane_network.Narrow backplane_network, or set node_ip to the right address on that machine’s line in the inventory.
[ACD-BACKPLANE-SPLIT]The machines’ cluster addresses are not all in one network.Put every machine’s backplane address inside backplane_network.
[ACD-JOIN-UNREACHABLE]A joining machine cannot reach the server over the backplane.Check the backplane’s switching and addressing, and that reverse path filtering does not drop the replies.

For every code, see Installation Troubleshooting.