Leer hoe Solomon Hykes en Docker containers populair maakten, waardoor images, Dockerfiles en registries de standaard werden om moderne apps te verpakken en uit te rollen.

Solomon Hykes is de engineer die een lang bestaand idee—software isoleren zodat het overal hetzelfde draait—omzette in iets dat teams dagelijks konden gebruiken. In 2013 werd het project dat hij publiek maakte Docker, en dat veranderde snel hoe bedrijven applicaties uitrollen.
Destijds was de pijn simpel en herkenbaar: een app werkte op de laptop van een ontwikkelaar, gedroeg zich anders op de machine van een collega en brak opnieuw in staging of productie. Die “inconsistente omgevingen” waren niet alleen irritant—ze vertraagden releases, maakten bugs moeilijk reproduceerbaar en zorgden voor eindeloze overdrachten tussen development en operations.
Docker gaf teams een herhaalbare manier om een applicatie te verpakken met de afhankelijkheden die het verwacht—zodat de app op dezelfde manier kan draaien op een laptop, een testserver of in de cloud.
Daarom zeggen mensen dat containers de “standaard verpakkings- en deploy-eenheid” werden. Simpel gezegd:
In plaats van te deployen met “een zipbestand plus een wiki vol setup-stappen” zetten veel teams een image in die al bevat wat de app nodig heeft. Het resultaat: minder verrassingen en snellere, voorspelbaardere releases.
Dit artikel mixt geschiedenis met praktische concepten. Je leert wie Solomon Hykes is in deze context, wat Docker op het juiste moment introduceerde en de basismechanica—zonder diepgaande infrastructuurkennis te veronderstellen.
Je ziet ook waar containers vandaag passen: hoe ze aansluiten op CI/CD en DevOps-workflows, waarom orkestratietools zoals Kubernetes later belangrijk werden, en wat containers niet automatisch oplossen (vooral op het gebied van veiligheid en vertrouwen).
Aan het einde zou je duidelijk en met vertrouwen moeten kunnen uitleggen waarom “ship it as a container” een standaardaanname werd voor moderne applicatie-deployments.
Voordat containers mainstream werden, was het vaak lastiger om een applicatie van de laptop van een ontwikkelaar naar een server te krijgen dan om de app zelf te schrijven. Teams misten niet het talent—ze misten een betrouwbare manier om “het ding dat werkt” tussen omgevingen te verplaatsen.
Een ontwikkelaar kon de app perfect draaien op zijn computer en vervolgens zien dat het faalde in staging of productie. Niet omdat de code veranderde, maar omdat de omgeving dat deed. Verschillende OS-versies, ontbrekende libraries, net iets andere configbestanden of een database met andere defaults konden dezelfde build laten breken.
Veel projecten leunden op lange, fragiele setup-instructies:
Zelfs zorgvuldig geschreven handleidingen verouderen snel. Eén collega die een dependency upgrade doet, kan per ongeluk de onboarding voor iedereen breken.
Erger nog: twee apps op dezelfde server kunnen incompatibele versies van dezelfde runtime of library nodig hebben, wat teams dwong tot omslachtige workarounds of aparte machines.
“Verpakken” betekende vaak een ZIP, tarball of installer maken. “Deployment” vroeg een andere set scripts en serverstappen: een machine provisionen, configureren, bestanden kopiëren, services herstarten en hopen dat niets anders op de server geraakt werd.
Die twee zorgen sloten zelden netjes op elkaar aan. Het pakket beschreef niet altijd de benodigde omgeving volledig, en het deploy-proces hing sterk af van de doelsystemen die “precies goed” voorbereid moesten zijn.
Wat teams nodig hadden was één draagbare eenheid die zijn afhankelijkheden meedraagt en consistent draait op laptops, testservers en productie. Die druk—herhaalbare setup, minder conflicten en voorspelbare deployment—legde de basis voor containers als standaard manier om applicaties te leveren.
Docker begon niet als groot plan om “software voor altijd te veranderen.” Het groeide uit praktisch engineeringwerk dat Solomon Hykes leidde tijdens het bouwen van een platform-as-a-service product. Het team had een herhaalbare manier nodig om applicaties te verpakken en te draaien op verschillende machines zonder de gebruikelijke “werkt op mijn laptop” verrassingen.
Voordat Docker een bekende naam was, was de onderliggende behoefte helder: lever een app met zijn afhankelijkheden, draai het betrouwbaar en doe dat keer op keer voor veel klanten.
Het project dat Docker werd, ontstond als interne oplossing—iets dat deployments voorspelbaar maakte en omgevingen consistent. Toen het team inzag dat die verpakkings- en draamweergave breed nuttig was buiten hun eigen product, brachten ze het publiekelijk uit.
Die release deed ertoe omdat het een privé-deploy-techniek veranderde in een gedeelde toolchain die de industrie kon adopteren, verbeteren en standaardiseren.
Het is makkelijk om die twee door elkaar te halen, maar ze zijn verschillend:
Containers bestonden al in verschillende vormen vóór Docker. Wat veranderde is dat Docker de workflow verpakte in een ontwikkelaarvriendelijke set commando’s en conventies—bouw een image, draai een container, deel hem met iemand anders.
Enkele breed bekende stappen duwden Docker van “interessant” naar “standaard”:
Het praktische resultaat: ontwikkelaars stopten met debatteren over hoe omgevingen te repliceren en begonnen dezelfde runnable eenheid overalheen te sturen.
Containers zijn een manier om een applicatie te verpakken en draaien zodat deze hetzelfde werkt op je laptop, op die van een collega en in productie. De kern is isolatie zonder een volledig nieuwe computer.
Een virtuele machine (VM) is als het huren van een heel appartement: je krijgt je eigen voordeur, je eigen nutsvoorzieningen en je eigen kopie van het besturingssysteem. Daarom kunnen VM's verschillende OS-types naast elkaar draaien, maar ze zijn zwaarder en starten meestal langzamer.
Een container is meer als het huren van een afgesloten kamer in een gedeeld gebouw: je brengt je meubels mee (app-code + libraries), maar de nutsvoorzieningen (de kernel van de host-OS) worden gedeeld. Je hebt scheiding van andere kamers, maar je start niet telkens een heel nieuw OS.
Op Linux vertrouwen containers op ingebouwde isolatiefuncties die:
Je hoeft de kernel-details niet te kennen om containers te gebruiken, maar het helpt om te weten dat ze OS-features gebruiken—geen magie.
Containers werden populair omdat ze:
Containers vormen standaard geen volledige veiligheidsgrens. Omdat containers de kernel van de host delen, kan een kernel-zwakte meerdere containers beïnvloeden. Het betekent ook dat je geen Windows-container op een Linux-kernel (en vice versa) kunt draaien zonder extra virtualisatie.
Kortom: containers verbeteren verpakking en consistentie—maar je hebt nog steeds slimme beveiliging, patching en configuratiepraktijken nodig.
Docker slaagde deels omdat het teams een eenvoudig mentaal model gaf met duidelijke “delen”: een Dockerfile (instructies), een image (het gemaakte artefact) en een container (de draaiende instantie). Als je die keten snappt, begint de rest van het Docker-ecosysteem logisch te worden.
Een Dockerfile is een platte-tekstbestand dat beschrijft hoe je je applicatieomgeving stap voor stap bouwt. Zie het als een kookrecept: het voedt niemand direct, maar vertelt precies hoe je elke keer hetzelfde gerecht maakt.
Typische Dockerfile-stappen omvatten: kiezen van een base (zoals een language runtime), je app-code kopiëren, afhankelijkheden installeren en het commando declareren dat moet draaien.
Een image is het gebouwde resultaat van een Dockerfile. Het is een verpakte snapshot van alles wat nodig is om te draaien: je code, afhankelijkheden en config-standaarden. Het is niet “levend”—meer een verzegelde doos die je kunt verzenden.
Een container krijg je als je een image draaien. Het is een live proces met een geïsoleerd bestandssysteem en instellingen. Je kunt het starten, stoppen, herstarten en meerdere containers van dezelfde image maken.
Images worden gebouwd in lagen. Elke instructie in een Dockerfile maakt meestal een nieuwe laag, en Docker probeert lagen te hergebruiken (cache) die niet veranderd zijn.
In eenvoudige termen: als je alleen je applicatiecode verandert, kan Docker vaak de lagen hergebruiken die het OS-pakketten en afhankelijkheden installeerden, waardoor rebuilds veel sneller zijn. Dit moedigt ook hergebruik tussen projecten aan—veel images delen gemeenschappelijke basislagen.
Dit is hoe het “recept → artefact → draaiende instantie” eruitziet:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["node", "server.js"]
docker build -t myapp:1.0 .docker run --rm -p 3000:3000 myapp:1.0Dit is de kernbelofte die Docker populair maakte: als je de image kunt bouwen, kun je hetzelfde betrouwbaar draaien—op je laptop, in CI of op een server—zonder steeds installatie-instructies opnieuw te schrijven.
Een container op je eigen laptop draaien is nuttig—maar dat was niet de doorbraak. De echte verschuiving kwam toen teams exact dezelfde build konden delen en overal draaien, zonder “werkt op mijn machine” discussies.
Docker maakte dat delen zo normaal als code delen.
Een container registry is een opslagplaats voor containerimages. Als een image de verpakte app is, is een registry de plek waar je verpakte versies bewaart zodat anderen of systemen ze kunnen ophalen.
Registries ondersteunen een eenvoudige workflow:
Publieke registries (zoals Docker Hub) maakten een eenvoudige start mogelijk. Maar de meeste teams wilden al snel een registry die aan hun toegangsregels en compliance-eisen voldeed.
Images worden meestal aangeduid als naam:tag—bijv. myapp:1.4.2. Die tag is meer dan een label: het is hoe mensen en automatisering overeenkomen welke build te draaien.
Een veelgemaakte fout is vertrouwen op latest. Het klinkt handig, maar het is dubbelzinnig: “latest” kan veranderen zonder waarschuwing, waardoor omgevingen kunnen verschuiven. Eén deploy kan een nieuwere build halen dan een vorige—zelfs als niemand een upgrade bedoelde.
Betere gewoonten:
1.4.2) voor releasesZodra je interne services, betaalde dependencies of bedrijfs-code deelt, wil je meestal een private registry. Die geeft je controle over wie kan pullen of pushen, integratie met single sign-on en houdt proprietaire software uit openbare indexen.
Dit is de sprong van “laptop naar team”: zodra images in een registry staan, kunnen je CI-systeem, collega’s en productie-servers allemaal dezelfde artifact pullen—en deployment wordt herhaalbaar, niet geïmproviseerd.
CI/CD werkt het best als het je applicatie als één herhaalbaar “ding” kan behandelen dat door fasen beweegt. Containers bieden precies dat: één verpakt artefact (de image) dat je één keer bouwt en vaak runt, met veel minder “werkt op mijn machine”-verrassingen.
Voor containers probeerden teams vaak omgevingen gelijk te trekken met lange setup-docs en gedeelde scripts. Docker veranderde de standaardworkflow: repo pullen, image bouwen, app draaien. Dezelfde commando’s werken meestal op macOS, Windows en Linux omdat de applicatie in de container draait.
Die standaardisatie versnelt onboarding. Nieuwe collega’s besteden minder tijd aan dependencies installeren en meer tijd aan het product begrijpen.
Een goede CI/CD-opzet streeft naar één pipeline-output. Met containers is die output een image die getagd is met een versie (vaak gekoppeld aan een commit SHA). Die zelfde image wordt gepromoveerd van dev → test → staging → productie.
In plaats van de app voor elke omgeving anders te bouwen, verander je configuratie (zoals omgevingsvariabelen) terwijl het artefact identiek blijft. Dat vermindert drift en maakt releases makkelijker te debuggen.
Containers mappen netjes op pipeline-stappen:
Omdat elke stap tegen dezelfde verpakte app draait, zijn fouten betekenisvoller: een test die in CI slaagt, gedraagt zich waarschijnlijk hetzelfde na deployment.
Als je je proces verfijnt, is het ook de moeite waard simpele regels vast te stellen (tagconventies, image signing, basis-scanning) zodat de pipeline voorspelbaar blijft. Je kunt van daaruit uitbreiden naarmate je team groeit (zie /blog/common-mistakes-and-how-to-avoid-them).
Waar dit aansluit op moderne AI-gestuurde workflows: platforms zoals Koder.ai kunnen volledige full-stack apps genereren en itereren (React voor web, Go + PostgreSQL voor backend, Flutter voor mobiel) via een chatinterface—maar je hebt nog steeds een betrouwbaar verpakkingsunit nodig om van “het draait” naar “het wordt uitgeleverd” te gaan. Iedere build als een versioned containerimage behandelen houdt ook AI-versnelde ontwikkeling in lijn met dezelfde CI/CD-verwachtingen: reproduceerbare builds, voorspelbare deploys en rollback-klaar releases.
Docker maakte het praktisch om een app één keer te verpakken en overal te draaien. De volgende uitdaging kwam snel: teams draaiden niet één container op één laptop—ze draaiden er tientallen (en later honderden) over veel machines, met voortdurend wisselende versies.
Dan wordt “een container starten” niet meer het moeilijke deel. Het moeilijke deel wordt het beheren van een vloot: beslissen waar elke container draait, het juiste aantal exemplaren online houden en automatisch herstellen als er iets faalt.
Als je veel containers over veel servers hebt, heb je een systeem nodig dat ze coördineert. Dat is wat containerorkestrators doen: ze behandelen je infrastructuur als een pool resources en werken continu om applicaties in de gewenste staat te houden.
Kubernetes werd het meest gebruikte antwoord op die behoefte (maar het is niet de enige). Het biedt een gedeelde set concepten en API's waar veel teams en platforms zich op standaardiseren.
Het helpt om verantwoordelijkheden te scheiden:
Kubernetes introduceerde (en populariseerde) praktische mogelijkheden die teams nodig hadden zodra containers verder gingen dan één host:
Kortom: Docker maakte de eenheid draagbaar; Kubernetes hielp die operabel te maken—voorspelbaar en continu—wanneer er veel eenheden tegelijk bewegen.
Containers veranderden niet alleen hoe we software deployen—ze duwden teams ook om software anders te ontwerpen.
Voor containers kostte het opsplitsen van een app in veel kleine services vaak extra operationele pijn: verschillende runtimes, conflicterende afhankelijkheden en ingewikkelde deploy-scripts. Containers verminderden die frictie. Als elke service als image wordt geleverd en op dezelfde manier draait, voelt het creëren van een nieuwe service minder riskant.
Toch werken containers ook goed voor monolieten. Een monoliet in een container kan eenvoudiger zijn dan een half-afgemaakte microservices-migratie: één deploybaar onderdeel, één set logs, één schaalhendel. Containers dwingen geen stijl af—ze maken meerdere stijlen beheersbaarder.
Containerplatforms moedigden apps aan zich te gedragen als goed-gedisciplineerde “black boxes” met voorspelbare inputs en outputs. Veelvoorkomende conventies zijn:
Deze interfaces maakten het eenvoudiger om versies te wisselen, terug te rollen en dezelfde app op laptop, CI en productie te draaien.
Containers populariseerden herhaalbare bouwstenen zoals sidecars (hulpcontainer naast de hoofdapp voor logging, proxies of certificaten). Ze versterkten ook de richtlijn van één proces per container—geen strikte regel, maar een nuttige default voor duidelijkheid, schaling en troubleshooting.
De belangrijkste valkuil is over-splitsen. Alleen omdat je alles in services kunt opdelen, betekent dat niet dat je het moet doen. Als een microservice meer coördinatie, latency en deploy-overhead toevoegt dan het wegneemt, houd het samen totdat er een duidelijke scheidingslijn is—zoals andere schaalbehoeften, eigenaarschap of foutisolatie.
Containers maken software makkelijker te leveren, maar ze maken het niet automatisch veiliger. Een container is nog steeds code plus afhankelijkheden en kan verkeerd geconfigureerd, verouderd of zelfs kwaadaardig zijn—vooral als images van internet worden gehaald zonder controle.
Als je niet kunt beantwoorden “Waar komt deze image vandaan?” loop je al risico. Teams bewegen naar een duidelijke keten van bewaring: images in gecontroleerde CI bouwen, tekenen of attesten wat is gebouwd, en bijhouden wat er in de image zit (afhankelijkheden, base image-versie, buildstappen).
Daar helpen SBOMs (Software Bills of Materials) bij: ze maken de inhoud van je container zichtbaar en auditbaar.
Scannen is de volgende praktische stap. Scan images regelmatig op bekende kwetsbaarheden, maar behandel resultaten als input voor beslissingen—niet als een garantie voor veiligheid.
Een veelgemaakte fout is containers draaien met te brede permissies—root als default, extra Linux-capabilities, host networking of privileged mode “omdat het werkt.” Elk van deze vergroot de blast radius als er iets misgaat.
Secrets vormen een andere valkuil. Omgevingsvariabelen, ingebakken configbestanden of gecommitte .env-bestanden kunnen credentials lekken. Gebruik bij voorkeur een secret store of orchestrator-managed secrets en roteer ze alsof blootstelling onvermijdelijk is.
Zelfs “schone” images kunnen gevaarlijk zijn tijdens runtime. Let op blootgestelde Docker-sockets, te permissieve volume-mounts en containers die toegang hebben tot interne services die ze niet nodig hebben.
Onthoud ook: het patchen van je host en kernel blijft belangrijk—containers delen de kernel.
Denk in vier fasen:
Containers verlagen frictie—maar vertrouwen moet nog steeds verdiend, geverifieerd en continu onderhouden worden.
Docker maakt verpakking voorspelbaar, maar alleen als je het met enige discipline gebruikt. Veel teams rijden in dezelfde kuilen—en geven daarna “containers” de schuld terwijl het eigenlijk workflowproblemen zijn.
Een klassieke fout is reusachtige images bouwen: volledige OS-base images gebruiken, build-tools installeren die je niet nodig hebt tijdens runtime, en de hele repo kopiëren (inclusief tests, docs en node_modules). Het resultaat is trage downloads, trage CI en meer aanvalsoppervlak voor beveiligingsproblemen.
Een andere veelvoorkomende fout is langzame, cache-brekende builds. Als je de hele source kopieert voordat je afhankelijkheden installeert, dwingt elke kleine code-wijziging een volledige dependency-herinstallatie af.
Tot slot gebruiken teams vaak vage of zwevende tags zoals latest of prod. Dat maakt rollbacks pijnlijk en verandert deployments in giswerk.
Dit komt meestal door verschillen in configuratie (missende env vars of secrets), networking (andere hostnames, poorten, proxies, DNS) of opslag (data naar het containerbestandssysteem schrijven in plaats van een volume, of bestandspermissies die tussen omgevingen verschillen).
Gebruik slim base images wanneer mogelijk (of distroless als je team er klaar voor is). Pin versies voor base images en belangrijke dependencies zodat builds herhaalbaar zijn.
Adopteer multi-stage builds om compilers en build-tools uit de uiteindelijke image te houden:
FROM node:20 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-slim
WORKDIR /app
COPY --from=build /app/dist ./dist
CMD ["node","dist/server.js"]
Tag images met iets traceerbaars, zoals een git SHA (en optioneel een gebruiksvriendelijke releasetag).
Als een app echt simpel is (énige statische binary, zelden draaien, geen schaalbehoefte), kunnen containers extra overhead toevoegen. Legacy-systemen met strakke OS-koppelingen of gespecialiseerde hardwaredrivers kunnen ook minder geschikt zijn—soms is een VM of een managed service de schonere keuze.
Containers werden de standaard-eenheid omdat ze een heel specifiek, herhaalbaar probleem oplosten: hetzelfde app op dezelfde manier laten draaien op laptops, testservers en productie. Het samen verpakken van de app en zijn afhankelijkheden maakte deployments sneller, rollbacks veiliger en overdrachten tussen teams minder fragiel.
Even belangrijk: containers standaardiseerden de workflow: build once, ship, run.
“Standaard” betekent niet dat alles overal in Docker draait. Het betekent dat de meeste moderne delivery-pijplijnen een containerimage als primair artefact behandelen—meer dan een zip-bestand, VM-snapshot of set handmatige setup-stappen.
Dat standaard omvat meestal drie onderdelen die samenwerken:
Begin klein en focus op herhaalbaarheid.
.dockerignore toe.1.4.2, main, sha-…) en bepaal wie mag pushen versus pullen.Als je experimenteert met snellere manieren om software te bouwen (inclusief AI-ondersteunde methoden), blijf dezelfde discipline toepassen: versies van de image, bewaar in een registry en laat deployments dat ene artefact promoten. Daarom profiteren teams die Koder.ai gebruiken ook van container-first delivery—snelle iteratie is geweldig, maar reproduceerbaarheid en rollback-mogelijkheid maken het veilig.
Containers verminderen “works on my machine”-problemen, maar ze vervangen geen goede operationele gewoonten. Je hebt nog steeds monitoring, incident response, secrets management, patching, toegangscontrole en duidelijke eigenaarschap nodig.
Behandel containers als een krachtig verpakkingsstandaard—niet als een shortcut om engineeringdiscipline te vermijden.
Solomon Hykes is een engineer die het werk leidde dat OS-niveau isolatie (containers) omzette naar een ontwikkelaar-vriendelijke workflow. In 2013 werd dat werk publiek uitgebracht als Docker, waardoor het praktisch werd voor teams om een app met zijn afhankelijkheden te verpakken en consistent te draaien in verschillende omgevingen.
Containers zijn het onderliggende concept: geïsoleerde processen die OS-functies gebruiken (zoals namespaces en cgroups op Linux). Docker is de tooling en de conventies die het makkelijk maakten om containers te bouwen, draaien en delen (bijv. Dockerfile → image → container). Tegenwoordig kun je containers ook zonder Docker gebruiken, maar Docker populariseerde de workflow.
Het loste het probleem “works on my machine” op door applicatiecode en de verwachte afhankelijkheden samen te verpakken tot één herhaalbare, draagbare eenheid. In plaats van een ZIP-bestand met installatie-instructies, zetten teams een containerimage in productie die op laptops, CI, staging en productie op dezelfde manier kan draaien.
Een Dockerfile is het bouwrecept.
Een image is het gebouwde artefact (een onveranderlijke snapshot die je kunt opslaan en delen).
Een container is een draaiende instantie van die image (een live proces met geïsoleerd bestandssysteem en instellingen).
Vermijd latest omdat het vaag is en onverwacht kan veranderen, waardoor omgevingen uiteen kunnen lopen.
Beter:
1.4.2sha-<hash>)Een registry is waar je containerimages opslaat zodat andere machines en systemen exact dezelfde build kunnen downloaden.
Typische workflow:
Voor de meeste teams is een belangrijk voor toegangscontrole, compliance en om interne code uit openbare indexes te houden.
Containers delen de kernel van de host, daarom zijn ze meestal lichter en starten ze sneller dan VM's.
Eenvoudig model:
Praktische limiet: je kunt meestal geen Windows-containers op een Linux-kernel draaien (en andersom) zonder extra virtualisatie.
Ze laten je één pipeline-output produceren: de image.
Veelvoorkomend CI/CD-patroon:
Je past per omgeving configuratie aan (env vars/secrets), niet het artefact zelf—dat vermindert drift en maakt rollbacks eenvoudiger.
Docker maakte het makkelijk om een container te draaien op één machine. Op schaal heb je óók nodig:
Kubernetes biedt die mogelijkheden zodat fleets containers voorspelbaar beheerd kunnen worden over meerdere machines.
Containers maken het eenvoudiger om software te verspreiden, maar ze maken het niet automatisch veiliger.
Praktische basics:
privileged, minimaliseer capabilities, draai niet als root indien mogelijk)Voor veelvoorkomende valkuilen (grote images, cache-busting builds, vage tags) zie ook de aanbevolen best practices.