Se recomienda realizar una previa lectura del post Instalación y configuración del escenario OpenStack, pues en este artículo se tratarán con menor profundidad u obviarán algunos aspectos vistos con anterioridad.

El objetivo de ésta tarea es el de continuar con la configuración del escenario de trabajo previamente generado en OpenStack, concretamente, llevando a cabo una actualización de la máquina Quijote, una máquina totalmente limpia (en cuanto a servicios instalados se refiere) que tiene actualmente instalado un CentOS 7, una versión bastante antigua de la distribución, así que pasaremos a la versión más reciente, CentOS 8.

Antes de proceder, me gustaría dejar claro que la serie de instrucciones a ejecutar que mencionaré están basadas en mi experiencia personal, y no tienen por qué ser iguales para otra máquina, ya que entran en juego varios factores. Aún así, servirán para hacerse una idea del procedimiento a seguir y de los posibles problemas que pueden surgir por el camino.

Recomiendo muy encarecidamente realizar un backup del servidor antes de proceder con la actualización, para que en el improbable caso de que la máquina quedase inútil, se pudiese recuperar su estado anterior. No considero necesario explicar cómo hacer un backup ya que se saldría del objetivo de éste artículo.

Otra recomendación personal es que previamente se trate de llevar a cabo el proceso en una máquina lo más parecida posible que no se encuentre en producción, para así experimentar un poco antes de hacerlo en la máquina original, pudiendo anteponerse así, a posibles dificultades.

Antes de comenzar con la actualización, vamos a comprobar la release de CentOS actualmente instalada, para así verificar que realmente estamos haciendo uso de CentOS 7. Dicha información podremos encontrarla contenida en el fichero /etc/redhat-release, por lo que visualizaremos su contenido haciendo uso de cat:

[centos@quijote ~]$ cat /etc/redhat-release 
CentOS Linux release 7.8.2003 (Core)

Como se puede apreciar, actualmente estamos haciendo uso de la release 7.8.2003, por lo que podremos proceder a realizar la actualización a CentOS 8.

El primer paso será instalar el repositorio EPEL (Extra Packages Enterprise Linux), repositorio que nos ofrece paquetes de mucha utilidad que no están incluidos en los repositorios por defecto, que puede ser utilizado en varias distribuciones, entre las que se encuentra CentOS.

Para su instalación, haremos uso de la herramienta yum, el gestor de paquetes por defecto en CentOS 7, al que le pasaremos el enlace del fichero .rpm a instalar, o bien, el nombre de paquete epel-release.

En mi caso, he optado por la última opción, ya que es más cómoda, pues se encargará de descargar e instalar la última versión disponible del repositorio. Para ello, ejecutaremos el comando (con permisos de administrador, ejecutando para ello el comando sudo su -):

[root@quijote ~]# yum install epel-release

Para verificar que el nuevo repositorio se ha añadido y habilitado correctamente, volveremos a hacer uso de dicho comando, ésta vez con la opción repolist enabled, que nos mostrará aquellos repositorios que se encuentran actualmente habilitados, estableciendo a su vez el correspondiente filtro por nombre:

\[root@quijote ~]# yum repolist enabled | egrep 'epel'
epel/x86_64           Extra Packages for Enterprise Linux 7 - x86_64      13,464

Como se puede apreciar, el nuevo repositorio EPEL se encuentra correctamente añadido y habilitado.

El siguiente paso consiste en instalar dos paquetes que nos facilitarán la tarea de actualización:

  • rpmconf: Herramienta que busca posibles conflictos en la configuración de un determinado paquete.
  • yum-utils: Colección de utilidades que extienden las funcionalidades de yum.

Para llevar a cabo la correspondiente instalación, haremos uso del comando:

[root@quijote ~]# yum install rpmconf yum-utils

