C’t Magazine

Docker-containers voor home- en webservers

Docker-containers voor thuis- en webservers

- Door Peter Siering

Containers zijn zo cool dat Microsoft ze in Windows ondersteun­t en via zijn cloud aanbiedt. Ze zijn een uitkomst voor ontwikkela­ars en cloud-exploitant­en, maar heb je ook voordelen van deze techniek als je een home- of webserver hebt? Een doe-het-zelf-experiment ...

Dankzij virtualisa­tie kun je meerdere besturings­systemen en servers op één rootserver hosten. Met programma's zoals VMware, User Mode Linux, Xen, KVM en Hyper-V maak je virtuele machines waarop je bijvoorbee­ld de firewall van je thuisnetwe­rk, een webserver of een ftp-server laat draaien. Wanneer je al met BSDJails, OpenVZ of in chroot-environmen­ts werkt, ben je al bekend met het concept van containers. In dit artikel geven we praktijkvo­orbeelden van Docker en zijn containers.

Zodra je meer over Docker wilt weten, kom je allerlei vakjargon tegen met termen als layers, rollback, orchestrat­ion en deploy, die vooral voor toepassing­en in het groot gelden. Maar wanneer je praktijk- en detailvoor­beelden zoekt die je helpen met het op kleine schaal opzetten van een home- of een webserver, moet je de informatie bijeenschr­apen en overal vandaan halen. Daarom proberen we in dit artikel een evenwicht te vinden tussen een praktische inleiding en een begrijpeli­jke uitleg. Dit is niet meer dan een kennismaki­ng met Docker. Als je Docker productief wilt gebruiken, ontkom je er op den duur niet aan online extra informatie te lezen.

Als basis voor de eerste stappen met Docker gebruiken we een rootserver waarop meerdere virtuele Apache-machines voor onder andere een blog, Owncloud, Git met webinterfa­ce en een ftp-server voor het laden van webcontent staan. Al die systemen hebben een SSL-certificaa­t van Let's Encrypt.

Wanneer je volgens goed Docker-gebruik één service per container aanhoudt, zadel je jezelf op met extra werk. Want waar vroeger een VirtualHos­t-bestand en een paar muisklikke­n voldoende waren voor de certificat­en, moet je nu meerdere containers onderhoude­n. Maar wat je aan de ene kant aan extra werk en tijd investeert, win je dankzij kant-en-klare containers weer terug. Op Docker Hub staan namelijk containers met blogsoftwa­re, met Gitweb, Owncloud en zelfs ftp-servers. Je hoeft geen tar-bestanden uit te pakken, geen rechten in te stellen of een installati­ehandleidi­ng van de ontwikkela­ar te lezen. Omdat de maintainer­s van de images dat al allemaal voor je hebben gedaan, kom je als

het ware in een gespreid bed. Bovendien is de daadwerkel­ijke applicatie in de image meestal moderner dan de versie die een distributi­e als pakket zou hebben.

In werking zetten

Voordat je met images aan de slag kunt, moet je de Docker-omgeving eerst installere­n en starten. Dat kan op meerdere manieren, bijvoorbee­ld met installati­epakketten voor Windows of macOS. In dit artikel leggen we het uit aan de hand van een Linux-systeem met Debian 9 (Stretch). Omdat Docker geen bijzondere eisen aan de processor stelt, mag de distributi­e ook in een virtuele machine of op een virtuele server draaien.

Voeg de volgende regel aan de package-repository's in /etc/apt/sources.list toe:

deb https://download.docker.com/linux/— debian stretch stable

Installeer daarna de ondersteun­ing voor HTTPS-verbinding­en in de package-manager, download de openbare PGP-sleutel en voeg die toe aan de lijst van vertrouwde sleutels en installeer Docker tot slot.

apt-get install apt-transport-https apt-get install curl curl -fsSL https://download.docker.com/—

linux/debian/gpg | apt-key add - apt-get update apt-get install docker-ce

Met het volgende commando kom je erachter of Docker werkt:

docker run hello-world

Daarmee start je een minimale container die de tekst 'Hello from Docker!' met wat aanvullend­e informatie op het scherm toont. Voordat Docker start, downloadt die de image 'hello-world' van de Docker Hub, waar dan een container van gemaakt wordt. Je kunt images dus als een template beschouwen en containers als instantie. Docker geeft elke container die het van een image maakt een kunstmatig­e naam. Welke dat is, zie je in de laatste kolom van de tabel als je het commando docker ps -a uitvoert, bijvoorbee­ld 'zen_khorana'. Dat commando toont alle bestaande containers. Wanneer je de optie '-a' weglaat, worden alleen de actieve containers getoond.

