Voor de optimale developmentworkflow wil je dat de ontwikkelomgeving identiek is aan de productieomgeving voor je app of website gaat draaien. Tegelijkertijd zijn verschillen noodzakelijk, bijvoorbeeld omwille van performance of debugging, of omdat je in productie geen gebruik wilt maken van een development build van je applicatie. Een ander sterk argumentdat verschillen tussen je lokale Docker-omgeving en de productieomgeving is dat je lokaal je applicatiebestanden niet in je image wilt opnemen en in productie wel.Ondanks deze punten is het mogelijk om met één Dockerfile te werken voor beide scenario's. Dat doe je met multi stage builds.

Multi stage Dockerfile: het concept

Een Dockerfile is in feite een klein tekstbestand waarin je definitieerd welk base image je wilt gebruiken voor je container, welke aanvullende software je nodig hebt, welke applicatiefiles je naar je container wilt kopieeren en welk commando binnen je container gestart dient te worden. Al deze opties kunnen van elkaar verschillen in de stadia in je ontwikkelproces. Daarom kan je je Dockerfile opdelen in 'stages': per ontwikkelstadium kan je aanvullende of aangepaste configuratie toepassen.

De multi stage-benadering is erg krachtig omdat je bestanden die in de ene stage zijn gegenereerd, kunt herbruiken in een andere stage. Dat stelt je in staat om je Docker image klein te houden en met één Dockerfile zowel een ontwikkelomgeving als een productieomgeving op te zetten.

Multi stage Dockerfile: een voorbeeld

Het is heel eenvoudig om meerdere stages in je Dockerfile te definiëren. Je kunt een nieuwe stage starten door een extra FROM-statement op te nemen. Onder het from statement kan je vervolgens alle mogelijke Dockerfile-opties gebruiken. Zie het volgende voorbeeld van docs.docker.com:

FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]  

In het blok na het eerste FROM-statement, wordt het baseimage golang:1.7.3 gepakt en wordt vervolgens een go build uitgevoerd met de bestanden die in /go/src/github.com/alexellis/href-counter zijn geplaatst. Om de gebuilde applicatie daadwerkelijk te starten, wordt middels een tweede FROM-stagement nog een stage gedefinieerd. In deze stage worden certificaten toegevoegd en worden alle files die in de eerste stages gebuild zijn, gekoppeerd naar de WORKDIR /root. Vervolgens wordt het command ./app uitgevoerd.

Tips voor multi stage builds

Er zijn een paar handigheden waarmee je je Dockerfiles en je build proces kunt optimaliseren:

  • Iedere stage een naam geven
    • Je kunt iedere stage een naam geven. Doe je dat niet, dan wordt iedere stage genummerd, vanaf nummer 0 voor de eerste stage. Een naam toekennen aan een stage doe je als volgt:
    • FROM naam_van_je_baseimage AS stagename
  • Bestanden uit een andere stage of image kopieren
    • Wil je bestanden uit een eerdere stage of uit een ander image kopiëren, dan kan je in het COPY-statement de flag -from= meegeven, zoals dat ook in bovenstaande voorbeeld gedaan wordt:
    • COPY -from=stagename of COPY -from=image
  • Docker build uitvoeren voor een specifieke stage:
    • docker build --target stagenaam -t naam_van_je_nieuwe_image:versietag .
    • Met bovenstaande commando wordt de docker build uitgevoerd tot en met de stage die je aangeeft.

Meer informatie of hulp nodig?

Voor meer informatie over het gebruik van multi stage build in je Dockerfiles raden we je aan de Docker-documentatie te lezen. Voor meer geavanceerde voorbeelden en tips & tricks is het artikel van Tõnis Tiigi op Medium.com een aanrader. Wil je graag hulp of advies voor je eigen situatie? Laat je contactgegevens achter, wij helpen je graag verder!