
De eerste stap in het implementeren van Kubernetes is het plaatsen van uw applicatie in een container. In deze serie zullen we bekijken hoe we een afbeelding van een kleine en veilige container kunnen maken.
Dankzij Docker is het maken van containerafbeeldingen nog nooit zo eenvoudig geweest. Geef de basisafbeelding op, voeg uw aanpassingen toe en maak de container aan.

Hoewel deze techniek uitstekend geschikt is om aan de slag te gaan, kan het gebruik van standaard basisafbeeldingen leiden tot onveilige situaties met grote afbeeldingen vol kwetsbaarheden.
Bovendien gebruiken de meeste afbeeldingen in Docker Debian of Ubuntu als basisafbeelding, en hoewel dit zorgt voor uitstekende compatibiliteit en gemakkelijke aanpassing (de Docker-file bevat slechts twee regels code), kunnen basisafbeeldingen honderden megabytes extra belasting aan uw container toevoegen. Bijvoorbeeld, een eenvoudig node.js 'hello-world' applicatiebestand bedraagt ongeveer 700 megabyte, terwijl de eigenlijke grootte van uw applicatie slechts enkele megabytes is.

Al deze extra belasting is dus een verspilling van digitale ruimte en een geweldige schuilplaats voor kwetsbaarheden en beveiligingsfouten. Laten we daarom twee manieren bespreken om de grootte van de containerafbeelding te verkleinen.
De eerste is het gebruik van basisafbeeldingen met een kleine omvang, de tweede is het gebruik van het Builder Pattern ontwerppatroon. Het gebruik van kleinere basisafbeeldingen is waarschijnlijk de eenvoudigste manier om de grootte van uw container te verminderen. Waarschijnlijk biedt uw taal of stack die u gebruikt een originele applicatieafbeelding die veel kleiner is dan de standaardafbeelding. Laten we eens kijken naar onze node.js container.

Standaard is de basisafbeelding node:8 in Docker 670 MB groot, terwijl node:8-alpine slechts 65 MB is, oftewel 10 keer kleiner. Door een kleinere basisafbeelding zoals Alpine te gebruiken, verklein je aanzienlijk de grootte van je container. Alpine is een lichte en kleine Linux-distributie die zeer populair is onder Docker-gebruikers, omdat het compatibel is met veel applicaties en tegelijkertijd de grootte van containers minimaliseert. In tegenstelling tot de standaard Docker-afbeelding 'node', verwijdert 'node:alpine' vele hulpprogramma's en bestanden, waardoor alleen de noodzakelijke componenten overblijven om je applicatie uit te voeren.
Om over te schakelen naar een kleinere basisafbeelding, werk je eenvoudig het Docker-bestand bij om te beginnen met de nieuwe basisafbeelding:

Nu moet je, in tegenstelling tot de oude onbuild-afbeelding, je code in de container kopiƫren en eventuele afhankelijkheden installeren. In het nieuwe Docker-bestand begint de container met de afbeelding node:alpine, maakt vervolgens een map voor de code, installeert afhankelijkheden met de NPM-pakketbeheerder en voert ten slotte server.js uit.

Met deze update krijg je een container die 10 keer kleiner is. Als je programmeertaal of stack geen functie heeft voor het verkleinen van de basisafbeelding, gebruik dan Alpine Linux. Het biedt ook de mogelijkheid om volledige controle te hebben over de inhoud van de container. Het gebruik van basisafbeeldingen met een kleine grootte is een geweldige manier om snel kleine containers te creƫren. Maar je kunt nog meer verkleiningen bereiken door het Builder Pattern te gebruiken.

In geĆÆnterpreteerde talen wordt de broncode eerst naar de interpreter gestuurd en vervolgens direct uitgevoerd. In gecompileerde talen wordt de broncode vooraf omgezet in gecompileerde code. Vaak gebruiken de compilatietools die nodig zijn om de code succesvol te maken, hulpmiddelen die in werkelijkheid niet nodig zijn om de code uit te voeren. Dit betekent dat je deze tools volledig uit de uiteindelijke container kunt verwijderen. Het Builder Pattern kan hiervoor worden gebruikt.

De code wordt aangemaakt in de eerste container en gecompileerd. Vervolgens wordt de gecompileerde code verpakt in de uiteindelijke container zonder de compilers en tools die nodig zijn om die code te compileren. Laten we dit proces doorlopen met een Go-applicatie. Allereerst schakelen we over van de onbuild-afbeelding naar Alpine Linux.

