Provisionamento Bare-Metal DIY ou Preparação Automática de Servidores do Zero

Olá, eu sou Denis e uma das minhas áreas de atuação é o desenvolvimento de soluções de infraestrutura na X5. Hoje, gostaria de compartilhar com você como é possível implementar um sistema automático de preparação de servidores utilizando ferramentas de acesso público. Na minha opinião, é uma solução interessante, simples e flexível.

Provisionamento Bare-Metal DIY ou Preparação Automática de Servidores do Zero

Preparação significa: transformar um novo servidor 'de caixa' em um servidor totalmente configurado com o sistema operacional Linux ou com o hypervisor ESXi (instalação servidores Windows não será discutido neste artigo).

Termos:

  • servidores – servidores que precisam ser configurados.
  • servidor de instalação – o servidor principal que fornece todo o processo de preparação pela rede.

Por que a automação é necessária?

Suponha que a tarefa seja: preparar servidores em massa desde o início, em pico – 30 por dia. Servidores de diversos fabricantes e modelos, que podem ter diferentes sistemas operacionais instalados, podendo ou não ter o hypervisor.

Quais operações fazem parte do processo de configuração (sem automação):

  • conectar teclado, mouse e monitor ao servidor;
  • configurar BIOS, RAID, IPMI;
  • atualizar o firmware dos componentes;
  • implantar a imagem do sistema de arquivos (ou instalar o hypervisor e copiar máquinas virtuais);

Nota. Como alternativa, a implantação do SO pode ser feita através da instalação com um arquivo de resposta automática. Mas isso não será abordado no artigo. Embora abaixo você verá que adicionar essa funcionalidade não é complicado.

  • configurar as opções do SO (hostname, IP, etc.).

Com essa abordagem, as mesmas configurações são realizadas sequencialmente em cada servidor. A eficiência desse trabalho é muito baixa.

A essência da automação é excluir a participação humana do processo de preparação do servidor. Maximamente, na medida do possível.

Graças à automação, o tempo de inatividade entre operações é reduzido e é possível preparar vários servidores simultaneamente. A probabilidade de erros devido ao fator humano também diminui muito.

Provisionamento Bare-Metal DIY ou Preparação Automática de Servidores do Zero

Como ocorre a configuração automática de servidores?

Vamos analisar todas as etapas com detalhes.

Você tem um servidor Linux que utiliza como servidor de instalação PXE. Nele, estão instalados e configurados os serviços: DHCP, TFTP.

Então, fazemos o boot do servidor (que precisa ser configurado) via PXE. Vamos lembrar como isso funciona:

  • No servidor, a opção de boot pela rede foi selecionada.
  • O servidor carrega o PXE-ROM da placa de rede e se conecta ao servidor de instalação via DHCP para obter um endereço de rede.
  • O servidor de instalação DHCP fornece o endereço, assim como instruções para o carregamento posterior via PXE.
  • O servidor carrega o carregador de rede do servidor de instalação via PXE, e o carregamento subsequente acontece de acordo com o arquivo de configuração PXE.
  • O carregamento ocorre com base nos parâmetros recebidos (núcleo, initramfs, pontos de montagem, imagem squashfs e outros).

Nota. Este artigo descreve o carregamento via PXE em modo BIOS. Atualmente, os fabricantes estão implementando ativamente o modo de inicialização UEFI. Para PXE, a diferença estará na configuração do servidor DHCP e na presença de um carregador adicional.

Vamos considerar um exemplo de configuração do servidor PXE (menu pxelinux).

Arquivo pxelinux.cfg/default:

default menu.c32
prompt 0
timeout 100
menu title X5 PXE Boot Menu
LABEL InstallServer Menu
	MENU LABEL InstallServer
	KERNEL menu.c32
	APPEND pxelinux.cfg/installserver
LABEL VMware Menu
	MENU LABEL VMware ESXi Install
	KERNEL menu.c32
	APPEND pxelinux.cfg/vmware
