Aplicaciones Legacy: Dockerización y Kubernetes
La modernización de aplicaciones es un desafío constante para las empresas que desean mantenerse ágiles y competitivas. Uno de los mayores obstáculos suele ser la gestión de aplicaciones legacy: aquellas que han sido desarrolladas con tecnologías obsoletas pero que aún son vitales para el funcionamiento del negocio.
En este artículo, exploraremos cómo hemos abordado este desafío en STR Sistemas, llevando una aplicación legacy desarrollada en PHP 7 a un entorno moderno utilizando contenedores Docker y Kubernetes.
El Desafío de las Aplicaciones Legacy
STR se encontraba frente a una aplicación crucial para nuestras operaciones pero que estaba desarrollada en PHP 7, una versión que ya había alcanzado su fin de vida y que presentaba riesgos de seguridad y compatibilidad. La tarea era clara: modernizar esta aplicación sin interrumpir su funcionamiento y asegurar su escalabilidad y mantenibilidad a largo plazo.
La Solución: Dockerización y Kubernetes
La clave para abordar este desafío fue la adopción de contenedores Docker y la orquestación de estos a través de Kubernetes. ¿Por qué esta elección? Porque nos permitía encapsular la aplicación legacy junto con todas sus dependencias en un entorno aislado y portátil, facilitando su despliegue y escalabilidad.
Adaptación del Código PHP: Uso de Variables de Entorno
Una de las tareas fundamentales fue la adaptación del código PHP para funcionar de manera eficiente en un entorno de contenedores. En particular, nos enfrentamos al desafío de parametrizar la configuración de los servidores remotos de supervisord sin modificar el código fuente directamente.
En el código original de PHP, teníamos un bloque estático que definía los servidores remotos:
$config['supervisor_servers'] = array(
'server01' => array(
'url' => 'http://server01.app/RPC2',
'port' => '9001',
'username' => 'yourusername',
'password' => 'yourpass'
),
// Other supervisord servers…
);
Para hacer este bloque más flexible y adaptable a diferentes entornos, implementamos una solución basada en variables de entorno. Ahora, utilizando un bucle y las variables de entorno adecuadas, podemos definir dinamicamente los servidores remotos:
for ($i = 1; $i <= $_ENV['SUPERVISOR_SERVERS_COUNT']; $i++) {
$config['supervisor_servers'][$_ENV["SUPERVISOR_SERVERS_{$i}_NAME"]] = array(
'url' => $_ENV["SUPERVISOR_SERVERS_{$i}_URL"],
'port' => $_ENV["SUPERVISOR_SERVERS_{$i}_PORT"],
'username' => $_ENV["SUPERVISOR_SERVERS_{$i}_USERNAME"],
'password' => $_ENV["SUPERVISOR_SERVERS_{$i}_PASSWORD"]
);
}
De esta forma, podemos definir N elementos de servidores remotos de supervisord mediante el uso de variables de entorno. Esta técnica nos brinda una mayor flexibilidad y adaptabilidad, permitiendo configurar la aplicación de manera dinámica sin necesidad de modificar el código fuente directamente.
El código fuente adaptado puede obtenerse de nuestro repositorio de GitHub: https://github.com/STRSistemas/supervisord-dashboard
Dockerfile: Construyendo la Imagen de Docker
Para implementar nuestra solución, creamos un Dockerfile que define los pasos necesarios para construir la imagen de Docker de nuestra aplicación. Este Dockerfile incluye la instalación de PHP y Apache, la configuración de variables de entorno y la copia del código de la aplicación al contenedor. También se encarga de configurar Apache para que sirva la aplicación correctamente.
A continuación se muestra el Dockerfile utilizado:
# Usa un argumento para especificar la versión de PHP
ARG PHP_VERSION=7.4
# Usa una imagen base de Ubuntu con Apache y PHP
FROM php:${PHP_VERSION}-apache
# Variables de entorno personalizadas (pueden ser utilizadas en tu aplicación)
ENV SUPERVISOR_SERVERS_COUNT 0
# Validar que la versión de PHP sea inferior a 8.0
RUN php -r "if (version_compare('${PHP_VERSION}', '8.0', '>')) exit(1);"
# Cambia los puertos de escucha de Apache2
RUN sed -i 's|Listen 80|Listen 8080|' /etc/apache2/ports.conf
RUN sed -i 's|Listen 443|Listen 8443|' /etc/apache2/ports.conf
RUN sed -i 's|VirtualHost \*:80|VirtualHost \*:8080|' /etc/apache2/sites-available/000-default.conf
RUN sed -i 's|VirtualHost _default_:443|VirtualHost _default_:8443|' /etc/apache2/sites-available/default-ssl.conf
# Creación de logs de Apache2 y corrección de permisos
RUN chown www-data:www-data /var/log/apache2/ -fR
# Cambia la directiva DocumentRoot en el archivo de configuración de Apache
RUN sed -i 's|DocumentRoot /var/www/html|DocumentRoot /var/www/html/public_html|' /etc/apache2/sites-available/000-default.conf
RUN sed -i 's|DocumentRoot /var/www/html|DocumentRoot /var/www/html/public_html|' /etc/apache2/sites-available/default-ssl.conf
# Genera certificado autofirmado para el SSL de Apache2
RUN openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 \
-subj "/CN=supervisord" \
-out /etc/ssl/certs/ssl-cert-snakeoil.pem \
-keyout /etc/ssl/private/ssl-cert-snakeoil.key
# Correccíón de permisos de directorios /etc/ssl/
RUN chmod 750 /etc/ssl/private/ -fR
RUN chown root:www-data /etc/ssl/private/ -fR
# Habilita el VirtualHost SSL
RUN a2ensite default-ssl
# Habilita el modulo requeridos de Apache2
RUN a2enmod rewrite
RUN a2enmod ssl
# Configura el directorio de trabajo
WORKDIR /var/www/html
# Copia el código de la aplicación PHP al contenedor
COPY supervisord_dashboard/ .
# Establece el usuario para ejecutar la aplicación (www-data)
USER 33
# Expone el puerto en el que Apache se ejecutará
EXPOSE 8080
EXPOSE 8443
# Inicia Apache al ejecutar el contenedor
CMD ["apache2-foreground"]
La imagen ya compilada previamente por STR Sistemas está publicada en DockerHub, pueden obtenerse de nuestro Registry:
https://hub.docker.com/r/strsistemas/supervisord-dashboard/tags
Separación de Preocupaciones: Contenedores Específicos
Una de las ventajas de la estrategia adoptada fue la capacidad de tener versiones obsoletas de PHP únicamente dentro del contenedor que alojaba nuestra aplicación legacy. Esto significaba que el resto de nuestros sistemas podían seguir utilizando versiones más modernas de PHP sin conflicto alguno. Esta separación de preocupaciones nos brindaba flexibilidad y seguridad, asegurando un entorno de desarrollo y producción más robusto.
Conclusiones
La modernización de aplicaciones legacy es un proceso complejo pero fundamental para garantizar la viabilidad a largo plazo de nuestros sistemas. La combinación de contenedores Docker y Kubernetes, junto con técnicas como la parametrización a través de variables de entorno, nos ha permitido abordar este desafío de manera efectiva, proporcionando una solución escalable, segura y mantenible para nuestra aplicación PHP legacy.
En futuros artículos, profundizaremos en los detalles técnicos de nuestro caso específico, compartiendo lecciones aprendidas y mejores prácticas para aquellos que se enfrentan a desafíos similares en sus propios entornos.