LVS and HAProxy

[topology]

1.      For LVS-NAT

 

2.      For LVS-DR

 

3.      For HAProxy

 

[test-lvs-nat-rr.py]

#!/usr/bin/env python

from mininet.net import Containernet

from mininet.cli import CLI

from mininet.link import Link,TCLink,Intf

from mininet.log import setLogLevel

from mininet.node import Docker

from time import sleep

 

if '__main__' == __name__:

  setLogLevel('info')

  net = Containernet(link=TCLink)

  h1 = net.addHost('h1',ip="10.0.1.1/24")

  r = net.addHost('r')

  h2 = net.addDocker('h2', mac = '00:00:00:00:02:02', ip="10.0.2.2/24", dimage="apache-php-mysql:v7",cpu_period=50000, cpu_quota=1000)

  h3 = net.addDocker('h3', mac = '00:00:00:00:03:03', ip="10.0.3.3/24", dimage="apache-php-mysql:v7",cpu_period=50000, cpu_quota=1000)

  net.addLink(h1, r, cls=TCLink, bw=10)

  net.addLink(h2, r, cls=TCLink, bw=10)

  net.addLink(h3, r, cls=TCLink, bw=10)

  net.start()

  h1,h2,h3,r=net.get('h1','h2','h3','r')

  r.cmd("ifconfig r-eth0 0")

  r.cmd("ifconfig r-eth1 0")

  r.cmd("ifconfig r-eth2 0")

  r.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward")

  r.cmd("ip addr add 10.0.1.254/24 brd + dev r-eth0")

  r.cmd("ip addr add 10.0.2.254/24 brd + dev r-eth1")

  r.cmd("ip addr add 10.0.3.254/24 brd + dev r-eth2")

  r.cmd("iptables -t nat -A POSTROUTING -s 10.0.2.0/24 -o r-eth0  -j MASQUERADE")

  r.cmd("iptables -t nat -A POSTROUTING -s 10.0.3.0/24 -o r-eth0  -j MASQUERADE")

  r.cmd("ipvsadm -A -t 10.0.1.254:80 -s rr")

  r.cmd("ipvsadm -a -t 10.0.1.254:80 -r 10.0.2.2:80 -m")

  r.cmd("ipvsadm -a -t 10.0.1.254:80 -r 10.0.3.3:80 -m")

  h1.cmd("ip route add default via 10.0.1.254")

  h2.cmd("ip route del default")

  h2.cmd("ip route add default via 10.0.2.254")

  h2.cmd("cd /var/www/html; echo h2 > a.htm ; python -m SimpleHTTPServer 80 &")

  h3.cmd("ip route del default")

  h3.cmd("ip route add default via 10.0.3.254")

  h3.cmd("cd /var/www/html; echo h3 > a.htm ; python -m SimpleHTTPServer 80 &")  

  CLI(net)

  net.stop()

 

[test-lvs-nat-wrr.py]

#!/usr/bin/env python

from mininet.net import Containernet

from mininet.cli import CLI

from mininet.link import Link,TCLink,Intf

from mininet.log import setLogLevel

from mininet.node import Docker

from time import sleep

 

if '__main__' == __name__:

  setLogLevel('info')

  net = Containernet(link=TCLink)

  h1 = net.addHost('h1',ip="10.0.1.1/24")

  r = net.addHost('r')

  h2 = net.addDocker('h2', mac = '00:00:00:00:02:02', ip="10.0.2.2/24", dimage="apache-php-mysql:v7",cpu_period=50000, cpu_quota=1000)

  h3 = net.addDocker('h3', mac = '00:00:00:00:03:03', ip="10.0.3.3/24", dimage="apache-php-mysql:v7",cpu_period=50000, cpu_quota=1000)

  net.addLink(h1, r, cls=TCLink, bw=10)

  net.addLink(h2, r, cls=TCLink, bw=10)

  net.addLink(h3, r, cls=TCLink, bw=10)

  net.start()

  h1,h2,h3,r=net.get('h1','h2','h3','r')

  r.cmd("ifconfig r-eth0 0")

  r.cmd("ifconfig r-eth1 0")

  r.cmd("ifconfig r-eth2 0")

  r.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward")

  r.cmd("ip addr add 10.0.1.254/24 brd + dev r-eth0")

  r.cmd("ip addr add 10.0.2.254/24 brd + dev r-eth1")

  r.cmd("ip addr add 10.0.3.254/24 brd + dev r-eth2")

  r.cmd("iptables -t nat -A POSTROUTING -s 10.0.2.0/24 -o r-eth0  -j MASQUERADE")

  r.cmd("iptables -t nat -A POSTROUTING -s 10.0.3.0/24 -o r-eth0  -j MASQUERADE")

  r.cmd("ipvsadm -A -t 10.0.1.254:80 -s wrr")

  r.cmd("ipvsadm -a -t 10.0.1.254:80 -r 10.0.2.2:80 -m -w 1")

  r.cmd("ipvsadm -a -t 10.0.1.254:80 -r 10.0.3.3:80 -m -w 2")

  h1.cmd("ip route add default via 10.0.1.254")

  h2.cmd("ip route del default")

  h2.cmd("ip route add default via 10.0.2.254")

  h2.cmd("cd /var/www/html; echo h2 > a.htm ; python -m SimpleHTTPServer 80 &")

  h3.cmd("ip route del default")

  h3.cmd("ip route add default via 10.0.3.254")

  h3.cmd("cd /var/www/html; echo h3 > a.htm ; python -m SimpleHTTPServer 80 &")  

  CLI(net)

  net.stop()

 

 

