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.