Serverless functies en containers kunnen dezelfde web- of AI-dienst uitvoeren, maar verschillen in levenscyclus, schaalgedrag en beheer. Lees welke eigenschappen bepalend zijn voor de runtimekeuze en waar applicaties in de praktijk tegenaan lopen.
Hoe serverless functies en containers code uitvoeren
Een serverless functie wordt doorgaans gestart als reactie op een gebeurtenis, zoals een HTTP-verzoek, een bericht uit een wachtrij of een wijziging in opslag. Het platform verzorgt de infrastructuur en bepaalt wanneer uitvoeromgevingen worden aangemaakt of hergebruikt. De applicatiecode moet passen binnen de grenzen van de gekozen runtime, bijvoorbeeld voor maximale uitvoeringsduur, geheugen en beschikbare systeemfuncties. Serverless betekent dus niet dat er geen servers zijn, maar dat het beheer van die servers grotendeels bij het platform ligt.
Bij een container wordt de applicatie verpakt met haar runtime en afhankelijkheden in een image. Een containerdienst kan die image als langlopend proces uitvoeren, bijvoorbeeld als webserver, worker of modelserver. Het team kiest meer van de proceslevenscyclus zelf: hoe de applicatie start, welke poorten ze opent en hoe ze afsluit. De container draait nog altijd op infrastructuur die beheerd moet worden, maar de dienst abstraheert een deel daarvan.
De applicatievorm bepaalt de vrijheid
Een functie past goed bij afgebakende taken met een duidelijk begin en einde. Een container biedt meer controle wanneer een proces continu actief moet zijn, eigen systeemlibraries nodig heeft of langdurige verbindingen onderhoudt. Problemen ontstaan wanneer code die ontworpen is als permanente server in een functie wordt gedwongen, of wanneer een kleine gebeurtenisgestuurde taak onnodig als langdurige service wordt ingericht. De runtimekeuze begint daarom bij het uitvoeringsmodel van de applicatie, niet bij de naam van een cloudproduct.
Schaalgedrag, koude starts en responsietijd
Serverless platforms schalen uitvoeromgevingen vaak op basis van inkomende gebeurtenissen of verzoeken. Bij een plotselinge piek kunnen extra instanties worden gestart zonder dat vooraf capaciteit is vastgelegd. Dat maakt de aanpak geschikt voor verkeer met sterke variatie, maar opschalen is niet altijd onmiddellijk. Wanneer er geen warme instantie beschikbaar is, moet het platform een omgeving initialiseren. Die koude start kan extra latentie veroorzaken, vooral bij grote pakketten, zware initialisatie of veel afhankelijkheden.
Containerdiensten schalen meestal op basis van ingestelde aantallen instanties en signalen zoals CPU-gebruik, geheugengebruik of het aantal verzoeken. Ook hier kan automatisch schalen worden gebruikt, maar nieuwe containers moeten starten, de image ophalen en gereed komen voor verkeer. Een continu draaiende container kan daardoor stabiele responstijden bieden, terwijl een te laag ingestelde minimumcapaciteit alsnog wachttijd veroorzaakt. Het gedrag hangt af van de configuratie én van hoe snel de applicatie opstart.
Meet pieken en staartlatentie
Gemiddelde responstijd vertelt weinig over de ervaring tijdens een piek. Meet ook percentielen, zoals p95 en p99, en vergelijk rustige perioden met koude starts en schaalmomenten. Stel bij serverless de concurrency en eventuele minimumcapaciteit af op de toegestane latentie en de capaciteit van downstreamsystemen. Bij containers moeten schaalregels voorkomen dat veel nieuwe instanties tegelijk een database of externe API overbelasten. Een runtime kan snel opschalen en toch trager worden als de afhankelijkheden niet dezelfde vraag aankunnen.
Wanneer achtergrondtaken en langlopende processen containers vragen
Een serverless functie is van nature geschikt voor werk dat in een begrensde uitvoering kan worden opgesplitst. Denk aan het verwerken van één bericht, het valideren van een upload of het uitvoeren van een korte API-aanroep. Voor langere taken is het nodig de uitvoeringslimieten van het platform te kennen. Een taak die die limieten overschrijdt, kan worden afgebroken of gedeeltelijk uitgevoerd. Door werk op te delen in kleinere stappen kan dat worden opgelost, maar daarmee komen ook checkpointing, herhaalbaarheid en foutafhandeling in beeld.
Een container is vaak praktischer voor processen die continu berichten uit een queue lezen, langdurige verbindingen onderhouden of een taak uitvoeren waarvan de duur moeilijk te voorspellen is. De worker kan zelf bepalen wanneer hij berichten ophaalt en hoe hij graceful shutdown afhandelt. Dat vraagt wel om expliciete regels voor signalen, time-outs en het opnieuw aanbieden van onafgerond werk. Een containerproces dat onverwacht stopt, mag geen bericht stilzwijgend kwijtraken of twee keer onbedoeld verwerken.
Ontwerp verwerking als herhaalbare stap
Bij beide runtimes moet een bericht veilig opnieuw verwerkt kunnen worden. Gebruik idempotente bewerkingen, bevestig een bericht pas nadat de verwerking duurzaam is vastgelegd en stuur herhaalde fouten naar een afzonderlijke afhandelroute. Serverless maakt gebeurtenisgestuurde verwerking vaak eenvoudig, maar neemt deze semantiek niet weg. Containers geven meer controle over de workerloop, maar vereisen dat die loop netjes reageert op onderbrekingen en capaciteitsdruk. De aard en duur van het werk zijn daarom belangrijker dan de voorkeur voor een bepaald platformmodel.
Configuratie, afhankelijkheden en reproduceerbare runtimes
Bij serverless wordt de functie vaak afzonderlijk verpakt en gekoppeld aan instellingen van het platform. Runtimeversies, omgevingsvariabelen, geheugengrenzen, time-outs en toegangsrechten maken deel uit van die configuratie. De beperkte omvang van een functie kan deployments overzichtelijk houden, maar een grote verzameling functies leidt gemakkelijk tot versnippering. Als functies verschillende versies van dezelfde library gebruiken of instellingen buiten versiebeheer worden aangepast, ontstaat er verschil tussen omgevingen dat lastig te reproduceren is.
Een containerimage legt de applicatie en veel van haar afhankelijkheden samen vast. Daardoor kan dezelfde image in ontwikkeling, test en productie worden gebruikt, mits configuratie en externe services consequent worden beheerd. Die voorspelbaarheid is nuttig voor toepassingen met native libraries, specifieke systeemtools of meerdere processen. Tegelijk vraagt een image om zorgvuldig versiebeheer, updates van de basislaag en een helder beleid voor secrets. Secrets horen niet in de image zelf: die kunnen uitlekken via image-registry’s, logs of lokale ontwikkelkopieën.
Maak platformconfiguratie onderdeel van de code
Beheer instellingen waar mogelijk als versieerbare configuratie, ongeacht de runtime. Leg vast welke variabelen verplicht zijn, welke waarden per omgeving verschillen en hoe ontbrekende instellingen worden afgehandeld. Pin afhankelijkheden en controleer updates, in plaats van productie ongemerkt een andere runtimeversie te laten gebruiken dan tests. Bij functies ligt het risico vaak in verspreide platforminstellingen; bij containers in verouderde images en ongedocumenteerde entrypoints. Reproduceerbaarheid ontstaat pas wanneer zowel de applicatie als haar uitvoeringscontext traceerbaar zijn.
Serverless en containers voor AI-inferentie
Voor lichte AI-inferentie kan een serverless functie een geschikte ingang zijn: het verzoek wordt gevalideerd, verrijkt en doorgestuurd naar een modelendpoint. Ook kleine modellen of embeddings die weinig initialisatietijd en geheugen vragen, kunnen in een functie draaien. De afweging verandert wanneer een model veel geheugen gebruikt, lang moet worden geladen of afhankelijk is van GPU-hardware. Het initialiseren van gewichten bij een koude start kan de responstijd domineren, terwijl een kortlevende functie de herhaalde initialisatie moeilijk kan rechtvaardigen.
Een container biedt meer controle over frameworkversies, modelbestanden, systeemlibraries en hardwarevereisten. Een langlevende modelserver kan gewichten één keer laden en meerdere verzoeken verwerken. Dat maakt batching en hergebruik van geheugen mogelijk, maar vraagt om aandacht voor concurrency: te veel gelijktijdige verzoeken kunnen GPU-geheugen uitputten of de wachtrij laten groeien. Ook het ophalen van modellen tijdens het starten is een operationeel risico. Een modelregistry, vaste modelversies en expliciete readiness-controles helpen voorkomen dat een instantie verkeer ontvangt voordat ze werkelijk gereed is.
Scheid inference van voorbereidende stappen
Veel AI-pijplijnen combineren korte validatie, langdurige inferentie en nabewerking. Die onderdelen hoeven niet dezelfde runtime te gebruiken. Een functie kan bijvoorbeeld een aanvraag authenticeren en in een queue plaatsen, terwijl een containerworker inference uitvoert. Beoordeel per stap de vereiste hardware, maximale wachttijd en hoeveelheid werk per verzoek. Houd daarnaast rekening met time-outs van clients en gateways: een model dat uiteindelijk correct antwoordt, is operationeel onbruikbaar als de verbinding eerder afloopt. Streaming antwoorden vragen weer om een runtime en netwerkpad die langdurige responsen ondersteunen.
Netwerkverbindingen, status en toegang tot data
Serverless functies zijn vaak kortlevend en mogen niet uitgaan van lokale status tussen uitvoeringen. Bestanden die tijdelijk op lokale schijf staan, kunnen verdwijnen wanneer een omgeving wordt verwijderd of vervangen. Sessies, voortgang en resultaten horen daarom in een passende externe opslaglaag, zoals een database, objectopslag of cache. Dat maakt de functie eenvoudiger vervangbaar, maar voegt netwerkverkeer en afhankelijkheden toe. Het is belangrijk om verbindingen niet onbeperkt te openen en om time-outs en retries bewust in te stellen.
Containers kunnen lokale cache of tijdelijke bestanden gebruiken zolang een instantie actief is, maar die gegevens zijn niet automatisch gedeeld met andere instanties. Een herstart, herschaling of verplaatsing kan lokale status alsnog verliezen. Bij langlopende containers moet bovendien worden voorkomen dat databaseverbindingen zich opstapelen. Een autoscaler kan in korte tijd veel instanties starten, die elk hun eigen pool openen. Zonder limieten raakt de database overbelast, waarna nieuwe instanties de storing verder versterken.
Beperk toegang en verbindingsdruk
Geef functies en containers alleen de netwerk- en datarechten die hun taak vereist. Gebruik afzonderlijke identiteiten voor verschillende diensten, beperk publieke endpoints en roteer geheimen via beheerde voorzieningen. Maak voor iedere externe verbinding expliciet welke time-out geldt, welke fouten herhaald mogen worden en hoe de applicatie reageert als de dienst niet beschikbaar is. Een runtimekeuze lost geen databasecapaciteitsprobleem op; wel beïnvloedt zij hoe snel verbindingen worden aangemaakt en hoeveel instanties tegelijk kunnen ontstaan. Test daarom ook gedrag bij verbindingslimieten en tijdelijke netwerkfouten.
Logs, fouten en operationele zichtbaarheid per runtime
Bij serverless wordt een uitvoering vaak geregistreerd als een afzonderlijke aanroep. Dat maakt het mogelijk fouten aan gebeurtenissen en verzoeken te koppelen, maar een bedrijfsproces kan uit meerdere functies bestaan. Zonder gedeelde correlatie-ID is het lastig te reconstrueren waar een aanvraag is blijven hangen. Logs moeten relevante context bevatten, zoals een trace-ID en een veilige aanduiding van de taak, zonder persoonsgegevens of geheimen vast te leggen. Metrics voor foutpercentage, duur, time-outs en throttling laten zien of een functie haar grenzen nadert.
Bij containers zijn logs en metrics meestal gekoppeld aan een proces of instantie. Dat helpt bij het onderzoeken van geheugenlekken, herstarts en capaciteitsproblemen, maar een schaalbare dienst kan veel kortlevende instanties produceren. Logs moeten daarom centraal worden verzameld en niet alleen lokaal worden bewaard. Healthchecks verdienen aparte aandacht: een proces kan nog draaien terwijl het geen verzoeken meer correct afhandelt. Een liveness-controle kan herstarten wat vastzit; een readiness-controle voorkomt dat onvoorbereide instanties verkeer ontvangen.
Maak foutafhandeling zichtbaar
Leg vast wat een succesvolle verwerking betekent en meet ook de fouten van afhankelijkheden. Een functie die berichten blijft herhalen kan een queue blokkeren; een containerworker kan ongemerkt achterlopen terwijl zijn processtatus gezond lijkt. Monitor daarom queue-lengte, leeftijd van het oudste bericht en het aantal herstarts naast gewone HTTP-metrics. Gebruik tracing om sprongen tussen gateway, functie, queue, worker en modelserver te volgen. Dezelfde observabilityprincipes gelden voor beide runtimes, maar de signalen verschillen: bij serverless zijn uitvoeringslimieten en throttling belangrijk, bij containers ook instantiestatus en resourceverbruik.
Een runtime kiezen op basis van applicatiegedrag
De keuze wordt concreter wanneer een applicatie wordt opgesplitst in afzonderlijke werksoorten. Een stateless endpoint met korte, onregelmatige verzoeken kan goed aansluiten op serverless. Een API die langdurige verbindingen onderhoudt, veel lokale initialisatie uitvoert of een eigen procesmodel nodig heeft, past mogelijk beter bij een container. Voor een AI-dienst kan de publieke aanvraagafhandeling losstaan van de modelserver: de eerste component verwerkt authenticatie en validatie, de tweede houdt het model geladen en beheert inferencecapaciteit.
Breng per onderdeel de maximale uitvoeringsduur, piekconcurrency, geheugenbehoefte, opstarttijd en afhankelijkheden in kaart. Noteer ook welke foutmodi aanvaardbaar zijn: kan werk veilig opnieuw worden aangeboden, moet een verbinding openblijven en mag een proces tijdelijk niet beschikbaar zijn? Deze gegevens maken zichtbaar wanneer een runtimegrens architectuurwerk veroorzaakt. Een functie die voortdurend tegen een time-out aanloopt vraagt om een andere taakindeling of uitvoeringsvorm. Een containerdienst die alleen af en toe werk uitvoert, kan juist onnodig als permanente worker zijn ingericht.
Combineren vraagt om duidelijke grenzen
Een hybride architectuur is bruikbaar wanneer elk onderdeel een afgebakende verantwoordelijkheid heeft, maar meer runtimes betekenen ook meer deployments, rechten en dashboards. Voorkom dat dezelfde logica zonder reden in zowel functies als containers wordt onderhouden. Definieer contracten voor berichten en API’s, beheer configuratie op een consistente manier en leg vast welk team of proces verantwoordelijk is voor incidenten per component. Evalueer de keuze met productieachtige belasting en fouten, niet alleen met een succesvolle lokale test. Zo wordt duidelijk of het schaalgedrag, de latentie en het operationele beheer aansluiten op het werkelijke gebruik.
Veelgestelde vragen
Hoe vergelijk je de totale kosten van serverless en containers?
Vergelijk de totale kosten met een representatief gebruikspatroon, niet alleen met de prijs per uitvoering of instantie. Serverless-kosten hangen onder meer af van het aantal aanroepen, de uitvoeringsduur en het toegewezen geheugen. Bij containers tellen ook de tijd dat instanties actief zijn en de gekozen capaciteit mee. Neem daarnaast kosten mee die niet direct aan de runtimeprijs zichtbaar zijn:
- Netwerkverkeer, opslag en dataoverdracht tussen diensten.
- Monitoring, logging en eventuele betaalde platformfuncties.
- Beheerwerk, zoals updates, incidentafhandeling en capaciteitsplanning.
Meet kosten bij rustig, gemiddeld en piekgebruik. Zo zie je ook of een keuze voordelig blijft wanneer het gebruik verandert.
Hoe voorkom je dat serverless-code moeilijk naar containers te verplaatsen is?
Voorkom afhankelijkheid van platformspecifieke functies door de bedrijfslogica los te houden van de aanroep- en infrastructuurlaag. Een overstap is zelden volledig automatisch, maar duidelijke grenzen maken het eenvoudiger om dezelfde logica in een container uit te voeren. Let bij het ontwerp onder meer op:
- Gebruik expliciete invoer- en uitvoerformaten in plaats van impliciete platformcontext.
- Houd configuratie buiten de code en maak afhankelijkheden zichtbaar.
- Scheid adapters voor events, opslag en identiteiten van de kernlogica.
- Leg gedrag vast met tests die niet alleen een specifieke runtime nabootsen.
Controleer ook of de nieuwe runtime dezelfde foutafhandeling, time-outs en berichtsemantiek kan bieden. Portabiliteit vraagt dus om bewuste ontwerpkeuzes en blijft afhankelijk van de gebruikte platformdiensten.
Hoe test je serverless functies en containers lokaal voordat je ze uitrolt?
Test lokaal eerst de applicatielogica en controleer daarna de integratie met de gekozen runtime en externe diensten. Unit-tests helpen fouten in afzonderlijke onderdelen vroeg te vinden, maar bewijzen niet dat platforminstellingen of netwerkgedrag in productie kloppen. Een praktische testaanpak bestaat uit meerdere lagen:
- Test functies met representatieve events en controleer invoer, uitvoer en foutpaden.
- Start containers met dezelfde image en configuratievorm als in de uitrolomgeving.
- Gebruik integratietests voor databases, queues en andere belangrijke afhankelijkheden.
- Voer een acceptatietest uit in een aparte cloudomgeving voor platformgedrag dat lokaal niet betrouwbaar na te bootsen is.
Beschouw emulators als hulpmiddel, niet als volledige vervanging voor tests op het doelplatform.
Hoe rol je een nieuwe versie van een serverless functie of container veilig terug?
Maak een veilige rollback mogelijk door elke release als een traceerbare, onveranderlijke versie te publiceren en vooraf te bepalen hoe verkeer terug kan naar de vorige versie. Pas de database- en berichtformaten zo aan dat oude en nieuwe versies tijdelijk naast elkaar kunnen werken. Neem in het uitrolproces bijvoorbeeld deze controles op:
- Bewaar de gebruikte image, functieversie en configuratie per release.
- Verhoog verkeer stapsgewijs en controleer fouten, responstijden en bedrijfsmetrics.
- Leg vast welke drempels automatisch of handmatig een rollback starten.
- Test terugschakelen vooraf; terugzetten van code herstelt niet automatisch gewijzigde data.
Een rollbackplan werkt alleen als afhankelijkheden en datamigraties ook rekening houden met meerdere versies.
Welke kosten en risico's brengt serverless of containers met zich mee bij piekverkeer?
Bij piekverkeer kunnen beide modellen onverwachte kosten en operationele risico's veroorzaken, dus stel vooraf grenzen in en test de volledige keten onder belasting. Een snelle groei van het aantal uitvoeringen of instanties kan bijvoorbeeld downstreamdiensten overbelasten, terwijl limieten van een cloudprovider verzoeken kunnen vertragen of weigeren. Maak daarom een piekplan dat ook deze punten behandelt:
- Stel budgetmeldingen en relevante gebruiksquota in.
- Test wat er gebeurt wanneer een database, API of queue haar capaciteit bereikt.
- Bepaal welke verzoeken kunnen worden uitgesteld, afgewezen of opnieuw geprobeerd.
- Controleer of piekbelasting leidt tot onverwachte netwerk-, opslag- of logkosten.
Een belastingtest met realistische afhankelijkheden maakt de gevolgen doorgaans beter zichtbaar dan een test van alleen de applicatiecode.