Komplettes Docker Feature Deployment mit Shopware, Traefik, Shopware, Digital Ocean, Rancher und Gitlab | Part 2

Im ersten Teil habe ich über die Vor- und Nachteile eines Docker Setups gesprochen und wie wir die Container aufteilen. In diesem Teil möchte ich näher auf Traefik, Shopware und dessen Datenbank eingehen.

Traefik

Traefik ist ein Reverse Proxy, welcher sich speziell an den Einsatz in der Docker Entwicklung richtet. Sicherlich kann man hier auch mit NGINX etc. arbeiten, aber Traefik bringt einige nette Features mit sich, mit dem eine Weiterleitung in nur wenigen Minuten ohne großes Vorwissen und aufwendige Konfiguration erreicht werden kann.

Wie einfach das geht seht Ihr in der aktuellen docker-compose.yml die ich einsetze:

version: '3.5'

services:
  reverse-proxy:
    image: traefik:v2.0
    command: --api.insecure=true --providers.docker
    ports:
      - "80:80"
      - "8889:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - traefik

networks:
  traefik:

Wir nutzen hier die Version 2.0 – noch relativ neu, aber funktioniert soweit einwandfrei. Als provider ist hier docker gewählt – ports könnt Ihr nach gusto frei wählen. Ich habe mich hier für den Standardport 80 entschieden, so muss ich später im Projekt nicht ständig an den Port denken. In dem Fall allerdings nur wichtig für das Backend.

Also volume wird hier direkt der docker Socket gemounted und das Netzwerk heißt traefik. Also wie sieht das ganze dann aus wenn wir es mit docker-compose up -d starten?

Traefik Dashboard

Hier haben wir dann einen Überblick welche Services aktiv sind und wie deren Status ist.

Info: Das ganze setzt auf Vue.Js auf und kann als PWA installiert werden.

Traefik setzt auf PWA

.htaccess Schutz

Nicht alle möchten, dass die Testumgebungen live sichtbar sind. Wer die URL kennt, kann sich theoretisch auf dem Shop umschauen. Für solche Fälle bietet Traefik sogenannte Middlewares für das bearbeiten von Requests. In unserem Fall nutzen wir dafür dann Basic Auth – so erscheint dann die übliche Login Maske. Das ganze packen wir einfach mit in unsere labels:

-"traefik.http.middlewares.thisauth.basicauth.users=swiss:$$apr1$$nb92341Rk$$swy9oAuHcz8YFXYdzwBwR1"
      - "traefik.http.routers.${CONTAINER_PREFIX}_php73.middlewares=thisauth@docker"

Wichtig: Escaped eure $ Zeichen beim MD5 Hash mit einem $ Zeichen 😉

Shopware

Shopware ist in unserem Fall die Applikation die wir mit mehreren Versionen „parallel“ laufen lassen möchten. Dafür nutze ich ein kleines Shellscript welches Dinge wie ein git clone, composer update, git checkout etc.pp. ausführt.

Ihr wollt also einen Ordner mit euren Frameworkdaten im Projekt haben. Bei mir ist das der shopware Ordner in dem ich ein Git Repository clone und dort den jeweiligen Branch auschecke (in unserem Fall den Branch fr80)

bash build.sh fr80
#!/bin/bash

DIR="$( cd "$( dirname "$0" )" && pwd )"
CONTAINER=$1
DOMAIN="reitsport.ch"

# comment will simply generate the shell output Headline
function comment {
test=${#1}
init="###"

while [ $test -gt 0 ]
do
   init=$init"#"
   test=$((test-1))
done

echo -e "\n"$init"###"
echo -e "## $1 ##"
echo -e $init"###\n"
}

# Start traefik reverse proxy
function traefik {
cd $DIR/traefik && docker-compose up -d
cd $DIR || exit
}

# prepares some configs
function prepare-start {
# If you want to clone your repo or do other stuff
# git clone YOURREPOSITORY
# cd $DIR/shopware && git checkout -b "$CONTAINER"

# Copy config with correct database host
sed "s/PLACEHOLDER/$CONTAINER\_db_1/g" $DIR/php/config.php > $DIR/php/tmp_config.php
cp $DIR/php/tmp_config.php $DIR/shopware/config.php

# Set SQL statement for url matching the feature
SQL=("UPDATE s_core_shops SET host = REPLACE(host, 'www'," "'$CONTAINER'" ") WHERE 1;")
echo "${SQL[@]}" > $DIR/mysql/dumps/4local.sql
}

# load or unload container
function compose {
if [[ $1 = "up" ]]; then
  CONTAINER_PREFIX=$CONTAINER docker-compose --project-name $CONTAINER up -d
else
  CONTAINER_PREFIX=$CONTAINER docker-compose --project-name $CONTAINER down
fi
# delete old cache
rm -r $DIR/shopware/var/cache/production_*/
}

# set or unset host
function host {
if [[ $1 = "set" ]]; then
  #Add host entry to match request on localhost
echo "127.0.0.1	$CONTAINER.$DOMAIN" >> /etc/hosts
else
sed -i "/127.0.0.1 $CONTAINER.$DOMAIN/d" /etc/hosts
fi
}

#  Main output
comment "Shopware Docker Builder"
ESC=$(printf "\e")
PS3="$ESC[44m $ESC[97m $ESC[1m Please choose your options: $ESC[0m"
options=("Start" "Stop" "Stop all" "Quit")
select opt in "${options[@]}"
do
    case $opt in
        "Start")
            comment "Start container $1"
            traefik
            prepare-start
            host set
            compose up
            break
            ;;
        "Stop")
            comment "Stop container $1"
            host unset
            compose down
            break
            ;;
         "Stop all")
            comment "Stop all containers"
            docker stop $(docker ps -a -q)
            break
            ;;
        "Quit")
            echo "Bye,bye..."
            exit
            ;;
        *) echo invalid option;;
    esac
