This episode runs Keepalived in container and VM environments: Docker with host networking, the Kubernetes DaemonSet pattern with hostNetwork, network namespace and VIP allocation concerns, and a container-based HAProxy plus Keepalived stack example.

Containerization changes how we run services, and Keepalived isn't immune to it. But one fact is non-negotiable: VRRP and virtual IPs work in the host's network namespace. Episode 17 explains how to run Keepalived correctly in Docker and Kubernetes, plus the traps that make containerized configurations fail silently.
You'll understand why --network host is mandatory in Docker, how the DaemonSet pattern with hostNetwork makes Keepalived available on every Kubernetes node, and how to assemble a fully containerized HAProxy plus Keepalived stack.
A default container uses its own isolated network namespace. Inside it, Keepalived can't install a VIP on a host interface, can't send VRRP multicast to the real network, and other nodes will never hear it. The consequence: every node thinks it is MASTER and the VIP is never really available.
Run the Keepalived container in host mode so it shares the host's network stack:
docker run -d \
--name keepalived \
--network host \
--cap-add NET_ADMIN \
--cap-add NET_RAW \
-v /etc/keepalived/keepalived.conf:/etc/keepalived/keepalived.conf:ro \
osixia/keepalived:2.2.7The --network host option makes the container use the host's network namespace, while --cap-add NET_ADMIN grants permission to install VIPs on interfaces. Without both, Keepalived inside a container won't work.
Keepalived needs access to raw sockets for VRRP and interface operations for installing VIPs. NET_ADMIN and NET_RAW are the minimum capabilities required. Don't use --privileged without a reason; specific capabilities are safer.
In Kubernetes, a Keepalived Pod must exist on every node that wants to join the HA. The right pattern is a DaemonSet with hostNetwork: true:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: keepalived
namespace: network
spec:
selector:
matchLabels:
app: keepalived
template:
metadata:
labels:
app: keepalived
spec:
hostNetwork: true
tolerations:
- operator: Exists
containers:
- name: keepalived
image: osixia/keepalived:2.2.7
securityContext:
capabilities:
add: ["NET_ADMIN", "NET_RAW"]
volumeMounts:
- name: config
mountPath: /etc/keepalived/keepalived.conf
subPath: keepalived.conf
volumes:
- name: config
configMap:
name: keepalived-confighostNetwork: true makes the Pod share the host's network namespace, so VIPs can be installed on node interfaces. tolerations ensures the Pod is also scheduled on control-plane nodes if needed, and the ConfigMap holds keepalived.conf.
A DaemonSet schedules on all nodes by default. If you only want HA on a specific group of nodes, restrict it with nodeSelector or affinity so only the nodes that are part of the virtual router receive the Pod.
A VIP is a host-level resource. Make sure no two controllers try to install the same VIP on one node. In Kubernetes, ensure the DaemonSet only runs on allowed nodes and use consistent priority and virtual_router_id values across nodes.
If you run LVS inside the Keepalived container, note that kube-proxy on the host also uses IPVS. Overlapping IPVS tables can interfere with each other. To avoid conflicts, run LVS on only one controller, or separate the Kubernetes service use case from Keepalived LVS.
A common architecture: one HAProxy container as the load balancer, one Keepalived container keeping the VIP and monitoring HAProxy. Both run with --network host on each node:
docker run -d --name haproxy --network host -v /etc/haproxy:/usr/local/etc/haproxy:ro haproxy:3.0
docker run -d --name keepalived --network host \
--cap-add NET_ADMIN --cap-add NET_RAW \
-v /etc/keepalived/keepalived.conf:/etc/keepalived/keepalived.conf:ro \
osixia/keepalived:2.2.7The haproxy container receives traffic, and the keepalived container keeps the VIP on the node whose HAProxy is healthy. The vrrp_script health check inside Keepalived makes sure the VIP doesn't stay on a node with a dead HAProxy.
Because the containers share the network namespace, verification works exactly like bare metal:
ip -brief addr show
sudo journalctl -u docker | grep -i keepalivedThe ip -brief addr show output shows the VIP on the host interface, and container logs can be viewed via docker log. Failover behavior stays visible on the network, no matter that the service runs inside containers.
Episode 17 brings Keepalived into the modern world: Docker with --network host and the right capabilities, the DaemonSet pattern with hostNetwork in Kubernetes, and a fully containerized HAProxy plus Keepalived stack without losing the original VRRP behavior.
Key takeaways:
--network host and NET_ADMIN plus NET_RAW in Docker.hostNetwork: true runs Keepalived on every node.In episode 18 next, we cover disaster recovery and backup strategies — backing up configuration and restoring state, failback policy and its timing, and handling split-brain and partitioned network scenarios.