diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..78fd378 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +**/*.sw* diff --git a/demo.md b/demo.md new file mode 100644 index 0000000..71607ab --- /dev/null +++ b/demo.md @@ -0,0 +1,494 @@ +# Mini-omschrijving voice platform + + * 3 hardware LXD hosts, met tig geheugen en tig CPU + * verspreid over 3 lokaties + * alle applicaties draaien in LXD containers op deze hosts + * naasts deze hosts nog een paar SBC clusters, die zorgen + voor goede en veilige interconnectie met externe partijen + (onze uplink naar het KPN netwerk en alle connecties met + de klantapparatuur / softphones) + * puppet beheert een stuk van de LXD host configuratie + * Ansible beheert andere stukken van de LXD host configuratie, + plus alle LXD containers in volledigheid (dus geen 2 kapiteins + op 1 schip, maar een strakke verdeling in taken) + +Het op te lossen vraagstuk voor Ansible was vooral: hoe beheren +we de LXD containers die op de 3 hardware nodes staan eenvoudig +vanuit 1 Ansible omgeving? + +Taken van Ansible: + + * Nieuwe LXD containers optrekken indien nodig (one-shot runs) + * Alle LXD containers en LXD hosts configureren (one-shot runs) + * Onderhoudstaken op regelmatige basis (periodieke runs in cron) + + +Installatie VM's voor de demo +============================= + +- 2 VM's: sidn-demo-01, sidn-demo-02 +- virtual machine met NAT netwerk: 192.168.56.0/24, gateway/DNS 192.168.56.1 +- Ubuntu 18.04 LTS + +Na installatie: + + sidn-demo-0X# apt update && apt upgrade -y + + +LXD snap versie installeren +=========================== + +Standaard gebruikt 18.04 een apt-package voor LXD. +Deze is prima bruikbaar, maar voor een meer up-to-date feature set +is het beter om de snap installatie te gebruiken. Snap is op dit moment +de aanbevolen method voor het draaien van LXD. + + sidn-demo-0X# snap refresh + sidn-demo-0X# snap install lxd + sidn-demo-0X# lxd.migrate ("no" voor automatisch verwijderen LXD) + sidn-demo-0X# apt remove --purge lxd lxd-client (want zo zie ik wel hoe ver deze is) + + +LXD initialiseren +================= + +Voor deze demo: + + sidn-demo-0X# lxd init + > clustering: no + > storage pool: yes, default, dir + > connect to MAAS: no + > network bridge: no + > available over the network: yes, all interfaces, port 8443, password + +Op productie doen we het (uiteraard) anders: + + - ZFS als filesystem + - "Available over network" alleen op een private space mgmt VLAN + + +Netwerk volledig op basis van LXD host bridges +============================================== + +Belangrijkste keuze qua netwerk: elk netwerk interface in de LXD host +is ondergebracht in een bridge interface. Voordeel is dat elke LXD +container daarmee "ingeplugd" kan worden op alle ontsloten netwerken. +Twee LXD containers op twee verschillende hosts die in eenzelfde +bridge netwerk zitten, kunnen simpel op layer 2 bij elkaar. + +** Dit lijkt dus op hoe je het met hardware switches zou regelen** + +Daarom wordt tijdens lxd init niet automatisch een bridge aangemaakt. +Je kunt natuurlijk de standaard lxdbr0 bridge maken en gebruiken, +maar dat netwerk is alleen voor intern gebruik binnen de host. +In een multi-host setup zou je netwerk-trucs moeten uithalen om +te zorgen dat hosts bij elkaar kunnen komen. + +Netplan-config op productie ziet er ongeveer zo uit: + + network: + version: 2 + ethernets: + eno1: {} # management network (untagged) + eno2: {} # SIP network (SIP signalling & services, tagged) + eno3: {} # public interface (untagged) + vlans: + # SIP core: proxy & SBC signalling + vlan.6 + id: 6 + link: eno2 + # SIP applications (voicemail, mediaserver, class5 services) + vlan.9 + id: 9 + link: eno2 + bridges: + br-mgmt: + dhcp4: no + dhcp6: no + interfaces: ["eno1"] + addresses: ["172.17.4.10/24"] + br-public: + dhcp4: no + dhcp6: no + interfaces: ["eno3"] + gateway4: 194.109.16.129 + addresses: ["194.109.16.132/26"] + nameservers: + addresses: ["194.109.6.66", "194.109.9.99"] + br-sipcore: + dhcp4: no + dhcp6: no + interfaces: ["vlan.6"] + addresses: ["10.160.64.132/24"] + br-sipapp: + dhcp4: no + dhcp6: no + interfaces: ["vlan.9"] + addresses: ["10.116.1.132/24"] + +Met een dergelijke setup is het heel eenvoudig om de LXD containers +beschikbaar te maken binnen bepaalde netwerksegmenten. De containers kunnen +een of meer netwerk interfaces krijgen, die verbonden kunnen worden met de +benodigde netwerken. Dat zien er dan bijvoorbeeld zo uit (afwijkende +bridge-namen ivm de ruimte): + + GATEWAY + | + | + +-------------------------+------+----------public--+ + | | | + | +-------------------------+----------SIP------------+ + | | | | | | + | | +-------------------------+---mgmt------------------+ + | | | | | | | | | + | | | | | | | | | + +---O------O------O----+ +---O------O------O----+ +---O------O------O----+ + | eno3 eno2 eno1 | | eno3 eno2 eno1 | | eno3 eno2 eno1 | + | | | | | | | | | | | | | | | + | | | | | | | | | | | | | | | + | br3 br2 br1 | | br3 br2 br1 | | br3 br2 br1 | + | | | \ | | | | | | | | | | + | | | | | | | \ | | | | | | + | CONTAINER1 | | | | `--CONTAINER3 | | | CONTAINER4 | + | | | | | | | | | + | CONTAINER2 | | | | CONTAINER5 | + | | | | | | + +----------------------+ +----------------------+ +----------------------+ + LXD Host 1 LXD Host 2 LXD Host 3 + + +Voor de demo gebruiken we een simpeler opzet: + + network: + version: 2 + ethernets: + enp1s0: {} + bridges: + br-demo: + dhcp4: no + dhcp6: no + interfaces: ["enp1s0"] + addresses: ["192.168.56.150/24"] # of 151 voor sidn-demo-02 + gateway4: "192.168.56.1" + nameservers: + addresses: ["192.168.56.1"] + +Dus maar 1 bridge en het "fysieke" interface enp1s0 van de VM zit +"ingeplugd" in deze bridge. In een plaatje: + + KVM host + 192.168.56.1 (gateway + DHCP + DNS) + | + | + +------192.168.56.0/24----+ + | | + +------O---------------+ +------O---------------+ + | enp1s0 | | enp1s0 | + | | | | | | + | +---O------------+ | | +---O------------+ | + | | br-demo | | | | br-demo | | + | | 192.168.56.150 | | | | 192.168.56.151 | | + | +--O---O---------+ | | +--O--O----------+ | + | | | | | | | | + | | CONTAINER2 | | | CONTAINER4 | + | | | | | | + | CONTAINER1 | | CONTAINER3 | + | | | | + +----------------------+ +----------------------+ + KVM guest: sidn-demo-01 KVM guest: sidn-demo-02 + + +Netwerkinterfaces op LXD containers +=================================== + +Met bovenstaande setup is het dus mogelijk om een LXD container netwerk +interfaces te geven die "ingeplugd" worden in een of meer van de br-* bridge +interfaces. Een SIPproxy server bijvoorbeeld, krijgt drie netwerk interfaces +in drie verschillende bridges: + + - br-mgmt: voor host management, o.a. Ansible aansturing + - br-public: op een SIPproxy voor SSH toegang en OS updates + - br-sipcore: voor SIP signalling verkeer richting SBC's + +Om op een container eenvoudig het doel voor de verschillende interfaces te +herkennen, wordt in de naamgeving de bridge-naamgeving gevolgd. Een interface +dat in "br-public" wordt geplugd heet bijvoorbeeld "if-public". Veel handiger +dan "eth0" o.i.d. + +Om bij het optrekken van een LXD container de benodigde netwerk interfaces +aan te maken, wordt gebruik gemaakt van profielen. Er zijn verschillende +profielen gemaakt voor verschillende netwerkbehoeftes: + + # lxc profile list + +---------------+---------+ + | NAME | USED BY | + +---------------+---------+ + | ansible-acc | 1 | + +---------------+---------+ + | default | 11 | + +---------------+---------+ + | sipproxy | 2 | + +---------------+---------+ + | voicemail | 2 | + +---------------+---------+ + | voiceservices | 2 | + +---------------+---------+ + +Hier het stuk van het profiel wat voor het bovenstaande SIPproxy netwerk wordt gebruikt. + + productie# lxc profile show sipproxy + config: + ---8<------- + devices: + if-mgmt: + name: if-mgmt + nictype: bridged + parent: br-mgmt + type: nic + if-public: + name: if-public + nictype: bridged + parent: br-public + type: nic + if-sipcore: + name: if-sipcore + nictype: bridged + parent: br-sipcore + type: nic + ---8<------- + + +Noot: +Voor het voice platform is dit een handige setup. Uiteraard kan elke mogelijk +setup worden gemaakt op basis van de behoefte. Als de behoefte alleen maar +een lokaal werkende bridge met private IP space was, dan zou ik het geheel nog +steeds wel handmatig inrichten zoals hierboven, alleen dan met een loopback +bridge met een naam als "br-local". + + +Voorbeeldprofiel voor de demo +============================= + +Op basis van de gevolgde lxd init methode, is er een default profiel aangemaakt +voor LXD. Deze is heel erg basaal, omdat we geen netwerk hebben geconfigureerd: + + sidn-demo-0X# lxc profile show default + config: {} + description: Default LXD profile + devices: + root: + path: / + pool: default + type: disk + + name: default + used_by: [] + +Het beheer van profielen regelen we primair vanuit Ansible, maar op dit punt +van de demo maak ik met de hand een profiel aan. + + sidn-demo-0X# lxc profile create demo + sidn-demo-0X# lxc profile edit demo + + config: + user.user-data: | + # cloud-config + package_upgrade: true + packages: + - python3 + timezone: Europe/Amsterdam + description: SIDN demo profile + devices: + if-demo: + name: if-demo + nictype: bridged + parent: br-demo + type: nic + root: + path: / + pool: default + type: disk + + sidn-demo-0X# lxc profile show demo + +In deze config zijn wat cloud-init statements toegevoegd om te laten zien dat +cloud-init te gebruiken is in een profiel. De installatie van Python is handig, +omdat daarmee de container klaar is voor Ansible. Echter, in het voice platform +wordt dit niet zo gedaan. Daar worden wat bootstrapping Ansible recipes gebruikt +om Python op een vers systeem te krijgen. Voordeel is dat de Ansible-methode +ook voor oudere versies van Ubuntu en voor niet cloud-init images te gebruiken is. + +Noot: +In de praktijk hebben wij tot op heden alleen maar timezone en netwerkconfiguratie +gepusht met de cloud-init configuratie. En zelfs de netwerkconfguratie slechts +deels, omdat deze met de cloud-init van Ubuntu 14.04 nog niet mogelijk was. + + +Geen LXD clustering +=================== + +Het klinkt heel goed: LXD clustering. Functioneel heb ik er echter nog +weinig nuttigs in gevonden voor onze setup. Bovendien heb ik op clustersystemen +regelmatig problemen gezien met het goed werkend houden van het cluster, +door het uit sync raken van de quorum database bijvoorbeeld. + +Een cluster zorgt er voornamelijk voor dat je een aantal LXD hosts aan elkaar +koppelt, die onderling gaan uitwisselen welke containers er op de hosts draaien. +Daarna krijg je met bijvoorbeeld "lxc list" geen inzicht in de containers die +op de lokale host draaien, maar inzicht in alle containers die op alle hosts +draaien. + +Voordat clustering bestond in LXD liepen wel al wel tegen het probleem aan +wat clustering probeert op te lossen: containers verspreid over meerdere hosts. +Onze aanpak: + + - De LXD daemon kan luisteren op het netwerk (zoals hierboven aangezet) + - Je kunt vanuit de ene LXD host een andere LXD host als "remote" toevoegen + onder een bepaalde naam. + - Vanaf dan kunnen lxc commando's de naam van de remote gebruiken om + operaties op de andere host te doen. + - We hebben alle LXD hosts op deze manier kruislings gekoppeld, zodat vanuit + elke host elke andere host aangesproken kan worden. + +Zorg eerst dat alle LXD hosts remote access actief hebben, mocht dat nog +niet geconfigureerd zijn vanuit lxd init. Doe het volgende op elke host: + + sidn-demo-0X# lxc config set core.https_address [::]:8443 + sidn-demo-0X# lxc config set core.trust_password SuperGeheimGoedWachtwoordHorseStaple + +Nu kunnen de remotes op elke LXD host worden aangemaakt. +Merk op dat we ook voor de lokale LXD daemon een remote aanmaken. +Dat maakt een aantal zaken vanuit Ansible een stuk simpeler. +Als wachtwoord gebruiken we uiteraard het bovenstaande wachtwoord. + + sidn-demo-0X# lxc remote add --accept-certificate sidn-demo-01 192.168.56.150 + sidn-demo-0X# lxc remote add --accept-certificate sidn-demo-02 192.168.56.151 + +Vanaf nu kun je vanaf elk van de twee LXD hosts commando's uitvoeren +op alle LXD hosts, bijv: + + sidn-demo-0X# lxc list -cns sidn-demo-01: + sidn-demo-0X# lxc list -cns sidn-demo-02: + sidn-demo-0X# lxc launch ubuntu:18.04 sidn-demo-02:test + + +Een eerste container: Ansible management host +============================================= + +De Ansible management host is een container op het voice platform zelf. Vanwege de +kip/ei problematiek en het feit dat deze container niet steeds opnieuw gebouwd +gaat worden, bootstrappen we deze container met de hand. + +De handigste manier voor de netwerkconfiguratie van deze container is gebruik +maken van een user.network-config. + + sidn-demo-01# vi /tmp/config + + version: 1 + config: + - type: physical + name: if-demo + subnets: + - type: static + address: 192.168.56.160 + netmask: 255.255.255.0 + gateway: 192.168.56.1 + dns_nameservers: [192.168.56.1] # zodat dezelfde resolving als de KVM host wordt gebruikt + +Bouw de container op en start hem: + + sidn-demo-01# H=ansible + sidn-demo-01# lxc init --storage default --no-profiles ubuntu:18.04 $H + sidn-demo-01# lxc config device add $H if-demo nic name=if-demo nictype=bridged parent=br-demo + sidn-demo-01# lxc config set $H volatile.if-demo.hwaddr 00:16:3e:00:00:a0 # mainly for VirtualBox + sidn-demo-01# lxc config set $H user.network-config - < /tmp/config + + sidn-demo-01# lxc config show $H + sidn-demo-01# lxc start $H + sidn-demo-01# lxc exec $H bash + + ansible# apt update && apt upgrade -y && apt autoclean -y && apt autoremove -y + +Noot: +Voor deze setup zou ook het eerder aangemaakte "demo" profiel gebruikt kunnen +worden. Echter, op het voice platform doen we het op deze manier, omdat we +de profielen vanuit Ansible opzetten en het benodigde profiel daarom niet +noodzakelijkerwijs al bestaat op de LXD host. + +Op de container is nu te zien dat het layer 2 netwerk bereikbaar is +vanuit de container: + + ansible# ip a (laat zien dat er nu een if-demo interface bestaat) + ansible# ping 192.168.56.150 (een ping naar de eigen LXD host) + ansible# ping 192.168.56.151 (een ping naar de andere LXD host) + + +Connectie Ansible -> managed hosts +================================== + +Even een uitstapje naar de manier waarop we vanuit Ansible verbinding +gaan maken naar de LXD hosts en de LXD containers, voor het uitvoeren +van de nodige commando's. + +In Ansible zit support voor het gebruik van lxc in plaats van ssh voor +het verbinden met de te configureren hosts. Aanvankelijk zijn we daar +100% voor gegaan, maar helaas bleek dat dit een behoorlijke impact op +de snelheid heeft. Met een SSH koppeling, kan de SSH verbinding open +worden gehouden en kunnen commando's in rap tempo's naar een host worden +gestuurd. De lxc connector _doet dit helemaal niet_. Voor elk commando +wordt een nieuwe connectie opgezet. + +Om de zaken te versnellen, gebruiken we nu een hybride setup: + + - Management van de LXD hosts wordt volledig met SSH gedaan vanuit + de Ansible container. + + - Het bootstrappen van nieuwe containers wordt gedaan door met SSH + naar een LXD host te gaan (delegate), en vervolgens worden van + daaruit (met de hierboven geconfigureerde remotes) met lxc + connecties de containers opgetrokken en geconfigureerd tot het + niveau dat de Ansible container er met SSH bij kan. + + - Het verder configureren van containers wordt volledig met SSH + gedaan, direct vanuit de Ansible container. + + +Ansible SSH toegang Ansible -> LXD hosts +============================================ + +Om de LXD hosts te kunnen beheren met SSH, is het nodig dat er een SSH key +wordt gegenereerd en dat deze naar de hosts wordt gekopieerd. + + ansible# ssh-keygen -b 2048 -N '' -f /root/.ssh/id_rsa + + sidn-demo-0X# mkdir -p /root/.ssh + sidn-demo-0X# chmod 700 /root/.ssh + sidn-demo-0X# touch /root/.ssh/authorized_keys + sidn-demo-0X# chmod 600 /root/.ssh/authorized_keys + sidn-demo-0X# lxc exec sidn-demo-01:ansible cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys + +Hierna moet het volgende werken: + + ansible# ssh 192.168.56.150 touch .hushlogin + ansible# ssh 192.168.56.151 touch .hushlogin + + +Installatie van de Ansible software +=================================== + +De basis infrastructuur staat. Nu kan de benodigde software op de +Ansible host worden geïnstalleerd. +Op het voiceplatform wordt overal gebruik gemaakt van Python3 voor Ansible. + + ansible# apt install -y python3 python3-pip + ansible# pip3 install ansible + +The Ansible configuration is managed in a git repository. Go get! + + ansible# apt install -y git + ansible# REPO=https://git.makaay.nl/mauricem/sidn-lxd-ansible-demo.git + ansible# git clone $REPO /etc/ansible + + + +