LABEL toolkit // menu padrão
	MENU LABEL Linux Scripting Toolkits
	MENU default
	KERNEL menu.c32
	APPEND pxelinux.cfg/toolkit // transição para o próximo menu

Arquivo pxelinux.cfg/toolkit:

prompt 0
timeout 100
menu title X5 PXE Boot Menu
label mainmenu
    menu label ^Retornar ao Menu Principal
    kernel menu.c32
    append pxelinux.cfg/default
label x5toolkit-auto // padrão - modo automático
        menu label x5 toolkit autoinstall
        menu default
        kernel toolkit/tkcustom-kernel
        append initrd=toolkit/tk-initramfs.gz quiet net.ifnames=0 biosdevname=0 nfs_toolkit_ip=192.168.200.1 nfs_toolkit_path=tftpboot/toolkit nfs_toolkit_script=scripts/mount.sh script_cmd=master-install.sh CMDIS2="..."
label x5toolkit-shell // para depuração - console
        menu label x5 toolkit shell
        kernel toolkit/tkcustom-kernel
        append initrd=toolkit/tkcustom-initramfs.gz quiet net.ifnames=0 biosdevname=0 nfs_toolkit_ip=192.168.200.1 nfs_toolkit_path=tftpboot/toolkit nfs_toolkit_script=scripts/mount.sh script_cmd=/bin/bash CMDIS2="..."

O núcleo e o initramfs neste estágio são uma imagem linux intermediária, por meio da qual ocorrerá a principal preparação e configuração do servidor.

Como você pode ver, o carregador transmite muitos parâmetros ao núcleo. Parte desses parâmetros é utilizada pelo próprio núcleo. E alguns podemos usar para nossos objetivos. Isso será abordado a seguir, mas, por enquanto, pode-se lembrar que todos os parâmetros transmitidos estarão disponíveis na imagem linux intermediária através de /proc/cmdline.

De onde obtê-los, núcleo e initramfs?
Podemos escolher qualquer distribuição linux como base. O que devemos observar ao escolher:

  • a imagem de inicialização deve ser universal (presença de drivers, capacidades de instalação de utilitários adicionais);
  • provavelmente, será necessário personalizar o initramfs.

Como isso é feito na nossa solução para o X5? Tomamos como base o CentOS 7. Vamos fazer o seguinte truque: prepararemos a futura estrutura da imagem, a empacotaremos em um arquivo e criaremos o initramfs, dentro do qual estará o nosso arquivo de sistema. Ao iniciar a imagem, o arquivo será descompactado na partição tmpfs criada. Assim, teremos uma imagem live do linux minimalista, mas completa, com todas as utilidades necessárias, consistindo apenas de dois arquivos: vmkernel e initramfs.

#создаем директории: 

mkdir -p /tftpboot/toolkit/CustomTK/rootfs /tftpboot/toolkit/CustomTK/initramfs/bin

#подготавливаем структуру:

yum groups -y install "Minimal Install" --installroot=/tftpboot/toolkit/CustomTK/rootfs/
yum -y install nfs-utils mariadb ntpdate mtools syslinux mdadm tbb libgomp efibootmgr dosfstools net-tools pciutils openssl make ipmitool OpenIPMI-modalias rng-tools --installroot=/tftpboot/toolkit/CustomTK/rootfs/
yum -y remove biosdevname --installroot=/tftpboot/toolkit/CustomTK/rootfs/

# подготавливаем initramfs:

wget https://busybox.net/downloads/binaries/1.31.0-defconfig-multiarch-musl/busybox-x86_64 -O /tftpboot/toolkit/CustomTK/initramfs/bin/busybox
chmod a+x /tftpboot/toolkit/CustomTK/initramfs/bin/busybox
cp /tftpboot/toolkit/CustomTK/rootfs/boot/vmlinuz-3.10.0-957.el7.x86_64 /tftpboot/toolkit/tkcustom-kernel