[test-lvs-dr.py]

#!/usr/bin/env python

from mininet.net import Containernet

from mininet.cli import CLI

from mininet.link import Link,TCLink,Intf

from mininet.log import setLogLevel

from mininet.node import Docker

from time import sleep

 

if '__main__' == __name__:

  setLogLevel('info')

  net = Containernet(link=TCLink)

  h1 = net.addHost('h1',ip="10.0.1.1/24")

  r = net.addHost('r')

  br = net.addHost('br')

  lb = net.addHost('lb', mac = '00:00:00:00:01:01', ip="10.0.2.1/24")

  h2 = net.addDocker('h2', mac = '00:00:00:00:02:02', ip="10.0.2.2/24", dimage="apache-php-mysql:v7",cpu_period=50000, cpu_quota=1000)

  h3 = net.addDocker('h3', mac = '00:00:00:00:03:03', ip="10.0.2.3/24", dimage="apache-php-mysql:v7",cpu_period=50000, cpu_quota=1000)

 

  net.addLink(h1, r, cls=TCLink, bw=10)

  net.addLink(br, r, cls=TCLink, bw=10)

  net.addLink(lb, br, cls=TCLink, bw=10)

  net.addLink(h2, br, cls=TCLink, bw=10)    

  net.addLink(h3, br, cls=TCLink, bw=10)

  net.start()

  h1,h2,h3,lb,br,r=net.get('h1','h2','h3','lb','br','r')

  r.cmd("ifconfig r-eth0 0")

  r.cmd("ifconfig r-eth1 0")

  r.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward")

  r.cmd("ip addr add 10.0.1.254/24 brd + dev r-eth0")

  r.cmd("ip addr add 10.0.2.254/24 brd + dev r-eth1")

  br.cmd("ifconfig br-eth0 0")

  br.cmd("ifconfig br-eth1 0")

  br.cmd("ifconfig br-eth2 0")

  br.cmd("ifconfig br-eth3 0")

  br.cmd("brctl addbr br0")

  br.cmd("brctl addif br0 br-eth0")

  br.cmd("brctl addif br0 br-eth1")

  br.cmd("brctl addif br0 br-eth2")

  br.cmd("brctl addif br0 br-eth3")

  br.cmd("ifconfig br0 up")

 

  lb.cmd("ifconfig lb-eth0:0 10.0.2.100/24")

  lb.cmd("ip route add default via 10.0.2.254")

  #lb.cmd("ipvsadm -A -t 10.0.2.100:80 -s rr")

  #lb.cmd("ipvsadm -a -t 10.0.2.100:80 -r 10.0.2.2 -g")

  #lb.cmd("ipvsadm -a -t 10.0.2.100:80 -r 10.0.2.3 -g")

  

  h1.cmd("ip route add default via 10.0.1.254")

  h2.cmd("ip route del default")

  h2.cmd("ip route add default via 10.0.2.254")

  h2.cmd("cd /var/www/html; echo h2 > a.htm ; python -m SimpleHTTPServer 80 &")

  h2.cmd("echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce")

  h2.cmd("echo 2 > /proc/sys/net/ipv4/conf/h2-eth0/arp_announce")

  h2.cmd("echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore")

  h2.cmd("echo 1 > /proc/sys/net/ipv4/conf/h2-eth0/arp_ignore")

  h2.cmd("ifconfig lo:0 10.0.2.100 netmask 255.255.255.255 broadcast 10.0.2.100")

  h2.cmd("route add -host 10.0.2.100 dev lo:0")

  h3.cmd("ip route del default")

  h3.cmd("ip route add default via 10.0.2.254")

  h3.cmd("cd /var/www/html; echo h3 > a.htm ; python -m SimpleHTTPServer 80 &")

  h3.cmd("echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce")

  h3.cmd("echo 2 > /proc/sys/net/ipv4/conf/h2-eth0/arp_announce")

  h3.cmd("echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore")

  h3.cmd("echo 1 > /proc/sys/net/ipv4/conf/h2-eth0/arp_ignore")

  h3.cmd("ifconfig lo:0 10.0.2.100 netmask 255.255.255.255 broadcast 10.0.2.100")

  h3.cmd("route add -host 10.0.2.100 dev lo:0")

     

  CLI(net)

  net.stop()

 

 

