Skip to content

Packaging de ClickHouse pour YunoHost

Ce document explique comment j'ai packagé ClickHouse pour YunoHost, les choix que j'ai faits pour ça et les difficultés que j'ai rencontrées.

APT, Sources et Version

Le package YunoHost a une version et il est d'usage de mettre la même version que celle du produit packagé. Par exemple si je package ClickHouse v24.3, je mettrais une version 24.3~ynh1 à mon package (~ynh1 correspond à la version du package lui-même pour le ClickHouse v24.3).

Mais cela veut dire que le package doit être capable d'installer une version particulière de ClickHouse.

J'ai commencé par vouloir installer ClickHouse avec l'aide des packages APT (voir https://clickhouse.com/docs/en/install#install-from-deb-packages) que j'ai définis dans manifest.toml :

    #[resources.apt]
    # This will automatically install/uninstall the following apt packages
    # and implicitly define the $phpversion setting as 8.0 (if phpX.Y-foobar dependencies are listed)
    packages = ["apt-transport-https", "ca-certificates", "curl", "gnupg"]
    extras.clickhouse.repo = "deb https://packages.clickhouse.com/deb lts main"
    extras.clickhouse.key = "https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key"
    extras.clickhouse.packages = ["clickhouse-server", "clickhouse-client"]

Ca fonctionne mais cela installe la dernière version disponible. J'ai tenté de fixer la version en changeant cette ligne :

    extras.clickhouse.packages = ["clickhouse-server=23.3.22.3", "clickhouse-client=23.3.22.3"]

Mais l'installation échouait...

De plus, dans l'esprit des packages YunoHost, APT est utilisé pour installer les dépendances de l'application mais pas l'application elle-même.

J'ai donc basculé vers une installation à partir des "sources" en utilisant les archives .tgz (Voir https://clickhouse.com/docs/en/install#from-tgz-archives).

J'ai fini par cette définition dans manifest.toml :

    [resources.sources]

    [resources.sources.common-static]
    amd64.url = "https://packages.clickhouse.com/tgz/lts/clickhouse-common-static-23.3.22.3-amd64.tgz"
    amd64.sha256 = "46a0c6a2842315b750cc3bd1f9eba6b59ab2758595f7e8452814940d3f832360"

    [resources.sources.server]
    amd64.url = "https://packages.clickhouse.com/tgz/lts/clickhouse-server-23.3.22.3-amd64.tgz"
    amd64.sha256 = "fad0ef056785263d7c7cb63bf484fba46aebea3e7e30aff803d503070400ebe2"

    [resources.sources.client]
    amd64.url = "https://packages.clickhouse.com/tgz/lts/clickhouse-client-23.3.22.3-amd64.tgz"
    amd64.sha256 = "b5f52d12a322acfa13066801d195b5fc04e66df467befec908c1d486d8c7565e"

La procédure officielle installe aussi clickhouse-common-static-dbg mais ce n'est pas nécessaire si clickhouse-common-static est déjà installé.

J'ai choisi de rester sur les versions LTS de ClickHouse. On peut avoir la liste des versions de ClickHouse ici : https://github.com/ClickHouse/ClickHouse/tags

Pour une version donnée, on peut télécharger les .tgz correspondants dont la liste se trouve ici pour la version v23.3.22.3-lts : https://github.com/ClickHouse/ClickHouse/releases/tag/v23.3.22.3-lts

On y trouve les sha512 pour chaque package mais YunoHost utilise un sha256 pour vérifier chaque package. J'ai donc dû les calculer. Le plus rapide étant de mettre un sha256 bidon, de lancer l'installation qui va échouer, et de copier-coller le bon sha256 dans le message d'erreur.

Utilisateur debian

YunoHost crée un utilisateur linux pour chaque application installée. Cet utilisateur a le même nom que l'ID du package.

J'ai commencé par choisir l'ID clickhouse et j'ai vu à l'installation de ClickHouse (avec les APT mais peut-être par avec les .tgz) que ClickHouse créait l'utilisateur (et le groupe) lui aussi. Cela affichait des Warnings.

D'autre part, le modèle de package de YunoHost utilise $app, qui est l'ID, dans les instructions par défaut comme :

ynh_secure_remove --file="/etc/$app"
ynh_secure_remove --file="/var/log/$app"

Mais ClickHouse utilise les répertoires /etc/clickhouse-server et /var/log/clickhouse-server.

J'ai donc changé l'ID de clickhouse à clickhouse-server. Mais c'était une mauvaise idée car l'installation de ClickHouse créait l'utilisateur clickhouse alors que YunoHost créait l'utilisateur clickhouse-server. Le service était démarré par clickhouse qui n'arrivait pas à accéder aux répertoires de données qui appartenait à clickhouse-server...

J'ai donc remis l'ID à clickhouse.

Puis j'ai mis "en dur" les répertoires :

ynh_secure_remove --file="/etc/clickhouse-server"
ynh_secure_remove --file="/var/log/clickhouse-server"

Configuration

ClickHouse a 2 fichiers principaux pour sa configuration qui se trouvent dans /etc/clickhouse-server/ : config.xml et users.xml.

Plutôt que de modifier directement ces fichiers, il est possible de les amender en ajoutant des fichiers de conf dans /etc/clickhouse-server/config.d ou dans /etc/clickhouse-server/users.d.

NOTA : les 2 répertoires config.d et users.d étaient créés par l'installation avec les APT mais pas par l'installation avec les .tgz

J'ai repris les fichiers que j'avais déjà faits pour notre clickhouse pour le Docker Swarm swarm01 et je les ai adaptés.

Comme j'utilise le helper ynh_add_config, je peux utiliser les variables de YunoHost dans les fichiers de configuration.

Par exemple, avec :

ynh_add_config --template="config.d/paths.xml" --destination="/etc/clickhouse-server/config.d/paths.xml"

Je peux avoir un fichier paths.xml contenant :

<?xml version="1.0"?>
<yandex>
    <!-- Path to data directory, with trailing slash. -->
    <path>__DATA_DIR__/</path>
    <!-- Directory in <clickhouse-path> containing schema files for various input formats.
         The directory will be created if it doesn't exist.
      -->
    <format_schema_path>__DATA_DIR__/format_schemas/</format_schema_path>
    <!-- Path to temporary data for processing hard queries. -->
    <tmp_path>__DATA_DIR__/tmp/</tmp_path>
    <!-- Directory with user provided files that are accessible by 'file' table function. -->
    <user_files_path>__DATA_DIR__/user_files/</user_files_path>
</yandex>

NOTA : la configuration résultant de la fusion du fichier config.xml avec tous les fichiers du répertoire config.d se trouve dans /home/yunohost.app/clickhouse/preprocessed_configs/config.xml. Idem pour users.xml. C'est utile pour vérifier le résultat.

Répertoires des données

Nous voulons être capable de backuper ClickHouse avec la méthode de backup intégrée à YunoHost. Cette méthode backupe le contenu du répertoire de données ($data_dir). Nous devons donc mettre les données de ClickHouse dans ce répertoire.

Le répertoire des données de ClickHouse par défaut est /var/lib/clickhouse/. J'ai donc remplacé ce répertoire par __DATA_DIR__ partout où il était utilisé.

Certificats SSL

Pour que le port HTTPS (8443) et le port "secure" (9440) puissent fonctionner correctement, il faut fournir des certificats SSL dans la configuration de ClickHouse.

Générer un certificat n'est pas une solution car il serait auto-signé et posserait des problèmes.

L'idée est donc d'utiliser les certificats SSL de Let's Encrypt générés par YunoHost à l'installation du package ClickHouse. Ces certificats se trouvent dans le dossier /etc/yunohost/certs/__DOMAIN__/ et sont mis à jour automatiquement par YunoHost. Il y a deux fichiers : crt.pem et key.pem.

La configuration permettant à ClickHouse d'utiliser ces fichiers est donc :

<yandex>
    <openSSL>
        <server> 
            <certificateFile>/etc/yunohost/certs/__DOMAIN__/crt.pem</certificateFile>
            <privateKeyFile>/etc/yunohost/certs/__DOMAIN__/key.pem</privateKeyFile>
        </server>
    </openSSL>
</yandex>

Mais, par défaut, l'utilisateur clickhouse n'a pas l'accès à ce dossier. Je l'ai donc ajouté au groupe ssl-cert durant la procédure d'installation : usermod -a -G ssl-cert $app.

nginx

L'UI ClickHouse play utilise un Basic Auth pour envoyer les login et mot de passe vers l'API de ClickHouse. Cela entre en conflit avec l'authentification de ClickHouse qui utilise aussi le Basic Auth.

Donc, pour pouvoir utiliser le playground, il faut que l'URL soit accessible aux visitors. J'ai également supprimé l'ajout pour le SSO. Le fichier de configuration est donc :

location __PATH__/ {

  include proxy_params;
  proxy_pass http://127.0.0.1:__PORT__/;

}

Fichiers utilisateur avec le SFTP

ClickHouse met à disposition 3 répertoires où un utilisateur peut déposer des fichiers pour les utiliser ensuite depuis les requêtes à ClickHouse.

J'ai défini les 3 répertoires avec ce fichier de configuration :

<yandex>
    <user_files_path>__DATA_DIR__/user_files/</user_files_path>
    <user_defined_path>__DATA_DIR__/user_defined/</user_defined_path>
    <user_scripts_path>__DATA_DIR__/user_scripts/</user_scripts_path>
</yandex>

Pour que les utilisateurs puissent déposer des fichiers dans ces répertoires, nous voulons leur donner un accès SFTP. D'abord, nous devons donner le "droit SFTP" depuis YunoHost (par exemple : sudo yunohost user permission add sftp pbrisacier). L'utilisateur peut alors se connecter en SFTP avec ses login et mot de passe. La racine de ce qu'il voit correspond au répertoire /home de la machine.

Afin que tous les utilisateurs puissent déposer et/ou modifier les fichiers pour ClickHouse, nous voulons les rendre accessibles dans un répertoire partagé entre tous les utilisateurs.

La procédure d'install crée ce répertoire /home/shared, y crée un répertoire clickhouse et donne l'accès en lecture et écriture à tout le monde.

Enfin, la procédure d'install crée les 3 répertoires utilisateur puis les liens vers le dossier data de ClickHouse :

mkdir -p /home/shared/clickhouse/user_files
ln -s /home/shared/clickhouse/user_files $data_dir/user_files
mkdir -p /home/shared/clickhouse/user_defined
ln -s /home/shared/clickhouse/user_defined $data_dir/user_defined
mkdir -p /home/shared/clickhouse/user_scripts
ln -s /home/shared/clickhouse/user_scripts $data_dir/user_scripts

DEBUG / Mise au point

Commandes pour installer / désinstaller

Depuis le répertoire contenant le package YunoHost, installer avec :

sudo yunohost app install . --debug --force --no-remove-on-failure --args "domain=sentinel-api.towerify.io&path=/clickhouse&init_main_permission=visitors&admin=twr_admin&password=twr-admin"

Désinstaller avec :

sudo yunohost app remove clickhouse --purge

sudo -u twr_admin

Voir https://clickhouse.com/docs/en/guides/troubleshooting#start-clickhouse-server-in-interactive-mode

Pour simuler le démarrage du service ClickHouse depuis ma ligne de commande (en SSH avec l'utilisateur twr_admin), j'ai fait :

sudo -u clickhouse /usr/bin/clickhouse-server --config-file /etc/clickhouse-server/config.xml

NOTA : il faudra saisir le mot de passe de twr_admin

Pour que cela fonctionne, il faut aussi que twr_admin ait les droits sudo suffisants. Je les ai modifiés (sudo nano /etc/sudoers) pour ajouter :

# User privilege specification
twr_admin       ALL=(ALL:ALL) ALL

Utiliser ClickHouse

Voir https://clickhouse.com/docs/en/getting-started/quick-start#3-start-the-client

En local, depuis le SSH, je peux lancer clickhouse-client. Par défaut, il se connecte au ClickHouse Server sur localhost et le port 9000.

On obtient un prompt où on peut faire des requêtes SQL :

twr_admin@sentinel-api:~$ clickhouse-client 
ClickHouse client version 23.3.22.3 (official build).
Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 23.3.22 revision 54462.

Warnings:
 * Linux transparent hugepages are set to "always". Check /sys/kernel/mm/transparent_hugepage/enabled

sentinel-api.towerify.io :) 

Pour tester la connexion sur le port sécurisé (9440), utiliser la commande :

clickhouse-client --secure

TODOs

Memory settings

Créer /etc/security/limits.d/clickhouse.conf ?