# создаем /tftpboot/toolkit/CustomTK/initramfs/init (ниже содержание скрипта):

#!/bin/busybox sh
/bin/busybox --install /bin
mkdir -p /dev /proc /sys /var/run /newroot
mount -t proc proc /proc
mount -o mode=0755 -t devtmpfs devtmpfs /dev
mkdir -p /dev/pts /dev/shm /dev/mapper /dev/vc
mount -t devpts -o gid=5,mode=620 devpts /dev/pts
mount -t sysfs sysfs /sys
mount -t tmpfs -o size=4000m tmpfs /newroot
echo -n "Extracting rootfs... "
xz -d -c -f rootfs.tar.xz | tar -x -f - -C /newroot
echo "done"
mkdir -p /newroot/dev /newroot/proc /newroot/sys
mount --move /sys  /newroot/sys
mount --move /proc /newroot/proc
mount --move /dev  /newroot/dev
exec switch_root /newroot /sbin/init

# упаковываем rootfs и initramfs:

cd /tftpboot/toolkit/CustomTK/rootfs
tar cJf /tftpboot/toolkit/CustomTK/initramfs/rootfs.tar.xz --exclude ./proc --exclude ./sys --exclude ./dev .
cd /tftpboot/toolkit/CustomTK/initramfs
find . -print0 | cpio --null -ov --format=newc | gzip -9 > /tftpboot/toolkit/tkcustom-initramfs-new.gz

Então, definimos o kernel e o initramfs que devem ser carregados. Como resultado, nesta etapa, ao carregar a imagem intermediária do linux via PXE, obteremos o console do SO.

Ótimo, mas agora precisamos transferir o controle para a nossa 'automatização'.

Isso pode ser feito assim.

Suponha que, após carregar a imagem, planejamos transferir o controle para o script mount.sh.
Vamos incluir o script mount.sh no início automático. Para isso, será necessário modificar o initramfs:

  • descompactar o initramfs (se estivermos usando a versão de initramfs acima, isso não é necessário)
  • incluir na inicialização o código que analisará os parâmetros passados através de /proc/cmdline e transferirá o controle adiante;
  • empacotar o initramfs.

Nota: No caso do toolkit X5, o controle de inicialização é transferido para o script /opt/x5/toolkit/bin/hook.sh с помощью override.conf в getty tty1 (ExecStart=…)

Então, a imagem é carregada, na qual o script mount.sh inicia na inicialização automática. Em seguida, o script mount.sh analisa os parâmetros passados (script_cmd=) e executa o programa/script necessário.

rótulo toolkit-auto
kernel …
anexar … nfs_toolkit_script=scripts/mount.sh script_cmd=master-install.sh

rótulo toolkit-shell
kernel …
anexar … nfs_toolkit_script=scripts/mount.sh script_cmd=/bin/bash

Provisionamento Bare-Metal DIY ou Preparação Automática de Servidores do Zero

Aqui à esquerda está o menu PXE, à direita – o esquema de transferência de controle.

Com a transferência de controle, estamos esclarecidos. Dependendo da escolha do menu PXE, inicia-se ou o script de auto-configuração ou o console para depuração.

Em caso de auto-configuração, os diretórios necessários do servidor de instalação são montados, contendo:

  • scripts;
  • templates BIOS/UEFI salvos de vários servidores;
  • firmwares;
  • utilitários para servidores;
  • logs.

Em seguida, o script mount.sh transfere o controle para o script master-install.sh do diretório com os scripts.

A árvore de scripts (ordem de execução) parece aproximadamente assim:

  • master-install
  • sharefunctions (funções comuns)
  • info (exibição de informações)
  • models (definição de parâmetros de instalação com base no modelo do servidor)
  • prepare_utils (instalação de utilitários necessários)
  • fwupdate (atualização de firmware)
  • diag (diagnóstico básico)
  • biosconf (configuração do BIOS/UEFI)
  • clockfix (ajuste de tempo na placa-mãe)
  • srmconf (configuração da interface remota)
  • raidconf (configuração de volumes lógicos)

