Docker: NodeJS Prozesse automatisch via GitLab als Private Docker Registry deployen

Einleitung

In diesen Aritkel beschreibe ich, wie man GitLab als Docker-Registry einrichten kann, um eigene NodeJS Projekte einfach als Image via Docker deployen zu können.

Hierzu beschreibe ich folgende Schritte:

  1. Erstellen einer sehr einfachen ExpressJS Demo Applikation
  2. Vorbereitung des GitLab Docker Containers als Registry
  3. Erstellen und Ablegen des Images
  4. Einbinden des Images in Docker Compose
  5. Anpassungen an NGINX und AWS DNS Services

Erstellen einer sehr einfachen ExpressJS Demo Applikation

Um es in diesen Artikel einfach zu machen, wird zunächst eine einfache Hello World Applikation geschrieben, die via ExpressJS/NodeJS diesen Text auf den Bildschirm ausgibt.

Insgesamt sind nur drei Dateien Relevant.

In der "package.json" wird nur das Start Kommando und die "Express" dependancy definiert:

package.json

{
  "name": "demo1",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"   
  },
  "repository": {
    "type": "git",
    "url": "http://git.vr-worlds.de/smoki99/demo1.git"
  },
  "author": "",
  "license": "MIT",
  "dependencies": {
    "express": "^4.16.2"
  }
}

Hier ist das eigentliche Javascript Programm das Anfragen annimmt und "Hello World" zurückliefert.

server.js

'use strict';

const express = require('express');

// Constants
const PORT = 3000;  
const HOST = '0.0.0.0';

// App
const app = express();  
app.get('/', (req, res) => {  
  res.send('Hello world\n');
});

app.listen(PORT, HOST);  
console.log(`Running on http://${HOST}:${PORT}`);  

Nun kann man es schon lokal ausprobieren, nachdem die folgenden Kommandos eingegeben wurden:

Anschließend wird der erwartete Text im Browser auch angezeigt:

Nun kommt der erste spannende Teil des Artikels. Es wird ein Dockerfile angelegt, dass später für den Build des Images benötigt wird:

FROM node:carbon

WORKDIR /usr/src/app

# Install all dependancies
COPY package*.json ./

# Install packages
RUN npm install

# Copy Everything local
COPY . .

# The port we want to expose
EXPOSE 3000

# Start of the command
CMD [ "npm", "start" ]  

Im einzelnen wird ein Basis Image heruntergeladen "node:carbon" -> https://hub.docker.com/_/node/
Es handelt sich hierbei immer um die letzte letzte Long-Time Support Version von NodeJS. Hiermit stellen wir sicher das die Grundlagen für eine NodeJS Applikation in unseren Docker-Container vorhanden ist.

Innerhalb des Containers wollen wir unsere Applikation im Verzeichnis "/usr/src/spp" betreiben. Daher das Kommando:

WORKDIR /usr/src/app  

Als nächstes Kopieren wir uns das "package.json" File und starten "npm install" um die notwendigen Module herunter zu laden:

# Install all dependancies
COPY package*.json ./

# Install packages
RUN npm install  

Anschließend kopieren wir alle Dateien, die wir hinterlegt haben. Als Port wollen wir nur die 3000 verwenden und aus dem Container exportieren, daher geben wir das an. Anschließend starten wir den Server mit "npm start".

Nun müssen wir die Dateien wie Üblich nur noch auf unser GitLab übertragen:

Vorbereitung des GitLab Docker Containers als Registry

Damit GitLab auch eine Registry hat muss diese aktiviert werden. In meinen Fall habe ich es als eigenen Docker-Container konfiguriert und muss nun die Datei "gitlab.rb" entsprechend konfigurieren, damit die Docker Registry auch läuft:

Hier ist zunächst (wenn nicht schon erfolgt) sicherzustellen, dass die "external_url" stimmt in meinen Fall "git.vr-worlds.de":

external_url 'http://git.vr-worlds.de'  

Zudem ist die Registry zu konfigurieren. In meinen Fall habe ich den Port 5555 ausgewählt:

################################################################################
## Container Registry settings
##! Docs: https://docs.gitlab.com/ce/administration/container_registry.html
################################################################################

registry_external_url 'https://git.vr-worlds.de:5555'

### Settings used by GitLab application
gitlab_rails['registry_enabled'] = true

Nach einen Neustart des Gitlab Docker Containers, ist nun die Registry verfügbar:

Die Registry kann aber noch nicht verwendet werden, da der Port noch nicht durchgereicht wird.

In meinen docker-compose.yml File trage ich nun den Port 5555 ein, dass dieser nach aussen als Port 5000 durchgereicht werden soll:

  gitlab:
    container_name: gitlab
    image: gitlab/gitlab-ce:9.3.11-ce.0
    network_mode: bridge
    ports:
       - "8443:443"
       - "8083:80"
       - "8022:22"
       - "8060:8060"
       - "5000:5555"

Zusätzlich muss ich bei Hetzner in der Firewall diesen Port auch freigeben:

Mit "docker-compose up -d" lass ich nun den Gitlab erneut starten:

Anschließend sollte eine Anmeldung an der Registy möglich sein:

Erstellen und Ablegen des Images

Anschließend kann auf dem Test-Server (mit Docker) das Demo ausgecheckt werden und das Image gebildet werden.

Das Auschecken erfolgt mit einen klassichen Git Clone:

Anschließend kann das Image erstellt werden:

Und anschließend kann das fertige Image auf GitLab gepushed werden: (hier sieht man im Screenshot schön, dass bereit Vorhande Teile nicht mehr neu abgelegt werden und man bekommt nur den Hinweis "Layer already existes")

Nun ist das Image auch in GitLab im Projekt zu sehen:

Einbinden des Images in Docker Compose

Nun kann das Image im docker-compose.yml eingepflegt werden:

Hat man temporär den Port 3000 offen, kann man es nun bereits hierüber sehen:

Anpassungen an NGINX und AWS DNS Services

Natürlich sollte der Port 3000 nicht für die Öffentlichkeit geöffnet werden. Besser ist es den Port 3000 über einen NGINX Proxy zu leiten, der bei anfragen an bspw. http://demo1.vr-worlds.de eine entsprechende Weiterleitung macht.

Das ist auch nicht wirklich schwer. NGINX muss entsprechend einen Eintrag in "localhost.conf" erhalten:

server {  
  listen 0.0.0.0:80;
  server_name demo1.vr-worlds.de;
  access_log /var/log/nginx/demo1.log;

  location / {
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header HOST $http_host;
      proxy_set_header X-NginX-Proxy true;

      proxy_pass http://demo1:3000;
      proxy_redirect off;
  }
client_max_body_size 40000M;  
}

Desweiteren muss nochmal die docker-compose.yml angepasst werden, damit Nginx auch Zugang zur Demo1 findet:

 nginxserver:
    container_name: nginxserver
    image: nginx
    network_mode: bridge
    links:
      - blog:blog
      - gitlab:gitlab
      - owncloud:owncloud
      - demo1:demo1

Zu guter letzt wird noch ein DNS Eintrag benötigt (bei mir in AWS):

Jetzt muss nur nochmal mit "docker-compose up -d" die Einstellung aktualisiert werden:

[root@CentOS-73-64-minimal dockercompose]# docker-compose up -d
demo1 is up-to-date  
ghost-mysql is up-to-date  
gitlab is up-to-date  
owncloud is up-to-date  
blog is up-to-date  
nginxserver is up-to-date  
[root@CentOS-73-64-minimal dockercompose]#

Anschließend funktioniert die URL:

Damit ist das Ziel erreicht

Zusammenfassung

Glücklicherweise sind die meisten Schritte nur einmal durchzuführen und anschließend ist für ein neues erstellen von Images viel weniger Aufwand notwendig.

Spannend wird es natürlich erst wenn man auch diese Schritte mittels CI automatisiert, aber das würde jetzt diesen Artikel sprengen und wird in einen meiner späteren Artikel beschrieben.

Ich wünsche viel Erfolg!