12 KiB
Moodle Deployment auf Cloud Foundry
Diese Anleitung beschreibt die Schritte für ein robustes und automatisch skalierendes Deployment der Lernplattform Moodle auf einer Cloud Foundry-Umgebung. Dies umfasst die Konfiguration für eine externe Datenbank, S3-Dateispeicher, Session-Handling für mehrere Instanzen und Autoskalierung.
Voraussetzungen
- Zugang zur STACKIT Cloud Foundry Umgebung.
- Das
cfCommand Line Interface (CLI) ist installiert. - Zugangsdaten den STACKIT S3-kompatiblen Object Storage sind vorhanden.
- DNS CNAME Eintrag auf "console.apps.01.cf.eu01.stackit.cloud." in passender Domäne
In diesem Beispiel wurde es im STACKIT DNS auf die folgende Route/URL durchgeführt: moodle.cf.demo.stackit.rocks
Verzeichnisstruktur
Bevor du am Ende die Anwendung pushst, stelle sicher, dass deine lokale Verzeichnisstruktur wie folgt aussieht. Dies ist entscheidend für den Erfolg.
.
├── manifest.yml
└── moodle/
├── .bp-config/
│ ├── options.json
│ └── php/
│ └── php.ini.d/
│ ├── moodle.ini
│ └── mysqli.ini
├── httpd/
│ └── logs/
│ └── httpd.pid -> /tmp/httpd.pid
├── lib/
├── logs/
│ ├── proc-man.log -> /dev/stdout
│ └── rewrite.log -> /dev/stdout
├── php/
│ └── var/
│ └── run/
│ └── php-fpm.pid -> /tmp/php-fpm.pid
├── config.php
├── index.php
└── ... (alle anderen Moodle-Dateien und Ordner)
Schritt-für-Schritt Anleitung
1. Moodle herunterladen
Erstelle ein Projektverzeichnis. Lade den Quellcode der Moodle-Version 5.0.1 mit wget herunter und entpacke ihn in einen Unterordner namens moodle.
wget https://packaging.moodle.org/stable500/moodle-5.0.1.tgz
tar -xzf moodle-5.0.1.tgz
2. Cloud Foundry Services erstellen
Erstelle die benötigten Service-Instanzen in deiner Cloud Foundry-Umgebung.
# Datenbank-Service erstellen
cf create-service <dein-mariadb-service> <plan> moodle-demo-mariadb
# Autoscaler-Service erstellen
cf create-service autoscaler autoscaler-free-plan moodle-autoscaler
3. Konfigurationsdateien anlegen und anpassen
Dies ist der wichtigste Schritt, bei dem alle spezifischen Konfigurationen für den Betrieb auf Cloud Foundry vorgenommen werden.
a) manifest.yml anlegen
Erstelle im Hauptverzeichnis deines Projekts die manifest.yml-Datei mit folgendem Inhalt. Passe die Routen sowie deine S3-Zugangsdaten an.
---
applications:
- name: moodle
memory: 2G
disk_quota: 2G
buildpack: php_buildpack
path: moodle
routes:
- route: deine-moodle-route.deine-domain.de
env:
# Buildpack anweisen, weniger Debug-Logs in Dateien zu schreiben
BP_PHP_LOG_LEVEL: WARNING
# S3-Zugangsdaten für den Object Storage
S3_ACCESS_KEY: DEIN_S3_ACCESS_KEY
S3_SECRET_KEY: DEIN_S3_SECRET_KEY
S3_BUCKET: DEIN_S3_BUCKET_NAME
S3_ENDPOINT: DEIN_S3_ENDPOINT_URL
services:
- moodle-demo-mariadb
- moodle-autoscaler
# Konfiguration für den Autoscaler-Service
autoscaling:
min_instances: 2
max_instances: 4
rules:
- metric_type: cpu
threshold: 50
operator: ">"
adjustment: "+1"
breach_duration_secs: 60
cool_down_secs: 60
- metric_type: cpu
threshold: 10
operator: "<"
adjustment: "-1"
breach_duration_secs: 60
cool_down_secs: 60
b) Buildpack-Konfiguration (.bp-config)
Diese Dateien steuern das Verhalten des PHP Buildpacks.
-
Web-Verzeichnis festlegen:
echo '{"WEBDIR": "."}' > moodle/.bp-config/options.json -
PHP-Erweiterungen und -Einstellungen konfigurieren:
mkdir -p moodle/.bp-config/php/php.ini.d/ echo "extension=mysqli" > moodle/.bp-config/php/php.ini.d/mysqli.ini echo "max_input_vars = 5000" > moodle/.bp-config/php/php.ini.d/moodle.ini
c) Workarounds für das schreibgeschützte Dateisystem
Erstelle die Verzeichnisse und symbolischen Links für Log- und PID-Dateien.
# Für Log-Dateien (Umleitung auf die Standardausgabe)
mkdir -p moodle/logs
ln -s /dev/stdout moodle/logs/rewrite.log
ln -s /dev/stdout moodle/logs/proc-man.log
# Für Prozess-ID-Dateien (Umleitung in das beschreibbare /tmp-Verzeichnis)
mkdir -p moodle/httpd/logs
mkdir -p moodle/php/var/run
ln -s /tmp/httpd.pid moodle/httpd/logs/httpd.pid
ln -s /tmp/php-fpm.pid moodle/php/var/run/php-fpm.pid
d) config.php erstellen und anpassen
Kopiere moodle/config-dist.php zu moodle/config.php und ersetze den gesamten Inhalt mit der folgenden Vorlage. Passe $CFG->wwwroot an deine Route an.
<?php // Moodle configuration file
unset($CFG);
global $CFG;
$CFG = new stdClass();
//=========================================================================
// 1. WEB SITE LOCATION
//=========================================================================
$CFG->wwwroot = 'https://deine-moodle-route.deine-domain.de';
//=========================================================================
// 2. DATABASE SETUP (wird automatisch aus VCAP_SERVICES gelesen)
//=========================================================================
$CFG->dbtype = 'mariadb';
$CFG->dblibrary = 'native';
$CFG->prefix = 'mdl_';
$CFG->dboptions = array (
'dbpersist' => 0,
'dbport' => '',
'dbsocket' => '',
'dbcollation' => 'utf8mb4_unicode_ci',
);
// --- Lese Datenbank-Konfiguration aus VCAP_SERVICES (inkl. SSL) ---
$vcap_services_json = getenv('VCAP_SERVICES');
if ($vcap_services_json) {
$vcap_services = json_decode($vcap_services_json, true);
$db_service_key = null;
if (isset($vcap_services['appcloud-mariadb1011'])) { // Passe diesen Service-Namen ggf. an
$db_service_key = 'appcloud-mariadb1011';
}
if ($db_service_key && isset($vcap_services[$db_service_key][0]['credentials'])) {
$db_creds = $vcap_services[$db_service_key][0]['credentials'];
$CFG->dbhost = $db_creds['host'];
$CFG->dbname = $db_creds['name'];
$CFG->dbuser = $db_creds['username'];
$CFG->dbpass = $db_creds['password'];
if (isset($db_creds['cacrt']) && !empty($db_creds['cacrt'])) {
$ca_cert_path = '/tmp/db-ca.crt';
file_put_contents($ca_cert_path, $db_creds['cacrt']);
$CFG->dboptions['ssl_ca'] = $ca_cert_path;
$CFG->dboptions['ssl_verify_server_cert'] = true;
}
}
}
// --- Ende der VCAP_SERVICES-Datenbank-Konfiguration ---
//=========================================================================
// 3. DATAROOT (verweist auf das beschreibbare /tmp-Verzeichnis)
//=========================================================================
$CFG->dataroot = '/tmp/moodledata';
$CFG->directorypermissions = 0777;
//=========================================================================
// 4. S3 FILE STORAGE (wird automatisch aus Umgebungsvariablen gelesen)
//=========================================================================
if (getenv('S3_BUCKET')) {
$CFG->alternative_file_system_class = '\core_files\files\s3_file_system';
$CFG->s3_bucket = getenv('S3_BUCKET');
$CFG->s3_accesskey = getenv('S3_ACCESS_KEY');
$CFG->s3_secretkey = getenv('S3_SECRET_KEY');
$CFG->s3_endpoint = getenv('S3_ENDPOINT');
}
//=========================================================================
// 5. SESSION HANDLING (für mehrere Instanzen)
//=========================================================================
$CFG->session_handler_class = '\core\session\database';
//=========================================================================
// DO NOT ADD ANYTHING BELOW THIS LINE
//=========================================================================
require_once(__DIR__ . '/lib/setup.php');
4. Anwendung deployen
Führe abschließend den Push-Befehl aus dem Hauptverzeichnis deines Projekts aus.
cf push
Nach Abschluss des Deployments ist deine Moodle-Instanz unter der konfigurierten Route erreichbar und wird gemäß deiner Policy automatisch skaliert.
Einsatz im Produktiven Umfeld
Um die Anwendung in einem produktiven Umfeld laufen zu lassen, sind die folgenden weiteren Anpassungen möglich
Datenbank
Es empfielt sich für den produktiven Einsatz für die MariaDB anstelle einer Single Instanz eine Datenbank mit Replicas zu wählen:
Siehe dazu: https://docs.stackit.cloud/stackit/en/service-plans-for-mariadb-79071839.html
Neben der reinen Hochverfügbarkeit ist auch die zu erwartetende Last zu beachten.
Session Persistenz
Im aktuellen Setup wird die Persistenz der Sitzungen über die Datenbank (MariaDB) sichergestellt. Besser geeignet ist hier der Einsatz eines Redis Caches, den es ebenfalls im Marketplace der STACKIT gibt und die auf ähnliche Weise wie die Datenank an die Moodle App gebunden werden kann.
cf create-service appcloud-redis60 redis-4.16.100-replica moodle-redis
Dazu ist dann auch eine Anpassung der config.php notwendig:
// --- Redis-Konfiguration für Sessions und Locks ---
$vcap_services = json_decode(getenv('VCAP_SERVICES'), true);
// Finde den Redis-Service (der Name kann variieren, z.B. 'redis')
$redis_service = null;
if (isset($vcap_services['redis'])) {
$redis_service = $vcap_services['redis'][0];
}
if ($redis_service) {
$redis_creds = $redis_service['credentials'];
// Redis für Sessions verwenden
$CFG->session_handler_class = '\cachestore_redis\session_handler';
$CFG->session_redis_host = $redis_creds['host'];
$CFG->session_redis_port = $redis_creds['port'];
$CFG->session_redis_password = $redis_creds['password'];
$CFG->session_redis_database = 0; // Normalerweise 0
$CFG->session_redis_prefix = 'moodlesess_';
// Redis auch für Application Locks verwenden (Best Practice)
$CFG->lock_factory = '\cachestore_redis\lock_factory';
}
// --- Ende der Redis-Konfiguration ---
Die Einstellung
$CFG->session_handler_class = '\core\session\database';
ist auszukommentieren.
Nun noch die angepasste manifest Datei:
---
applications:
- name: moodle
memory: 2G
disk_quota: 2G
buildpack: php_buildpack
path: moodle
routes:
- route: deine-moodle-route.deine-domain.de
env:
# Buildpack anweisen, weniger Debug-Logs in Dateien zu schreiben
BP_PHP_LOG_LEVEL: WARNING
# S3-Zugangsdaten für den Object Storage
S3_ACCESS_KEY: DEIN_S3_ACCESS_KEY
S3_SECRET_KEY: DEIN_S3_SECRET_KEY
S3_BUCKET: DEIN_S3_BUCKET_NAME
S3_ENDPOINT: DEIN_S3_ENDPOINT_URL
services:
- moodle-demo-mariadb
- moodle-autoscaler
- moodle-redis # <-- Neuer Service hinzugefügt
# Konfiguration für den Autoscaler-Service
autoscaling:
min_instances: 2
max_instances: 10
rules:
- metric_type: cpu
threshold: 50
operator: ">"
adjustment: "+1"
breach_duration_secs: 60
cool_down_secs: 60
- metric_type: cpu
threshold: 10
operator: "<"
adjustment: "-1"
breach_duration_secs: 60
cool_down_secs: 60
CDN (Content Delivey Network)
STACKIT bietet ein eigenes CDN an, welches nun im produktiven Einsatz noch zusätzlich die Performance erhöhen kann und die überregionale Erreichbarkeit erleichtert.
Dazu legt man bei STACKIT einen CDN Eintrag auf die Orginale Route an (In diesem Beispiel: https://moodle.cf.demo.stackit.rocks )
https://docs.stackit.cloud/stackit/en/create-a-distribution-332824982.html
Das CDN erzeugt damit nun eine eigene URL, in unserem Fall v22sf2s1td84d5hz6rsf2715mw.aa.cdn.onstackit.cloud. Um diese wieder "schön" zu bekommen, legt man in STACKIT noch einen weiteren DNS Eintrag an. In unserem Fall ein CNAME Eintrag von moodle.demo.stackit.rocks auf die vom CDN Service vorgeschlagene URL (hier v22sf2s1td84d5hz6rsf2715mw.aa.cdn.onstackit.cloud.) und legt damit im CDN eine Custom Domain an:
https://docs.stackit.cloud/stackit/en/add-a-custom-domain-to-your-distribution-332824866.html
Um moodle, die neue URL mitzuteilen, braucht es noch eine Anpassung der Datei config.php. Dazu den alten Eintrag von:
$CFG->wwwroot = 'https://moodle.cf.demo.stackit.rocks';
Durch den neuen:
$CFG->wwwroot = 'https://moodle.demo.stackit.rocks';
ersetzen und die Anwendung erneut deployen mittels:
cf push
Nun kann der weltweite Zugriff auf die URL https://moodle.demo.stackit.rocks erfolgen.