Oriëntatie

Met docker image ls of docker images krijg je een overzicht van alle images die je binnengeha­ald hebt. In de laatste kolom 'VIRTUAL SIZES' zie je hoeveel schijfruim­te elke image lokaal inneemt. De image van het zojuist gestarte hello-world is slechts twee kilobyte groot en bevat alleen een ELF-programma dat de tekst weergeeft. In een image kan meer staan, maar dat hoeft zeker geen volledige Linux runtime-omgeving te zijn. Voor het programma 'helloworld' zijn de kernelinte­rfaces genoeg.

Er zijn meerdere mogelijkhe­den om uit te vinden wat er in een image zit. Je kunt hem met docker image save > /tmp/ hello.tar als TAR-bestand opslaan, waarvan je de inhoud – wederom TAR-bestanden – als een ui met lagen kunt uitpakken. Je kunt ook op de naam van een image googelen. Als je naar 'library/hello-world' zoekt, staan op de eerste pagina met resultaten al de belangrijk­e domeinen hub. docker.com en github.com (aangevuld met de prefix 'docker-library').

De website van Docker Hub (https:// hub.docker.com/_/hello-world) beschrijft de image die je met de docker-run-opdracht hebt opgehaald. Bij dergelijke beschrijvi­ngen staan meestal aanwijzing­en voor het gebruik van de image, zoals het instellen van een wachtwoord voor de services die in de image aangeboden worden. Verder staat er op de Docker Hub-site van een image meestal nog een verwijzing naar het projectpla­tform GitHub, waar je de build-instructie­s, een bugtracker en meer informatie vindt. Vaak heb je die gedetaille­erde informatie later nodig. Officiële images hebben 'library' of 'docker-library' als prefix voor hun naam. 'Officieel' betekent in deze context niet dat de images van Docker zelf komen, maar alleen dat het team gesponsord wordt dat de images naar de Docker Hub uploadt. Het team moet aan de hand van goede voorbeelde­n tonen wat de bestpracti­ces bij het bouwen van images zijn, de images goed documenter­en en eventuele veiligheid­supdates snel in de images verwerken. Maar garanties zijn er niet.

De Docker Hub biedt een speciale service voor geregistre­erde gebruikers. Voor die gratis registrati­e is alleen een e-mailadres nodig en we raden dat ook echt aan. De service controleer­t regelmatig of de 'officiële' images bekende veiligheid­slekken hebben. Alleen teams en ontwikkela­ars die voor hun eigen repository op Docker Hub betalen, kunnen die service inkopen. Dat geeft de gebruiker toch meer vertrouwen in hun images.

Nog een laatste opmerking over de bouwplanne­n op GitHub: daarin kun je zien hoe de image gemaakt is. Het voor het maken van een image centrale bestand Dockerfile beschrijft niet alleen hoe de image in elkaar gezet is, maar ook welke externe bronnen ervoor nodig zijn. Die informatie is niet, of slechts met heel veel moeite, uit een voltooide image te herleiden. Naast de informatie uit Dockerfile en de overige documentat­ie is de bugtracker een grote bron van kennis. Daarin worden

veelgestel­de vragen en problemen beantwoord en opgelost.

Eerste service

Het commando docker search gitweb op de commandlin­e is voldoende om op Docker Hub naar de eenvoudige webserver Gitweb te zoeken waarmee je met een webbrowser in Git-repository's kunt bladeren. Die zoekopdrac­ht levert minstens zeventien resultaten op, maar geen enkele daarvan is een 'officiële' image. Het overzicht heeft drie hulpvolle kolommen. Stars geeft aan hoe andere gebruikers een image beoordelen. Als er OK in Official staat, gaat het om een 'officiële' image en Automated geeft aan of een image automatisc­h opnieuw gemaakt wordt wanneer de maintainer hem updatet.

Op Docker Hub zie je hoe vaak een bepaalde image gebruikt werd (Pulls). Als je het overzicht nauwkeurig bekijkt, kom je images tegen waarvan de GitHub-pagina's niet meer bestaan of waarvan de inhoud al jaren niet bijgewerkt is. Omdat je die bij voorkeur níet moet gebruiken, houd je een lijstje over van favoriete images die je kunt uitprobere­n. Want zo snel je ze aan het draaien krijgt, zo snel kom je er ook weer vanaf.

We kiezen de minimale aanpak en gebruiken 'fraoustin/gitweb'. Met docker pull fraoustin/gitweb download je de image. Met docker run -d --name gitweb fraoustin/gitweb maak en start je daar een container van die je de naam 'gitweb' geeft. De webserver in die container werkt standaard met de poorten 80 en 443 voor een webbrowser of Git-client.

Voordat je een verbinding met de webserver kunt maken, moet je eerst een gebruikers­account en een repository maken. Daar heeft de maintainer van de image eenvoudige scripts voor geschreven die je met Docker aanroept. Met

docker exec gitweb addauth test test_ww

maak je de gebruiker 'test' met het wachtwoord 'test_ww' aan en met

docker exec gitweb addrepos test

maak je een repository met de naam 'test'. Om erachter te komen hoe je de webserver in de container kunt bereiken, gebruik je het commando docker inspect gitweb | more, dat de configurat­ie van de container gedetaille­erd weergeeft. Bijna aan het eind van dat overzicht staan bij Network de netwerkgeg­evens inclusief het ip-adres dat docker aan de container gegeven heeft.

Zonder verdere tussenkoms­t geeft Docker private ip-adressen aan alle gestarte containers en koppelt hij ze aan de bridge 'docker0' die tijdens het starten van de Docker-daemon ingericht werd. De Docker-host waarop de Docker-deamon draait, krijgt meestal het eerste ip-adres van het netwerk, bijvoorbee­ld 172.17.0.1. De eerste container krijgt dan 172.17.0.2. Je kunt dat adres direct in een webbrowser op de host intypen, als die een grafische gebruikers­interface heeft. Heb je geen grafische interface nodig, dan maak je een SSH-verbinding via een SOCKSproxy (zie het kader 'Bruggen bouwen met SSH en SOCKS-proxy' hiernaast).

Wegwerpmaa­tschappij

Indien de services van buiten het hostsystee­m toegankeli­jk moeten zijn, moet je de instructie­s daarvoor al bij het maken van de container meegeven. Je kunt de instelling­en daarvoor niet achteraf bij een draaiende container uitvoeren omdat dat tegen de basisprinc­ipes van containers indruist. Containers zijn in principe zonder waarde. Gooi de Gitweb-container weg en start hem opnieuw met

docker rm -f gitweb docker run -d --name gitweb fraoustin/gitweb

Als je met de browser dan weer verbinding met de webserver maakt, leer je een belangrijk­e les: het lijkt alsof Gitweb de configurat­iebestande­n vergeten is, want de gebruiker en de repository zijn weg. Dat is geen fout, maar juist de bedoeling. Je moet vóór het starten van een container namelijk aangeven welke gegevens hij permanent moet opslaan en Docker dan laten weten wáár die data opgeslagen moeten worden.

Doe je dat niet, dan maakt de Docker-daemon tijdens de eerste start automatisc­h één of meerdere volumes voor dergelijke data aan en geeft die dan een naam die uit willekeuri­ge tekens bestaat. Zolang de container niet verwijderd wordt, blijft die de volumes ook na een herstart gebruiken. Door het verwijdere­n van de container wordt de koppeling verbroken, met als resultaat dat een nieuwe container van dezelfde image een vers volume bevat. Met docker inspect gitweb kom je erach-

ter waar de volumes van een container zich bevinden. Bij een standaardi­nstallatie staan onder Mount en Source in de map /var/lib/docker/volumes één of meerdere submappen die eindigen op '_data'. Met docker volume ls --filter dangling=true zie je de overbodig geworden volumes en met docker volume prune verwijder je ze.

Om er al voor het starten van een container achter te komen waar de gegevens staan die permanent opgeslagen moeten worden, voer je docker inspect fraoustin/ gitweb uit. Dus niet voor de container, maar voor de image. Zoek dan naar Volumes. In dit voorbeeld zul je zien dat het '/var/lib/ git' is. Als je dat weet, start je Gitweb met een volume dat je zelf een naam geeft:

docker run -d --name gitweb -v gitwebrepo­s:/var/lib/git fraoustin/gitweb

Docker maakt dan automatisc­h een volume met de naam gitwebrepo­s aan door op de host de map var/lib/docker/gitwebrepo­s te creëren.

In dit voorbeeld is dat nog steeds niet voldoende voor de image fraoustin/gitweb om de toegangsge­gevens te herstellen die je via docker exec gitweb addauth had aangemaakt. Die staan in het bestand /etc/nginx/.htpasswd, dat de maker van de image helaas niet op de juiste wijze gedeclaree­rd heeft. Als je de oplossing daarvoor wilt weten, moet je de bronnen bestuderen en dingen uitprobere­n. Dan kom je erachter dat je het probleem met dit configurat­iebestand eenvoudig oplost door het bestand al voor het aanmaken van de container te maken:

mkdir -p /usr/local/share/docker;touch /usr/local/share/docker/.gitweb_—

htpasswd

Bij het starten voeg je het bestand als optie toe. Het gehele commando is dan:

docker run -d --name gitweb -v gitwebrepo­s:/var/lib/git -v /usr/local/share/docker/—

.gitweb_htpasswd:/etc/nginx/.htpasswd fraoustin/gitweb

Wanneer je de Gitweb-containers altijd met die opties aanmaakt, gaan er geen gegevens verloren.

Communicer­en met de wereld

Met die basiskenni­s kun je andere images draaien. We raden je aan zo lang met dokker run en docker rm te oefenen tot je zeker weet dat je daarbij geen gegevens verliest. Het verschilt per container hoe je ze configuree­rt. Behalve de werkwijze met scripts in Gitweb worden de gegevens ook vaak als omgevingsv­ariabelen meegegeven. Webapplica­ties verzamelen hun gegevens meestal via configurat­iepagina's die verschijne­n wanneer je de applicatie voor de eerste keer in een browser opent.

Als je een shell-sessie in een draaiende container wilt starten, kan dat met docker exec -it gitweb /bin/sh. Daarna kun je de container vanaf de commandlin­e onderzoeke­n en configurer­en. Onthoud dat eventuele wijziginge­n alleen permanent zijn bij bestanden die buiten de draaiende container opgeslagen worden, dus op volumes of in een externe database. Met het commando docker commit verander je een container weer in een image, maar die moet je niet te vaak gebruiken. Daarmee maak je alleen images zonder bouwplan (Dockerfile) die moeilijk te onderhoude­n zijn.

Zonder verdere configurat­ie blijven de services van de container alleen toegankeli­jk vanaf het hostsystee­m. Dat komt doordat Docker elke container in een private netwerk zet, wat vergelijkb­aar is met de situatie van een thuisnetwe­rk achter een router die verbinding met internet maakt. Er is geen portforwar­ding die het verkeer naar een poort van de host doorstuurt naar een proces in de container. Docker kan zo'n portforwar­ding inrichten als je dat tijdens het starten van de container aangeeft. De extra parameter die je daarvoor nodig hebt is bijvoorbee­ld -p 8001:80. Die verbindt poort 80 van de Gitweb-webserver met poort 8001 van de host.

Voor webservice­s zou dat snel een onwerkbare situatie opleveren, zeker als meerdere containers als virtuele hosts via één officieel ip-adres op de standaard webpoorten 80 en 443 bereikbaar moeten zijn. Dat probleem los je op met de image jwilder/nginx-proxy, die een vooraf geconfigur­eerde nginx-webserver als automatisc­he reverse-proxy bevat.

De reverse-proxyserve­r luistert aan een speciale Unix-socket waar de Docker zijn API aanbiedt (/var/run/docker.sock). Omdat je (hacker)aanvallen op de host niet kunt uitsluiten, geef je alleen betrouwbar­e containers toegang tot die socket. Zodra je een nieuwe container start, krijgt de proxy dat via de socket te horen. Wanneer die container een specifieke omgevingsv­ariabele in de vorm van de parameter -e VIRTUAL_HOST=gitweb.example.com, heeft, maakt de proxy een bijpassend configurat­iebestand dat in de nginx-server geladen wordt. Daardoor kunnen verzoeken van de

 ??  ?? Wanneer je een geregistre­erde gebruiker bent, kun je bij Docker Hub zien welke veiligheid­slekken 'officiële' images hebben.
Wanneer je een geregistre­erde gebruiker bent, kun je bij Docker Hub zien welke veiligheid­slekken 'officiële' images hebben.
 ??  ??

Newspapers in Dutch

Newspapers from Netherlands