diff --git a/README.md b/README.md index bc6e3ae..cf47714 100644 --- a/README.md +++ b/README.md @@ -1 +1,672 @@ -# SIDN LXD / Ansible demo +# Onderwerpen van de demo +* Mini-omschrijving XS4ALL voice platform +* Waarom LXD? +* Doel van de demo: LXD + Ansible + Galera cluster +* Installatie VM's voor de demo +* Netwerktopologie +* LXD clustering +* De Ansible container +* Ansible-vault voor opslag secrets +* Dynamische inventory +* Playbook roles structuur and handige aliases +* Container bootstrapping vanuit Ansible +* Installatie van het Galera cluster +* Rolling upgrade Galera cluster + +# Mini-omschrijving XS4ALL voice platform + + * een aantal hardware LXD hosts, met tig geheugen en tig CPU + * verspreid over meerdere lokaties + * alle applicaties draaien in LXD containers op deze hosts + * naasts deze hosts zijn er 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) + +Configuration management is een hybride setup: + + * 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) + +De op te lossen vraagstukken voor Ansible waren vooral: + + * Hoe kunnen we geautomatiseerd LXD containers optrekken? + * Hoe beheren we het OS op al die LXD containers vanuit 1 Ansible omgeving? + * Hoe kunnen we development en acceptatie handig inrichten? + +Verschillende soorten inzet van Ansible: + + * Nieuwe LXD containers optrekken indien nodig (one-shot runs) + * Configuratiemanagement LXD containers en LXD hosts (one-shot runs) + * Onderhoudstaken op regelmatige basis (periodieke runs in cron) + +# Waarom LXD? +* Het platform bestaat uit heel veel verschillende applicaties +* Allemaal in het verleden gebouwd als Ubuntu hosts (hardware en VM's) +* Te veel niet gebruikte resources, containerization was een logische keuze +* Veel van de applicaties hebben ook een veelheid aan scheduled jobs en support scripts +* Statisch netwerk, omdat SBC's geen dynamische config kennen +* Daardoor ook geen hippe autoscaling behoefte +* Migratie naar LXD binnen XS4ALL was strak tijdgebonden (gekoppeld aan einde Edutel) + +Doordat de beschikbare tijd gelimiteerd was en LXD de mogelijkheid bood om de +bestaande omgeving vrijwel 1-op-1 na te bouwen op basis van LXD systeemcontainers, +was de keuze voor virtualisatie snel gemaakt. + +Het platform omzetten naar bijvoorbeeld Docker was ongetwijfeld mogelijk geweest, +maar dat zou heel veel extra werk hebben opgeleverd en voor extra complexiteit +op de netwerklaag hebben gezorgd. + +Jammer? Nee! Met LXD en Ansible hebben we een mooi evenwicht bereikt tussen de +bekende cattle en pets analogie. Het voice platform heeft diverse pets in zich, +maar die kunnen zonder blikken of blozen naar de slachtbank. + +# 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 + +#### Upgrade na installatie + +```text +sidn-demo-0X# apt update && apt upgrade -y +``` + +#### LXD snap-versie installeren ipv apt-versie + +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) +``` +Om te zorgen dat alle tooling lxc goed kan vinden: +``` +sidn-demo-0X# ln -s /snap/bin/lxc /usr/bin/lxc +``` + +#### LXD initialiseren + +Voor deze demo: + +```text +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 het management VLAN + + +# Netwerktoplogie +Belangrijke keuze qua netwerk: elk netwerk interface in de LXD host +is ondergebracht in een bridge interface. + + * Elke container kan simpel op elk benodigd netwerk "ingeplugd" worden + door een interface van de container aan de bridge toe te voegen. + * Elke container is daarmee ook direct exposed op dat netwerk. + * Containers kunnen ook containers op een andere LXD host bereiken, + mits het layer 2 netwerk doorgetrokken is uiteraard. + * Containers kunnen eenvoudig naar een andere LXD host worden verplaatst, + mits de nieuwe host dezelfde netwerkbridges heeft geconfigureerd. + +__Praktisch gezien lijkt dit op hoe je het netwerk met hardware hosts en +switches zou regelen__ + +#### Netwerk bridges op de LXD hosts + +Tijdens lxd init maken we niet de standaard lxdbr0 bridge aan. +Die bridge is alleen voor intern gebruik binnen de host. Wanneer +je services beschikbaar wilt stellen aan andere systemen, dan moeten +daar trucs voor uitgehaald worden (vgl. met Docker/Traefik). + +In plaats daarvan worden de bridges door onszelf geconfigureerd in Netplan. +Netplan-config op productie ziet er ongeveer zo uit: + +```yaml +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): + +```text + 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 ... n +``` + +Hier is bijvoorbeeld CONTAINER1 aangesloten op het public en het SIP netwerk, terwijl +CONTAINER2 aangesloten is op SIP en mgmt. CONTAINER4 is alleen aangesloten op het +SIP netwerk, en kan via dat netwerk op layer 2 CONTAINER1 en CONTAINER2 ook bereiken. + + +__Voor de demo gebruiken we een iets simpeler opzet:__ + +```yaml +network: + version: 2 + ethernets: + enp1s0: {} + enp6s0: {} + bridges: + br-public: + dhcp4: no + dhcp6: no + interfaces: ["enp1s0"] + addresses: ["192.168.56.150/24"] # en 151 op de andere host + gateway4: "192.168.56.1" + nameservers: + addresses: ["8.8.8.8", "9.9.9.9"] + br-demo: + dhcp4: no + dhcp6: no + interfaces: ["enp6s0"] + addresses: ["10.0.0.150/24"] # en 151 op de andere host +``` + +Bridge br-public is aangesloten op een bridge die NAT netwerk verzorgt op +de VM host en daarmee gebruikt kan worden om via NAT naar het internet te +komen. Bridge br-demo zit aangesloten op een host-only bridge op de VM host +en heeft dus de rol van een losse, niet-connected netwerkswitch. + +In een plaatje: + +```text + KVM host + 192.168.56.1 (gateway + DHCP + DNS) + | + | + +------192.168.56.0/24-----------+ + | | + | private | + | +----bridge----+ | + | | 10.0.0.0/24 | | + | | | | + +------O------O--------+ +--O----------O--------+ + | enp1s0 enp6s0 | | enp6s0 enp1s0 | + | | | | | | | | + | br-public br-demo | | br-demo br-public | + | | \ / | | | | \ / | | + | | \/ | | | | \/ | | + | | /\ | | | | /\ | | + | ansible-01 \ | | | galera-02 \ | | + | | | | | \ | | + | galera-01 | | galera-03 | + +----------------------+ +----------------------+ + KVM guest: sidn-demo-01 KVM guest: sidn-demo-02 +``` + + +#### Netwerk interfaces op de 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-\* bridges. +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 binnen een container het herkennen van de netwerk interfaces zo simpel +mogelijk te houden, wordt de naamgeving van de bridges gevolg. Bijvoorbeeld +een interface dat in bridge "br-aap" wordt geplugd, heet dan "if-aap". +Veel handiger dan "eth0" o.i.d. + +Op de SIPproxy zul je dan ook de interfaces if-mgmt, if-public en if-sipcore +terug kunnen vinden. + +__Interfaces vanuit LXD profielen__ + +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: + +```text +# 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 netwerk van de hierboven beschreven +SIPproxy container wordt gebruikt: + +```text +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 duidelijk naam als "br-local" of "br-private". + + +#### Aanmaken LXD profile voor de demo + +Op basis van de gevolgde lxd init methode, is er al een default profiel aangemaakt +voor LXD. Deze is heel erg basaal, omdat we geen netwerk bridge hebben geconfigureerd: + +```text +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. + +```text +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-public: + name: if-public + nictype: bridged + parent: br-public + type: nic + 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 demodeze met de cloud-init van Ubuntu 14.04 nog niet mogelijk was. + + + +# LXD clustering +Of beter gezegd: __geen__ LXD clustering. + +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" niet alleen inzicht in de containers +die op de lokale host draaien, maar ook in alle containers die op alle cluster +hosts draaien. +demo +Het klinkt heel goed: LXD clustering. Functioneel heb ik er echter nog +weinig heil in gevonden voor onze setup. Bovendien heb ik op clustersystemen +regelmatig problemen gezien met het goed werkend houden van het cluster, +door bijvoorbeeld het uit sync raken van de quorum database (gebaseerd op dqlite, +wat een distributed sqlite database is.) + +Voordat clustering bestond in LXD liepen wel al wel tegen een probleem aan +dat clustering probeert op te lossen: het werken met containers, verspreid +over meerdere LXD hosts. + +Onze aanpak: + + * De LXD daemon laten luisteren op het netwerk (zoals bij lxd init al 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. + +Om dit op te zetten, zorg dan 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, omdat we dan +vanaf elke willekeurige host bijv `lxc list sidn-demo-01:` kunnen doen en niet +op die bestreffende host `lxc list local:` hoeven te gebruiken +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 +``` + +__Ja, maar, hoe wordt dit gebruikt dan?__ + +Het belangrijkste gebruik hiervan, is dat er vanuit cron op elke LXD host een job draait +die een `lxc list` uitvoert op alle remotes. Daarmee wordt een lijst gemaakt waarin +de containers en hun LXD hosts staan. Vanuit die lijst wordt een bestand gemaakt, met +daarin een serie bash aliases voor `lxc exec : bash`. + +Als ik wil inloggen op bijvoorbeeld de container `tel-prd-sipproxy-02`, dan kan ik na +het sourcen van het gegenereerde aliassen bestand simpelweg `tel-prd-sipproxy-02` als +commando uitvoeren op een willekeurige LXD host, waarna ik binnenval op een shell op +die container. + + +# De Ansible container +De Ansible management host is een container op het voice platform zelf. Vanwege de +kip/ei problematiek en het feit dat deze container toch niet steeds opnieuw gebouwd +gaat worden, bootstrappen we deze container met de hand. Hier kan natuurlijk ook een +playbook van worden gemaakt, maar vooralsnog is het minder werk om het zo te doen. + +De handigste manier voor het leveren van de netwerkconfiguratie van deze container, +is gebruikmaken van een `user.network-config` in de container configuratie. + +```text +sidn-demo-01# vi /tmp/config + +version: 1 +config: +- type: physical + name: if-public + subnets: + - type: static + address: 192.168.56.160 + netmask: 255.255.255.0 + gateway: 192.168.56.1 + dns_nameservers: [192.168.56.1] +- type: physical + name: if-demo + subnets: + - type: static + address: 10.0.0.160 + netmask: 255.255.255.0 +``` + +Bouw de container op en start hem: + +```text +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 +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 +``` + +Opmerkingen: + +* 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. + +* Er wordt een hard MAC-adres gezet. Dat is vooral nodig als je gebruik maakt + van VirtualBox voor het maken van de VM's. De bridge in VirtualBox kan + problemen geven wanneer je eenzelfde host met hetzelfde IP-adres maar een + nieuw MAC-adres opnieuw optrekt. In andere omgeving zou dat MAC-adres + ook weggelaten kunnen worden. + + +Op de container is nu te zien dat het layer 2 netwerk via de netwerk bridges +ontsloten 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) +ansible# ping 10.0.0.150 (een ping naar de eigen LXD host) +ansible# ping 10.0.0.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. + +__Cool, lxc support binnen Ansible!__ + +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, door op de Ansible host alle LXD hosts als remotes +toe te voegen en Ansible voor elk uit te voeren commando o een container +lxc te laten gebruken. + +__meh__ + +Helaas bleek dat dit een behoorlijke impact op de snelheid had. 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 daarom inmiddels een hybride setup: + + * Management van de LXD hosts wordt volledig met SSH gedaan vanuit + de Ansible container (dit is de standaard methode voor Ansible). + + * Het bootstrappen van nieuwe containers en het configureren van het + netwerk van containers worden gedaan door met SSH naar een LXD host + te gaan (middels Ansible delegate). Vervolgens worden van daaruit met + lxc commando's (met name `lxc exec` en `lxc file`) 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 de standaard + SSH methode gedaan, direct vanuit de Ansible container. + +Het mooie aan deze opzet, is dat we: + + * Containers uit het niet automatisch kunnen bootstrappen. + * Kapotte netwerkconfiguratie ook altijd weer kunnen repareren, omdat + de `lxc` commando's geen containernetwerk nodig hebben. + * Missende SSH keys voor Ansible toegang kunnen plaatsen. + * Voor de bulk van de configuratie commando's snel via SSH kunnen versturen. + + +#### 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 LXD hosts wordt gekopieerd. + +```text +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: + +```bash +ansible# ssh 10.0.0.150 touch .hushlogin +ansible# ssh 10.0.0.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. + +```text +ansible# apt install -y python3 python3-pip +ansible# pip3 install ansible +``` + +De Ansible configuratie staat in een git repository. Go get! + +```text +ansible# apt install -y git +ansible# REPO=https://git.makaay.nl/mauricem/sidn-lxd-ansible-demo.git +ansible# git clone $REPO /etc/ansible +``` + +De configuratie van Ansible zelf is redelijk eenvoudig: + +```text +ansible# vi /root/.ansible.cfg + +[defaults] +inventory = /etc/ansible/environments/demo/hosts +vault_password_file = /root/.ansible-vault-password +jinja2_extensions = jinja2.ext.do + +[ssh_connection] +pipelining = True +``` + +De vault_password_file wordt gebruikt als password file voor Ansible vault. +Met vault is het mogelijk om geheime informatie (normaliter: wachtwoorden) +op te slaan in gecrypte vorm. Het te gebruiken symmetrische wachtwoord is +opgeslagen in de password file. Bijvoorbeeld: + +```text +ansible# echo "My very secret 1337 super passw0rd##" \ + > /root/.ansible-vault-password +ansible# chmod 600 /root/.ansible-vault-password +``` + diff --git a/demo.md b/demo.md deleted file mode 100644 index 7d11865..0000000 --- a/demo.md +++ /dev/null @@ -1,671 +0,0 @@ -# Onderwerpen van de demo -* Mini-omschrijving XS4ALL voice platform -* Waarom LXD? -* Doel van de demo: LXD + Ansible + Galera cluster -* Installatie VM's voor de demo -* Netwerktopologie -* LXD clustering -* De Ansible container -* Ansible-vault voor opslag secrets -* Dynamische inventory -* Container bootstrapping vanuit Ansible -* Installatie van het Galera cluster -* Rolling upgrade Galera cluster - -# Mini-omschrijving XS4ALL voice platform - - * een aantal hardware LXD hosts, met tig geheugen en tig CPU - * verspreid over meerdere lokaties - * alle applicaties draaien in LXD containers op deze hosts - * naasts deze hosts zijn er 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) - -Configuration management is een hybride setup: - - * 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) - -De op te lossen vraagstukken voor Ansible waren vooral: - - * Hoe kunnen we geautomatiseerd LXD containers optrekken? - * Hoe beheren we het OS op al die LXD containers vanuit 1 Ansible omgeving? - * Hoe kunnen we development en acceptatie handig inrichten? - -Verschillende soorten inzet van Ansible: - - * Nieuwe LXD containers optrekken indien nodig (one-shot runs) - * Configuratiemanagement LXD containers en LXD hosts (one-shot runs) - * Onderhoudstaken op regelmatige basis (periodieke runs in cron) - -# Waarom LXD? -* Het platform bestaat uit heel veel verschillende applicaties -* Allemaal in het verleden gebouwd als Ubuntu hosts (hardware en VM's) -* Te veel niet gebruikte resources, containerization was een logische keuze -* Veel van de applicaties hebben ook een veelheid aan scheduled jobs en support scripts -* Statisch netwerk, omdat SBC's geen dynamische config kennen -* Daardoor ook geen hippe autoscaling behoefte -* Migratie naar LXD binnen XS4ALL was strak tijdgebonden (gekoppeld aan einde Edutel) - -Doordat de beschikbare tijd gelimiteerd was en LXD de mogelijkheid bood om de -bestaande omgeving vrijwel 1-op-1 na te bouwen op basis van LXD systeemcontainers, -was de keuze voor virtualisatie snel gemaakt. - -Het platform omzetten naar bijvoorbeeld Docker was ongetwijfeld mogelijk geweest, -maar dat zou heel veel extra werk hebben opgeleverd en voor extra complexiteit -op de netwerklaag hebben gezorgd. - -Jammer? Nee! Met LXD en Ansible hebben we een mooi evenwicht bereikt tussen de -bekende cattle en pets analogie. Het voice platform heeft diverse pets in zich, -maar die kunnen zonder blikken of blozen naar de slachtbank. - -# 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 - -#### Upgrade na installatie - -```text -sidn-demo-0X# apt update && apt upgrade -y -``` - -#### LXD snap-versie installeren ipv apt-versie - -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) -``` -Om te zorgen dat alle tooling lxc goed kan vinden: -``` -sidn-demo-0X# ln -s /snap/bin/lxc /usr/bin/lxc -``` - -#### LXD initialiseren - -Voor deze demo: - -```text -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 het management VLAN - - -# Netwerktoplogie -Belangrijke keuze qua netwerk: elk netwerk interface in de LXD host -is ondergebracht in een bridge interface. - - * Elke container kan simpel op elk benodigd netwerk "ingeplugd" worden - door een interface van de container aan de bridge toe te voegen. - * Elke container is daarmee ook direct exposed op dat netwerk. - * Containers kunnen ook containers op een andere LXD host bereiken, - mits het layer 2 netwerk doorgetrokken is uiteraard. - * Containers kunnen eenvoudig naar een andere LXD host worden verplaatst, - mits de nieuwe host dezelfde netwerkbridges heeft geconfigureerd. - -__Praktisch gezien lijkt dit op hoe je het netwerk met hardware hosts en -switches zou regelen__ - -#### Netwerk bridges op de LXD hosts - -Tijdens lxd init maken we niet de standaard lxdbr0 bridge aan. -Die bridge is alleen voor intern gebruik binnen de host. Wanneer -je services beschikbaar wilt stellen aan andere systemen, dan moeten -daar trucs voor uitgehaald worden (vgl. met Docker/Traefik). - -In plaats daarvan worden de bridges door onszelf geconfigureerd in Netplan. -Netplan-config op productie ziet er ongeveer zo uit: - -```yaml -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): - -```text - 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 ... n -``` - -Hier is bijvoorbeeld CONTAINER1 aangesloten op het public en het SIP netwerk, terwijl -CONTAINER2 aangesloten is op SIP en mgmt. CONTAINER4 is alleen aangesloten op het -SIP netwerk, en kan via dat netwerk op layer 2 CONTAINER1 en CONTAINER2 ook bereiken. - - -__Voor de demo gebruiken we een iets simpeler opzet:__ - -```yaml -network: - version: 2 - ethernets: - enp1s0: {} - enp6s0: {} - bridges: - br-public: - dhcp4: no - dhcp6: no - interfaces: ["enp1s0"] - addresses: ["192.168.56.150/24"] # en 151 op de andere host - gateway4: "192.168.56.1" - nameservers: - addresses: ["8.8.8.8", "9.9.9.9"] - br-demo: - dhcp4: no - dhcp6: no - interfaces: ["enp6s0"] - addresses: ["10.0.0.150/24"] # en 151 op de andere host -``` - -Bridge br-public is aangesloten op een bridge die NAT netwerk verzorgt op -de VM host en daarmee gebruikt kan worden om via NAT naar het internet te -komen. Bridge br-demo zit aangesloten op een host-only bridge op de VM host -en heeft dus de rol van een losse, niet-connected netwerkswitch. - -In een plaatje: - -```text - KVM host - 192.168.56.1 (gateway + DHCP + DNS) - | - | - +------192.168.56.0/24-----------+ - | | - | private | - | +----bridge----+ | - | | 10.0.0.0/24 | | - | | | | - +------O------O--------+ +--O----------O--------+ - | enp1s0 enp6s0 | | enp6s0 enp1s0 | - | | | | | | | | - | br-public br-demo | | br-demo br-public | - | | \ / | | | | \ / | | - | | \/ | | | | \/ | | - | | /\ | | | | /\ | | - | ansible-01 \ | | | galera-02 \ | | - | | | | | \ | | - | galera-01 | | galera-03 | - +----------------------+ +----------------------+ - KVM guest: sidn-demo-01 KVM guest: sidn-demo-02 -``` - - -#### Netwerk interfaces op de 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-\* bridges. -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 binnen een container het herkennen van de netwerk interfaces zo simpel -mogelijk te houden, wordt de naamgeving van de bridges gevolg. Bijvoorbeeld -een interface dat in bridge "br-aap" wordt geplugd, heet dan "if-aap". -Veel handiger dan "eth0" o.i.d. - -Op de SIPproxy zul je dan ook de interfaces if-mgmt, if-public en if-sipcore -terug kunnen vinden. - -__Interfaces vanuit LXD profielen__ - -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: - -```text -# 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 netwerk van de hierboven beschreven -SIPproxy container wordt gebruikt: - -```text -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 duidelijk naam als "br-local" of "br-private". - - -#### Aanmaken LXD profile voor de demo - -Op basis van de gevolgde lxd init methode, is er al een default profiel aangemaakt -voor LXD. Deze is heel erg basaal, omdat we geen netwerk bridge hebben geconfigureerd: - -```text -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. - -```text -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-public: - name: if-public - nictype: bridged - parent: br-public - type: nic - 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 demodeze met de cloud-init van Ubuntu 14.04 nog niet mogelijk was. - - - -# LXD clustering -Of beter gezegd: __geen__ LXD clustering. - -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" niet alleen inzicht in de containers -die op de lokale host draaien, maar ook in alle containers die op alle cluster -hosts draaien. -demo -Het klinkt heel goed: LXD clustering. Functioneel heb ik er echter nog -weinig heil in gevonden voor onze setup. Bovendien heb ik op clustersystemen -regelmatig problemen gezien met het goed werkend houden van het cluster, -door bijvoorbeeld het uit sync raken van de quorum database (gebaseerd op dqlite, -wat een distributed sqlite database is.) - -Voordat clustering bestond in LXD liepen wel al wel tegen een probleem aan -dat clustering probeert op te lossen: het werken met containers, verspreid -over meerdere LXD hosts. - -Onze aanpak: - - * De LXD daemon laten luisteren op het netwerk (zoals bij lxd init al 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. - -Om dit op te zetten, zorg dan 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, omdat we dan -vanaf elke willekeurige host bijv `lxc list sidn-demo-01:` kunnen doen en niet -op die bestreffende host `lxc list local:` hoeven te gebruiken -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 -``` - -__Ja, maar, hoe wordt dit gebruikt dan?__ - -Het belangrijkste gebruik hiervan, is dat er vanuit cron op elke LXD host een job draait -die een `lxc list` uitvoert op alle remotes. Daarmee wordt een lijst gemaakt waarin -de containers en hun LXD hosts staan. Vanuit die lijst wordt een bestand gemaakt, met -daarin een serie bash aliases voor `lxc exec : bash`. - -Als ik wil inloggen op bijvoorbeeld de container `tel-prd-sipproxy-02`, dan kan ik na -het sourcen van het gegenereerde aliassen bestand simpelweg `tel-prd-sipproxy-02` als -commando uitvoeren op een willekeurige LXD host, waarna ik binnenval op een shell op -die container. - - -# De Ansible container -De Ansible management host is een container op het voice platform zelf. Vanwege de -kip/ei problematiek en het feit dat deze container toch niet steeds opnieuw gebouwd -gaat worden, bootstrappen we deze container met de hand. Hier kan natuurlijk ook een -playbook van worden gemaakt, maar vooralsnog is het minder werk om het zo te doen. - -De handigste manier voor het leveren van de netwerkconfiguratie van deze container, -is gebruikmaken van een `user.network-config` in de container configuratie. - -```text -sidn-demo-01# vi /tmp/config - -version: 1 -config: -- type: physical - name: if-public - subnets: - - type: static - address: 192.168.56.160 - netmask: 255.255.255.0 - gateway: 192.168.56.1 - dns_nameservers: [192.168.56.1] -- type: physical - name: if-demo - subnets: - - type: static - address: 10.0.0.160 - netmask: 255.255.255.0 -``` - -Bouw de container op en start hem: - -```text -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 -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 -``` - -Opmerkingen: - -* 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. - -* Er wordt een hard MAC-adres gezet. Dat is vooral nodig als je gebruik maakt - van VirtualBox voor het maken van de VM's. De bridge in VirtualBox kan - problemen geven wanneer je eenzelfde host met hetzelfde IP-adres maar een - nieuw MAC-adres opnieuw optrekt. In andere omgeving zou dat MAC-adres - ook weggelaten kunnen worden. - - -Op de container is nu te zien dat het layer 2 netwerk via de netwerk bridges -ontsloten 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) -ansible# ping 10.0.0.150 (een ping naar de eigen LXD host) -ansible# ping 10.0.0.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. - -__Cool, lxc support binnen Ansible!__ - -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, door op de Ansible host alle LXD hosts als remotes -toe te voegen en Ansible voor elk uit te voeren commando o een container -lxc te laten gebruken. - -__meh__ - -Helaas bleek dat dit een behoorlijke impact op de snelheid had. 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 daarom inmiddels een hybride setup: - - * Management van de LXD hosts wordt volledig met SSH gedaan vanuit - de Ansible container (dit is de standaard methode voor Ansible). - - * Het bootstrappen van nieuwe containers en het configureren van het - netwerk van containers worden gedaan door met SSH naar een LXD host - te gaan (middels Ansible delegate). Vervolgens worden van daaruit met - lxc commando's (met name `lxc exec` en `lxc file`) 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 de standaard - SSH methode gedaan, direct vanuit de Ansible container. - -Het mooie aan deze opzet, is dat we: - - * Containers uit het niet automatisch kunnen bootstrappen. - * Kapotte netwerkconfiguratie ook altijd weer kunnen repareren, omdat - de `lxc` commando's geen containernetwerk nodig hebben. - * Missende SSH keys voor Ansible toegang kunnen plaatsen. - * Voor de bulk van de configuratie commando's snel via SSH kunnen versturen. - - -#### 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 LXD hosts wordt gekopieerd. - -```text -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: - -```bash -ansible# ssh 10.0.0.150 touch .hushlogin -ansible# ssh 10.0.0.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. - -```text -ansible# apt install -y python3 python3-pip -ansible# pip3 install ansible -``` - -De Ansible configuratie staat in een git repository. Go get! - -```text -ansible# apt install -y git -ansible# REPO=https://git.makaay.nl/mauricem/sidn-lxd-ansible-demo.git -ansible# git clone $REPO /etc/ansible -``` - -De configuratie van Ansible zelf is redelijk eenvoudig: - -```text -ansible# vi /root/.ansible.cfg - -[defaults] -inventory = /etc/ansible/environments/demo/hosts -vault_password_file = /root/.ansible-vault-password -jinja2_extensions = jinja2.ext.do - -[ssh_connection] -pipelining = True -``` - -De vault_password_file wordt gebruikt als password file voor Ansible vault. -Met vault is het mogelijk om geheime informatie (normaliter: wachtwoorden) -op te slaan in gecrypte vorm. Het te gebruiken symmetrische wachtwoord is -opgeslagen in de password file. Bijvoorbeeld: - -```text -ansible# echo "My very secret 1337 super passw0rd##" \ - > /root/.ansible-vault-password -ansible# chmod 600 /root/.ansible-vault-password -``` - diff --git a/roles/lxd_container/tasks/bootstrap-ubuntu14.04.yml b/roles/lxd_container/tasks/bootstrap-ubuntu14.04.yml new file mode 100644 index 0000000..e594f5d --- /dev/null +++ b/roles/lxd_container/tasks/bootstrap-ubuntu14.04.yml @@ -0,0 +1,32 @@ +--- +# In the Ubuntu 14.04 cloud image, cloud-init is supported, but it is an old +# version and network configuration does not seem to work. Therefore, the +# network configuration is handled in a clunky way. + +- name: "Create Ubuntu 14.04 LXD container" + delegate_to: "{{ hostvars[inventory_hostname].lxd_host }}" + lxd_container: + name: "{{ inventory_hostname }}" + state: started + source: + type: image + mode: pull + server: "{{ vars.lxd_image_server }}" + protocol: simplestreams + alias: "{{ vars.lxd_image_name }}" + profiles: + - "{{ vars.lxd_profile }}" + wait_for_ipv4_addresses: True + +- name: "Generate network config for Ubuntu 14.04 LXD container" + delegate_to: "{{ hostvars[inventory_hostname].lxd_host }}" + template: + src: network-interfaces.j2 + dest: /tmp/network-interfaces-{{ inventory_hostname }} + +- name: "Install network config for Ubuntu 14.04 LXD container" + delegate_to: "{{ hostvars[inventory_hostname].lxd_host }}" + shell: >- + lxc file push + /tmp/network-interfaces-{{ inventory_hostname }} + {{ inventory_hostname }}/etc/network/interfaces diff --git a/roles/lxd_container/tasks/bootstrap.yml b/roles/lxd_container/tasks/bootstrap.yml index 63aaa09..528afac 100644 --- a/roles/lxd_container/tasks/bootstrap.yml +++ b/roles/lxd_container/tasks/bootstrap.yml @@ -1,7 +1,13 @@ --- +- include: bootstrap-ubuntu14.04.yml + when: > + inventory_hostname not in lxd_status and + vars.distribution_codename == 'trusty' + - include: bootstrap-other.yml when: > - inventory_hostname not in lxd_status + inventory_hostname not in lxd_status and + vars.distribution_codename != 'trusty' - name: "Set interface MAC addresses" delegate_to: "{{ hostvars[inventory_hostname].lxd_host }}" @@ -12,7 +18,7 @@ with_items: "{{ hostvars[inventory_hostname].network.values() | list }}" when: '"mac_address" in item' -- name: "Set LXD custom configuration parameters" +- name: "Set LXD configuration parameters" delegate_to: "{{ hostvars[inventory_hostname].lxd_host }}" shell: >- lxc config set @@ -26,6 +32,21 @@ - name: boot.autostart.priority value: "{{ hostvars[inventory_hostname].lxd_boot_priority | default(0) }}" +- name: "Make NFS client work in the container" + delegate_to: "{{ hostvars[inventory_hostname].lxd_host }}" + shell: >- + lxc config set + {{ hostvars[inventory_hostname].lxd_host | quote }}:{{ inventory_hostname | quote }} + {{ item.name | quote }} {{ item.value | quote }} + with_items: + - name: "raw.apparmor" + value: "mount fstype=nfs," + - name: "security.privileged" + value: "true" + when: '"nfs_mount" in hostvars[inventory_hostname]' + +- include: hostname.yml + - name: "Stop created LXD container" delegate_to: "{{ hostvars[inventory_hostname].lxd_host }}" lxd_container: