Eigene Docker-Images für GitLab CI: Node.js Build-Container und lokale Registry


In diesem Beitrag geht es darum, wie man ein eigenes Docker-Image auf Debian-Basis erstellt, das Node.js enthält und sich ideal für den Einsatz in GitLab CI/CD-Pipelines eignet. Das Ziel: eine statische Website mit Astro bauen und automatisch auf einen Webserver deployen – ganz ohne externe Abhängigkeiten wie Docker Hub.

Ich nutze dafür eine eigene Docker-Registry, die lokal oder direkt auf meinem GitLab-Server läuft.


Ziel des Setups

  • 🧱 Ein reproduzierbarer CI-Container, der nur das enthält, was wirklich gebraucht wird
  • 🚀 Kein Abhängigkeits- oder Pull-Limit vom Docker Hub
  • 🔐 Deployment via SCP direkt auf den Zielserver
  • 🔁 Wiederverwendbar für andere Node.js-Projekte

Dockerfile: Node.js auf Debian 12

FROM debian:12
 
ENV DEBIAN_FRONTEND=noninteractive
 
RUN apt-get update && \
    apt-get install -y \
        apt-transport-https \
        ca-certificates \
        curl \
        gnupg \
        openssh-client \
        lsb-release \
    && rm -rf /var/lib/apt/lists/*
 
ENV NODE_MAJOR=18
 
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_MAJOR}.x | bash - && \
    apt-get install -y nodejs

Dieses Image ist bewusst schlank gehalten:

  • Debian 12 als stabile Basis
  • Node.js 18 aus den offiziellen Nodesource-Repos
  • SSH-Tools für das spätere Deployment via scp

Image bauen und lokal taggen

docker build -t nodebuilder:latest -f nodebuilder.docker .
docker tag nodebuilder:latest localhost:5000/nodebuilder:latest

Lokale Docker-Registry starten

Falls du noch keine lokale Registry betreibst, kannst du sie so starten:

docker run -d -p 5000:5000 --restart=always --name registry registry:2

Die Registry lauscht dann unter http://localhost:5000.

Wenn du GitLab verwendest, kannst du auch die integrierte Container Registry nutzen (z. B. gitlab.dunzweiler.me:5050), sofern deine Runner Zugriff darauf haben.


Image in Registry pushen

docker push localhost:5000/nodebuilder:latest

Oder bei GitLab Registry:

docker tag nodebuilder:latest gitlab.dunzweiler.me:5050/dunzweiler_public/nodebuilder_docker/nodebuilder
docker push gitlab.dunzweiler.me:5050/dunzweiler_public/nodebuilder_docker/nodebuilder

GitLab CI/CD: Build und Deployment

Das ist meine gitlab-ci.yml, wie ich sie für meine Astro-basierte Blogseite einsetze:

image: gitlab.dunzweiler.me:5050/dunzweiler_public/nodebuilder_docker/nodebuilder
 
cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - node_modules/
 
pages:
  script:
    - npm install
    - npm run build
    - mkdir ~/.ssh/
    - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - ssh-keyscan -H $SCP_HOST >> ~/.ssh/known_hosts
    - scp -r -i ~/.ssh/id_rsa dist/* $SCP_USER@$SCP_HOST:/var/www/blog/
  only:
    - master

Erklärung:

  • image: Das eigene, vorher gepushte Docker-Image
  • cache: Spart Zeit bei wiederholten Builds (z. B. node_modules)
  • script:
    • Build-Prozess mit npm
    • Einrichtung des SSH-Zugriffs
    • Deployment via scp
  • Die SSH-Variablen SSH_PRIVATE_KEY, SCP_USER und SCP_HOST sind in GitLab als geschützte Variablen (protected variables) hinterlegt

Typische Fehlerquellen

  • Image nicht gepusht: Das CI-Joblog sagt „Image not found“ → Push in Registry vergessen?
  • SSH-Fehler: Schlüssel nicht gesetzt oder falsche Berechtigungen (chmod 600)
  • Deployment schlägt fehl: Hostname falsch, Pfad nicht vorhanden oder SSH-Host unbekannt → ssh-keyscan hilft

Vorteile des eigenen CI-Images

VorteilBeschreibung
Keine Drittanbieter-AbhängigkeitKein Docker Hub notwendig
Kontrolle über UmgebungReproduzierbares Build-Verhalten
Schnellere BuildsKein externer Pull, Caching lokal oder via GitLab möglich
SicherheitDeployment mit SSH-Schlüssel, keine Passwörter im Klartext
ErweiterbarTools wie rsync, imagemagick, etc. können bei Bedarf ergänzt werden

Fazit

Wer mit GitLab arbeitet und regelmäßig Builds ausführt, sollte über eigene CI-Images nachdenken. Besonders bei statischen Seiten wie Astro oder Next.js macht ein aufgeräumtes Node.js-Image Sinn – und spart auf Dauer Nerven, Zeit und externen Traffic.

Ob lokal oder per GitLab Registry – so ein Image ist schnell gebaut und bringt viel Kontrolle zurück ins eigene Setup.