Il existe un moissonneur très cool pour la gestion de projet conjointe, l'autorisation LDAP, la synchronisation de fichiers avec gestion des versions et quelque chose comme un messager d'entreprise avec vidéoconférence, qui ont été foirés dans les dernières versions. Oui, je parle de Nextcloud. D'une part, je suis un partisan de la méthode Unix et d'une division claire des applications en fonctions distinctes. En revanche, ce produit est plus que stable, il travaille depuis de nombreuses années dans plusieurs projets sans aucun problème et des sifflets supplémentaires n'interfèrent pas particulièrement avec son travail. Si vous le voulez vraiment, vous pouvez y visser presque tous les jeux. La communauté est vivante et complète entièrement divers plugins disponibles sous forme d'applications distinctes.
Aujourd'hui, nous allons le déployer. Je ne donnerai pas une instruction étape par étape complète, mais j'essaierai de mentionner les points clés de l'architecture qui méritent une attention particulière. En particulier, nous analyserons l'équilibrage de charge, la réplication de la base de données et la maintenance de routine sans interruption de service.
Nous déploierons dans une version à sécurité intégrée pour une petite entreprise de 150 à 1000 utilisateurs, mais cela sera également utile pour les utilisateurs à domicile.
De quoi les entreprises ont-elles besoin?
La principale différence entre le service sur un serveur domestique confortable fait de glands et les allumettes du segment des entreprises est la responsabilité envers les utilisateurs. Cependant, même dans mon installation à domicile, je considère qu'il est bon d'envoyer des messages aux utilisateurs avec un avertissement concernant un travail prévu ou un accident potentiel. Après tout, c'est samedi soir que votre ami peut soudainement décider de travailler avec les données qu'il héberge avec vous.
Dans le cas d'une entreprise, même petite, tout service important simple signifie des pertes et des problèmes potentiels. Surtout s'il existe de nombreux processus liés au service.
En particulier, d'après mon expérience, Nextcloud est en demande pour plusieurs fonctionnalités parmi les petites entreprises:
- Fournir l'accès aux répertoires partagés et la synchronisation.
- Une fonctionnalité qui tue avec la fourniture d'accès externe au sein de la fédération. Vous pouvez intégrer un produit similaire de collègues et d'une autre entreprise.
- Fournir un accès externe via un lien direct. Cela aide beaucoup si, par exemple, vous travaillez dans l'industrie de l'imprimerie et avez besoin d'échanger de grandes quantités de données lourdes avec des clients.
- Éditeur de documents Collabora qui s'exécute côté serveur et agit comme une interface pour LibreOffice.
- Chats et appels vidéo. Une fonctionnalité légèrement controversée, pas entièrement stable, mais elle est là et fonctionne. Dans la dernière version, il a déjà été stabilisé.
Nous construisons l'architecture
Malheureusement, dans les dernières versions, la documentation Nextcloud Enterprise Implementation n'est disponible que pour les membres payants. Cependant, comme référence, vous pouvez prendre des manuels plus anciens qui sont encore dans le domaine public.
Typique pour un usage domestique et des installations simples.
Une option «tout-en-un» n'est pas mauvaise tant que vous avez peu d'utilisateurs et que vous pouvez vous permettre des temps d'arrêt pour la maintenance de routine. Par exemple, lors d'une mise à jour. En outre, un schéma monolithique avec placement sur un nœud présente des problèmes de mise à l'échelle. Par conséquent, nous allons essayer la deuxième option.
Option de déploiement évolutive recommandée pour les charges de travail plus élevées.
Les principaux composants du système:
- 1 équilibreur. Vous pouvez utiliser HAproxy ou Nginx. Je vais considérer l'option avec Nginx.
- 2-4 pièces Serveur d'application (serveur Web). L'installation de Nextcloud lui-même avec le code principal en php.
- 2 DB. Dans la configuration standard recommandée, il s'agit de MariaDB.
- Stockage NFS.
- Redis pour la mise en cache des requêtes de base de données
Balancier
Avec cette architecture, vous aurez moins de points de défaillance. Le principal point de défaillance est l'équilibreur de charge. S'il n'est pas disponible, les utilisateurs ne pourront pas accéder au service. Heureusement, sa configuration du même nginx est assez simple, comme nous le verrons plus loin, et il tient la charge sans aucun problème. La plupart des échecs sur l'équilibreur sont résolus en redémarrant le démon, le nœud entier ou en déployant à partir d'une sauvegarde. Il ne sera pas superflu d'avoir une réserve froide configurée dans un autre emplacement avec un trafic manuel basculant vers elle dans DNS.
Veuillez noter que l'équilibreur est également un point de terminaison SSL / TLS pour vos clients et que la communication avec le backend peut passer soit via HTTP pour les réseaux internes de confiance, soit avec HTTPS supplémentaire si le trafic vers le serveur d'applications passe par des canaux généraux non approuvés.
Base de données
Une solution typique est MySQL / MariaDB en exécution en cluster dans la réplication maître-esclave. En même temps, vous n'avez qu'une seule base de données active, et la seconde fonctionne en mode hot standby en cas de panne d'urgence de la principale ou pendant le travail planifié. L'équilibrage de charge peut également être envisagé, mais il est techniquement plus difficile. Lorsque vous utilisez MariaDB Galera Cluster avec l'option de réplication maître-maître, vous devez utiliser un nombre impair de nœuds, mais au moins trois. Ainsi, le risque de situations de split-brain est minimisé lorsque la connectivité entre les nœuds est coupée.
Espace de rangement
Toute solution qui vous convient le mieux fournie par le protocole NFS. Pour des charges élevées, pensez à IBM Elastic Storage ou Ceph. Il est également possible d'utiliser le stockage d'objets compatible S3, mais c'est plutôt une option pour les très grandes installations.
HDD ou SSD
En principe, pour les installations de taille moyenne, il suffit d'utiliser uniquement le disque dur. Le goulot d'étranglement ici sera iops lors de la lecture à partir de la base de données, ce qui affecte grandement la réactivité du système, mais si vous avez Redis, qui met tout en cache en RAM, ce ne sera pas un gros problème. En outre, une partie du cache sera stockée dans Memcached sur les serveurs d'applications. Cependant, je recommanderais d'héberger vos serveurs d'applications sur un SSD dans la mesure du possible. L'interface Web est beaucoup plus réactive. Dans ce cas, la même synchronisation de fichiers sur les clients de bureau fonctionnera à peu près de la même manière que lors de l'utilisation du disque dur pour ces nœuds.
La vitesse de synchronisation et de téléchargement des fichiers sera déterminée par les performances de votre stockage NFS.
Configurer l'équilibreur
A titre d'exemple, je vais donner un simple en configuration de base et un nginx efficace. Oui, divers chignons de basculement supplémentaires ne sont disponibles que dans la version payante, mais même dans la version de base, il remplit parfaitement sa tâche. Veuillez noter que le round robin ou l'équilibrage aléatoire ne nous convient pas, car les serveurs d'applications stockent des caches pour des clients spécifiques.
Heureusement, cela est résolu en utilisant la méthode ip_hash . Dans ce cas, les sessions de l'utilisateur seront attribuées à un backend spécifique, vers lequel toutes les demandes de l'utilisateur seront dirigées. Ce point est décrit dans la documentation:
, IP- . IPv4- IPv6- . , . , . .
Malheureusement, lors de l'utilisation de cette méthode, il peut y avoir des problèmes avec les utilisateurs qui sont derrière une adresse IP dynamique et la changent constamment. Par exemple, sur les clients avec Internet mobile, qui peuvent être lancés le long de différentes routes lors du passage d'une cellule à l'autre. le cookie collant qui résout ce problème n'est disponible que dans la version payante.
Le fichier de configuration nginx décrit cela comme suit:
upstream backend {
ip_hash;
server backend1_nextcloud.example.com;
server backend2_nextcloud.example.com;
server backend3_nextcloud.example.com;
server backend4_nextcloud.example.com;
}
Dans ce cas, la charge sera aussi uniformément répartie que possible entre les serveurs d'application, bien qu'en raison de la liaison du client à une session spécifique, des déséquilibres de charge puissent se produire. Pour les petites et moyennes installations, cela peut être négligé. Si vos backends ont une puissance différente, vous pouvez définir le poids de chacun d'eux. Ensuite, l'équilibreur essaiera de répartir la charge proportionnellement aux poids donnés:
upstream backend {
ip_hash;
server backend1_nextcloud.example.com weight=3;
server backend2_nextcloud.example.com;
server backend3_nextcloud.example.com;
}
Dans l'exemple ci-dessus, sur 5 demandes reçues, 3 iront au backend1, 1 au backend2 et 1 au backend3.
Si l'un des serveurs d'applications échoue, nginx essaiera de rediriger la demande vers le serveur suivant à partir de la liste des backends.
Configurer la base de données
Les détails de la configuration maître-esclave peuvent être trouvés dans la documentation principale .
Jetons un coup d'œil à quelques points clés. Tout d'abord, nous créons un utilisateur pour la réplication des données:
create user 'replicant'@'%' identified by 'replicant_password';
grant replication slave on *.* to replicant;
flush privileges;
Ensuite, nous éditons la configuration principale:
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
Dans la zone du bloc "Journalisation et réplication", effectuez les modifications nécessaires:
[mysqld]
log-bin = /var/log/mysql/master-bin
log-bin-index = /var/log/mysql/master-bin.index
binlog_format = mixed
server-id = 01
replicate-do-db = nextcloud
bind-address = 192.168.0.6
Sur l'esclave, nous configurons la config:
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
Dans la zone du bloc "Journalisation et réplication", effectuez les modifications nécessaires:
[mysqld]
server-id = 02
relay-log-index = /var/log/mysql/slave-relay-bin.index
relay-log = /var/log/mysql/slave-relay-bin
replicate-do-db = nextcloud
read-only = 1
bind-address = 192.168.0.7
Redémarrez les deux serveurs:
sudo systemctl restart mariadb
Ensuite, vous devrez copier la base de données vers Slave.
Sur le maître, nous effectuons d'abord le verrouillage de table:
flush tables with read lock;
Et puis nous regardons le statut:
MariaDB [(none)]> show master status;
+-------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| master-bin.000001 | 772 | | |
+-------------------+----------+--------------+------------------+
1 row in set (0.000 sec)
Ne quittez pas la console de base de données, sinon les verrous seront supprimés!
Nous aurons besoin de master_log_file et master_log_pos d'ici pour la configuration Slave.
Vidage et retrait des verrous:
sudo mysqldump -u root nextcloud > nextcloud.sql
> unlock tables;
> exit;
Ensuite, nous importons le vidage dans Slave et redémarrons le démon:
sudo mysqldump -u root nextcloud < nextcloud.sql
sudo systemctl restart mariadb
Après cela, configurez la réplication dans la console:
MariaDB [(none)]> change master 'master01' to
master_host='192.168.0.6',
master_user='replicant',
master_password='replicant_password',
master_port=3306,
master_log_file='master-bin.000001',
master_log_pos=772,
master_connect_retry=10,
master_use_gtid=slave_pos;
Nous lançons et vérifions:
> start slave 'master01';
show slave 'master01' status\G;
Il ne devrait y avoir aucune erreur dans la réponse et deux points indiqueront le succès de la procédure:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Déployer des nœuds d'application
Il existe plusieurs options de déploiement:
- casser
- image-docker
- mise à jour manuelle
Snap est disponible principalement pour Ubuntu. Il est assez bon pour fournir des applications propriétaires complexes, mais par défaut. Mais il a une fonctionnalité plutôt ennuyeuse dans un environnement industriel: il met automatiquement à jour ses packages plusieurs fois par jour. Vous devrez également scier des accès supplémentaires vers l'extérieur si vous disposez d'un réseau interne strictement délimité. Dans le même temps, la mise en miroir de ses référentiels à l'intérieur n'est pas entièrement triviale.
Oui, il existe des canaux d'abonnement et des versions majeures, en théorie, il ne faut pas changer, mais pensez-y. Je recommanderais un contrôle total sur le processus de mise à jour, d'autant plus qu'il s'accompagne souvent d'un changement dans la structure des données dans la base de données.
Docker-image est une bonne option, surtout si votre infrastructure est déjà en cours d'exécution sur Kubernetes. Le même nœud Redis est susceptible d'accéder au cluster après les serveurs d'applications.
Si vous ne disposez pas de l'infrastructure pour le faire, la mise à jour et le déploiement manuels à partir de tar.gz sont assez pratiques et contrôlables.
N'oubliez pas que vous devrez installer un serveur Web sur le serveur d'applications pour gérer les demandes entrantes. Je recommanderais un bundle de nginx + php-fpm7.4. Avec les dernières versions de php-fmp, les performances et la réactivité se sont considérablement améliorées.
Configuration de SSL / TLS
Vous devez absolument compter sur TLS 1.3 si vous effectuez une nouvelle installation et qu'il n'y a aucun problème avec les paquets nginx qui dépendent de la fraîcheur du système openssl. En particulier, le 0-RTT et d'autres goodies permettent parfois d'accélérer considérablement la reconnexion du client en raison de la mise en cache. La sécurité est également plus élevée en raison de la suppression des protocoles obsolètes.
Je vais donner la configuration réelle du serveur d'application nginx, qui communique avec l'équilibreur via TLS:
Configuration Nginx
upstream php-handler {
server unix:/var/run/php/php7.4-fpm.sock;
}
server {
listen 80;
server_name backend1_nextcloud.example.com;
# enforce https
root /var/www/nextcloud/;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
ssl_early_data on;
# listen [::]:443 ssl http2;
server_name backend1_nextcloud.example.com;
# Path to the root of your installation
root /var/www/nextcloud/;
# Log path
access_log /var/log/nginx/nextcloud.nginx-access.log;
error_log /var/log/nginx/nextcloud.nginx-error.log;
### SSL CONFIGURATION ###
ssl_certificate /etc/letsencrypt/live/backend1_nextcloud.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/backend1_nextcloud.example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/backend1_nextcloud.example.com/fullchain.pem;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
#ssl_ciphers "EECDH+AESGCM:EECDH+CHACHA20:EECDH+AES256:!AES128";
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POL>
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 5m;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.4.4 8.8.8.8;
add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains; preload' always;
### SSL ###
# Add headers to serve security related headers
# Before enabling Strict-Transport-Security headers please read into this
# topic first.
# add_header Strict-Transport-Security "max-age=15768000;
# includeSubDomains; preload;";
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Download-Options "noopen" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "none" always;
add_header X-XSS-Protection "1; mode=block" always;
# Remove X-Powered-By, which is an information leak
fastcgi_hide_header X-Powered-By;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# The following 2 rules are only needed for the user_webfinger app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
#rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json
# last;
location = /.well-known/carddav {
return 301 $scheme://$host/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host/remote.php/dav;
}
# set max upload size
client_max_body_size 512M;
fastcgi_buffers 64 4K;
# Enable gzip but do not remove ETag headers
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fon>
# Uncomment if your server is build with the ngx_pagespeed module
# This module is currently not supported.
#pagespeed off;
location / {
rewrite ^ /index.php;
}
location ~ ^\/(?:build|tests|config|lib|3rdparty|templates|data)\/ {
deny all;
}
location ~ ^\/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_param HTTPS on;
# Avoid sending the security headers twice
fastcgi_param modHeadersAvailable true;
# Enable pretty urls
fastcgi_param front_controller_active true;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}
location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
try_files $uri/ =404;
index index.php;
}
# Adding the cache control header for js, css and map files
# Make sure it is BELOW the PHP block
location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
try_files $uri /index.php$request_uri;
add_header Cache-Control "public, max-age=15778463";
# Add headers to serve security related headers (It is intended to
# have those duplicated to the ones above)
# Before enabling Strict-Transport-Security headers please read into
# this topic first.
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Download-Options "noopen" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "none" always;
add_header X-XSS-Protection "1; mode=block" always;
# Optional: Don't log access to assets
access_log off;
}
location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap)$ {
try_files $uri /index.php$request_uri;
# Optional: Don't log access to other assets
access_log off;
}
}
Maintenance de routine
N'oubliez pas que dans un environnement industriel, vous devez fournir un temps d'arrêt minimal et nul pour les mises à niveau ou même plus de sauvegardes. La principale difficulté ici est la dépendance de l'état des métadonnées dans la base de données et des fichiers eux-mêmes, qui sont disponibles via NFS ou le stockage d'objets.
Lors de la mise à niveau des serveurs d'applications vers une nouvelle version mineure, il n'y a pas de problèmes particuliers. Mais le cluster doit encore être transféré en mode maintenance pour mettre à jour la structure de la base de données.
Éteignez l'équilibreur au moment de la moindre charge et procédez à la mise à jour.
Après cela, nous effectuons le processus de mise à jour manuelle dessus à partir du tar.gz téléchargé, tout en enregistrant le fichier de configuration config.php. Mettre à jour sur le Web sur de grandes installations est une très mauvaise idée!
Nous mettons à jour via la ligne de commande:
sudo -u www-data php /var/www/nextcloud/occ upgrade
Après cela, nous activons l'équilibreur et envoyons le trafic au serveur mis à jour. Pour ce faire, nous supprimons tous les serveurs d'applications non mis à jour de l'équilibrage:
upstream backend {
ip_hash;
server backend1_nextcloud.example.com;
server backend2_nextcloud.example.com down;
server backend3_nextcloud.example.com down;
server backend4_nextcloud.example.com down;
}
Le reste des nœuds est progressivement mis à jour et mis en service. Dans ce cas, la mise à jour occ n'a pas besoin d'être effectuée! Il vous suffit de remplacer les fichiers php et de sauvegarder la configuration.
Lors de la sauvegarde, vous devez arrêter la réplication sur l'esclave et effectuer un vidage simultané des métadonnées de la base de données en même temps que la création d'un instantané des fichiers dans le stockage. Vous devez les stocker par paires. La récupération doit être effectuée de la même manière à partir d'un vidage de base de données et de fichiers pour la même période. Sinon, la perte de données est possible, car le fichier peut être dans le stockage, mais ne pas avoir de métadonnées dans la base de données.