In het nieuwe Docker-bestand begint de container met de afbeelding golang:alpine. Vervolgens creƫert het een map voor de code, kopieert deze naar de broncode, bouwt deze broncode en start de applicatie. Deze container is veel kleiner dan de onbuild-container, maar bevat nog steeds de compiler en andere Go-tools die we feitelijk niet nodig hebben. Laten we dus gewoon het gecompileerde programma extraheren en in onze eigen container plaatsen.

Je kunt iets vreemds opmerken in dit Docker-bestand: het bevat twee FROM-regels. De eerste sectie van 4 regels ziet er precies hetzelfde uit als het vorige Docker-bestand, behalve dat het het sleutelwoord AS gebruikt om deze fase een naam te geven. In de volgende sectie is er een nieuwe FROM-regel die een nieuwe afbeelding start, waarbij we Raw alpine gebruiken in plaats van de afbeelding golang:alpine als basisafbeelding.
Raw Alpine Linux heeft geen geĆÆnstalleerde SSL-certificaten, wat de meeste API-aanroepen via HTTPS zou laten falen, dus laten we een paar root-CA-certificaten installeren.
En nu het interessantste: voor het kopiƫren van de gecompileerde code van de eerste container naar de tweede kun je eenvoudig de COPY-opdracht gebruiken, die zich in regel 5 van de tweede sectie bevindt. Hiermee kopieer je slechts ƩƩn applicatiebestand en tast je de hulpprogramma's van Go niet aan. Het nieuwe multi-stage Docker-bestand zal een containerafbeelding bevatten van slechts 12 megabyte, terwijl de oorspronkelijke containerafbeelding 700 megabyte groot was, wat een groot verschil is!
Dus het gebruik van kleine basisafbeeldingen en het Builder Patroon zijn geweldige manieren om containers van veel kleinere maten te maken zonder veel werk.
Afhankelijk van de applicatiestack zijn er misschien aanvullende manieren om de grootte van de afbeelding en container te verkleinen, maar hebben echt kleine containers een meetbaar voordeel? Laten we twee aspecten bekijken waar kleine containers uiterst effectief zijn ā dat zijn prestaties en veiligheid.
Om de prestatieverbetering te waarderen, bekijken we de duur van het proces voor het maken van een container, het uploaden ervan naar de registry (push) en het vervolgens ophalen ervan (pull). U kunt zien dat een kleinere container een onmiskenbaar voordeel heeft ten opzichte van een grotere container.

Docker cachet de lagen, waardoor latere builds zeer snel verlopen. Echter, in veel CI-systemen die worden gebruikt voor het bouwen en testen van containers worden de lagen niet gecached, wat een aanzienlijke tijdsbesparing oplevert. Zoals blijkt, varieert de bouwtijd van een grote container, afhankelijk van de kracht van uw machine, van 34 tot 54 seconden, terwijl het gebruik van een verkleinde container met behulp van het Builder Pattern tussen de 23 en 28 seconden duurt. Voor dit soort operaties ligt de prestatieverbetering tussen de 40-50%. Dus denk er eens over na hoeveel keer u uw code bouwt en test.
Nadat de container is gebouwd, moet u zijn afbeelding (push container image) in de container registry plaatsen, zodat deze vervolgens in uw Kubernetes-cluster kan worden gebruikt. Ik raad aan om de Google container registry te gebruiken.

Met Google Container Registry (GCR) betaalt u alleen voor de 'ruwe' opslag en netwerkverbruik, en zijn er geen extra kosten voor het beheren van containers. Het is vertrouwelijk, veilig en zeer snel. GCR gebruikt veel trucs om de pull-operatie te versnellen. Zoals u ziet, duurt het uploaden van een Docker Container Image met behulp van go:onbuild, afhankelijk van de prestaties van de computer, tussen de 15 en 48 seconden, terwijl dezelfde operatie met een kleinere container tussen de 14 en 16 seconden duurt. Voor minder krachtige machines neemt het snelheidvoordeel van de operatie toe tot 3 keer. Voor grotere machines is de tijd ongeveer gelijk, omdat GCR een globale cache gebruikt voor de gemeenschappelijke afbeeldingendatabase, wat betekent dat u ze helemaal niet hoeft te downloaden. Op een machine met een lage verwerkingskracht is de CPU de beperkende factor, dus het voordeel van het gebruik van kleinere containers is hier veel voelbaarder.
Als u GCR gebruikt, raad ik ten zeerste aan om Google Container Builder (GCB) als onderdeel van uw build-systeem te gebruiken.

