Blog de dada

DevOps, bidouilleur et routard plein de logiciels libres

Nextcloud

Nextcloud, PHP-FPM, Nginx et Kubernetes

Rédigé par dada / 14 janvier 2019 / 6 commentaires




Ma première installation de Nextcloud dans Kubernetes était basée sur l'image Docker contenant Apache2. Aucun souci notable au niveau de la synchro des agendas, des fichiers ou encore des contacts. Par contre, la génération des miniatures des photos s'est révélée être un drame : Apache s'emballait et entraînait le nœud sur lequel il tournait avec lui, dans la tombe. Il me fallait une solution, j'ai donc décidé de changer de conteneur et de prendre celui basé sur PHP-FPM.

Un pod avec deux conteneurs

On entend souvent la rumeur racontant qu'un pod ne contient qu'un conteneur. C'est souvent vrai, mais c'est aussi faux. Dans l'exemple qui va suivre, le pod gérant Nextcloud contiendra le conteneur officiel de Nextcloud et un conteneur Nginx.

Contexte

Pour suivre, sachez que mon cluster, celui grâce auquel vous lisez ces quelques lignes, gère son système de fichier avec Rook, dont j'ai déjà parlé ici. Mes nœuds sont chez Hetzner, ce sont des CX21, du cloud public donc, et mes services sont exposés en NodePort derrière un Nginx configuré en LoadBalancer. Maintenant que vous savez ça, on peut y aller.

Le Deployment

On va commencer par balancer le Yaml qui marche :
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nextcloud-deployment
spec:
  selector:
    matchLabels:
      app: nextcloud
  replicas: 1
  template:
    metadata:
      labels:
        app: nextcloud
    spec:
      containers:
      - name: nginx
        image: nginx:1.15
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nginx-config
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
        - name: pv-nextcloud
          mountPath: /var/www/html
        lifecycle:
          postStart:
            exec:
             command: ["bin/sh", "-c", "mkdir -p /var/www/html"]
      - name: nextcloud
        image: nextcloud:14.0-fpm
        ports:
        - containerPort: 9000
        volumeMounts:
        - name: pv-nextcloud
          mountPath: /var/www/html
        resources:
          limits:
            cpu: "1"
      volumes:
      - name : nginx-config
        configMap:
           name: nginx-config
      - name: pv-nextcloud
        flexVolume:
          driver: ceph.rook.io/rook
          fsType: ceph
          options:
            fsName: myfs
            clusterNamespace: rook-ceph
            path: /nextcloud2

Il n'y a pas le Service associé pour la simple et bonne raison que chacun fait comme il le veut. Si vous êtes chez DigitalOcean, OVH ou chez un des GAFAM qui propose du k8s, vous aurez un LoadBalancer qui va bien. Si vous êtes comme moi, vous êtes réduit à faire du NodePort.

Ce qu'il faut comprendre

Vous remarquerez qu'il y a deux conteneurs : Nginx et Nextcloud-FPM. Nginx écoute sur le port 80 et va router le trafic à travers vers le port 9000 du conteneur de Nextcloud.

Nginx

      - name: nginx
        image: nginx:1.15
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nginx-config
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
        - name: pv-nextcloud
          mountPath: /var/www/html
        lifecycle:
          postStart:
            exec:
             command: ["bin/sh", "-c", "mkdir -p /var/www/html"]
On va faire gober à Nginx deux points de montage : sa configuration et les sources de Nextcloud. Sans les sources de l'application, Nginx ne pourra pas avoir accès aux fichiers PHP, et ne servira donc à rien. On va donc prendre le point de montage originalement dédié à Nextcloud pour le monter une deuxième fois dans un deuxième conteneur, celui de Nginx.

Lifecycle

Remarquez la présence de la section lifecycle, elle permet d’exécuter ce que vous voulez au démarrage du conteneur. Quand j'apprenais à me servir de ce couple, je ne comprenais pas pourquoi Nginx ne voulait pas correctement fonctionner. J'ai passé du temps à comprendre que le conteneur Nginx et le conteneur Nextcloud n'avaient pas le même docRoot :
  • Nginx : /srv/html
  • Nextcloud : /var/www/html
Comprenez que les requêtes Nginx allaient chercher des fichiers dans /srv/html/blabla.php quand Nextcloud annonçait la présence de ses sources dans /var/www/html/blabla.php. Le bordel.