done
Simples Shellscript für den Container Start

Die compose Funktion enthält hier die wichtigste Zeile:

CONTAINER_PREFIX=$CONTAINER docker-compose --project-name $CONTAINER up -d

zu finden. Den CONTAINER_PREFIX nutzen wir in unsere docker-compose.yml und ist wie auch jeder Branch in Git einzigartig.

version: '3.5'

services:
  db:
    build: mysql
    environment:
      MYSQL_ROOT_PASSWORD: app
      MYSQL_USER: app
      MYSQL_PASSWORD: app
      MYSQL_DATABASE: app
    expose:
      - 3360
    networks:
      - traefik_traefik
    #restart: always
    volumes:
      - ./mysql/dumps:/docker-entrypoint-initdb.d
  php73:
    build: php
    links:
      - db
    volumes:
      - ./shopware:/var/www/html
    depends_on:
      - db
    networks:
      - traefik_traefik
    labels:
      - "traefik.http.routers.${CONTAINER_PREFIX}_php73.rule=Host(`${CONTAINER_PREFIX}.reitsport.ch`)"
networks:
  traefik_traefik:
    external: true

Info: Das Netzwerk heißt traefik_traefik, da es im traefik Unterordner des Projektes sitzt.

Nach dem Start des Shellscripts mit sudo bash build.sh fr5 wird also traefik hochgefahren (falls noch nicht aktiv), die Container geladen und die Datenbanken importiert. Dazu im nächsten Punkt mehr.

Das ganze sieht dann in Phpstorm z.B. so aus:

Docker Setup Übersicht in Phpstorm

Datenbank

Wer schon mal mit Shopware oder Magento gearbeite hat, weiß wie wichtig die Datenbank ist (ordernumber counters, Domains in der s_core_shops etc.). Ich habe hier einige SQL Dateien in das Repo hinzugefügt und einige nicht:

Datenbank Dumps

grant.sql

GRANT ALL ON *.* TO 'app'@'%';

dynamic.sql

-- Deactivate all cronjobs, remove SSL and make it noindex if it accidentally goes in the interwebs
UPDATE s_crontab SET active = 0 WHERE 1;
UPDATE s_core_shops SET secure = 0 WHERE 1;
UPDATE s_core_snippets SET value = 'noindex,nofollow' WHERE namespace = 'frontend/index/header' AND name = 'IndexMetaRobots';

-- Add custom updates or deletes here
UPDATE s_core_snippets SET value = '' WHERE name = 'scGoogleTagManager';
UPDATE s_core_snippets SET value = '' WHERE name = 'scEmarsysId';

structure.sql enthält die Datenbankstruktur und data.sql die eigentlichen Daten (also inserts). local.sql wird vom Shellscript mit einer einfachen Zeile für die Domain befüllt:

UPDATE s_core_shops SET host = REPLACE(host, 'www', 'fr80') WHERE 1;

Info: Die Zahlen sind notwendig um die automatischen Ausführung vom Mysql Container zu steuern. Alles was in docker-entrypoint-initdb.d steht wird nämlich automatisch importiert.

Und was bringt das ganze? || Zwischenfazit

Warum nicht einfach mit der lokalen Datenbank arbeiten und Features wie gewohnt über git ein und auschecken.

  1. Stets ein sauberes System bei allen Entwicklern
  2. Immer die neusten Daten aus der Datenbank
  3. Jedes Feature hat eine eigene Datenbank Instanz und ist daher komplett entkoppelt
  4. Schnelles wechseln zwischen größeren Branches

Nächster Part:

Bisher haben wir uns das ganze nur im lokalen System angeschaut. Dafür ist das ganze schon ganz praktisch, aber noch einen größeren Impact hat das ganze für das Testen von Features und Bugfixes im daily business für Endkunden oder interne Tester. Dafür benötigen wir für die Automatisierung Gitlab und Rancher. Denn wir möchten ja nicht immer lokal deployen und das ganze manuell mit einem Script ausführen. Dies diente lediglich zur Veranschaulichung des Prozesses. Wir werden im Part 3 zunächst auf die Infrastruktur eingehen, welche wir mit Digital Ocean zur Verfügung stellen und danach auf die ersten Schritt von Gitlab eingehen.

zum Part 3

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.