397 lines
No EOL
12 KiB
Markdown
397 lines
No EOL
12 KiB
Markdown
# Umfassende Anleitung: Moodle auf STACKIT Cloud Foundry
|
|
|
|
Diese Anleitung dokumentiert den gesamten Prozess, um eine Moodle-Instanz auf STACKIT Cloud Foundry zu deployen. Sie ist als allgemeingültige Vorlage konzipiert und verwendet Platzhalter, die an Ihre Umgebung angepasst werden müssen.
|
|
|
|
## Architektur
|
|
|
|
Die folgende Abbildung zeigt die Architektur der Moodle-Umgebung. CDN und Redis sind als optionale, aber für den Produktivbetrieb empfohlene Komponenten dargestellt.
|
|
|
|
```mermaid
|
|
graph TD
|
|
subgraph "Nutzer & Netzwerk Edge"
|
|
A[Anwender] --> B(STACKIT DNS);
|
|
B --> C["STACKIT CDN<br/>(Optional)"];
|
|
end
|
|
|
|
subgraph "Zentrale Infrastruktur"
|
|
D{Cloud Foundry Router};
|
|
end
|
|
|
|
C -.-> D;
|
|
B --> D;
|
|
|
|
subgraph "Cloud Foundry App-Instanzen"
|
|
D --> E1[Moodle Instanz 1];
|
|
D --> E2[Moodle Instanz ...n];
|
|
end
|
|
|
|
subgraph "Backing Services"
|
|
F[(MariaDB<br/>Datenbank)];
|
|
G["Redis<br/>Sessions & Locks<br/>(Optional)"];
|
|
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
|
|
|
|
* **Cloud Foundry CLI:** `https://github.com/cloudfoundry/cli/releases`
|
|
* **STACKIT CLI:** `https://docs.stackit.cloud/stackit/de/automatisieren/cli/cli-installieren-200720436.html`
|
|
|
|
### 1.2. Bei STACKIT Cloud Foundry anmelden
|
|
|
|
```bash
|
|
cf login -a https://api.cf.eu01.stackit.cloud --sso
|
|
```
|
|
|
|
### 1.3. Organisation und Space erstellen
|
|
|
|
```bash
|
|
cf create-org <DEINE_ORGANISATION>
|
|
cf create-space <DEIN_SPACE> -o <DEINE_ORGANISATION>
|
|
cf target -o <DEINE_ORGANISATION> -s <DEIN_SPACE>
|
|
```
|
|
|
|
## 2\. Moodle-Projekt lokal vorbereiten
|
|
|
|
### 2.1. Moodle und Plugins herunterladen
|
|
|
|
```bash
|
|
# Moodle 5.0.1
|
|
wget https://packaging.moodle.org/stable500/moodle-5.0.1.tgz
|
|
tar -xzf moodle-5.0.1.tgz
|
|
|
|
# Redis-Plugin
|
|
wget https://moodle.org/plugins/download.php/30019/cachestore_redis_moodle44_2024051300.zip
|
|
unzip cachestore_redis_moodle44_2024051300.zip
|
|
mv redis moodle/cache/stores/
|
|
|
|
# S3 Object File System Plugin
|
|
cd moodle
|
|
git clone https://github.com/catalyst/moodle-tool_objectfs.git admin/tool/objectfs
|
|
cd ..
|
|
```
|
|
|
|
### 2.2. Buildpack- & System-Workarounds einrichten
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```bash
|
|
stackit object-storage bucket create --name <DEIN_S3_BUCKET_NAME>
|
|
```
|
|
|
|
```bash
|
|
stackit object-storage credential create --project-id <DEINE_PROJEKT_ID>
|
|
```
|
|
|
|
**Notieren Sie sich den ausgegebenen `accessKey` und `secretAccessKey`.**
|
|
|
|
#### 3.2. CDN-Distribution erstellen (STACKIT CLI, Optional)
|
|
|
|
Die Erstellung und Konfiguration des CDN erfolgt in mehreren Schritten.
|
|
|
|
1. **CDN-Distribution erstellen:**
|
|
|
|
```bash
|
|
stackit curl -X POST --body '{
|
|
"name": "<DEIN_CDN_DISTRIBUTION_NAME>",
|
|
"origin": { "path": "/", "hostname": "<DEINE_INTERNE_CF_ROUTE>", "port": 443 },
|
|
"originRequestHeaders": [ { "name": "Host", "values": [ "<DEINE_MOODLE_DOMAIN>" ] } ],
|
|
"enabled": true
|
|
}' /cdn/v1beta/projects/<DEINE_PROJEKT_ID>/distributions
|
|
```
|
|
|
|
**Notieren Sie sich die `id` der Distribution aus der Antwort.**
|
|
|
|
2. **Benutzerdefinierte Domain hinzufügen:**
|
|
|
|
```bash
|
|
stackit curl -X POST --body '{
|
|
"domain": "<DEINE_MOODLE_DOMAIN>"
|
|
}' /cdn/v1beta/projects/<DEINE_PROJEKT_ID>/distributions/<DISTRIBUTION_ID>/domains
|
|
```
|
|
|
|
3. **Wichtige CDN-Einstellungen per Support-Ticket anfordern:**
|
|
Damit Moodle hinter dem CDN korrekt funktioniert, müssen spezielle Caching- und Cookie-Regeln gesetzt werden, die aktuell nicht als Self-Service verfügbar sind. Erstellen Sie ein Ticket im STACKIT Support-Portal.
|
|
|
|
* **Support-Portal:** `https://support.stackit.cloud/servicedesk/customer/portal/3`
|
|
|
|
* **Anfrage-Vorlage:**
|
|
|
|
> Hallo STACKIT-Team,
|
|
> für unsere CDN-Distribution mit der ID `<DISTRIBUTION_ID>` benötigen wir bitte die folgenden Einstellungen:
|
|
|
|
> 1. **"Strip Response Cookies" muss deaktiviert sein.** Moodle benötigt dies, um Session-Cookies an den Browser zu senden.
|
|
> 2. **Edge Rule zum Umgehen des Caches:** Bitte erstellen Sie eine Edge Rule, die das Caching für alle dynamischen Moodle-Inhalte deaktiviert:
|
|
> * **Action:** Bypass Cache
|
|
> * **Conditions (Match Any):**
|
|
> * Request URL (Match Wildcard): `*<DEINE_MOODLE_DOMAIN>/*`
|
|
> * Request URL (Match Wildcard): `*<DEINE_MOODLE_DOMAIN>/*index.php*`
|
|
> * Request URL (Match Wildcard): `*<DEINE_MOODLE_DOMAIN>/*javascript.php*`
|
|
> * Request URL (Match Wildcard): `*<DEINE_MOODLE_DOMAIN>/*styles.php*`
|
|
> * Request URL (Match Wildcard): `*<DEINE_MOODLE_DOMAIN>/*yui_combo.php*`
|
|
|
|
> Vielen Dank.
|
|
|
|
#### 3.3. DNS-Einträge konfigurieren (STACKIT CLI)
|
|
|
|
1. **Zone-ID ermitteln:**
|
|
|
|
```bash
|
|
stackit dns zone list
|
|
```
|
|
|
|
2. **CDN-Standard-Domain auslesen (nur für CDN-Setup):**
|
|
|
|
```bash
|
|
stackit curl -X GET /cdn/v1beta/projects/<DEINE_PROJEKT_ID>/distributions/<DISTRIBUTION_ID>
|
|
```
|
|
|
|
**Notieren Sie sich den Wert des `domain`-Feldes. Dies ist Ihr CNAME-Ziel für das CDN.**
|
|
|
|
3. **CNAME-Eintrag erstellen:**
|
|
|
|
```bash
|
|
# Für den Betrieb MIT CDN
|
|
stackit dns record-set create --zone-id <DEINE_ZONE_ID> --name <DEINE_MOODLE_DOMAIN> --type CNAME --ttl 300 --records "<DEIN_CDN_ZIEL_AUS_SCHRITT_2>."
|
|
|
|
# Für den Betrieb OHNE CDN (falls benötigt)
|
|
stackit dns record-set create --zone-id <DEINE_ZONE_ID> --name <DEINE_INTERNE_CF_ROUTE> --type CNAME --ttl 300 --records "console.apps.01.cf.eu01.stackit.cloud."
|
|
```
|
|
|
|
#### 3.4. Cloud Foundry Services erstellen (CF CLI)
|
|
|
|
```bash
|
|
# Datenbank-Service
|
|
cf create-service <dein-mariadb-service> <plan> <DEINE_MARIADB_INSTANZ>
|
|
|
|
# Redis-Service (Optional)
|
|
cf create-service appcloud-redis7 redis-4.16.100-replica <DEINE_REDIS_INSTANZ>
|
|
|
|
# Autoscaler-Service
|
|
cf create-service autoscaler autoscaler-free-plan <DEIN_AUTOSCALER_INSTANZ>
|
|
|
|
# User-Provided Service für die S3-Credentials
|
|
cf create-user-provided-service <DEINE_S3_CUPS_INSTANZ> -p '{
|
|
"access_key": "<DEIN_ZUVOR_GENERIERTER_ACCESS_KEY>",
|
|
"secret_key": "<DEIN_ZUVOR_GENERIERTER_SECRET_KEY>",
|
|
"bucket": "<DEIN_S3_BUCKET_NAME>",
|
|
"endpoint": "https://object.storage.eu01.onstackit.cloud/"
|
|
}'
|
|
```
|
|
|
|
## 4\. Konfigurationsdateien erstellen
|
|
|
|
#### a) Manifest-Dateien
|
|
|
|
**`manifest-cdn.yml` (Produktion):**
|
|
|
|
```yaml
|
|
---
|
|
applications:
|
|
- name: moodle
|
|
memory: 2G
|
|
disk_quota: 2G
|
|
buildpack: https://github.com/cloudfoundry/php-buildpack.git
|
|
path: moodle
|
|
routes:
|
|
- route: <DEINE_INTERNE_CF_ROUTE>
|
|
- route: <DEINE_MOODLE_DOMAIN>
|
|
env:
|
|
USE_CDN: 'true'
|
|
WWW_ROOT: "https://<DEINE_MOODLE_DOMAIN>"
|
|
BP_PHP_LOG_LEVEL: WARNING
|
|
services:
|
|
- <DEINE_MARIADB_INSTANZ>
|
|
- <DEINE_REDIS_INSTANZ>
|
|
- <DEIN_AUTOSCALER_INSTANZ>
|
|
- <DEINE_S3_CUPS_INSTANZ>
|
|
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):**
|
|
|
|
```yaml
|
|
---
|
|
applications:
|
|
- name: moodle
|
|
memory: 2G
|
|
disk_quota: 2G
|
|
buildpack: https://github.com/cloudfoundry/php-buildpack.git
|
|
path: moodle
|
|
routes:
|
|
- route: <DEINE_INTERNE_CF_ROUTE>
|
|
env:
|
|
USE_CDN: 'false'
|
|
WWW_ROOT: "https://<DEINE_INTERNE_CF_ROUTE>"
|
|
BP_PHP_LOG_LEVEL: WARNING
|
|
services:
|
|
- <DEINE_MARIADB_INSTANZ>
|
|
- <DEINE_REDIS_INSTANZ>
|
|
- <DEIN_AUTOSCALER_INSTANZ>
|
|
- <DEINE_S3_CUPS_INSTANZ>
|
|
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 Inhalt mit dieser Vorlage.
|
|
|
|
```php
|
|
<?php // Moodle configuration file
|
|
|
|
$useCdn = (getenv('USE_CDN') === 'true');
|
|
$wwwRoot = getenv('WWW_ROOT');
|
|
|
|
unset($CFG);
|
|
global $CFG;
|
|
$CFG = new stdClass();
|
|
|
|
$CFG->wwwroot = $wwwRoot;
|
|
$CFG->dirroot = __DIR__;
|
|
$CFG->dataroot = '/tmp/moodledata';
|
|
$CFG->admin = 'admin';
|
|
$CFG->directorypermissions = 0777;
|
|
|
|
$CFG->sslproxy = 1;
|
|
$CFG->slasharguments = false;
|
|
if ($useCdn) {
|
|
$CFG->reverseproxy = 1;
|
|
$CFG->trustedproxies = '127.0.0.1, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, <IP_DES_CDN_KNOTENS>';
|
|
}
|
|
|
|
if (!file_exists($CFG->dataroot)) {
|
|
@mkdir($CFG->dataroot, $CFG->directorypermissions, true);
|
|
}
|
|
|
|
$CFG->dbtype = 'mariadb';
|
|
$CFG->dblibrary = 'native';
|
|
$CFG->prefix = 'mdl_';
|
|
$CFG->dboptions = array ('dbpersist' => 0, 'dbcollation' => 'utf8mb4_unicode_ci');
|
|
|
|
$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
|
|
$redis_service_key = null;
|
|
if (isset($vcap_services['appcloud-redis7'])) { $redis_service_key = 'appcloud-redis7'; }
|
|
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'] === '<DEINE_S3_CUPS_INSTANZ>') {
|
|
$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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (empty($CFG->session_handler_class)) {
|
|
$CFG->session_handler_class = '\core\session\database';
|
|
}
|
|
|
|
if ($useCdn) {
|
|
$CFG->cookiepath = '/';
|
|
$CFG->cookiedomain = '<DEINE_MOODLE_DOMAIN>';
|
|
$CFG->cookiesecure = 1;
|
|
$CFG->cookiehttponly = 1;
|
|
}
|
|
|
|
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):**
|
|
|
|
```bash
|
|
cf push -f manifest-cdn.yml
|
|
```
|
|
|
|
**Ohne CDN (Test / Direkter Zugriff):**
|
|
|
|
```bash
|
|
cf push -f manifest-no-cdn.yml
|
|
```
|
|
|
|
Nach Abschluss des Deployments und dem Durchlaufen der Moodle-Web-Installation ist Ihre Instanz einsatzbereit. |