um dos:

  • preinstall (transferência de controle para o instalador do SO ou hipervisor, por exemplo, ESXi)
  • merged-install (início direto da extração da imagem)

Agora sabemos:

  • como inicializar o servidor pelo PXE;
  • como transferir o controle para o nosso próprio script.


Vamos continuar. Surgiram as seguintes questões:

  • Como identificar o servidor que estamos preparando?
  • Quais utilitários utilizar e como configurar o servidor?
  • Como obter configurações para um servidor específico?

Como identificar o servidor que estamos preparando?

É simples – DMI:

dmidecode –s system-product-name
dmidecode –s system-manufacturer
dmidecode –s system-serial-number

Aqui estão todas as informações necessárias: fornecedor, modelo, número de série. Se você não tiver certeza de que essas informações estão disponíveis em todos os servidores, você pode identificá-los pelo endereço MAC. Ou utilizar ambos os métodos ao mesmo tempo, se os fornecedores dos servidores forem diferentes e em alguns modelos as informações do número de série simplesmente não estiverem disponíveis.

Com base nas informações obtidas, são montadas pastas de rede a partir do servidor de instalação e todos os necessários (utilitários, firmwares etc.) são carregados.

Quais utilitários utilizar e como configurar o servidor?

Aqui estão utilitários para Linux de alguns fabricantes. Todos os utilitários estão disponíveis nos sites oficiais dos fornecedores.

Provisionamento Bare-Metal DIY ou Preparação Automática de Servidores do Zero

Com os firmwares, acredito que tudo está claro. Normalmente, eles são fornecidos na forma de arquivos executáveis compactados. O arquivo executável controla o processo de atualização do firmware e informa o código de retorno.

BIOS e IPMI geralmente são configurados por meio de modelos. Se necessário, o modelo pode ser editado antes da inicialização.

Os utilitários RAID de alguns fornecedores também podem ser configurados por modelo. Se não for o caso, será necessário escrever um script de configuração.

A sequência de configuração do RAID é frequentemente a seguinte:

  • Solicitamos a configuração atual.
  • Se já houver arrays lógicos – apagamos.
  • Verificamos quais discos físicos estão presentes e quantos são.
  • Criamos um novo array lógico. Interrompemos o processo em caso de erro.

Como obter configurações para um servidor específico?

Suponhamos que as configurações de todos os servidores serão armazenadas no servidor de instalação. Nesse caso, para responder à nossa pergunta, é preciso primeiro decidir: como transferir as configurações para o servidor de instalação.

No início, é perfeitamente possível usar arquivos de texto. (No futuro, um arquivo de texto pode ser utilizado como um meio de backup para transmitir configurações).

É possível 'compartilhar' um arquivo de texto no servidor de instalação. E adicionar sua montagem no script mount.sh.

As linhas terão, por exemplo, o seguinte formato:

Essas linhas serão transmitidas em um arquivo pelo engenheiro a partir de sua máquina de trabalho. E, em seguida, durante a configuração do servidor, os parâmetros para o servidor específico serão lidos do arquivo.

Mas, a longo prazo, é melhor envolver um banco de dados para armazenar configurações, estados e logs de instalações de servidores.

Claro, não basta um banco de dados, e será necessário criar uma parte cliente, através da qual as configurações serão enviadas para o banco. Implementar isso é mais complicado em comparação com um arquivo de texto, mas, na verdade, não é tão difícil quanto parece. A versão mínima do cliente, que apenas transmitirá dados para o banco, pode ser facilmente escrita por você mesmo. E a melhoria do programa cliente pode ser feita mais tarde de forma livre (relatórios, impressão de etiquetas, envio de notificações e mais, o que ocorrer à mente).

