2.3. Umsetzung¶
2.3.1. Gitea on Docker Compose mit PostgreSQL¶
Zum Aufsetzen der Gitea-Instanz auf einem Docker-Host wird Docker Compose verwendet, um die Konfiguration und Bereitstellung von Gitea und PostgreSQL zu vereinfachen. Der Nginx Webserver wird nicht in Docker Compose konfiguriert, sondern in den nächsten Schritten manuell auf dem Host-System eingerichtet, inklusive Reverse-Proxy-Funktionalität. Folgendes Docker-Compose-Beispiel zeigt die Konfiguration von Gitea und PostgreSQL in getrennten Containern.
networks:
gitea:
external: false
services:
server:
image: gitea/gitea:1.21.7
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=db:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=*#+*4sv*sjmEWfY:U88D$$gRzFvSNE9;H
restart: always
networks:
- gitea
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "222:22"
depends_on:
- db
db:
image: postgres:14
restart: always
environment:
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=*#+*4sv*sjmEWfY:U88D$$gRzFvSNE9;H
- POSTGRES_DB=gitea
networks:
- gitea
volumes:
- ./postgres:/var/lib/postgresql/data
Die finale und reproduzierbare Version ist in Gitea/docker-compose.yml abgelegt.
Erklärung der Dockerfile-Konfiguration¶
Die Docker-Konfiguration umfasst die Einrichtung einer Gitea-Instanz und einer PostgreSQL-Datenbank in getrennten Containern innerhalb eines Docker-Netzwerks.
Netzwerkkonfiguration¶
Das Netzwerk
gitea
wird definiert und ist ausschließlich innerhalb der Docker-Umgebung sichtbar.Über das isolierte Netzwerk können die Gitea- und PostgreSQL-Container miteinander kommunizieren.
Servicekonfiguration¶
Gitea-Service¶
Verwendet das offizielle Gitea-Image
gitea/gitea:1.21.7
.Setzt den Container-Namen auf
gitea
.Konfiguriert Gitea mit Umgebungsvariablen für Benutzer-IDs und Datenbankverbindungen.
Sorgt für den automatischen Neustart des Containers.
Verbindet den Service mit dem
gitea
Netzwerk.Bindet Host-Verzeichnisse für persistente Daten und Systemzeit-Synchronisation.
Leitet Ports für Webinterface und SSH weiter.
Stellt die Abhängigkeit zum Datenbank-Service sicher.
Datenbank-Service (PostgreSQL)¶
Nutzt das PostgreSQL-Image
postgres:14
.Konfiguriert PostgreSQL mit Umgebungsvariablen für Benutzer, Passwort und Datenbank.
Bindet den Service an das
gitea
Netzwerk.Speichert Datenbankdaten persist auf dem Host-System.
Diese Konfiguration ermöglicht eine effiziente Einrichtung von Gitea und PostgreSQL in Docker, wobei die Portabilität und einfache Skalierung der Dienste im Vordergrund stehen.
2.3.2. Let’s Encrypt & CertBot¶
Let’s Encrypt ist eine Zertifizierungsstelle, die kostenlose SSL/TLS-Zertifikate ausstellt, um die Verschlüsselung von Websites zu fördern.
Die CA stellt eine ACME (Automated Certificate Management Environment) API bereit, die von Tools wie Certbot genutzt wird, um Zertifikate automatisch zu erhalten und zu erneuern.
Certbot ist ein Open-Source-Tool, das entwickelt wurde, um die Einrichtung von SSL-Zertifikaten zu vereinfachen und zu automatisieren.
Installation¶
snap
ist ein Paket-Manager für Ubuntu und wird benötigt zum Installieren von certbot
.
Mit dem simplen Befehl wird dieses installiert:
sudo apt install snapd
Anschließend kann dieses getestet werden mittels:
sudo snap install hello-world
Um certbot
zu installieren nutzen wir den snap
Paket-Manager:
sudo snap install --classic certbot
Anschließend fügen wir die ausführbare Datei unserem Pfad hinzu um certbot
von jeden Verzeichnis aus bequem aufrufen zu können:
sudo ln -s /snap/bin/certbot /usr/bin/certbot
Der oben aufgeführte Befehl erstellt eine symbolische Verknüpfung zur certbot
Datei.
Dies bedeutet dass die Datei in /usr/bin/
lediglich auf die Datei in /snap/bin/
verweist und der eigentlich Aufruf dort erfolgt.
Konfiguration¶
Nun ist es möglich Zertifikate anzufragen. Dies geschieht über den Befehl:
sudo certbot --nginx
Oder über diesen Befehl, wenn wir keine automatische Installation in Nginx wünschen:
sudo certbot certonly --nginx
certbot
legt automatisch einen cron
Auftrag an, welche genutzt werden um Befehle zu einem bestimmten Zeitpunkt auszuführen wie „Jeden Tag um 08:00 Uhr“.
Dadurch kommt es zu keinen Fehlschlägen bei der SSL Verschlüsselung durch abgelaufene Zertifikate.
Um diese Funktionalität zu testen ist folgender Befehl vorhanden:
sudo certbot renew --dry-run
2.3.3. NGINX¶
Installation¶
Um nginx
zu installieren sind ein paar Schritte nötig.
Um die benötigten Abhängigkeiten zu installieren nutzen wir folgenden Befehl:
sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring
Um nginx
aus der offiziellen Repository zu beziehen wird ein „Signing Key“ benötigt, welcher die Authentifizierung der Datei bestätigt:
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg
Die Ausgabe sollte nun den folgenden Fingerabdruck beinhalten:
pub rsa2048 2011-08-19 [SC] [expires: 2024-06-14]
573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62
uid nginx signing key <signing-key@nginx.com>
Nun können wir das Repository hinzufügen:
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
Der letzte Schritt legt das hinzugefügte Repository als bevorzugtes Repository fest um zu verhindern dass nginx
aus den Standard Repositories bezogen wird:
echo -e "Package: \*\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
| sudo tee /etc/apt/preferences.d/99nginx
Nun können wir nginx
installieren:
sudo apt install nginx
Konfiguration¶
Um die Reverse Proxy zu konfigurieren ist es nötig ins nginx
Verzeichnis zu wechseln:
cd /etc/nginx/
Aus Organisationszwecken erstellen wir nun zwei Ordner im Verzeichnis: sites-available
und sites-enabled
mkdir sites-available sites-enabled
Im ersteren Ordner werden alle Konfigurationen aufbewahrt und sobald diese „aktiviert“ werden sollen, werden diese mittels symbolischer Links verknüpft mit dem letzteren Ordner.
Nun wird die Konfigurationsdatei für unseren Gitea Service erstellt im Ordner sites-enabled
:
cd sites-available
sudo nano gitea.conf
Innerhalber dieser Datei schreiben wir folgende Anweisungen an nginx
:
server {
listen 80 http2;
listen 443 http2 ssl;
server_name dva.mahart.ma;
ssl_certificate /etc/letsencrypt/live/dva.mahart.ma/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/dva.mahart.ma/privkey.pem; # managed by Certbot
location / {
client_max_body_size 512M;
proxy_set_header Connection $http_connection;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:3000$uri;
}
}
Diese Konfigurationdatei drückt aus dass wir auf den Ports 80 und 443 auf Anfragen hören möchten, sowie dass wir HTTP2 und SSL für Port 443 unterstützen.
Darauffolgend geben wir unsere Domain and und die Pfade zu unseren SSL Zertifikaten welche wir generiert haben.
Im location /
Tag können wir nun bestimmen was passiert wenn die Ressource unter dem Pfad /
angefragt wird.
Um Probleme mit Git Pushes zu vermeiden erlauben wir es dem Client größere Anfragen zu senden (512 MB), zudem setzen wir bestimmte Header innerhalb der Anfrage für die weitere Verarbeitung durch Gitea und leiten anschließend die Anfrage weiter and den internen Port 3000 auf welchem Gitea auf Anfragen wartet und diese weiterverarbeitet.
Anschließend „aktivieren“ wir diese Konfiguration mittels einer Verknüpfung:
sudo ln -s /etc/nginx/sites-available/gitea.conf /etc/nginx/sites-enabled/gitea.conf
Damit diese Konfiguration auch von nginx
beachtet wird, fügen wir sie und alle zukünftigen Konfigurationen der Hauptkonfigurationsdatei unter /etc/nginx/nginx.conf
hinzu:
cd /etc/nginx/
sudo nano /etc/nginx/nginx.conf
include /etc/nginx/sites-enabled/*.conf
Dadurch sollte die Konfigurationdatei ungefähr so aussehen:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*.conf;
}
Nun ist erfolgreich eine Reverse Proxy Konfiguration mit SSL Verschlüsselung erstellt.
Die NGINX Konfigurationsdatei ist zusätzlich unter Gitea/nginx.conf abgelegt.
2.4. Uncomplicated Firewall (UFW)¶
UFW ist nützlich für die Verwaltung von Firewall-Regeln auf Linux-Systemen. Es handlet sich um eine einfache Schnittstelle, um Netzwerkverbindungen auf unserem System zu steuern und Zugriffe auf Dienste entweder zu ermöglichen oder zu blockieren.
2.4.1. Verwaltung von IPTables:¶
UFW verwaltet IPTables im Hintergrund, indem es eine vereinfachte Benutzeroberfläche bereitstellt, um Regeln zu erstellen, zu ändern und zu löschen. IPTables ist ein leistungsstarkes Framework für das Filtern und Weiterleiten von Netzwerkdaten in Linux. UFW ermöglicht es Benutzern, IPTables-Regeln zu erstellen, ohne sich mit der komplexen Syntax von IPTables befassen zu müssen.
2.4.2. Default-Optionen:¶
Default Deny Incoming (Standardmäßig eingehenden Datenverkehr ablehnen): Diese Option blockiert jeglichen eingehenden Datenverkehr, der nicht explizit erlaubt ist. Dadurch wird das System vor unautorisiertem Zugriff von außen geschützt.
Default Allow Outgoing (Standardmäßig ausgehenden Datenverkehr zulassen): Diese Option erlaubt standardmäßig allen ausgehenden Datenverkehr, was sicherstellt, dass Anwendungen auf dem System problemlos auf externe Ressourcen zugreifen können.
2.4.3. Bedienung von UFW:¶
Hier sind einige grundlegende Befehle, um UFW zu verwenden:
UFW aktivieren: sudo ufw enable
UFW deaktivieren: sudo ufw disable
Regel hinzufügen: sudo ufw allow [Port/Protokoll]
Regel entfernen: sudo ufw delete [Nummer der Regel]
Status anzeigen: sudo ufw status verbose
sudo ufw allow 80/tcp - erlaubt eingehende TCP-Verbindungen auf Port 80, dem Standardport für HTTP-Verbindungen
sudo ufw allow 443/tcp - gestatten wir eingehenden TCP-Verkehr auf Port 443, dem Standardport für HTTPS-Verbindungen
sudo ufw allow ssh bzw. sudo ufw allow 22/tcp - erlauben eingehende SSH-Verbindungen auf Port 22, dem Standard-Port für SSH (Secure Shell)
sudo ufw allow 22/udp - erlaubt eingehenden UDP-Verkehr auf Port 22
Das vollständige reproduzierbare Script für die Umsetzung von UFW findet sich in Gitea/ufw.sh.
2.4.4. Traefik¶
Zur Demonstration der Einfachheit von Traefik wurde eine alternative Konfiguration für die Gitea-Instanz erstellt. Traefik ist ein moderner Reverse-Proxy und Load-Balancer, der speziell für Container-Umgebungen entwickelt wurde.
Die folgende YAML zeigt die Konfiguration von Traefik in Docker Compose:
traefik:
image: "traefik:v2"
container_name: "traefik"
command:
#- "--log.level=DEBUG"
#- "--api.insecure=true"
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=web"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.websecure.http.middlewares=https_config@docker,www-redirect@docker"
- "--entrypoints.websecure.http.tls.options=default"
- "--entrypoints.websecure.http.tls.certresolver=myresolver"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
#- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
- "--certificatesresolvers.myresolver.acme.email=mahartma@mahartma.com"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
labels:
traefik.enable: true
# https redirect
traefik.http.middlewares.https_config.redirectscheme.scheme: "https"
traefik.http.middlewares.https_config.redirectscheme.permanent: true
# www -> non-www
traefik.http.middlewares.www-redirect.redirectregex.regex: "^https://www.(.*)"
traefik.http.middlewares.www-redirect.redirectregex.replacement: "https://$${1}"
traefik.http.middlewares.www-redirect.redirectregex.permanent: true
# basic-auth
# Note: when used in docker-compose.yml all dollar signs in the hash need to be doubled for escaping.
# echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g
traefik.http.middlewares.dev-auth.basicauth.users: "username:TODO"
# dashboard
traefik.http.routers.api.rule: Host(`traefik.dva.mahart.ma`)
traefik.http.routers.api.service: api@internal
traefik.http.routers.api.middlewares: dev-auth
traefik.http.routers.api.entrypoints: websecure
com.centurylinklabs.watchtower.enable: true
ports:
- "443:443"
- "80:80"
volumes:
- "/var/lib/traefik/letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
networks:
- gitea
- default
restart: unless-stopped
Beachtlich ist, dass diese Docker-Compose Definition alle Features abdeckt, die vorher über NGINX konfiguriert wurden. Traefik bietet also eine einfache und effiziente Möglichkeit, Reverse-Proxy- und Load-Balancer-Funktionalitäten in Container-Umgebungen bereitzustellen.
Die Konfiguration bietet zusätzlich die Möglichkeit für basic auth und ein Dashboard für das Monitoring von Traefik.
Die Docker-Compose Definition ist unter Gitea/docker-compose-traefik.yml abgelegt.
2.4.5. Watchtower¶
Was ist Watchtower?¶
Watchtower ist ein Open-Source-Projekt, das entwickelt wurde, um Docker-Container automatisch zu überwachen und zu aktualisieren. Es überwacht laufende Container auf dem System und überprüft regelmäßig, ob neue Versionen der Images verfügbar sind. Wenn eine neue Version gefunden wird, aktualisiert Watchtower automatisch den entsprechenden Container, ohne dass manuelle Eingriffe erforderlich sind.
Installation und Verwendung¶
Die installation von Watchtower kann einfach als Docker realisierbar. Ein schneller Start ist mit folgenden Befehl möglich:
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower
Dieser Befehl startet den Watchtower-Container im Hintergrund und bindet an den Docker-Socket an das entsprechende Verzeichnis im Container, um auf die Docker-API Zugriff zu erhalten.
In unserem Fall verwenden wir eine docker-compose.yml, um die Anwendung mit Parametern zu erweitern:
version: "3"
services:
watchtower:
image: containrrr/watchtower
container_name: watchtower
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --label-enable --interval=43200 --cleanup
environment:
WATCHTOWER_NOTIFICATIONS: email
WATCHTOWER_NOTIFICATION_EMAIL_FROM: notifications@mail.net
WATCHTOWER_NOTIFICATION_EMAIL_TO: ops@mail.com
WATCHTOWER_NOTIFICATION_EMAIL_SERVER: mail.server.biz
WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER: notifications@mail.net
WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT: 587
WATCHTOWER_NOTIFICATION_EMAIL_SUBJECTTAG: web1
WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD: TODO
dieser kann mit folgendem command gestartet werden:
docker-compose up -d
Zur Konfiguration von Watchtower können Labels verwendet werden, um das Verhalten des Containers zu steuern.
Folgendes Label aktiviert Auto-Updates für einen Container und muss lediglich an den Container angehängt werden:
labels:
- "com.centurylinklabs.watchtower.enable=true"
Major und Minor Updates werden abhängig von der Konfiguration automatisch installiert. Wenn der Container auf Version 2 läuft, werden die Minor-Versionen (2.1, 2.2, 2.3 usw.) automatisch installiert. Wenn der Container auf Version 2.1 läuft, werden die Patch-Versionen (2.1.1, 2.1.2, 2.1.3 usw.) automatisch installiert.
Folgerung¶
Watchtower ist ein äußerst nützliches Werkzeug zur Automatisierung von Docker-Container-Aktualisierungen. Die nahtlose Integration in bestehende Infrastruktur macht es zu einer attraktiven option, Automatisierung für Docker umzusetzen. Durch die Nutzung von Watchtower können Administratoren sicherstellen, dass ihre Docker-Container immer auf dem neuestem Stand sind, ohne dass ein manuelles Eingreifen erforderlich ist.
Insgesamt ist Watchtower eine wertvolle Ergänzung für jede Docker-Umgebung, um die wiederkehrende Aufgabe von Container-Updates erledigen zu lassen.