Docker multi-stage gebruiken om Windows-images te bouwen
Dag Allemaal! Mijn naam is Andrey en ik werk als DevOps engineer bij Exness in het ontwikkelteam. Mijn hoofdactiviteit heeft betrekking op het bouwen, implementeren en ondersteunen van applicaties in docker onder het Linux besturingssysteem (hierna het OS genoemd). Nog niet zo lang geleden had ik een taak met dezelfde activiteiten, maar het doelbesturingssysteem van het project was Windows Server en een reeks C++-projecten. Voor mij was dit de eerste nauwe interactie met docker-containers onder Windows OS en, in het algemeen, met C++-applicaties. Hierdoor had ik een interessante ervaring en leerde ik over enkele fijne kneepjes van het containeriseren van applicaties in Windows.
In dit artikel wil ik je vertellen met welke moeilijkheden ik te maken kreeg en hoe ik ze heb weten op te lossen. Ik hoop dat dit nuttig is voor uw huidige en toekomstige uitdagingen. Veel plezier met lezen!
Waarom containers?
Het bedrijf beschikt over een bestaande infrastructuur voor de containerorkestrator Hashicorp Nomad en aanverwante componenten: Consul en Vault. Daarom werd gekozen voor containerisatie van applicaties als een uniforme methode voor het leveren van een complete oplossing. Omdat de projectinfrastructuur docker-hosts bevat met Windows Server Core OS-versies 1803 en 1809, is het noodzakelijk om afzonderlijke versies van docker-images voor 1803 en 1809 te bouwen. In versie 1803 is het belangrijk om te onthouden dat het revisienummer van de build-docker-host moet overeenkomen met het revisienummer van de basisdocker-image en de host waar de container van deze image wordt gelanceerd. Versie 1809 heeft zo'n nadeel niet. Je kunt meer lezen hier.
Waarom meertraps?
Ontwikkelteamingenieurs hebben geen of zeer beperkte toegang om hosts te bouwen; er is geen manier om snel de set componenten te beheren voor het bouwen van een applicatie op deze hosts, door bijvoorbeeld een extra toolset of werklast voor Visual Studio te installeren. Daarom hebben we besloten om alle componenten te installeren die nodig zijn om de applicatie in de build Docker-image te bouwen. Indien nodig kunt u snel alleen het dockerbestand wijzigen en de pijplijn starten voor het maken van deze afbeelding.
Van theorie naar actie
Bij een ideale Docker-imagebouw in meerdere fasen wordt de omgeving voor het bouwen van de applicatie voorbereid in hetzelfde Dockerfile-script als waarin de applicatie zelf is gebouwd. Maar in ons geval is er een tussenliggende link toegevoegd, namelijk de stap van het voorlopig maken van een docker-image met alles wat nodig is om de applicatie te bouwen. Dit werd gedaan omdat ik de docker-cachefunctie wilde gebruiken om de installatietijd van alle afhankelijkheden te verkorten.
Laten we eens kijken naar de belangrijkste punten van het dockerfile-script voor het maken van deze afbeelding.
Om images van verschillende besturingssysteemversies te maken, kunt u een argument definiëren in het dockerbestand waardoor het versienummer wordt doorgegeven tijdens de build, en dit is ook de tag van de basisimage.
U kunt een volledige lijst met Microsoft Windows Server-afbeeldingstags vinden hier.
ARG WINDOWS_OS_VERSION=1809
FROM mcr.microsoft.com/windows/servercore:$WINDOWS_OS_VERSION
Standaard staan de opdrachten in de instructies RUN in het dockerbestand op Windows OS worden ze uitgevoerd in de cmd.exe-console. Voor het gemak van het schrijven van scripts en het uitbreiden van de functionaliteit van de gebruikte opdrachten, zullen we de console voor het uitvoeren van opdrachten in Powershell opnieuw definiëren via de instructie SHELL.
Om pakketten te installeren met behulp van chocolatey, kunt u ze eenvoudigweg doorgeven als een lijst, of ze één voor één installeren als u voor elk pakket unieke parameters moet doorgeven. In onze situatie hebben we een manifestbestand in XML-indeling gebruikt, dat een lijst met vereiste pakketten en hun parameters bevat. De inhoud ziet er als volgt uit:
Vervolgens installeren we de applicatie-bouwomgeving, namelijk MS Build Tools 2019 - dit is een lichtgewicht versie van Visual Studio 2019, die de minimaal vereiste set componenten bevat voor het compileren van code.
Om volledig met ons C++-project te kunnen werken, hebben we aanvullende componenten nodig, namelijk:
Workload C++-tools
Gereedschapset v141
Windows 10 SDK (10.0.17134.0)
U kunt automatisch een uitgebreide set tools installeren met behulp van een configuratiebestand in JSON-indeling. Inhoud configuratiebestand:
Een volledige lijst met beschikbare componenten vindt u op de documentatiesite Microsoft Visual Studio.
De dockerfile voert het installatiescript uit en voegt voor het gemak het pad naar de uitvoerbare bestanden van de buildtools toe aan de omgevingsvariabele PATH. Het is ook raadzaam om onnodige bestanden en mappen te verwijderen om de grootte van de afbeelding te verkleinen.
In dit stadium is ons image voor het compileren van de C++-applicatie gereed en kunnen we direct doorgaan met het maken van een docker-meerfasige build van de applicatie.
Meertraps in actie
We zullen de gemaakte afbeelding met alle tools aan boord gebruiken als een build-image. Net als in het vorige dockerfile-script zullen we de mogelijkheid toevoegen om het versienummer/de afbeeldingstag dynamisch te specificeren, zodat de code gemakkelijk opnieuw kan worden gebruikt. Het is belangrijk om een label toe te voegen as builder naar de montageafbeelding in de instructies FROM.
ARG WINDOWS_OS_VERSION=1809
FROM buildtools:$WINDOWS_OS_VERSION as builder
Nu is het tijd om de applicatie te bouwen. Alles is hier vrij eenvoudig: kopieer de broncode en alles wat daarmee samenhangt, en start het compilatieproces.
De laatste fase van het maken van de uiteindelijke afbeelding is het specificeren van de basisafbeelding van de applicatie, waar alle compilatieartefacten en configuratiebestanden zich zullen bevinden. Om gecompileerde bestanden van de tussenmontage-image te kopiëren, moet u de parameter opgeven --from=builder in de instructies COPY.
FROM mcr.microsoft.com/windows/servercore:$WINDOWS_OS_VERSION
COPY --from=builder C:/x64/Release/myapp/ ./
COPY ./configs ./
Het enige dat nu nog overblijft is het toevoegen van de noodzakelijke afhankelijkheden om onze applicatie te laten werken en het specificeren van de startopdracht via de instructies ENTRYPOINT of CMD.
Conclusie
In dit artikel heb ik gesproken over hoe je een volwaardige compilatieomgeving voor C++-applicaties in een container onder Windows kunt creëren en hoe je de mogelijkheden van docker-meerfasige builds kunt gebruiken om volwaardige images van onze applicatie te maken.