Tras ello, procederemos a hacer uso de la herramienta que acabamos de instalar para así comprobar que no existan conflictos en los ficheros de configuración de los paquetes, en cuyo caso tendríamos luz verde para proceder con la actualización. Para ello, ejecutaremos el comando:

[root@quijote ~]# rpmconf -a

Donde:

  • -a: Comprueba los ficheros de configuración de todos los paquetes instalados en el sistema.

En mi caso, no hubo ninguna salida en el comando, deduciendo por tanto que no existía ningún conflicto. En caso de haberlos, es recomendable marcar la opción N, manteniendo así el fichero de configuración original, aunque depende del sistema.

Posteriormente, haremos uso del comando package-cleanup existente en el paquete yum-utils previamente instalado para así listar aquellas dependencias que ya no son necesarias (–leaves) y aquellos paquetes que no se encuentran disponibles en los repositorios actualmente configurados (–orphans), con la finalidad de desinstalarlos.

Es muy importante lo último que he mencionado, ya que he estado leyendo algunos artículos en Internet que se limitan a listar los paquetes, pero no le pasan la salida de dicho comando a yum para desinstalarlos, por lo que realmente, no están limpiando la máquina. Para ello, ejecutaremos los comandos:

[root@quijote ~]# yum remove `package-cleanup --leaves`
[root@quijote ~]# yum remove `package-cleanup --orphans`

Nuestra máquina ya está limpia de paquetes innecesarios, así que es importante saber que en CentOS 8, el gestor de paquetes predeterminado es dnf, en lugar de yum. Realmente, podríamos hacer uso de éste último sin problema alguno, ya que existe compatibilidad, pero por elección propia, he decidido cambiarlo. Para instalar el nuevo gestor de paquetes, haremos uso del comando:

[root@quijote ~]# yum install dnf

Dado que ya hemos instalado el nuevo gestor de paquetes, podremos proceder a desinstalar el anterior, ya que no nos será necesario, ejecutando para ello el comando:

[root@quijote ~]# dnf remove yum yum-metadata-parser

A pesar de haber desinstado el paquete, podremos comprobar que todavía existe el correspondiente directorio en /etc/, haciendo uso del comando:

[root@quijote ~]# ls -l /etc/yum
total 0
drwxr-xr-x. 2 root root 28 Nov 20 12:03 pluginconf.d
drwxr-xr-x. 2 root root 26 Nov 12 09:36 protected.d
drwxr-xr-x. 2 root root 37 Apr  2  2020 vars

Dado que ya no necesitamos dicho directorio, procederemos a eliminarlo, ejecutando para ello el comando:

[root@quijote ~]# rm -rf /etc/yum

Donde:

  • -r: Indica que la eliminación se lleve a cabo de forma recursiva, eliminando los subdirectorios y sus contenidos.
  • -f: Evitamos que pida confirmación para cada uno de los ficheros contenidos, forzando por tanto su eliminación.

En un principio, el subdirectorio referente al paquete yum ha sido ya eliminado del directorio /etc/, así que procederemos a comprobarlo una vez más, ejecutando para ello el comando utilizado con anterioridad:

[root@quijote ~]# ls -l /etc/yum
ls: cannot access /etc/yum: No such file or directory

Efectivamente, el subdirectorio ha sido eliminado. Cada vez estamos más cerca de proceder con la actualización como tal, pero antes de ello, vamos a asegurarnos de que toda la paquetería esté completamente actualizada, haciendo para ello uso del nuevo gestor de paquetes instalado:

[root@quijote ~]# dnf upgrade

Tras ello, habrá llegado el momento de instalar la última versión de los paquetes necesarios para CentOS 8 (repos, release y gpg-keys), que podremos encontrar en el mirror oficial de CentOS. Su instalación la llevaremos a cabo ejecutando el comando:

[root@quijote ~]# dnf install \\
http://mirror.centos.org/centos/8/BaseOS/x86_64/os/Packages/centos-repos-8.2-2.2004.0.2.el8.x86_64.rpm \\
http://mirror.centos.org/centos/8/BaseOS/x86_64/os/Packages/centos-release-8.2-2.2004.0.2.el8.x86_64.rpm \\
http://mirror.centos.org/centos/8/BaseOS/x86_64/os/Packages/centos-gpg-keys-8.2-2.2004.0.2.el8.noarch.rpm

Una vez que la instalación de los paquetes referentes a la versión 8.2.2004 ha finalizado, tendremos que actualizar también la versión del repositorio EPEL, para que dicha versión sea ahora la que usaremos en CentOS 8. Para ello, volveremos a hacer uso del comando:

[root@quijote ~]# dnf upgrade epel-release

Posteriormente, vamos a limpiar los archivos temporales existentes en la máquina, como consecuencia de la paquetería que se ha tenido que descargar y que habrá quedado cacheada, ocupando espacio en disco de manera innecesaria. Para ello, ejecutaremos el comando:

[root@quijote ~]# dnf clean all
62 files removed

Como se puede apreciar, se han eliminado un total de 62 archivos que no eran necesarios.

Todavía no hemos terminado, ya que la actualización a CentOS 8, implica a su vez una actualización de kernel, así que procederemos a eliminar todos los paquetes asociados al que estamos utilizando actualmente, pues no vamos a necesitarlo más, haciendo uso del comando:

[root@quijote ~]# rpm -e `rpm -q kernel`

Donde:

  • -e: Indicamos que queremos desinstalar el paquete introducido.
  • -q: Nos mostrará todos aquellos paquetes que contengan una determinada cadena en su nombre, en este caso, kernel.

En un principio, nos queda un último paquete por desinstalar, y se trata de sysvinit-tools, que contiene las herramientas necesarias para el arranque básico de la máquina, el cuál desinstalaremos para evitar posibles conflictos, ejecutando para ello el comando:

[root@quijote ~]# rpm -e --nodeps sysvinit-tools

Donde:

  • –nodeps: Indicaremos que no revise las dependencias antes de desinstalar el paquete.

Lo que hemos estado haciendo hasta ahora son los preparativos necesarios para la actualización a CentOS 8, así que ha llegado el momento de llevarla a cabo. Para ello, haremos uso del comando:

[root@quijote ~]# dnf --releasever=8 --allowerasing --setopt=deltarpm=false distro-sync
...
Error: Transaction check error:
  file /usr/lib/python3.6/site-packages/rpmconf/__pycache__/__init__.cpython-36.opt-1.pyc from install of python3-rpmconf-1.0.21-1.el8.noarch conflicts with file from package python36-rpmconf-1.0.22-1.el7.noarch
  file /usr/lib/python3.6/site-packages/rpmconf/__pycache__/__init__.cpython-36.pyc from install of python3-rpmconf-1.0.21-1.el8.noarch conflicts with file from package python36-rpmconf-1.0.22-1.el7.noarch
  file /usr/lib/python3.6/site-packages/rpmconf/__pycache__/rpmconf.cpython-36.opt-1.pyc from install of python3-rpmconf-1.0.21-1.el8.noarch conflicts with file from package python36-rpmconf-1.0.22-1.el7.noarch
  file /usr/lib/python3.6/site-packages/rpmconf/__pycache__/rpmconf.cpython-36.pyc from install of python3-rpmconf-1.0.21-1.el8.noarch conflicts with file from package python36-rpmconf-1.0.22-1.el7.noarch
  file /usr/share/man/man3/rpmconf.3.gz from install of python3-rpmconf-1.0.21-1.el8.noarch conflicts with file from package python36-rpmconf-1.0.22-1.el7.noarch

Donde:

  • –releasever: Configura dnf como si la release fuese la introducida. Ésto puede afectar a las rutas de caché, los valores de los ficheros de configuración y los enlaces de repositorios. En éste caso, la versión es la 8.
  • –allowerasing: Permite que se eliminen determinados paquetes instalados para resolver dependencias en caso de ser necesario.
  • –setopt: Establece una opción que prevalece sobre aquella especificada en el fichero de configuración. En éste caso, desactivamos la opción deltarpm, cuya finalidad era ahorrar ancho de banda, pues descargaba ficheros delta que posteriormente tendría que reconstruir de manera local, un trabajo bastante intensivo para la CPU, que al tratarse en ésta ocasión de una gran cantidad de ficheros, no sería eficiente.

Como se puede apreciar en la salida del comando, han habido algunos conflictos con un paquete de Python previamente instalado en CentOS 7, concretamente con python36-rpmconf-1.0.22-1.el7.noarch, el cuál procederemos a desinstalar, ejecutando para ello el comando:

[root@quijote ~]# dnf remove python36-rpmconf-1.0.22-1.el7.noarch

Tras ello, volveremos a ejecutar el comando para realizar la actualización, para intentar llevarla a cabo de forma exitosa en ésta ocasión:

[root@quijote ~]# dnf --releasever=8 --allowerasing --setopt=deltarpm=false distro-sync

Tras alrededor de 10 minutos de espera, la actualización ha finalizado sin ningún tipo de error. Antes de llevar a cabo las comprobaciones oportunas, tenemos que instalar la nueva versión del kernel, ya que en memoria tenemos cargada la versión de kernel correspondiente a CentOS 7, haciendo para ello uso del comando:

[root@quijote ~]# dnf install kernel-core

Por último, vamos a tratar de actualizar dos grupos de paquetes (colección de paquetes que tienen un propósito común), para así asegurar que tenemos las utilidades mínimas para el correcto funcionamiento del sistema. Para ello, ejecutaremos el comando:

[root@quijote ~]# dnf groupupdate "Core" "Minimal Install"

La actualización a CentOS 8 ha finalizado, así que para verificar que actualmente estamos haciendo uso de la nueva versión, volveremos a visualizar el contenido del fichero /etc/redhat-release, haciendo uso del comando:

[root@quijote ~]# cat /etc/redhat-release
CentOS Linux release 8.2.2004 (Core)

Como se puede apreciar, nos encontramos haciendo uso de la release 8.2.2004. Tras ello, verificaremos el kernel que actualmente estamos utilizando, ejecutando para ello el comando:

[root@quijote ~]# uname -r
3.10.0-1127.19.1.el7.x86_64

Donde:

  • -r: Le pedimos que nos muestre la release en lugar del nombre.

Como era de esperar, la versión de kernel cargada en memoria es la correspondiente a la instalada en CentOS 7, de manera que para cargar el nuevo núcleo instalado, no tendremos más remedio que reiniciar la máquina, haciendo uso del comando:

[root@quijote ~]# reboot

Tras ello, volveremos a comprobar la versión de kernel cargada en memoria, ejecutando para ello el comando visto con anterioridad:

[centos@quijote ~]$ uname -r
4.18.0-193.28.1.el8_2.x86_64

Una vez completado el reinicio, la nueva versión del núcleo ha sido correctamente cargada en memoria, por lo que podemos asegurar que la actualización se ha completado exitosamente.

Podríamos dejar aquí el artículo, ya que la actualización se ha completado, pero personalmente, considero necesario comprobar que las configuraciones llevadas a cabo previamente en la máquina siguen estando activas y funcionales, así que comenzaremos por listar la información correspondiente a las interfaces de red existentes en la máquina, haciendo para ello uso del comando:

[centos@quijote ~]$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 8950 qdisc fq_codel state UP group default qlen 1000
    link/ether fa:16:3e:3b:bb:e2 brd ff:ff:ff:ff:ff:ff
    inet 10.0.1.5/24 brd 10.0.1.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fe3b:bbe2/64 scope link 
       valid_lft forever preferred_lft forever

Como se puede apreciar, la máquina tiene configurada una interfaz eth0 con direccionamiento privado 10.0.1.5, configurado de forma estática, tal y como establecimos en el anterior artículo.

Al tratarse de una máquina ubicada en una red privada, vamos a verificar que sus tablas de enrutamiento tienen la correspondiente entrada para asegurar la conectividad con el exterior, mediante la máquina que actúa como router (Dulcinea), ubicada en 10.0.1.9, ejecutando para ello el comando:

[centos@quijote ~]$ ip r
default via 10.0.1.9 dev eth0 proto static metric 100 
10.0.1.0/24 dev eth0 proto kernel scope link src 10.0.1.5 metric 100

Efectivamente, su configuración es la correcta, por lo que en un principio debería tener salida al exterior. Para comprobarlo, vamos a hacer ping a una dirección que sabemos que nos va a responder, como por ejemplo la 8.8.8.8:

[centos@quijote ~]$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=111 time=776 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=111 time=560 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=111 time=663 ms
^C
--- 8.8.8.8 ping statistics ---
4 packets transmitted, 3 received, 25% packet loss, time 1002ms
rtt min/avg/max/mdev = 560.030/666.278/776.012/88.208 ms

Como era de esperar, la máquina sigue teniendo conectividad con el exterior.

La siguiente comprobación consistirá en verificar que la máquina tiene correctamente configurado el hostname y el FQDN, haciendo para ello uso de los comandos:

[centos@quijote ~]$ hostname
quijote

[centos@quijote ~]$ hostname -f
quijote.alvaro.gonzalonazareno.org

Una vez más, la configuración es correcta.

He considerado necesario también el hecho de verificar que la resolución estática de nombres a las máquinas Dulcinea y Sancho sigue funcionando, así que trataremos de alcanzarlas mediante un ping:

[centos@quijote ~]$ ping dulcinea
PING dulcinea.alvaro.gonzalonazareno.org (10.0.1.9) 56(84) bytes of data.
64 bytes from dulcinea.alvaro.gonzalonazareno.org (10.0.1.9): icmp_seq=1 ttl=64 time=0.699 ms
64 bytes from dulcinea.alvaro.gonzalonazareno.org (10.0.1.9): icmp_seq=2 ttl=64 time=0.848 ms
64 bytes from dulcinea.alvaro.gonzalonazareno.org (10.0.1.9): icmp_seq=3 ttl=64 time=0.715 ms
^C
--- dulcinea.alvaro.gonzalonazareno.org ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 65ms
rtt min/avg/max/mdev = 0.699/0.754/0.848/0.066 ms

[centos@quijote ~]$ ping sancho
PING sancho.alvaro.gonzalonazareno.org (10.0.1.4) 56(84) bytes of data.
64 bytes from sancho.alvaro.gonzalonazareno.org (10.0.1.4): icmp_seq=1 ttl=64 time=2.09 ms
64 bytes from sancho.alvaro.gonzalonazareno.org (10.0.1.4): icmp_seq=2 ttl=64 time=1.20 ms
64 bytes from sancho.alvaro.gonzalonazareno.org (10.0.1.4): icmp_seq=3 ttl=64 time=1.29 ms
^C
--- sancho.alvaro.gonzalonazareno.org ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 5ms
rtt min/avg/max/mdev = 1.204/1.528/2.093/0.403 ms

La resolución estática de nombres ha funcionado correctamente, de manera que nos quedaría comprobar que la resolución mediante servidores DNS también lo hace, tratando de llevar a cabo para ello un ping a google.es, por ejemplo:

[centos@quijote ~]$ ping google.es

Al parecer, hay un problema con la resolución de nombres (podemos asegurar que no es de conectividad ya que anteriormente hemos sido capaces de alcanzar a 8.8.8.8). Lo primero que haremos será revisar el fichero en el que se establecen los servidores DNS a los que preguntar, es decir, el fichero /etc/resolv.conf, ejecutando para ello el comando:

[centos@quijote ~]$ cat /etc/resolv.conf
search openstacklocal
nameserver 192.168.200.2

Como se puede apreciar, ha habido un problema, y es que únicamente ha configurado 1 de los 3 servidores DNS (el cuál no se encuentra operativo) previamente especificados en el fichero de configuración de la interfaz de red, muy posiblemente, debido a alguna configuración del mecanismo cloud-init existente en CentOS 8 pero no en CentOS 7.

Tras algo de investigación al respecto, descubrí que la solución era bastante sencilla. Lo primero que haremos será limpiar el fichero de configuración de la interfaz de red, es decir, /etc/sysconfig/network-scripts/ifcfg-eth0, eliminando todas las entradas referentes a los servidores DNS. Para ello, haremos uso del comando:

[centos@quijote ~]$ sudo vi /etc/sysconfig/network-scripts/ifcfg-eth0

El contenido actual es el siguiente:

BOOTPROTO=none
DEVICE=eth0
HWADDR=fa:16:3e:3b:bb:e2
MTU=8950
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
IPADDR=10.0.1.5
PREFIX=24
GATEWAY=10.0.1.9
DNS1=192.168.202.2
DNS2=192.168.200.2
DNS3=8.8.8.8

El contenido tras eliminar las entradas referentes a los servidores DNS es el siguiente:

BOOTPROTO=none
DEVICE=eth0
HWADDR=fa:16:3e:3b:bb:e2
MTU=8950
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
IPADDR=10.0.1.5
PREFIX=24
GATEWAY=10.0.1.9

Tras ello, guardaremos los cambios y procederemos a modificar directamente el fichero /etc/resolv.conf, estableciendo en el mismo los servidores DNS que queremos utilizar, que serán los mismos que estaban previamente definidos en el fichero que acabamos de modificar. Para ello, ejecutaremos el comando:

[centos@quijote ~]$ sudo vi /etc/resolv.conf

El resultado final sería el siguiente:

search openstacklocal
nameserver 192.168.202.2
nameserver 192.168.200.2
nameserver 8.8.8.8

Cuando hayamos terminado la modificación del mismo, guardaremos los cambios y volveremos a tratar de hacer ping a google.es, para comprobar si la resolución se lleva ahora a cabo de forma correcta:

[centos@quijote ~]$ ping google.es
PING google.es (216.58.211.35) 56(84) bytes of data.
64 bytes from muc03s14-in-f3.1e100.net (216.58.211.35): icmp_seq=1 ttl=112 time=43.2 ms
64 bytes from muc03s14-in-f3.1e100.net (216.58.211.35): icmp_seq=2 ttl=112 time=43.3 ms
64 bytes from muc03s14-in-f3.1e100.net (216.58.211.35): icmp_seq=3 ttl=112 time=43.5 ms
^C
--- google.es ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 466ms
rtt min/avg/max/mdev = 43.207/43.364/43.544/0.277 ms

Efectivamente, la resolución del nombre google.es se ha realizado correctamente, además de haber conseguido que dicha configuración perdure incluso tras un reinicio.

Por último, voy a verificar que el reloj del sistema esté correctamente sincronizado, pues fue la última configuración que llevé a cabo en CentOS 7, haciendo para ello uso del comando:

[centos@quijote ~]$ timedatectl
               Local time: Sun 2020-11-22 13:50:03 CET
           Universal time: Sun 2020-11-22 12:50:03 UTC
                 RTC time: Sun 2020-11-22 12:50:03
                Time zone: Europe/Madrid (CET, +0100)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

Como era de esperar, el reloj se encuentra correctamente sincronizado (System clock synchronized) con la zona horaria de Madrid, por lo que la actualización de CentOS 7 a CentOS 8 y su correspondiente comprobación de funcionamiento ha llegado hasta aquí.