C'est là que je n'ai trouvé pas idiot l'idée de créer le chemin manquant au démarrage du pod avec un postStart. Du coup, j'avais Nginx et Nextcloud au diapason. Il est sans doute possible de configurer Nginx pour surcharger son docRoot, mais c'était l'occasion de jouer avec des commandes en amont de la création d'un conteneur.

Les deux points de montage

On a donc un point de montage pour les sources de Nextcloud :
        - name: pv-nextcloud
          mountPath: /var/www/html
Et un point de montage pour la configuration de Nginx :
        - name: nginx-config
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf

Là aussi, j'ai perdu un peu de temps avant de comprendre qu'il fallait balancer toute la configuration de Nginx et pas seulement ce que j'ai l'habitude de mettre dans les sites-enabled. C'est du moins à faire quand on écrase le nginx.conf du pod. En y réfléchissant, c'est sans doute plus simple de modifier le point montage pour n'ajouter qu'un fichier dans le fameux sites-enabled.

Pour gérer la configuration de Nginx, je passe par une ConfigMap :
kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-config
data:
  nginx.conf: |
    worker_processes  1;

    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;

    events {
        worker_connections  1024;
    }

    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;

        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';

        access_log  /var/log/nginx/access.log  main;

        sendfile        on;
        #tcp_nopush     on;

        keepalive_timeout  65;

        #gzip  on;

        server {
            listen 80;

            add_header X-Content-Type-Options nosniff;
            add_header X-XSS-Protection "1; mode=block";
            add_header X-Robots-Tag none;
            add_header X-Download-Options noopen;
            add_header X-Permitted-Cross-Domain-Policies none;
            add_header Referrer-Policy no-referrer;

            root /var/www/html;

            location = /robots.txt {
                allow all;
                log_not_found off;
                access_log off;
            }

            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 10G;
            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-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

            location / {
                rewrite ^ /index.php$request_uri;
            }

            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/.+|ocs-provider/.+)\.php(?:$|/) {
                fastcgi_split_path_info ^(.+\.php)(/.*)$;
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_param PATH_INFO $fastcgi_path_info;
                # fastcgi_param HTTPS on;
                #Avoid sending the security headers twice
                fastcgi_param modHeadersAvailable true;
                fastcgi_param front_controller_active true;
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_intercept_errors on;
                fastcgi_request_buffering off;
            }

            location ~ ^/(?:updater|ocs-provider)(?:$|/) {
                try_files $uri/ =404;
                index index.php;
            }

            # Adding the cache control header for js and css files
            # Make sure it is BELOW the PHP block
            location ~ \.(?:css|js|woff|svg|gif)$ {
                try_files $uri /index.php$request_uri;
                add_header Cache-Control "public, max-age=15778463";
                add_header X-Content-Type-Options nosniff;
                add_header X-XSS-Protection "1; mode=block";
                add_header X-Robots-Tag none;
                add_header X-Download-Options noopen;
                add_header X-Permitted-Cross-Domain-Policies none;
                add_header Referrer-Policy no-referrer;

                # Optional: Don't log access to assets
                access_log off;
            }

            location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ {
                try_files $uri /index.php$request_uri;
                # Optional: Don't log access to other assets
                access_log off;
            }
        }

    }
Eh oui, il y a tout dedans. Ça déforme l'affichage de ce billet, m'enfin. C'est une configuration Nginx classique.

On peut quand même s'arrêter sur la configuration du fastcgi_pass : il tape sur le 127.0.0.1 et le port 9000 du conteneur Nextcloud. Je n'ai pas encore gratté pour comprendre le pourquoi du comment mais je suppose que les deux conteneurs tournant dans le réseau du pod, ils se comportent comme deux services dans une seule et même machine. À confirmer.

On apply tout ça

Attention ! Avant de balancer le Deployment, balancez le yaml de la ConfigMap. Sans ça, Nginx ne chargera pas votre configuration !
dada@k8smaster1:~$ kubectl apply -f configmap.yaml
dada@k8smaster1:~$ kubectl apply -f nextcloud.yaml
Si tout se passe bien, vous devriez pouvoir voir ça :
dada@k8smaster1:~$ kubectl get pods
nextcloud-deployment-d6cbb8446-87ckf   2/2     Running   0          15h
Remarquez que Kubernetes vous montre bien qu'il y a deux conteneurs dans ce pod : 2/2.

Pour aller plus loin