Fazendo uma solicitação específica ao banco e informando o número de série do servidor, obteremos os parâmetros necessários para a configuração do servidor.

Além disso, não precisaremos inventar bloqueios para acesso simultâneo, como no caso de um arquivo de texto.

Podemos registrar o log de configuração em todas as etapas no banco e controlar o processo de instalação através de eventos e flags das etapas de preparação.

Agora sabemos como:

  • carregar o servidor via PXE;
  • transmitir o controle para o nosso script;
  • identificar o servidor que precisa ser preparado pelo número de série;
  • configurar o servidor com as utilidades apropriadas;
  • transmitir as configurações para o banco de dados do servidor de instalação através da parte cliente.

Descobrimos como:

  • o servidor a ser instalado recebe as configurações necessárias do banco de dados;
  • todo o progresso da preparação é registrado no banco de dados (logs, eventos, flags das etapas).

E quanto aos diferentes tipos de software a ser instalado? Como instalar um hypervisor, copiar uma VM e configurar tudo isso?

No caso de implantação de uma imagem de sistema de arquivos (linux) no hardware, tudo é bastante simples:

  • Após configurar todos os componentes do servidor, implantamos a imagem.
  • Instalamos o carregador grub.
  • Fazemos chroot e configuramos tudo o que é necessário.

Como passar o controle para o instalador do sistema operacional (exemplo ESXi).

  • Organizamos a transferência de controle do nosso script para o instalador do hypervisor através do arquivo de resposta automática (kickstart):
  • Removemos as partições atuais do disco.
  • Criamos uma partição de 500MB.
  • Marcamos-a como inicializável.
  • Formatamos em FAT32.
  • Copiamos os arquivos de instalação do ESXi para a raiz dela.
  • Instalamos o syslinux.
  • Copiamos syslinux.cfg para /syslinux/

default esxi
prompt 1
timeout 50
label esxi
kernel mboot.c32
append -c boot.cfg

  • Copiamos mboot.c32 para /syslinux.
  • Em boot.cfg deve constar kernelopt=ks=ftp:///ks_esxi.cfg
  • Reiniciamos o servidor.

Após reiniciar o servidor a partir de seu disco rígido, o instalador do ESXi será carregado. Todos os arquivos necessários do instalador serão carregados na memória e, em seguida, a instalação do ESXi começará, de acordo com o arquivo de resposta automática indicado.

Cito aqui algumas linhas do arquivo de resposta automática ks_esxi.cfg:

%firstboot --interpreter=busybox
…
# obtém o número de série

SYSSN=$(esxcli hardware platform get | grep Serial | awk -F " " '{print $3}')

# obtém o IP

IPADDRT=$(esxcli network ip interface ipv4 get | grep vmk0 | awk -F " " '{print $2}')
LAST_OCTET=$(echo $IPADDRT | awk -F'.' '{print $4}')

# conecta ao servidor de instalação NFS

esxcli storage nfs add -H is -s /srv/nfs_share -v nfsshare1

# copia as configurações temporárias do ssh, para uso do cliente ssh

mv /etc/ssh /etc/ssh.tmp
cp -R /vmfs/volumes/nfsshare1/ssh /etc/
chmod go-r /etc/ssh/ssh_host_rsa_key

# copia o ovftool, para o provisionamento da VM agora, além de talvez ser útil depois

cp -R /vmfs/volumes/nfsshare1/ovftool /vmfs/volumes/datastore1/

# provisiona a VM

/vmfs/volumes/datastore1/ovftool/tools/ovftool --acceptAllEulas --noSSLVerify --datastore=datastore1 --name=VM1 /vmfs/volumes/nfsshare1/VM_T/VM1.ova vi://root:esxi_password@127.0.0.1
/vmfs/volumes/datastore1/ovftool/tools/ovftool --acceptAllEulas --noSSLVerify --datastore=datastore1 --name=VM2 /vmfs/volumes/nfsshare1/VM_T/VM2.ova vi://root:esxi_password@127.0.0.1