Zoals u ziet, stelt het gebruik ervan u in staat om veel betere resultaten te behalen in het verminderen van de duur van de Build+Push-operatie dan zelfs op een krachtige machine - in dit geval wordt het proces van het bouwen en verzenden van containers naar de host bijna 2 keer versneld. Bovendien ontvangt u elke dag 120 minuten gratis buildtijd, wat in de meeste gevallen voldoet aan de behoeften voor het creƫren van containers.
Daarna volgt de belangrijkste prestatiemetriet - de snelheid van het extraheren of downloaden van containers (Pull). En als u zich niet al te veel zorgen maakt over de tijd die aan de push-operatie wordt besteed, heeft de duur van het pull-proces een aanzienlijke invloed op de algehele systeemprestaties. Stel dat u een cluster van drie knooppunten hebt en er met een daarvan een storing optreedt. Als u een beheersysteem gebruikt, zoals Google Kubernetes Engine, vervangt het automatisch het defecte knooppunt door een nieuw. Echter, dit nieuwe knooppunt zal helemaal leeg zijn, en u moet al uw containers naar dit knooppunt verplaatsen om het te laten werken. Als de pull-operatie lang genoeg duurt, zal uw cluster gedurende deze tijd met een lagere prestatie draaien.
Er zijn veel situaties waarin dit kan gebeuren: er kan een nieuw knooppunt aan het cluster worden toegevoegd, knooppunten kunnen worden geüpdatet of zelfs kunnen switchen naar een nieuwe container voor implementatie. Daarom wordt het minimaliseren van de pull-extractietijd een cruciale factor. Het staat buiten kijf dat een kleine container veel sneller gedownload wordt dan een grote. Als u meerdere containers in een Kubernetes-cluster gebruikt, kan de tijdsbesparing aanzienlijk zijn.

Kijk eens naar de onderstaande vergelijking: de pull-operatie met kleine containers duurt 4-9 keer minder tijd, afhankelijk van de kracht van de machine, dan dezelfde operatie met gebruik van go:onbuild. Het gebruik van gedeelde basisafbeeldingen van kleine containers versnelt de tijd en snelheid waarmee nieuwe Kubernetes-knooppunten kunnen worden uitgerold en online kunnen gaan.
Laten we de kwestie van veiligheid bekijken. Containers van kleinere omvang worden als veel veiliger beschouwd dan grote, omdat ze een kleiner aanvalsoppervlak hebben. Is dat echt zo? Een van de nuttigste functies van Google Container Registry is de mogelijkheid om uw containers automatisch te scannen op kwetsbaarheden. Een paar maanden geleden heb ik zowel onbuild- als meertrapscontainers gemaakt, dus laten we kijken of er kwetsbaarheden zijn.

Het resultaat is verbazingwekkend: in de kleine container zijn slechts 3 gemiddelde kwetsbaarheden ontdekt, terwijl de grote container 16 kritische en 376 andere kwetsbaarheden bevat. Als we de inhoud van de grote container bekijken, zien we dat de meeste veiligheidsproblemen niets met onze applicatie te maken hebben, maar verband houden met programma's die we zelfs niet gebruiken. Dus wanneer mensen praten over een groot aanvalsoppervlak, hebben ze het daar precies over.

De conclusie is duidelijk: maak kleine containers, omdat ze echte voordelen bieden voor de prestaties en veiligheid van uw systeem.

Een beetje reclame š
Bedankt dat je bij ons blijft. Houd je van onze artikelen? Wil je meer interessante inhoud zien? Ondersteun ons door een bestelling te plaatsen of ons aan vrienden aan te bevelen, , een unieke variant van entry-level servers, die we voor jou hebben bedacht: (opties beschikbaar met RAID1 en RAID10, tot 24 cores en tot 40GB DDR4).
Dell R730xd is 2 keer goedkoper in datacenter Equinix Tier IV in Amsterdam? Alleen bij ons in Nederland! Dell R420 ā 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB ā vanaf $99! Lees over hoe
Bron: habr.com
