Por: @vitorp
Publicado em: 2021-04-19
Gerenciamento completo do Cluster
Este laboratório tem como objetivo:
- Orientar nos ajustes, comandos e configurações de infra do Cluster para auxiliar no desenvolvimento do épico de Gerenciamento completo do Cluster.
Provisionamento
Precisamos adicionar ao provisionamento do servidor a instalação dos seguintes serviços: corosync, pcs, pacemaker
Setup do cluster
STEP 2
Criação Chaves SSH - Se necessário
As chaves SSH ficam armazenadas na pasta .ssh do usuário. No caso do cluster precisamos fazer troca de chave entre o root dos servidores.
Quando chegamos no step 2 do setup, é necessário consultar se já existe um par de chaves criado no root.
Validar se existem os arquivos: /root/.ssh/id_rsa
e /root/.ssh/id_rsa.pub
Se existirem, exibir o conteúdo do /root/.ssh/id_rsa.pub
em tela para poder ser copiado.
Caso não existam os arquivos, é necessário aparecer um botão para gerar o par de chaves. Eles podem ser gerados através do usuário root usando o comando:
ssh-keygen -b 2048 -t rsa -f /root/.ssh/id_rsa -q -N ""
Obs: A execução deste comando pode demorar
Troca de chaves SSH entre os nós
Como a chave SSH já está gerada nos dois nós e as chaves públicas foram informadas no step anterior, basta adicionar permissão de acesso.
Validar se existe e se não existir, criar arquivo: /root/.ssh/authorized_keys
Adicionar uma linha neste arquivo com a chave pública informada no step anterior.
Adicionar fingerprint
Por padrão, o primeiro acesso SSH ao outro host precisa validar o fingerprint, então executamos um ssh-keyscan para que isso não seja necessário:
ssh-keyscan -H $ip_node_primario >> ~/.ssh/known_hosts
ssh-keyscan -H $ip_node_secundario >> ~/.ssh/known_hosts
Permissão SSH
Os nós do cluster precisam de permissão para conectar via ssh entre eles. Atualmente como não há gerenciamento, fazemos este permissionamento via provisionamento. Vamos precisar alterar o formato de funcionamento pois simplifica e deixamos de depender do provisionamento.
Houveram atualizações recentes no formato de funcionamento: https://projetos.itflex.com.br/issues/45722
A ideia era utilizarmos includes no sshd_config, porém só está disponível na versão 8.2 do openssh-server: https://bugzilla.mindrot.org/show_bug.cgi?id=2468
Considerando pronto o que será feito no ticket #45722, podemos criar/atualizar o .json com as informações cadastradas em tela e rodar o “itflex-access-update” para ajustar as configurações do sshd_config.
Atualmente o “itflex-access-update” não chama a role “itflex-ssh-client”, então temos que incluir.
Também era ideal rodar este comando já no início das configurações do cluster e também retornar erro caso o comando dê erro (pode acontecer caso a máquina esteja sem internet).
Botão Teste
O teste para o outro host pode ser feito através do comando abaixo passando o IP do outro host.
Retorno OK = 0 Retorno FALHA = 255
ssh -q -o BatchMode=yes -o StrictHostKeyChecking=no -o ConnectTimeout=5 $IP_OUTRO_NODE 'exit 0'
STEP 3
Atualmente configuramos o cluster através do ansible: https://git.itflex.com.br/itflex/server-v2-ansible/-/blob/master/v3/cluster-v3/roles/cluster-new/tasks/main.yml
As funções do ansible deverão ser convertidas para um motor de setup da iTFlex.
O ansible é executado nos dois nós até certo ponto, a partir das configurações do pcs é executado somente em um node. Diferenciarmos a instalação de um nó primário e um nó secundário é importante para que possamos seguir esta mesma lógica.
No STEP3 o nó principal já tem acesso ao secundário e irá conectar nele para efetuar as configurações.
Configurando arquivo hosts
Deve adicionar as duas linhas ao /etc/hosts:
$ip_node_primario $nome_node_primario
$ip_node_secundario $nome_node_secundario
Deve ser executado nos dois nós.
Executando escaneamento de chaves
Por padrão, o primeiro acesso SSH ao outro host precisa validar o fingerprint, então executamos um ssh-keyscan para que isso não seja necessário:
ssh-keyscan -H $nome_node_primario,$ip_node_primario >> ~/.ssh/known_hosts
ssh-keyscan -H $nome_node_secundario,$ip_node_secundario >> ~/.ssh/known_hosts
Deve ser executado nos dois nós.
Alterando senha do usuário hacluster
Setar senha “semprelinux” ou senha mais forte padrão para o usuário hacluster.
Deve ser executado nos dois nós
Criando arquivos de configuração do cluster
Provisionar template do arquivo /etc/corosync/corosync.conf
:
# Please read the corosync.conf.5 manual page
totem {
version: 2
# Set name of the cluster
cluster_name: clusterflex
token: 10000
# crypto_cipher and crypto_hash: Used for mutual node authentication.
# If you choose to enable this, then do remember to create a shared
# secret with "corosync-keygen".
# enabling crypto_cipher, requires also enabling of crypto_hash.
# crypto works only with knet transport
crypto_cipher: none
crypto_hash: none
}
logging {
# Log the source file and line where messages are being
# generated. When in doubt, leave off. Potentially useful for
# debugging.
fileline: off
# Log to standard error. When in doubt, set to yes. Useful when
# running in the foreground (when invoking "corosync -f")
to_stderr: yes
# Log to a log file. When set to "no", the "logfile" option
# must not be set.
to_logfile: yes
logfile: /var/log/cluster/corosync.log
# Log to the system log daemon. When in doubt, set to yes.
to_syslog: yes
# Log debug messages (very verbose). When in doubt, leave off.
debug: off
# Log messages with time stamps. When in doubt, set to hires (or on)
#timestamp: hires
logger_subsys {
subsys: QUORUM
debug: off
}
}
quorum {
# Enable and configure quorum subsystem (default: off)
# see also corosync.conf.5 and votequorum.5
#provider: corosync_votequorum
}
nodelist {
# Change/uncomment/add node sections to match cluster configuration
node {
# Hostname of the node
name: {{ $nome_node_primario }}
# Cluster membership node identifier
nodeid: 1
# Address of first link
ring0_addr: {{ $ip_node_primario }}
# When knet transport is used it's possible to define up to 8 links
#ring1_addr: 192.168.1.1
}
node {
# Hostname of the node
name: {{ $nome_node_secundario }}
# Cluster membership node identifier
nodeid: 2
# Address of first link
ring0_addr: {{ $ip_node_secundario }}
# When knet transport is used it's possible to define up to 8 links
#ring1_addr: 192.168.1.2
}
# ...
}
Deve ser executado nos dois nós
Iniciando serviços do Cluster
Os serviços do cluster precisam estar rodando e na inicialização dos dois nós, são eles:
pcsd
corosync
Autenticando no serviço do cluster
Comando deve ser executado via shell SOMENTE no nó PRIMÁRIO:
echo -e "$senha_hacluster" | pcs cluster auth -u hacluster
Criando cluster
Comando deve ser executado via shell SOMENTE no nó PRIMÁRIO:
pcs cluster setup clusterflex $nome_node_primario $nome_node_secundario --force
Iniciando cluster
Comando deve ser executado via shell SOMENTE no nó PRIMÁRIO:
pcs cluster start --all
pcs cluster enable --all
Ajustando parâmetros padrões do Cluster
Comando deve ser executado via shell SOMENTE no nó PRIMÁRIO:
pcs property set stonith-enabled=false
pcs property set no-quorum-policy=ignore
pcs resource defaults resource-stickiness=100
pcs resource defaults failure-timeout=20
Adicionando IP Virtual ao Cluster
Comando deve ser executado via shell SOMENTE no nó PRIMÁRIO:
pcs resource create ClusterIP1 ocf:heartbeat:IPaddr2 ip={{ clu_ip }} cidr_netmask={{ clu_prefix }} iflabel=150 op monitor interval=30s
pcs resource group add clusterIP ClusterIP1
É necessário tratar o IP informado na interface web para separar o IP do Netmask e adicionar nos campos corretos.
Gerenciamento individual dos nós
Gerenciamento de recursos do Cluster
Serviços - Nomenclaturas
Hoje nós adicionamos serviços ao cluster utilizando o comando itflex-cluster resource add service 'openvpn-client@itflex'
. Neste caso é necessário sempre passar o nome completo do serviço no systemd e isso se torna confuso para o usuário em tela.
Por padrão somente alguns serviços precisam e podem ser adicionados ao cluster, são eles: DHCP (kea-dhcp4), DHCP - DDNS (kea-dhcp-ddns), OpenVPN Client - X (X é o nome do cliente cadastrado na interface, exemplo: itflex. Neste caso o serviço do systemd será openvpn-client@itflex).
Precisamos que os serviços que apareçam para selecionar sejam somente os informados. No caso do openvpn-client, aparecer uma opção para cada cliente que é cadastrado.
Ordenação dos resources no cluster
A ordenação das constraints através do “pcs” é complexa e não aplicavável para nosso produto.
Porém é possível exportar todas as informações do pacemaker para um .xml, reordenar e importar novamente.
A ferramente responsável por isso é o cibadmin.
Links da ferramenta: https://linux.die.net/man/8/cibadmin , https://clusterlabs.org/pacemaker/doc/en-US/Pacemaker/2.0/html/Pacemaker_Administration/s-cibadmin.html
A ordenação dos recursos é feita através da exportação de um .XML completo do pacemaker, alteração da seção “Resources” e importação.
- Exportar os dados do cluster:
cibadmin --query > /tmp/pcs.xml
- Manipular o XML e deletar todos os dados, deixando somente o conteúdo da seção resources. Ficará semelhante ao .xml das Constraints
- Identificar quais resources serão ordenados (VirtualIPs ou Services) e ordenar os recuursos dentro (< Primitive id="" >) Dentro de resources, nenhum dados pode ser apagado, somente movido de lugar.
- Aplicar XML novamente:
cibadmin --replace --xml-file /tmp/pcs.xml
Adicionar recursos ao cluster
Hoje já temos o itflex-cluster que adiciona recursos ao Cluster e há uma função que adiciona IP’s e outra que adiciona Serviços. Vamos utilizar a mesma lógica de adicionar recurso, porém remover o comando que adiciona uma constraint e acrescentar um comando que adiciona o resource à um grupo.
Adicionar Serviço
commands = [
["systemctl", "stop", service],
["systemctl", "disable", service],
[
"pcs",
"resource",
"create",
name,
"systemd:" + service,
"op",
"monitor",
"interval={}s".format(interval),
"meta",
"multiple-active=" + multiple_active,
],
[
"pcs",
"resource",
"group",
"add",
"Services",
name,
],
]
Adicionar IP Virtual
cmd_resource = [
"pcs",
"resource",
"create",
name,
"ocf:heartbeat:IPaddr2",
"ip=" + ip,
"cidr_netmask=" + netmask,
]
if interface:
cmd_resource.append("nic=" + interface)
cmd_resource.extend(
["op", "monitor", "interval={}s".format(interval)]
)
commands = [
cmd_resource,
[
"pcs",
"resource",
"group",
"add",
"VirtualIPs",
name,
],
]
Gerenciamento das configurações
Deletar o cluster
O cluster deve ser destruído no nó local.
- Apagar as duas linhas com os nomes do dos hosts do /etc/hosts
- Usar o IP dos nós (está no banco) para localizar linhas no /etc/hosts e deletar
- Apagar chave pública do outro node do authorized_keys
- Usar a chave (está no banco) para localizar linhas no /root/.ssh/authorized_keys
- Apagar arquivo de estado do nó secundário
- Apagar /tmp/cluster_config_step3.json
- Obs: O arquivo pode não existir
- Apagar informações de configuração do cluster do banco (Objetivo é deixar o servidor como se nunca tivesse alguma configuração)
- Deletar cluster:
pcs cluster destroy
Melhoria do status do cluster
Modo manutenção
Para colocar um nó do pcs em manutenção, pode utilizar o comando:
pcs node standby $node_name --wait
Para tirar de modo manutenção:
pcs node unstandby $node_name --wait
Recursos locais
O cluster em geral gerencia serviços que estão adicionados como recursos do pcs (Neste caso o pacemaker deixa o serviço ativo somente no nó ativo) e serviços do FWFLEX que o itflex-cluster sincroniza o status de um node pro outro, como SDWAN, firewall, DBC, Webfilter e instâncias OpenVPN. Neste caso, quando o serviço está enable no FW ativo o sync-cluster irá deixá-lo enable e ativo no FW02.
A ideia é que a tela mostre o status do serviço nos dois nós. Assim teremos certeza que os serviços estão ativos e com status OK no nó inativo. Neste caso a consulta do systemd pode trazer lentidão, então o ideal seria validar um formato onde não interfira no desempenho da tela.
Melhorias sync-cluster
Logs do sync-cluster
Atualmente quando realizamos o sync-cluster não temos logs nem o status da execução. Quando há algum problema, a task na interface conclui como OK e não temos como saber se está correto.
Precisamos ajustar o status para saber se foi possível conectar no outro nó, sincronizar todos os dados e manipular os serviços corretamente.
Além disso é importante guardar um log da sincronização (Pode ser importante em eventual debug posterior) e habilitar rotate destes logs. Esta pasta onde estarão os logs pode ser adicionada para ser exibida em “Arquivos de logs”.
Ao final do script poderia ser inserida a informação do status do sync e também o horário em banco para consulta.