| .gitignore | ||
| readme.md | ||
Umfassende Anleitung: Moodle auf STACKIT Cloud Foundry
Diese Anleitung dokumentiert den gesamten Prozess, um eine Moodle-Instanz auf STACKIT Cloud Foundry zu deployen. Sie umfasst die Ersteinrichtung der CF-Umgebung, die Vorbereitung der Moodle-Anwendung inklusive aller notwendigen Anpassungen für den Proxy- und CDN-Betrieb sowie die Konfiguration für eine externe Datenbank, S3-Dateispeicher, Redis-Caching und Autoskalierung.
Architektur
Die folgende Abbildung zeigt die Architektur der Moodle-Umgebung auf STACKIT als Mermaid-Diagramm.
graph TD
A[Anwender] --> B(STACKIT DNS);
B --> C(STACKIT CDN);
C --> D{Cloud Foundry Router};
subgraph Cloud Foundry Plattform
D --> E1[Moodle Instanz 1];
D --> E2[Moodle Instanz ...n];
end
subgraph Backing Services
F[(MariaDB<br/>Datenbank)];
G[(Redis<br/>Sessions & Locks)];
H[(S3 Object Storage<br/>Dateien)];
end
E1 --> F;
E1 --> G;
E1 --> H;
E2 --> F;
E2 --> G;
E2 --> H;
1. Voraussetzungen & initiales Setup
1.1. CLIs installieren
Für diese Anleitung werden zwei Command Line Interfaces (CLIs) benötigt:
-
Cloud Foundry CLI: Das primäre Werkzeug zur Interaktion mit der Cloud Foundry Plattform.
- Download: github.com/cloudfoundry/cli/releases
-
STACKIT CLI: Wird benötigt, um STACKIT-spezifische Services wie Object Storage zu verwalten.
- Installationsanleitung: Befolgen Sie die offizielle Anleitung unter docs.stackit.cloud.
1.2. Bei STACKIT Cloud Foundry anmelden
Nach der Installation des CF CLI müssen Sie sich bei der STACKIT Cloud Foundry API anmelden.
-
API-Endpunkt:
https://api.cf.eu01.stackit.cloud -
Login-Befehl:
cf login -a https://api.cf.eu01.stackit.cloud --sso
1.3. Organisation und Space erstellen
Eine "Organisation" ist der höchste Mandant, ein "Space" eine Umgebung (z.B. Entwicklung, Produktion).
-
Organisation erstellen:
cf create-org DEINE_ORGANISATION -
Space erstellen:
cf create-space produktion -o DEINE_ORGANISATION -
Ziel festlegen:
cf target -o DEINE_ORGANISATION -s produktion
2. Moodle-Projekt lokal vorbereiten
2.1. Moodle und Plugins herunterladen
# Moodle 5.0.1 herunterladen und entpacken
wget https://packaging.moodle.org/stable500/moodle-5.0.1.tgz
tar -xzf moodle-5.0.1.tgz
# Redis-Plugin für Moodle installieren
wget https://moodle.org/plugins/download.php/29037/cachestore_redis_moodle41_2022112800.zip
unzip cachestore_redis_moodle41_2022112800.zip
mv redis moodle/cache/stores/
# S3 Object File System Plugin installieren
cd moodle
git clone https://github.com/catalyst/moodle-tool_objectfs.git admin/tool/objectfs
cd ..
2.2. Buildpack- & System-Workarounds einrichten
Diese Schritte sind für das cloudfoundry/php-buildpack notwendig.
# Web-Verzeichnis festlegen und PHP-Version auf 8.2 erzwingen
echo '{"WEBDIR": ".", "PHP_VERSION": "{PHP_82_LATEST}"}' > moodle/.bp-config/options.json
# PHP-Erweiterungen und Moodle-Einstellungen konfigurieren
mkdir -p moodle/.bp-config/php/php.ini.d/
echo "extension=mysqli" > moodle/.bp-config/php/php.ini.d/mysqli.ini
echo "extension=redis" > moodle/.bp-config/php/php.ini.d/redis.ini
echo "max_input_vars = 5000" > moodle/.bp-config/php/php.ini.d/moodle.ini
# Symbolische Links für Log- und PID-Dateien anlegen
mkdir -p moodle/logs
ln -s /dev/stdout moodle/logs/rewrite.log
ln -s /dev/stdout moodle/logs/proc-man.log
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
3. Cloud Foundry & STACKIT Services erstellen
3.1. Object Storage Bucket erstellen (STACKIT CLI)
Verwenden Sie das STACKIT CLI, um einen Bucket zu erstellen.
# Erstellt einen neuen Bucket
stackit object-storage bucket create --name <BUCKET_NAME>
Anschließend benötigen Sie Zugangsdaten, um auf den Bucket zugreifen zu können.
# Erstellt neue Zugangsdaten für Ihr Projekt
# Sie müssen Ihre STACKIT Projekt-ID angeben.
stackit object-storage credential create --project-id <DEINE_PROJEKT_ID>
Notieren Sie sich den ausgegebenen accessKey und secretAccessKey. Sie werden im nächsten Schritt benötigt.
3.2. Cloud Foundry Services erstellen (CF CLI)
Diese Befehle legen die für Moodle notwendigen CF-Services an.
# Datenbank-Service
cf create-service <dein-mariadb-service> <plan> moodle-demo-mariadb
# Redis-Service (Optional)
cf create-service appcloud-redis7 redis-4.16.100-replica moodle-redis
# Autoscaler-Service
cf create-service autoscaler autoscaler-free-plan moodle-autoscaler
# User-Provided Service für die S3-Credentials aus dem vorherigen Schritt
cf create-user-provided-service moodle-s3-credentials -p '{
"access_key": "DEIN_ZUVOR_GENERIERTER_ACCESS_KEY",
"secret_key": "DEIN_ZUVOR_GENERIERTER_SECRET_KEY",
"bucket": "DEIN_ZUVOR_GENERIERTES_BUCKET",
"endpoint": "https://object.storage.eu01.onstackit.cloud/"
}'
4. Konfigurationsdateien erstellen
a) Manifest-Dateien
Erstellen Sie zwei Manifest-Dateien, um einfach zwischen dem Betrieb mit und ohne CDN wechseln zu können.
manifest-cdn.yml (Produktion):
---
applications:
- name: moodle
memory: 2G
disk_quota: 2G
buildpack: https://github.com/cloudfoundry/php-buildpack.git
path: moodle
routes:
- route: moodle.cf.demo.stackit.rocks
- route: moodle.demo.stackit.rocks
env:
USE_CDN: 'true'
WWW_ROOT: "https://moodle.demo.stackit.rocks"
BP_PHP_LOG_LEVEL: WARNING
services:
- moodle-demo-mariadb
- moodle-redis
- moodle-autoscaler
- moodle-s3-credentials
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
manifest-no-cdn.yml (Test):
---
applications:
- name: moodle
memory: 2G
disk_quota: 2G
buildpack: https://github.com/cloudfoundry/php-buildpack.git
path: moodle
routes:
- route: moodle.cf.demo.stackit.rocks
env:
USE_CDN: 'false'
WWW_ROOT: "https://moodle.cf.demo.stackit.rocks"
BP_PHP_LOG_LEVEL: WARNING
services:
- moodle-demo-mariadb
- moodle-redis
- moodle-autoscaler
- moodle-s3-credentials
autoscaling:
min_instances: 1
max_instances: 4
# ... deine Regeln
b) Dynamische config.php
Kopieren Sie moodle/config-dist.php zu moodle/config.php und ersetzen Sie den gesamten Inhalt mit dieser finalen, dynamischen Vorlage.
<?php // Moodle configuration file
// =========================================================================
// UMWELTSPEZIFISCHE KONFIGURATION
// =========================================================================
$useCdn = (getenv('USE_CDN') === 'true');
$wwwRoot = getenv('WWW_ROOT');
unset($CFG);
global $CFG;
$CFG = new stdClass();
//=========================================================================
// 1. WEBSEITE, VERZEICHNISSE & PROXY EINSTELLUNGEN
//=========================================================================
$CFG->wwwroot = $wwwRoot;
$CFG->dirroot = __DIR__;
$CFG->dataroot = '/tmp/moodledata';
$CFG->admin = 'admin';
$CFG->directorypermissions = 0777;
// --- Proxy-Einstellungen ---
$CFG->sslproxy = 1;
$CFG->slasharguments = false;
if ($useCdn) {
// Diese Einstellungen sind NUR für den CDN-Betrieb notwendig, um den "reverseproxyabused"-Fehler zu vermeiden.
$CFG->reverseproxy = 1;
$CFG->trustedproxies = '127.0.0.1, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 185.124.192.185';
}
// --- Workaround: Manuelles Erstellen des dataroot-Verzeichnisses ---
if (!file_exists($CFG->dataroot)) {
@mkdir($CFG->dataroot, $CFG->directorypermissions, true);
}
//=========================================================================
// 2. DATENBANK-SETUP
//=========================================================================
$CFG->dbtype = 'mariadb';
$CFG->dblibrary = 'native';
$CFG->prefix = 'mdl_';
$CFG->dboptions = array ('dbpersist' => 0, 'dbcollation' => 'utf8mb4_unicode_ci');
// --- Lese Service-Konfigurationen aus VCAP_SERVICES ---
$vcap_services_json = getenv('VCAP_SERVICES');
if ($vcap_services_json) {
$vcap_services = json_decode($vcap_services_json, true);
// Datenbank
$db_service_key = null;
if (isset($vcap_services['appcloud-mariadb1011'])) { $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'];
$CFG->dboptions['dbport'] = $db_creds['port'];
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;
}
}
// Redis (Optional, für bessere Performance)
$redis_service_key = null;
if (isset($vcap_services['appcloud-redis60'])) { $redis_service_key = 'appcloud-redis60'; }
if ($redis_service_key && isset($vcap_services[$redis_service_key][0]['credentials'])) {
$redis_creds = $vcap_services[$redis_service_key][0]['credentials'];
$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_prefix = 'moodlesess_';
$CFG->lock_factory = '\cachestore_redis\lock_factory';
}
// S3
if (isset($vcap_services['user-provided'])) {
foreach ($vcap_services['user-provided'] as $service) {
if ($service['name'] === 'moodle-s3-credentials') {
$s3_creds = $service['credentials'];
$CFG->objectfs_s3_key = $s3_creds['access_key'];
$CFG->objectfs_s3_secret = $s3_creds['secret_key'];
$CFG->objectfs_s3_bucket = $s3_creds['bucket'];
$CFG->objectfs_s3_endpoint = $s3_creds['endpoint'];
break;
}
}
}
}
// Fallback auf Datenbank-Sessions, falls Redis nicht konfiguriert ist
if (empty($CFG->session_handler_class)) {
$CFG->session_handler_class = '\core\session\database';
}
//=========================================================================
// SESSION COOKIE HANDLING (bedingt durch CDN)
//=========================================================================
if ($useCdn) {
$CFG->cookiepath = '/';
$CFG->cookiedomain = 'moodle.demo.stackit.rocks';
$CFG->cookiesecure = 1;
$CFG->cookiehttponly = 1;
}
//=========================================================================
// DO NOT ADD ANYTHING BELOW THIS LINE
//=========================================================================
require_once(__DIR__ . '/lib/setup.php');
5. Deployment auf Cloud Foundry
Wählen Sie das gewünschte Manifest für Ihr Deployment aus.
Mit CDN (Produktion):
cf push -f manifest-cdn.yml
Hinweis: Der CDN-Fall hat sich als problematisch erwiesen. Wenn Fehler auftreten, liegt es wahrscheinlich an den Caching- oder Header-Einstellungen im CDN selbst, die hier nicht behandelt werden können.
Ohne CDN (Test / Direkter Zugriff):
cf push -f manifest-no-cdn.yml
Nach Abschluss des Deployments und dem Durchlaufen der Moodle-Web-Installation ist Ihre Instanz einsatzbereit.