LXC – Mais uma aplicação corporativa legacy salva.

Olá a todos,

Foi me colocado recentemente o desafio de migrar uma aplicação, existente num sistema extremamente velho (32bits) para um chassis novo mais moderno.

Tendo em conta que a aplicação estava totalmente falhada, e que não existia suporte da mesma, não havia muito para correr bem ou mal.

Todo o processo começou de uma forma bastante trivial com a tentativa de instalar um  sistema operativo suportado pelo chassis novo (só suportava 64bits).
Contudo, e após a instalação do SO, copia dos dados aplicacionais e instalando as bibliotecas a 32bits, a aplicação teimosamente recusava arrancar.

A minha primeira sugestão para o Cliente foi virtualizar a máquina existente para uma VM (um p2v tendo em conta que das poucas coisas que sobraram da máquina foi o controlador RAID e um dos discos do RAID1).

Infelizmente, o Cliente declinou esta  hipótese, pois iria colocar a máquina dele num ambiente partilhado, coisa que ele explicitamente queria evitar.

A minha segunda sugestão foi a conversão da máquina atual, para um LXC container mantendo por baixo todo a nova IFT nova e suportada. Foi este o caminho escolhido.

shutterstock_172537049

Em primeiro lugar, e após instalar uma instalação suportada de Linux na máquina física (RHEL 7.1 – 64bits) e configurada a componente de rede, chegou a altura de recuperar o  volume do raid, utilizando para tal uma máquina temporária.

Na pratica, a máquina arranca o sistema operativo (Linux) de um disco SATA local, e deixa os volumes do RAID idle.

Com o sistema temporário  em cima, ativei os antigos volume groups do RAID legacy e efetuei as copias do logical volumes que necessitava, utilizando para tal o dd_rescue, que é um pequeno aplicativo perfeito para recuperação de discos com IO errors (ou possíveis), para outros devices ou ficheiros:

# vgscan
# vgchange -ay vglegacy
# dd_rescue /dev/vglegacy/lvol0 /mnt/lvol0.img
# dd_rescue /dev/vglegacy/lvol1 /mnt/lvol1.img

Copiei em seguida os ficheiros gerados para a máquina final, e montei os mesmos como loop devices, de forma a eliminar alguns componentes que não interessavam para o arranque:

# mkdir /mnt/container0/rootfs
# mkdir /mnt/data1
# mount -o loop /mnt/lvol0.img /mnt/container0/rootfs
# mount -o loop /mnt/lvol1.img /mnt/data1

Nota: Para o caso especifico em mãos, foi necessário remover de dentro do /mnt/container0/rootfs/ os initscripts para UDEV, dentro da diretoria de init.d da máquina antiga, referencias a swap e configurações especificas de hardware que agora já não existiam. Lembrem-se igualmente que muito provavelmente os mac addresses das placas de rede irão igualmente mudar e que no caso de um LXC container, as placas de rede e endereçamentos são definidos exteriormente aos containers no ficheiro de configuração do mesmo.

Em seguida, foi necessário ainda criar dentro do container todos os devices necessários.

#target=/mnt/container0/rootfs
#mkdir -m 755 “$target”/dev
#mknod -m 600 “$target”/dev/console c 5 1
#mknod -m 600 “$target”/dev/initctl p
#mknod -m 666 “$target”/dev/full c 1 7
#mknod -m 666 “$target”/dev/null c 1 3
#mknod -m 666 “$target”/dev/ptmx c 5 2
#mknod -m 666 “$target”/dev/random c 1 8
#mknod -m 666 “$target”/dev/tty c 5 0
#mknod -m 666 “$target”/dev/tty0 c 4 0
#mknod -m 666 “$target”/dev/urandom c 1 9
#mknod -m 666 “$target”/dev/zero c 1 5

# mknod -m 666 /dev/tty1 c 4 1
# mknod -m 666 /dev/tty2 c 4 2

E atribuir permissões para acesso por consola:

echo “pts/0” >>/etc/securetty

#sed -i s/”session    required     pam_selinux.so close”/”#session    required     pam_selinux.so close”/g /etc/pam.d/login
#sed -i s/”session    required     pam_selinux.so open”/”#session    required     pam_selinux.so open”/g /etc/pam.d/login
#sed -i s/”session    required     pam_loginuid.so”/”#session    required     pam_loginuid.so”/g /etc/pam.d/login

Em seguida, e após registar o novo servidor (LXC Host) na RHN,  procedeu-se ao update do sistema operativo e à instalação dos pacotes do libvirt que gerem o LXC:

# yum -y update
# yum -y install xauth libvirt-daemon-driver-lxc  virt-manager urw-fonts

Após a instalação finalizar chegou a altura de ativar o novo container baseado nos dados recuperados da máquina antiga:

# virt-install –connect lxc:/// –name app01 –ram 3096 –vcpu 2   –arch i686 –filesystem /mnt/container0/rootfs,/ –noautoconsole

Após a configuração do container, foi necessário fornecer ao mesmo o volume que salvamos inicialmente com os dados aplicacionais. Isto foi conseguido fornecendo o mountpoint onde o loop device estava montado.
Foi igualmente adicionada uma placa de rede virtual de forma a garantir conectividade ao container.

Nota: Para estas configurações recomendo vivamente o virt-manager, pois permite graficamente a configuração, tanto da vethernet como de outros recursos necessários.

Como resultado final temos uma maquina chrooted de 32bits a funcionar em pleno dentro de um servidor a 64bits:

(no host):

# uname -a
Linux XXXXXX 3.10.0-229.el7.x86_64 #1 SMP Thu Jan 29 18:37:38 EST 2015 x86_64 x86_64 x86_64 GNU/Linux

(no guest):

# uname -a
LinuxXXXXXX 3.10.0-229.el7.x86_64 #1 SMP Thu Jan 29 18:37:38 EST 2015 i686 i686 i386 GNU/Linux

Com esta configuração, a aplicação já arrancou conforme desejado e está presentemente a funcionar sem problemas. Suspeito que algures no código da mesma, está uma função que deteta o tipo de arquitetura onde está a ser executada e bloqueia se não for a correta.

Como consideração final, lembro que esta solução é uma solução de recurso, não suportada, e que o ciclo de vida aplicacional tem de ser respeitado.

É importante igualmente lembrar que embora o LXC tenha sido o futuro, o standard para containers é agora o docker e em instalações futuras, a Red Hat irá retirar o suporte da gestão de componentes LXC desde o libvirt – ver esta nota.

Em breve farei uma adaptação deste post para gerar um docker container ao invés de um típico LXC, conseguindo ainda maior streamline do recurso – passamos a ter uma aplicação virtual  ao invés de um sistema virtual.

Se tiverem alguma duvida já sabem onde me encontrar.

Abraço
Nuno