[test-haproxy.py]

#!/usr/bin/env python

from mininet.net import Containernet

from mininet.cli import CLI

from mininet.link import Link,TCLink,Intf

from mininet.log import setLogLevel

from mininet.node import Docker

from time import sleep

from datetime import datetime

import time

 

 

if '__main__' == __name__:

  setLogLevel('info')

  net = Containernet (link=TCLink)

  h1 = net.addHost('h1',ip="10.0.1.1/24")

  r = net.addHost('r')

  h2 = net.addDocker('h2', mac = '00:00:00:00:02:02', ip="10.0.2.2/24", dimage="apache-php-mysql:v7",cpu_period=50000, cpu_quota=1000)

  h3 = net.addDocker('h3', mac = '00:00:00:00:03:03', ip="10.0.3.3/24", dimage="apache-php-mysql:v7",cpu_period=50000, cpu_quota=1000)

 

  Link(h1, r)

  Link(r, h2)

  Link(r, h3)

 

  net.build()

  h1,h2,h3,r,=net.get('h1','h2','h3','r')

  r.cmd("ifconfig r-eth0 0")

  r.cmd("ifconfig r-eth1 0")

  r.cmd("ifconfig r-eth2 0")

 

  r.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward")

  r.cmd("ip addr add 10.0.1.254/24 brd + dev r-eth0")

  r.cmd("ip addr add 10.0.2.254/24 brd + dev r-eth1")

  r.cmd("ip addr add 10.0.3.254/24 brd + dev r-eth2")

 

  r.cmd("iptables -t nat -A POSTROUTING -s 10.0.2.0/24 -o r-eth0  -j MASQUERADE")

  r.cmd("iptables -t nat -A POSTROUTING -s 10.0.3.0/24 -o r-eth0  -j MASQUERADE")

 

  h1.cmd("ip route add default via 10.0.1.254")

  h2.cmd("ip route del default")

  h2.cmd("ip route add default via 10.0.2.254")

  h2.cmd("cd /var/www/html; echo h2 > a.htm ; python -m SimpleHTTPServer 80 &")

  h3.cmd("ip route del default")

  h3.cmd("ip route add default via 10.0.3.254")

  h3.cmd("cd /var/www/html; echo h3 > a.htm ; python -m SimpleHTTPServer 80 &")

 

  CLI(net)

  net.stop()

 

 

[haproxy.cfg]

listen test

    bind 10.0.1.254:80

    mode tcp

    balance static-rr

    balance roundrobin

    server web1 10.0.2.2:80 check weight 1 check inter 1s

    server web2 10.0.3.3:80 check weight 1 check inter 1s

 

[Execution]

For LVS-NAT-RR (We can see that h1 gets the web pages from h3 or h2 in a round-robin way.)

 

For LVS-NAT-WRR (We can see that h1 gets the web pages from h3 or h2 in a weighted round-robin way. The ratio for h2:h3 is 1:2.)

 

Open another terminal to log into h3. Terminate the web service

 

Go back to mininet terminal to get the webpage from h1. We can see some executions of curl program fail. Because lvs itself does not have health check function. (LVS needs “keepalived” to do health check job.)

 

For LVS-DR

 

For HAProxy

 

Open another terminal to log into h3. Terminate the web service. We can see only the web page can be obtained from h2. No curl program fail.

 

[References]

https://blog.51cto.com/lansgg/1229421

 

Dr. Chih-Heng Ke (smallko@gmail.com)

Department of Computer Science and Information Engineering,

National Quemoy University, Kinmen, Taiwan.