Produktions lignende lokalt udviklingsmiljø med Docker

Hvis man som udvikler bare én gang har brugt sætningen "Jamen det virkede på min maskine", og grunden hertil er, at det er "svært" at få noget, der ligner en produktions server, der kører lokalt…... så har man ikke længere en god undskyldning.

Når en udvikler´s eget lokale udviklingsmiljø ikke er magen til miljøet i produktion, kan utallige ting gå galt, når man går live med et website. Små ting som eksempelvis forskellige software versioner eller opsætning heraf, kan have stor betydning for, hvordan tingene efterfølgende fungerer.

For at undgå dette, må man sikre, at alle udviklere har adgang til et produktions lignende miljø, så man specifikt kan opnå følgende:

Genbrugelighed

Miljøet skal nemt kunne genskabes og det skal være magen til det tidligere miljø, når det bliver genskabt. Man skal kunne overskrive lokalt kode/data med kode/data fra produktion og have en fungerende applikation.

Isolation

Ændringer til ens eget lokale system, skal ikke have indflydelse på udviklingsmiljøet. Applikationen skal kunne køre uden at forstyrre omverdenen, f.eks. ved at sende E-mails ud til rigtige brugere.

Ensartethed

Miljøet skal kunne deles med andre udviklere og det skal fungere ens for alle. Opdatering til kode/data skal kunne indføres på samme måde som under produktion (f.eks. Git og Features til Drupal). Når man opdaterer produktion, skal koden kunne fungere på samme måde som den lokale kode.

Containere og virtuelle maskiner

Der findes en række teknologier som kan hjælpe med at opnå ovenstående, f.eks. Vagrant/Virtualbox, som er en virtuel maskine, der kan sættes op som en rigtig server. Dog er en fuld virtuel maskine ofte unødvendig, hvis man kun skal bruge en webserver og en databaseserver, som kan dele filer imellem den virtuelle maskine og den lokale maskine.

En elegant løsning herpå er at bruge Docker. Docker giver muligheden for, at køre en eller flere processer isoleret fra den lokale maskine, så man eksempelvis kan køre software fra Debian i Docker og Ubuntu på sin lokale maskine. I dette blog indlæg kigger vi på at køre PHP+Apache+MySQL i en Docker container med Debian, som svarer til vores produktions opsætning. Det er en forudsætning at have Docker installeret og at det fungerer på en Linux distribution. Se www.docker.com for mere info.

Opsætning af Docker

Hvis man ønsker, at ens Docker skal være så tæt på produktionsudgaven som muligt, kan man køre det samme konfigurations styrings software (puppet eller lignende) som der er i produktionsudgaven. Dog kan man via sin Dockerfile nå ret langt ved at installere det samme software og benytte de samme konfigurations filer som på produktion.

Dockerfile

Alle produktions maskiner er måske ikke 100% ens. Eksempelvis kan de køre forskellige udgaver af Debian (Squeeze, Wheezy og Jessie). Man kan så oprette en Dockerfile til hver version, som eksempel kan man hente min Wheezy Dockerfile (fjern .txt endelsen).

Byg Docker image

Kør følgende kommando i den mappe, hvor Dockerfile ligger. Bemærk at følgende 2 filer skal findes i en undermappe, som hedder add-files: phpmyadmin-config.inc.php og startup-in-container.sh (fjern .txt endelse fra begge og fjern _).

docker build --rm -t bellcom/localdev:wheezy .

Filerne som man tilføjer, kan være magen til filerne i produktion, de skal dog manuelt opdateres ved ændringer i produktion og et nyt image skal laves og distribueres.

Efter at man har bygget et Docker image, bør man undgå at ændre noget inde i sin Docker container, da man bryder med "Genbrugelighed" og "Ensartethed". Hvis man har brug for at eksperimentere eller inspicere den kørende container kan man dog bruge:

docker exec -ti localdev-wheezy bash

Deling af image

For at sikre at udviklingsmiljøet er 100% ens, kan man dele sit Docker image i stedet for Dockerfilen. På maskinen hvor man har kørt docker build:

docker save -o localdev-wheezy.tar
gzip localdev-wheezy.tar

Så kopierer man filen til en anden maskine og kører:

docker load -i localdev-wheezy.tar.gz

Start Docker container

Følgende kommando starter en container med navn localdev-wheezy, som kan bruges til at henvise til containeren.

To lokale mapper “mappes” / linkes ind i containeren, så filer der ændres holdes uden for containeren.

  • www skal være en undermappe og indeholde de sites som skal findes i containeren
  • apache skal også findes, og den skal indeholde aktive vhosts
docker run -d -h wheezy -p 80:80 -v $(pwd)/www:/var/www -v $(pwd)/apache:/etc/apache2/sites-enabled --name localdev-wheezy bellcom/localdev:wheezy

Kommandoen gør følgende:

run -d
starter containeren i baggrunden og outputter dens id
-h wheezy
sætter hostnavnet
-p 80:80
gør det muligt at tilgå hvad der kører i containeren på port 80 på den lokale maskine
-v $(pwd)/www:/var/www
mappe www mappen i den mappe man står i til /var/www inde i containeren
-v $(pwd)/apache:/etc/apache2/sites-enabled
som www, bare til apache vhosts
--name localdev-wheezy
giver containeren et navn vi kan henvise til senere
bellcom/localdev:wheezy
hvilket image containeren skal bruge

Når man så vil genstarte containeren kan man bruge:

docker restart localdev-wheezy

Håndtering af E-Mails

For at undgå at spamme rigtige brugere, kan man bruge Mailhog som smtp server. Programmet har et simpelt webinterface, hvor man kan se de mails, som er blevet sendt til det. Start mailhog og gå til http://127.0.0.1:8025

Afsluttende tanker

Nu hvor man har et ens udviklingsmiljø, er det næste man bør kigge på, at alle udviklers IDE/Editore er sat op på samme måde, for at sikre fælles kodestandard og kvalitet. Efterfølgende kan man så se på, hvordan man kan lave continuous integration, eksempelvis via Travis CI som bruger ens Docker image som basis... men det er til en anden blog post :)