Je ne parle pas des vérifications de l'état des conteneurs. Il faudrait placer des sondes liveness et readness pour parfaitement vérifier l'état des conteneurs. Sans ça, si l'un des services tombe, Kubernetes ne sera pas forcément en mesure de le détecter et de relancer le pod.
Il est aussi possible, pour respecter le concept de micro-service, de ne pas concaténer deux conteneurs dans un seul pod mais de faire un pod par conteneur et des services associés. Ça demande plus de travail pour un résultat qui, dans mon cas, n'apporte pas grand chose.

Passer à Nextcloud 13 rapidement

Rédigé par dada / 06 février 2018 / 4 commentaires




Nextcloud 13 est enfin disponible ! Cette dernière n'est cependant pas encore disponible pour tout le monde via l'application Updater. Seul 15% des utilisateurs ont la chance de pouvoir se mettre à jour en 3 clics. Pour le reste d'entre nous, il va falloir attendre un peu. En effet, les développeurs expliquent qu'ils ne la balancent pas à tout le monde dès le premier jour pour pouvoir la couper en cas de bugs et/ou de soucis découverts pendant la première salve. Ils déploient calmement, c'est bien.

Ceci dit, pour les plus pressés, il est possible de se lancer dans l'aventure avec les quelques actions suivantes :
  • Passer l'Updater sur le canal «beta»
  • Recharger la page
  • Appliquer la mise à jour proposée, qui est bien la version stable
  • Ne pas oublier de repasser sur le canal stable une fois la màj terminée


Si vous avez peur de cette manipulation, sachez qu'elle sort tout droit du billet de blog annonçant la sortie de la nouvelle version de mon cloud adoré ! Si si, tout en bas, juste avant le »Thank you».

Maintenant, la mise en garde :

Les applications officielles ne vous poseront pas de souci, contrairement aux applications terces !
Pensez à bien aller faire un tour dans le magasin d'application pour vérifier que vos outils sont biens compatibles avec cette toute nouvelle mouture !
Solution rapide : aller faire un tour dans la page Applications de votre instance et cliquez sur Afficher dans le magasin d'application dès que vous en avez l'occasion.


Si, comme dans la capture si dessus, vous ne voyez pas apparaitre Nextcloud 13, vous savez que vous devez attendre !

J'ai, personnellement, pas encore de versions compatibles avec NC 13 de Nextant et de Tasks. Cette dernière devrait arriver très vite, d'après cette issue Github.

Pour terminer : si vous le pouvez, soyez patient !

Streamer sa musique librement

Rédigé par dada / 05 décembre 2017 / 14 commentaires


Il existe des tonnes de façon d'apprécier sa musique sans pour autant la traîner sur des CD ou sur la carte mémoire de son téléphone. Les plus simples consistent à prendre un abonnement chez Deezer ou chez Spotify mais, manque de chance, c'est plein de DRM et ça ne fonctionne pas partout sur la planète. Oui, je reste un grand traumatisé de Spotify : je n'ai jamais réussi à écouter mes playlists alors que je vadrouillais en Syrie (avant !).

Du coup, voici ma solution. Ce n'est peut-être pas la plus simple mais elle me permet de combiner Nextcloud, Sonerezh et Power Ampache. Avec tout ça, j'écoute ma musique via une interface web et via une application mobile partout où je veux et je contrôle tout. Le seul souci, c'est que ça me coûte cher en musique.

Nextcloud ?

Pour n'avoir qu'à copier/coller mes dernières trouvailles dans un répertoire de mon PC. Il va être parcouru par le client de synchronisation : son contenu va donc directement être envoyé sur le serveur de streaming. C'est simple, facile et pour les feignants. En plus, ça fait déjà un backup.

Music ?

C'est l'application qui permet de lire ses fichiers audios dans NC. Ça fait du bon boulot, mais c'est moche et assez lent. Je préfère carrément Sonerezh. Ceci-dit, elle supporte l'API d'Ampache, et ça, c'est cool. Vous le voyez arriver, le lien avec Power Ampache ?

Power Ampache ?

Là, c'est le Graal. Votre NC est configuré, Music fournit l'API d'Ampache : Power Ampache va tout récupérer. Vous avez maintenant du streaming audio de qualité sur votre Smartphone. Bah oui, ça supporte le FLAC, tout ça !
Ah, et pensez à cocher "Offline Songs" si ça vous embête de pomper votre forfait 3/4G.

Sonerezh ?

Quand votre NC récupère vos fichiers audios, vous y avez accès via Music et Power Ampache, mais pas via une belle et rapide interface web. C'est là que Sonerezh débarque.
Pour que ça marche, il faut lui dire d'aller récupérer le contenu de votre répertoire Musique qui est dans Nextcloud, tout simplement.
Perso, je suis passé par le principe du stockage externe de Nextcloud pour que tous les partis puissent se parler, et que je puisse faire du gros copier/coller depuis mon PC sans avoir jamais à me connecter au serveur.

Qu'est-ce que ça donne ?

Sonerezh :



Power Ampache :


Tout cela n'est pas parfait, mais c'est de la bonne bidouille ! Du logiciel libre et un peu d'idées pour ne plus jamais se prendre le choux à gérer sa musique entre le local et le distant. Y'a sans doute plus simple, mais bon, une fois que ce système est en place, on n'a plus qu'à vérifier les tags avec EasyTAG et à faire un copier/coller. Cool.

Améliorer la recherche dans Nextcloud avec Nextant

Rédigé par dada / 03 juin 2017 / 1 commentaire




La recherche dans Nextcloud est bien foutue mais commence à montrer ses limites quand on s'amuse à stocker une grande quantité de fichiers. En plus, elle ne va pas analyser ce qui se passe au niveau du contenu. C'est là que l'ami Solr débarque via une extension plutôt pratique : Nextant.
J'annonce tout de suite, ce billet va parler d'un outil en Java, et même qu'il va falloir l'installer. Si vous faites partie de ceux qui s'obstinent à dire que Java, c'est de la merde, plutôt que de pester sur des développeurs d'applications, au mieux, maladroits, passez votre chemin.
C'est aussi un peu compliqué, mais bon, je vais tenter de faire de mon mieux pour vous rendre la tâche presque simple !

Installer Java

On attaque fort, j'avais prévenu ! Si vous êtes sous Debian 8, vous aurez besoin de passer par les backports puisque la version présente dans les dépôts classiques est trop ancienne. Il faut les mettre en place et taper la commande suivante :
apt-get -t jessie-backports install openjdk-8-jdk

Vérifier la version utilisée par le système

Les versions de Java cohabitent dans votre système. Si vous aviez déjà du java, il faut faire comprendre à l'OS que c'est la toute dernière qu'il faut  :
root@dadall:/var/www/# java -version
openjdk version "1.8.0_131"
OpenJDK Runtime Environment (build 1.8.0_131-8u131-b11-1~bpo8+1-b11)
OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)
Si le résultat retourné n'est pas le même que le mien, corrigez le souci en passant par l'update-alternatives :
root@dadall:/var/www/html/nc#  update-alternatives --config java
Il existe 2 choix pour l'alternative java (qui fournit /usr/bin/java).

  Sélection   Chemin                                          Priorité  État
------------------------------------------------------------
  0            /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java   1071      mode automatique
  1            /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java   1071      mode manuel
* 2            /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java   1069      mode manuel

Appuyez sur <Entrée> pour conserver la valeur par défaut[*] ou choisissez le numéro sélectionné :
Dans mon cas, tapez 2 et vous en aurez fini avec Java.

Installer Solr

On va passer par l'installeur automatique. C'est bien plus simple et ça permet de ne pas se prendre la tête.
D'abord, prenez le temps de créer un utilisateur solr :
adduser --disabled-login solr
su solr
cd ~
Placez-vous dans sa home et récupérez les sources :
$ wget http://mirrors.ircam.fr/pub/apache/lucene/solr/6.5.1/solr-6.5.1.tgz
$ tar -zxvf solr-6.5.1.tgz
Puis lancez la procédure :
# bash solr-6.5.1/bin/install_solr_service.sh solr-6.5.1.tgz 
Une fois terminée, on va faire un peu de configuration. On va simplement dire à Solr de ne répondre qu'aux sollicitations locales en remplaçant cette ligne :
<Set name="host"><Property name="jetty.host" /></Set>
par :
<Set name="host"><Property name="jetty.host" default="127.0.0.1" /></Set>
dans le fichier présent là-bas : /opt/solr/server/etc/jetty-http.xml. C'est une configuration simple mais importante : elle évite de rendre vos données accessibles à l'extérieur.

