App-Deployment in LXD-Container
Wie LXD grundsaetzlich funktioniert, hatten wir ja im letzten Blog-Beitrag kennengelernt. Jetzt haben wir schon einige Erfahrungen und koennen versuchen, eine Applikation zu installieren. Automatisch.
DIe schlimmste Erfahrung, die ich bislang mit LXD gemacht habe ist die, wenn der ZFS-Pool voll ist. Das Experimentieren mit verschiedenen Images und Snapshots kostet nun mal etwas Festplattenspeicher und wenn der zu schmal berechnet ist, ist er ziemlich schnell aufgebraucht. Wenn dann noch der Speicher der ganzen Festplatte aufgebraucht ist, nimmt das LXD ziemlich uebel. Was man dann noch an Fehler machen kann ist, den LXD-Host neu zu booten (um etwa die Festplatte zu vergroessern). ZFS wird beim Booten versuchen, die Pools zu recovern. Da kein Platz dazu da ist, wird das natuerlich ewig dauern und nichts bringen. Dennoch ist ZFS fuer LXD dringend empfohlen. Eine Anleitung fuer Ubuntu findet sich hier
Sehr schoene Erfahrungen macht man aber mit
Shell
lxc copy c1 c2 |
um einfach mal einen bestehenden Container zu kopieren. Oder
Shell
lxc snapshot --stateful |
um einfach mal einen Snapshot eines laufenden Container anzufertigen, um ihn dann mit
Shell
lxc move c1 zwei: |
auf einen anderen Host zu migrieren. Das hatte am Anfang nicht funktioniert, aber der vermutete Bug war gar keiner. Unter Ubuntu muss nur das Paket linux-image-extra-4.4.0-22-generic installiert sein, weil von dort einige Module verwendet werden
Jetzt wollen wir aber endlich unsere App installieren.Lamp on OpenStack hatte ich ja schon ausprobiert. Kann man das auch als Lamp on Container verwenden? Unter Ubuntu geht das relativ problemlos, nur unter OpenSuSE 13.2 war es ein langer Weg, alle Fehler in den verwendeten Puppet-Modulen und OpenSuSe selbst zu umschiffen.
Entstanden ist dann dieses Install-Script, welches nach dem Starten im Container aufgerufen werden muss,
Shell
#!/bin/sh | |
| |
# add extra repo for monitoring packages | |
zypper addrepo http://download.opensuse.org/repositories/server:monitoring/openSUSE_13.2/server:monitoring.repo | |
zypper --gpg-auto-import-keys refresh | |
| |
# install puppet and git | |
zypper --non-interactive --no-gpg-checks --quiet install puppet vim git | |
| |
# copy git repo | |
rm -rf /etc/puppet/ | |
export GIT_SSL_NO_VERIFY=true | |
git clone -b opensuse-13.2 https://github.com/eumel8/lamp.git /etc/puppet | |
cd /etc/puppet | |
git submodule update --init | |
| |
# install lamp | |
puppet apply /etc/puppet/manifests/site.pp | |
| |
# hotfixes against systemd | |
sed -i 's/PrivateTmp=true/PrivateTmp=false\nNoNewPrivileges=yes/' /etc/systemd/system/httpd.service | |
sed -i 's/PrivateTmp=true/PrivateTmp=false\nNoNewPrivileges=yes/' /etc/systemd/system/multi-user.target.wants/apache2.service | |
systemctl daemon-reload | |
systemctl restart httpd.service | |
| |
echo "done" |
Das Git-Repo wird also runterkopiert und mit puppet apply der LAMP-Stack installiert. Allerdings sind in dem eigenen Branch die meisten Anpassungen fuer opensuse-13.2 drin. Und trotzdem muessen noch Einstellungen am systemd behandelt werden, damit solche haesslichen Fehlermeldungen wie
Failed at step NAMESPACE spawning /usr/sbin/start_apache2: Permission denied
verschwinden.
Auf dem LXD-Host haben wir nur ein paar Kommandos zu betaetigen, um unseren Container zu erstellen und das Deployment anzustossen und unseren Container vom externen Netzwerk erreichbar zu machen.:
Shell
lxc remote add images https://images.linuxcontainers.org/ --public true --protocol=lxd | |
lxc launch images:opensuse/13.2/amd64 s2 | |
lxc file push install.sh s2/ | |
lxc exec s2 -- /install.sh | |
| |
CONTAINER_IP=`lxc info s2 | grep eth0 | head -1 | awk '{print $3}'` | |
iptables -t nat -A POSTROUTING -j MASQUERADE | |
sysctl net.ipv4.ip_forward=1 | |
iptables -t nat -A PREROUTING -p tcp -d 192.168.0.105 --dport 10080 -j DNAT --to-destination ${CONTAINER_IP}:80 |
Voila, unter http://192.168.0.105:10080/icinga sollten wir das Monitoring unserr VM begutachten koennen. Beschrieben etwa auch hier
Zwei Usecases noch zur Ergaenzung.
Vom jetzigen Stand des Containers ein neues Image erstellen:
Shell
lxc snapshot s2 | |
lxc publish s2/snap0 --alias lampsuse |
Den in der Entwicklungsumgebung aufgebauten Container in die Produktionsplattform verschieben:
Shell
lxc remote add prod 5.104.106.106 | |
lxc move s2 prod: |
Oder wie oben schon geliebt:
Shell
lxc remote add prod 5.104.106.106 | |
lxc copy s2 prod: |

Deswegen ist es eine schlechte Idee, die Nutzdaten wie Webcontent und Datenbanken ausserhalb der Container zu lagern und ueber Device-Mapping einzubinden wie in dieser kleinen Studie. Um sich die Flexibiitaet zu bewahren, gehoeren die Daten in die Container und sind somit schnell versandfaehig.

1 Kommentar
Kommentar von: eumel Mitglied

OpenVPN im LXD-Container geht nicht von Hause aus, da man zusaetzliche Netzwerkschnittstellen dafuer benoetigt. Dass macht man mit “lxc profile edit default":
devices:
eth0:
name: eth0
nictype: bridged
parent: lxdbr0
type: nic
tun:
path: /dev/net/tun
type: unix-char
Jetzt kann man mit Tunnel-Devices im Containter arbeiten, bekommt man aber bei “systemctl start openvpn@client.service“
Job for openvpn@client.service failed because the control process exited with error code. See “systemctl status openvpn@client.service” and “journalctl -xe” for details.
Die genaue Fehlermeldung lautet:
Failed to reset devices.list
und hat eigentlich gar nichts mit lxd zutun.
Das openvpn service profile vom systemd moechte hier Prozesslimits setzen, was cgroups vom lxd host nicht erlaubt. Kein Problem, in
/lib/systemd/system/openvpn@.service
kommentieren wir den Eintrag “LimitNPROC=10″ aus und laden die Config neu mit “systemctl daemon-reload”
Jetzt sollte “systemctl start openvpn@client.service” funktionieren.
Die VPN-Verbindung ist nur in diesem Container verfuegbar.
Moechte man die VPN-Verbindung fuer alle Container verfuegbar machen, spart man sich die Prozedur und startet das VPN einfach auf dem LXD-Host. Durch die SNAT-Verbindung sind die Hosts des VPN in allen Containern verfuegbar.