# obtém a linha com as configurações do nosso servidor

ssh root@is "mysql -h'192.168.0.1' -D'servers' -u'user' -p'secretpassword' -e "SELECT ... WHERE servers.serial='$SYSSN'"" | grep -v ^$ | sed 's/NULL//g' > /tmp/servers
...
# gera o script de configuração de rede

echo '#!/bin/sh' > /vmfs/volumes/datastore1/netconf.sh
echo "esxcli network ip interface ipv4 set -i=vmk0 -t=static --ipv4=$IPADDR --netmask=$S_SUB || exit 1" >> /vmfs/volumes/datastore1/netconf.sh
echo "esxcli network ip route ipv4 add -g=$S_GW -n=default || exit 1" >> /vmfs/volumes/datastore1/netconf.sh
chmod a+x /vmfs/volumes/datastore1/netconf.sh

# define o parâmetro guestinfo.esxihost.id, especificando o número de série

echo "guestinfo.esxihost.id = "$SYSSN"" >> /vmfs/volumes/datastore1/VM1/VM1.vmx
echo "guestinfo.esxihost.id = "$SYSSN"" >> /vmfs/volumes/datastore1/VM2/VM2.vmx
...
# atualiza as informações no banco de dados

SYSNAME=$(esxcli hardware platform get | grep Product | sed 's/Product Name://;s/^ *//')
UUID=$(vim-cmd hostsvc/hostsummary | grep uuid | sed 's/ //g;s/,$//;s/^uuid="//;s/"$//')
ssh root@is "mysql -D'servers' -u'user' -p'secretpassword' -e "UPDATE servers ... SET ... WHERE servers.serial='$SYSSN'""
ssh root@is "mysql -D'servers' -u'user' -p'secretpassword' -e "INSERT INTO events ...""

# restaura as configurações do SSH

rm -rf /etc/ssh
mv /etc/ssh.tmp /etc/ssh

# configura a rede e reinicia

esxcli system hostname set --fqdn=esx-${G_NICK}.x5.ru
/vmfs/volumes/datastore1/netconf.sh
reboot

Neste estágio, o hipervisor foi instalado e configurado, e as máquinas virtuais foram copiadas.

Como agora configurar as máquinas virtuais?

Fizemos um pequeno truque: durante a instalação, definimos o parâmetro guestinfo.esxihost.id = "$SYSSN" no arquivo VM1.vmx, especificando o número de série do servidor físico.

Agora, após a inicialização, a máquina virtual (com o pacote vmware-tools instalado) pode acessar esse parâmetro:

ESXI_SN=$(vmtoolsd --cmd "info-get guestinfo.esxihost.id")

Ou seja, a VM conseguirá se identificar (ela conhece o número de série do host físico), fazer uma solicitação ao banco de dados do servidor de instalação e obter os parâmetros que precisam ser configurados. Tudo isso é organizado em um script que deve ser acionado automaticamente ao iniciar a guestos vm (mas apenas uma vez: RunOnce).

Agora sabemos como:

  • carregar o servidor via PXE;
  • transmitir o controle para o nosso script;
  • identificar o servidor que precisa ser preparado pelo número de série;
  • configurar o servidor com as ferramentas apropriadas;
  • transmitir as configurações para o banco de dados do servidor de instalação por meio da parte cliente;
  • configurar diferentes tipos de software, incluindo a implantação do hipervisor ESXi e a configuração de máquinas virtuais (tudo automaticamente).

Descobrimos como:

  • o servidor a ser instalado recebe as configurações necessárias do banco de dados;
  • todo o progresso da preparação é registrado no banco de dados (logs, eventos, flags das etapas).


Resultado:

Acredito que a singularidade desta solução está na flexibilidade, simplicidade, suas capacidades e versatilidade.

Por favor, escreva nos comentários o que você pensa.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster