Olá a todos,
Hoje o post é mais técnico – já tinha saudades – e vamos abordar a configuração que teremos de fazer para configurar um redis em cluster (non-sentinel) para dar serviço a duas instancias de nextcloud.
Qual a necessidade? Bem, como certamente já devem saber, o nextcloud beneficia grandemente de sistemas de cache de objectos em memória como o memcached e/ou o redis.
Devido ao desenho multi-tier da minha arquitetura, sempre usei duas instancias em docker de memcached. Contudo, ambas as instancias não falavam uma com a outra – memcached por defeito não é clustered / replicated e existem problemas de segurança com a ultima versão clustered que existe e que aparentemente foi abandonada (recordam-se deste post?).
Embora o nextcloud consiga gerir isto em termos aplicacionais, em caso de falha ou restart de ambas as instancias de memcached (nem precisavam de ser ao mesmo tempo, bastava ambas ficarem limpas), o nextcloud iria perder todas as keys de autenticação obrigado a gerar novas passwords aplicacionais únicas quando os utilizadores com OTP se voltassem a ligar a esta instancia.
Pode não parecer nada de absurdo, até se pensarem que todos nós temos 3 ou 4 dispositivos digitais moveis e fixos.
Imaginem ter que trocar a password das vossas contas de caldav, carddav, etc em todas sempre que tivessem que re-inicar as plataformas de memcached – por exemplo para patching.
Fiz experiencias, e notei que as keys em redis, como são replicadas em cluster, não sofriam deste problema. Basta não ter que parar tudo ao mesmo tempo, pois os serviços após reiniciarem, irão buscar novamente aos irmãos de cluster as keys perdidas em reboot.
A somar a isto, um cluster de redis é algo que dá sempre jeito e o mesmo cluster pode ser usado para várias aplicações que dele necessitem, desde que tenham o cuidado de separar as DB’s de keys em si.
Em termos de mão na massa, a coisa é relativamente simples:
3 servers/lxc container em rockylinux 8.X 64bits x86_64 com 4GB de RAM. Atenção: Rockylinux e não Centos. IBM .|.
Nos hosts dos lxc containers colocar caso não estejam já carregados:
# redis cluster stuff # echo never > /sys/kernel/mm/transparent_hugepage/enabled sysctl -w net.core.somaxconn=65535 sysctl -w vm.overcommit_memory=1
Em seguida, dentro dos containers, instalar normalmente o Redis, e configurar desta forma em todos os nós:
sudo mkdir -p /etc/redis/cluster sudo mkdir /etc/redis/cluster/7000 sudo mkdir /var/lib/redis/7000 sudo mkdir /etc/redis/cluster/7001 sudo mkdir /var/lib/redis/7001
Em seguida, criar dois ficheiros de configuração com o vosso editor de texto favorito:
/etc/redis/cluster/7000/redis_7000.conf
port 7000 dir /var/lib/redis/7000/ appendonly no protected-mode no cluster-enabled yes cluster-node-timeout 5000 cluster-config-file /etc/redis/cluster/7000/nodes_7000.conf pidfile /var/run/redis/redis_7000.pid logfile /var/log/redis/redis_7000.log loglevel notice requirepass [PASSWORDKEY] masterauth [PASSWORDKEY]
/etc/redis/cluster/7001/redis_7001.conf
port 7001 dir /var/lib/redis/7001/ appendonly no protected-mode no cluster-enabled yes cluster-node-timeout 5000 cluster-config-file /etc/redis/cluster/7001/nodes_7001.conf pidfile /var/run/redis/redis_7001.pid logfile /var/log/redis/redis_7001.log loglevel notice requirepass [PASSWORDKEY] masterauth [PASSWORDKEY
Em seguida, criar os systemd files para gerir as instancias:
/etc/systemd/system/redis_7000.service
[Unit] Description=Redis key-value database on 7000 After=network.target [Service] ExecStart=/usr/bin/redis-server /etc/redis/cluster/7000/redis_7000.conf --supervised systemd ExecStop=/bin/redis-cli -h 127.0.0.1 -p 7000 shutdown Type=notify User=redis Group=redis RuntimeDirectory=redis RuntimeDirectoryMode=0755 LimitNOFILE=65535 [Install] WantedBy=multi-user.target
/etc/systemd/system/redis_7000.service
[Unit] Description=Redis key-value database on 7001 After=network.target [Service] ExecStart=/usr/bin/redis-server /etc/redis/cluster/7001/redis_7001.conf --supervised systemd ExecStop=/bin/redis-cli -h 127.0.0.1 -p 7001 shutdown Type=notify User=redis Group=redis RuntimeDirectory=/etc/redis/cluster/7001 RuntimeDirectoryMode=0755 LimitNOFILE=65535 [Install] WantedBy=multi-user.target
Em seguida, alterar permissões de diretorias, e fazer enable dos serviços de redis, dois por máquina:
sudo systemctl enable /etc/systemd/system/redis_7000.service sudo systemctl enable /etc/systemd/system/redis_7001.service sudo chown redis:redis -R /var/lib/redis sudo chmod 770 -R /var/lib/redis sudo chown redis:redis -R /etc/redis
Em seguida, replicar estas configurações e passos pelos três containers e fazer reboot aos mesmos.
Após o reboot e assumindo que todas as instancias de redis vieram acima sem problemas – podem as verificar pelos logs das mesmas conforme descritos nas configuracoes acima – chegou a altura de criar o nosso cluster através de um comando muito simples:
redis-cli --cluster create 172.16.0.44:7000 172.16.0.45:7000 172.16.0.46:7000 172.16.0.44:7001 172.16.0.45:7001 172.16.0.46:7001 --cluster-replicas 1 -a [PASSWORDKEY]
No meu caso em especifico, os três lxc-containers são o 172.16.0.44–>172.16.0.46 e as portas as 7000 e 7001, sendo a 7000 a master, e a 7001 a replica.
Respondam as questões, aguardem, e ele deverá vos devolver o prompt de sistema.
Para validarem se a vossa configuração está correta, será questão de se ligarem ao vosso redis cluster. Para o meu exemplo temos:
redis-cli -c -h 172.16.0.44 -p 7000 -a [PASSWORDKEY] 127.0.0.1:7000> CLUSTER INFO cluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:6 cluster_size:3 cluster_current_epoch:6 cluster_my_epoch:1 cluster_stats_messages_ping_sent:9912 cluster_stats_messages_pong_sent:9899 cluster_stats_messages_sent:19811 cluster_stats_messages_ping_received:9894 cluster_stats_messages_pong_received:9912 cluster_stats_messages_meet_received:5 cluster_stats_messages_received:19811 127.0.0.1:7000> CLUSTER NODES d9b6be8d6071cbfa1272a7ac0c54c448aa7d0e80 172.16.0.44:7000@17000 myself,master - 0 1694696438000 1 connected 0-5460 3159e9abe5bba803583dd5718189349350520a9d 172.16.0.45:7000@17000 master - 0 1694696440000 2 connected 5461-10922 9b95046fbe27c3264e64c9eb56f7ccfb2310a18a 172.16.0.46:7000@17000 master - 0 1694696439344 3 connected 10923-16383 4838802c8a3878f8183f06c1f41abdbed501a1be 172.16.0.45:7001@17001 slave 9b95046fbe27c3264e64c9eb56f7ccfb2310a18a 0 1694696440550 5 connected c366cdc3661922e5fb1f1bd3de40c739a694993b 172.16.0.44:7001@17001 slave 3159e9abe5bba803583dd5718189349350520a9d 0 1694696440350 4 connected ceb787c0de685b7714250953bcc2b3c51e6052f0 172.16.0.46:7001@17001 slave d9b6be8d6071cbfa1272a7ac0c54c448aa7d0e80 0 1694696440550 6 connected 127.0.0.1:7000>
Agora que já temos o nosso cluster em funcionamento será apenas uma questão de adicionarem a configuração ao vosso nextcloud, ficheiro config.php, depois de adicionarem o vosso modulo php8-redis. No meu caso tive de o instalar com o pecl – pecl install redis.
A configuração, no meu caso ficou algo assim:
'memcache.local' => '\\OC\\Memcache\\Redis', 'memcache.locking' => '\\OC\\Memcache\\Redis', 'memcache.distributed' => '\\OC\\Memcache\\Redis', 'redis.cluster' => [ 'seeds' => [ '172.16.0.44:7000', '172.16.0.45:7000', '172.16.0.46:7000', ], 'timeout' => 2.0, 'read_timeout' => 2.0, 'failover_mode' => \RedisCluster::FAILOVER_ERROR, 'password' => '[PASSWORDKEY]', 'dbindex' => XXX, // colocar um indice diferente para cada instancia que esteja a partilhar o redis.
],
E pronto, assumindo que nada correu mal, passaram a ter um nextcloud com suporte de OTP, com passwords aplicacionais perssistentes através dos vossos equipamentos, mesmo quando tiverem de fazer um reboot aos vossos servidores (desde que seja feito um de cada vez).
Se tiverem alguma duvida ou reparo, já sabem onde me encontrar.
Um abraço e até para a semana.
Nuno
PS: a configuração do cluster de redis, foi derivada de uma que a outsystems tem muito completa e muito bem feita que pode ser consultada aqui.