Automatisering is niets vreemds
De vorige keer heb ik via 10 minuten downtime en een incidentrapport een harde les geleerd. Deployment is geen magie, maar moet een opeenvolging zijn van strenge veiligheidsmechanismen: “Git, vastleggen – Test, verifiëren – Build, verpakken – Deploy, afleveren”.
Nu is het doel duidelijk. Ik kan deze complexe en irritante veiligheidsmechanismen niet elke keer met mijn eigen handen blijven controleren. Ik heb een “ijverige robot” nodig die in mijn plaats werkt, zelfs nadat ik naar huis ben gegaan of wanneer ik op vakantie ben.
“Automatisering? Is dat niet wat overdreven groots?”
In het begin schrok ik ervan, maar als ik er goed over nadacht, had ik al iets heel vergelijkbaars meegemaakt. Namelijk “Docker”, waar we het in de vorige serie over hadden.
Wanneer we in een Dockerfile schrijven “installeer Ubuntu, installeer Java, kopieer de code”, leest Docker dat en bouwt het de serveromgeving vanzelf op. Daardoor zijn we bevrijd van het handmatige geploeter van commando’s intypen.
Een “CI/CD-pipeline” werkt precies hetzelfde. Als Docker “serverinstellingen” heeft geautomatiseerd, dan automatiseert de pipeline “het volledige deploymentproces”. Alleen het toneel is groter geworden: van mijn eigen computer naar een grotere wereld genaamd “GitLab en de productie-server”.

CI/CD: de geautomatiseerde lopende band
Laten we nu een “automatiseringslijn” installeren in ons “digitale logistieke centrum”. Het klinkt groots, maar het principe is eenvoudig.
1. CI (Continuous Integration, continue integratie)
- Betekenis: “De code van ontwikkelaars voortdurend samenvoegen en controleren.”
- Rol: [build + test]. Dit is de fase waarin de machine, zodra ik code upload, voor mij nagaat: “Klopt de syntax?” en “Is er geen bestaande functionaliteit kapotgegaan?” Ondeugdelijke producten worden hier tegengehouden.
2. CD (Continuous Delivery/Deployment, continue levering/deployment)
- Betekenis: “Gecontroleerde code bij de klant afleveren.”
- Rol: [image maken + deployen naar de server]. Dit is de fase waarin het goedgekeurde product (Docker Image) op de vrachtwagen wordt geladen, naar de productie-server wordt gebracht en daar ook meteen wordt opgestart.
De blauwdruk van de pipeline: .gitlab-ci.yml
“Dus hoe laat je die robot werken?” In GitLab hoef je alleen maar een bestand met de naam .gitlab-ci.yml aan te maken in de hoofdmap van het project. Dat is precies het “werkbriefje” dat je aan de robot geeft.
Herinner je je de pijn van handmatig deployen nog die ik de vorige keer heb meegemaakt? Laten we precies dat proces in code omzetten. Net als bij het schrijven van een Dockerfile schrijf je het gewoon regel voor regel uit.
# .gitlab-ci.yml (de werkopdracht)
stages: # 1. Definieer de volgorde van de hele job
- test # (Stap 1: controle)
- build # (Stap 2: verpakken)
- deploy # (Stap 3: verzenden)
# [Stap 1] Test: machine, controleer of mijn code in orde is (CI)
unit_test_job:
stage: test
image: openjdk:17-alpine # Voer uit in een omgeving met Java geinstalleerd
script:
- ./gradlew test # "Voer de tests uit!" (voorkomt vorige fout)
# [Stap 2] Build: als tests slagen, maak er een image van (CI)
build_image_job:
stage: build
image: docker:latest # Voer uit in een omgeving met Docker
script:
- docker build -t my-app:v1 . # "Bouw de image!"
- docker push my-regisry/my-app:v1 # "Push naar de registry!" (rollback-tag verplicht)
# [Stap 3] Deploy: zet het op de productieserver (CD)
deploy_job:
stage: deploy
script:
- ssh user@server "docker service update my-app" # "Update de server!"
Dit ene bestand is voldoende. Op het moment dat ik een git push doe, dus op het trigger-moment, leest GitLab dit werkbriefje en maakt een werkrobot wakker die “GitLab Runner” heet om het werk uit te voeren.
[Check] De veiligheidsmechanismen die we moeten meenemen
In deze pipeline zitten alle drie de veiligheidsmechanismen ingebouwd die ik de vorige keer zo pijnlijk heb geleerd.
- Git (Trigger):
- Het moment waarop ik lokaal code
push, is zelf al de “startknop” van de pipeline. Zonder vastlegging (Commit) begint er ook geen deployment.
- Het moment waarop ik lokaal code
- Unit Test (Quality Gate):
- Wat als de test in
unit_test_jobfaalt? Dan “stopt” de pipeline onmiddellijk (Fail). Zo wordt bij de bron voorkomen dat een ondeugdelijk product doorschuift naar de volgende fase (build/deploy). (Tests overslaan omdat je het druk hebt, is er nu niet meer bij!)
- Wat als de test in
- Docker Image (Artifact):
- De image die in de build-fase wordt gemaakt, wordt veilig opgeslagen in Docker Hub. Ook als de server later crasht, kun je met alleen deze image binnen 1 seconde herstellen.

Praktisch advies: een pipeline is een levend wezen
Probeer niet vanaf het begin een perfecte pipeline te schrijven. Ik begon zelf ook met maar twee fasen, build en deploy, en pas nadat er iets misging, voegde ik de test-fase ervoor toe.
- Beginfase: build -> deploy (het ging er vooral om dat het überhaupt geautomatiseerd was)
- Tussenfase: test -> build -> deploy (veiligheidsmechanisme toegevoegd)
- Volwassen fase: test -> statische analyse (SonarQube) -> build -> deploy naar dev-server -> (goedkeuring) -> deploy naar productie-server
Een pipeline is een “levend systeem” dat blijft evolueren in het tempo waarin je team groeit.
Tot slot: de instructies zijn geschreven, maar wie doet het werk eigenlijk?
Nu is de perfecte blauwdruk, .gitlab-ci.yml, klaar. Maar een instructieblad op papier gaat niet vanzelf bewegen. Net zoals een Dockerfile nog steeds Docker Daemon nodig heeft om uitgevoerd te kunnen worden, heeft ook een pipeline-instructieblad een “robot op de werkvloer” nodig die echt zweet door de code te bouwen en uit te voeren.
De naam van deze robot is “GitLab Runner”. De fabrieksmanager, dus de GitLab Server, geeft alleen instructies. Het echte werk wordt uitgevoerd door deze runner.
De volgende keer installeren we deze runner op mijn computer of op een aparte server, koppelen we hem aan GitLab en laten we de pipeline echt draaien. Dit is eindelijk het moment waarop de eerste knoop van automatisering wordt dichtgemaakt.