Vous pouvez maintenant démarrer la bête :
# /etc/init.d/solr start 
Solr est maintenant démarré mais il lui marque un dernier truc : un core. On va le créer en deux minutes en tapant ça avec le user solr créé pour l'occasion :
/opt/solr/bin/solr create -c nextant 
Et voilà pour Solr ! Place à l'extension !

Installer Nextant

Bon, là, si vous avez réussi toutes les étapes précédentes, c'est que vous pouvez aller cliquer dans la gestion des applications de votre Nextcloud pour activer le bousin. Tout est déjà rempli pour vous. C'est très clair et un bouton «tester» est là pour vous permettre de tout valider !



Solr fonctionne sur le principe des indexations : à un instant T, il va gober tout ce qu'il y a à savoir dans vos fichiers et l'organiser à sa sauce. Pour la première, il est plus que conseillé de la faire à la main en tapant la commande (avec le user de votre Nextcloud, pas le user solr) :
./occ nextant:index 
L'indexation de nouveau contenu ne se fera pas en temps réel mais via un cron Nextcloud. C'est à dire de temps en temps, alors ne vous étonnez pas si le dernier document que vous venez d'ajouter n’apparaît pas immédiatement dans les résultats de recherche.

Une section «Pour aller plus loin» est disponible dans la doc de Nextant. Elle indique, entre autre, comment exclure des répertoires de l'indexation. C'est pas mal si vous ne voulez pas voir certaines infos apparaître maladroitement.

Vous pouvez maintenant faire vos recherches dans vos fichiers !

Installer Collabora Online avec Nextcloud

Rédigé par dada / 05 avril 2017 / 19 commentaires




Le soleil repointe le bout de son nez et je ne trouve plus le temps de sortir des billets. L'apéro passe avant tout mais malgré ça, j'ai quand même pas mal joué avec mon serveur.
D'abord, j'ai changé de crémerie, encore, pour laisser tomber mon C1 chez Scaleway pour une Kimsufi aux caractéristiques bien plus rigolotes : adieu l'ARM, coucou le Core i3. Ça m'a permis de mettre en place l'objet de ce billet : Collabora Online dans Nextcloud via Docker !

je présuppose que votre machine tourne sous Debian Jessie (what else ?) avec Nextcloud 11.0.2.

Installer Docker

Je suis passé par l'installation de Docker CE. Ça permet d'avoir une version plus récentes de la bête.

On commence par les dépendances qui vont bien :
apt-get install apt-transport-https ca-certificates curl software-properties-common 
On enchaîne sur la clé GPG du dépôt :
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
On ajoute le dépôt dan le sources.list :
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" 
Pour finir, on installe notre nouveau jouet et c'est parti !
apt-get update && apt-get install docker-ce

Mise en place du conteneur de Collabora

On le télécharge :
docker pull collabora/code 
On le lance :
docker run -t -d -p 127.0.0.1:9980:9980 -e 'domain=votre\\.instance\\.com' --restart always --cap-add MKNOD collabora/code 
C'est pendant cette étape que je me suis le plus pris la tête... Ils disent de lancer docker avec pour paramètre un sous-domaine pour Collabora alors qu'il ne le faut pas, pas chez moi du moins. En fait, comme Collabora tourne sur le même serveur que mon instance, pas besoin de sous-domaine.

Configurer votre Vhost

Pour Nginx, ajoutez ces lignes dans votre vhost : (snippet ici).

    # static files     
    location ^~ /loleaflet {
        proxy_pass https://127.0.0.1:9980;
        proxy_set_header Host $http_host;
    }       
    # WOPI discovery URL
        location ^~ /hosting/discovery {
        proxy_pass https://127.0.0.1:9980;
        proxy_set_header Host $http_host;    
    }        
    # websockets, download, presentation and image upload
    location ^~ /lool {        
        proxy_pass https://127.0.0.1:9980;
        proxy_set_header Upgrade $http_upgrade;  
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
   }
Pour Apache2. c'est trop long alors cliquez sur snippet !

Et voilà pour le plus chiant !

Activer Collabora

Maintenant, pour terminer, allez donc activer l'application en la configurant avec le sous-domaine de votre instance : https://votre.instance.com. Pensez bien à cliquer sur "Appliquer" si vous ne voulez pas risquer de devenir chèvre...

Tous ces efforts vous permettront de cliquer paisiblement sur ces 3 nouvelles options :



Amusez-vous bien !