Instalar y Automatizar Despliegues de RHEL

Red Hat Enterprise LinuxBeginner
Practicar Ahora

Introducción

En este laboratorio, aprenderá los fundamentos del despliegue y la automatización de contenedores de Red Hat Enterprise Linux (RHEL) 9 utilizando Docker. Los despliegues modernos nativos de la nube dependen cada vez más de entornos RHEL en contenedores en lugar de máquinas virtuales tradicionales. Comenzará explorando las Imágenes Base Universales (UBI, por sus siglas en inglés) de Red Hat, que proporcionan entornos RHEL de nivel empresarial en formato de contenedor.

Examinará cómo los conceptos tradicionales de Kickstart se traducen a la automatización de contenedores, creará Dockerfiles personalizados que reflejen las configuraciones de instalación y construirá scripts de despliegue automatizados. Al final de este laboratorio, comprenderá cómo desplegar contenedores RHEL de manera eficiente y automatizar el proceso para despliegues consistentes y repetibles en entornos de nube modernos.

Explorar las Imágenes Base Universales (UBI) de Red Hat

En este paso, explorará las Imágenes Base Universales (UBI, por sus siglas en inglés) de Red Hat, que son imágenes de contenedor de nivel empresarial basadas en RHEL. A diferencia de las instalaciones tradicionales de RHEL que requieren máquinas virtuales completas, las imágenes UBI proporcionan entornos RHEL en contenedores ligeros y portátiles. Estas imágenes son de libre redistribución y están diseñadas para aplicaciones modernas nativas de la nube.

Red Hat proporciona varias variantes de UBI optimizadas para diferentes casos de uso. La imagen redhat/ubi9 proporciona un entorno de contenedor completo basado en RHEL con el gestor de paquetes dnf, lo que la hace adecuada para aplicaciones que requieren instalación de software y automatización del sistema.

Primero, examinemos la plantilla de configuración de contenedor de Red Hat que se ha preparado para este laboratorio. Este archivo demuestra cómo los conceptos tradicionales de Kickstart se traducen a entornos de contenedor.

sudo cat /etc/labex/rhel-container-config.cfg

Verá una salida que muestra una configuración al estilo Dockerfile que refleja los conceptos de instalación tradicionales:

## RHEL Container Configuration Template
## Based on traditional Kickstart concepts adapted for containers

## Base image specification
FROM redhat/ubi9

## System locale and timezone
ENV LANG=en_US.UTF-8
ENV TZ=America/New_York

## User configuration
ENV CONTAINER_USER=labex
ENV ROOT_PASSWORD=redhat

## Package installation
## Packages: httpd, curl (container-appropriate equivalents)
RUN dnf install -y --allowerasing httpd curl && \
    dnf clean all

## Service configuration
EXPOSE 80

## Startup command
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]

Ahora, exploremos las imágenes UBI de Red Hat disponibles. Primero, compruebe si Docker se está ejecutando y es accesible:

docker --version

Descargue la imagen Red Hat UBI 9, que proporciona un entorno de contenedor completo basado en RHEL:

docker pull redhat/ubi9

Debería ver una salida similar a:

Using default tag: latest
latest: Pulling from redhat/ubi9
Digest: sha256:...
Status: Downloaded newer image for redhat/ubi9:latest
docker.io/redhat/ubi9:latest

Enumere las imágenes descargadas para confirmar que la descarga fue exitosa:

docker images redhat/ubi9

La salida mostrará detalles sobre la imagen:

REPOSITORY      TAG       IMAGE ID       CREATED      SIZE
redhat/ubi9     latest    b1c2d3e4f5g6   5 days ago   216MB

Ahora, ejecutemos un contenedor básico para explorar el entorno RHEL:

docker run -it --rm redhat/ubi9 /bin/bash

Dentro del contenedor, explore el entorno RHEL comprobando la versión del sistema operativo:

cat /etc/redhat-release

Debería ver algo como:

Red Hat Enterprise Linux release 9.6 (Plow)

Compruebe el gestor de paquetes disponible:

dnf --version

Salga del contenedor escribiendo:

exit

Copie la configuración de la plantilla a su directorio de proyecto para personalizarla:

sudo cp /etc/labex/rhel-container-config.cfg ~/project/rhel-container.dockerfile
sudo chown labex:labex ~/project/rhel-container.dockerfile

Verifique que el archivo se copió correctamente:

ls -l ~/project/rhel-container.dockerfile

Ahora ha explorado con éxito las imágenes UBI de Red Hat y está listo para crear configuraciones de contenedor personalizadas en el siguiente paso.

Crear una Configuración de Contenedor RHEL Personalizada

En este paso, creará un Dockerfile personalizado basado en la imagen UBI de Red Hat. Este proceso refleja cómo personalizaría un archivo Kickstart para instalaciones automatizadas, pero adaptado para entornos de contenedor. El Dockerfile sirve como plantilla de automatización para crear despliegues de contenedores RHEL consistentes.

Primero, asegúrese de estar en su directorio de proyecto:

cd ~/project

Cree un nuevo Dockerfile, más específico, para nuestro despliegue de contenedor RHEL automatizado:

cp rhel-container.dockerfile rhel9-automated.dockerfile

Verifique que ambos archivos existan:

ls -l *.dockerfile

Debería ver ambos archivos:

-rw-r--r--. 1 labex labex 423 Jul 22 10:30 rhel-container.dockerfile
-rw-r--r--. 1 labex labex 423 Jul 22 10:35 rhel9-automated.dockerfile

Ahora, abra el nuevo Dockerfile para examinar su estructura antes de la personalización:

nano rhel9-automated.dockerfile

Dentro del archivo, verá el equivalente en contenedor de las directivas Kickstart:

  • Directiva FROM: Especifica la imagen RHEL base (equivalente al medio de instalación)
  • Directivas ENV: Establecen variables de entorno (equivalentes a la configuración del sistema)
  • Directivas RUN: Ejecutan comandos durante la construcción de la imagen (equivalente a la instalación de paquetes)
  • EXPOSE y CMD: Configuran servicios e inicio (equivalente a la configuración del servicio)

Por ahora, simplemente salga del editor presionando Ctrl+X para proceder al paso de personalización.

Comprender esta estructura lo prepara para el siguiente paso, donde personalizará la configuración del contenedor para satisfacer los requisitos específicos de despliegue, tal como personalizaría un archivo Kickstart para instalaciones automatizadas de VM.

Personalizar la Configuración del Contenedor para la Implementación Automatizada

En este paso, reemplazará el contenido de rhel9-automated.dockerfile con una configuración personalizada para el despliegue automatizado de contenedores RHEL. Este proceso es similar a la personalización de un archivo Kickstart, pero utiliza el enfoque declarativo de Docker para definir el entorno y los servicios del contenedor.

Primero, asegúrese de estar en el directorio del proyecto:

cd ~/project

Ahora, cree el Dockerfile personalizado completo reemplazando todo el contenido de rhel9-automated.dockerfile:

cat > rhel9-automated.dockerfile << 'EOF'
## RHEL 9 Automated Container Deployment
## Based on Red Hat Universal Base Image 9
FROM redhat/ubi9:latest

## Container metadata
LABEL maintainer="LabEx Admin"
LABEL description="Automated RHEL 9 container with web services"
LABEL version="1.0"

## System locale and timezone configuration
ENV LANG=en_US.UTF-8
ENV TZ=America/New_York
ENV CONTAINER_USER=labex
ENV CONTAINER_UID=1001

## Package installation and system configuration
RUN dnf update -y \
  && dnf install -y --allowerasing \
    httpd \
    curl \
    tar \
    gzip \
  && dnf clean all \
  && rm -rf /var/cache/dnf

## Create non-root user for security
RUN useradd -u ${CONTAINER_UID} -m -s /bin/bash ${CONTAINER_USER} \
  && echo "${CONTAINER_USER}:labex" | chpasswd

## Configure Apache for container environment
RUN sed -i 's/Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf \
  && chown -R ${CONTAINER_USER}:${CONTAINER_USER} /var/log/httpd /var/run/httpd

## Create startup script
RUN echo '#!/bin/bash' > /start.sh \
  && echo 'echo "RHEL Container started on $(date)" > /var/www/html/index.html' >> /start.sh \
  && echo 'echo "<h1>RHEL 9 Container</h1><p>Deployed via automated configuration</p>" >> /var/www/html/index.html' >> /start.sh \
  && echo 'exec /usr/sbin/httpd -D FOREGROUND' >> /start.sh \
  && chmod +x /start.sh

## Switch to non-root user
USER ${CONTAINER_USER}

## Expose port and define startup
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/ || exit 1

CMD ["/start.sh"]
EOF

Ahora, examinemos la estructura de este Dockerfile personalizado y comprendamos cómo cada sección cumple el mismo propósito que las diferentes partes de una configuración Kickstart:

1. Sección de Imagen Base y Metadatos:

## RHEL 9 Automated Container Deployment
## Based on Red Hat Universal Base Image 9
FROM redhat/ubi9:latest

## Container metadata
LABEL maintainer="LabEx Admin"
LABEL description="Automated RHEL 9 container with web services"
LABEL version="1.0"

Esta sección es equivalente a especificar el medio de instalación y la información básica del sistema en un archivo Kickstart. La directiva FROM especifica nuestra imagen RHEL base, mientras que las directivas LABEL proporcionan metadatos sobre el contenedor.

2. Configuración del Entorno:

## System locale and timezone configuration
ENV LANG=en_US.UTF-8
ENV TZ=America/New_York
ENV CONTAINER_USER=labex
ENV CONTAINER_UID=1001

Esto es similar a las directivas timezone y lang en los archivos Kickstart. Estamos configurando la configuración regional del sistema, la zona horaria y definiendo variables para la creación de usuarios.

3. Instalación de Paquetes:

## Package installation and system configuration
RUN dnf update -y \
  && dnf install -y --allowerasing \
    httpd \
    curl \
    tar \
    gzip \
  && dnf clean all \
  && rm -rf /var/cache/dnf

Esta sección realiza la misma función que la sección %packages en Kickstart. Actualizamos el sistema, instalamos los paquetes requeridos usando --allowerasing para manejar conflictos y limpiamos las cachés de paquetes para reducir el tamaño de la imagen.

4. Configuración de Usuario y Seguridad:

## Create non-root user for security
RUN useradd -u ${CONTAINER_UID} -m -s /bin/bash ${CONTAINER_USER} \
  && echo "${CONTAINER_USER}:labex" | chpasswd

## Configure Apache for container environment
RUN sed -i 's/Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf \
  && chown -R ${CONTAINER_USER}:${CONTAINER_USER} /var/log/httpd /var/run/httpd

Esto refleja la directiva user y la configuración posterior a la instalación en Kickstart. Creamos un usuario no root para la seguridad y configuramos Apache para que se ejecute en el puerto 8080 (adecuado para entornos de contenedor).

5. Configuración de Inicio:

## Create startup script
RUN echo '#!/bin/bash' > /start.sh \
  && echo 'echo "RHEL Container started on $(date)" > /var/www/html/index.html' >> /start.sh \
  && echo 'echo "<h1>RHEL 9 Container</h1><p>Deployed via automated configuration</p>" >> /var/www/html/index.html' >> /start.sh \
  && echo 'exec /usr/sbin/httpd -D FOREGROUND' >> /start.sh \
  && chmod +x /start.sh

## Switch to non-root user
USER ${CONTAINER_USER}

## Expose port and define startup
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/ || exit 1

CMD ["/start.sh"]

Esta sección final es equivalente a la sección %post y la configuración del servicio en Kickstart. Creamos un script de inicio, cambiamos al usuario no root, exponemos el puerto del servicio web, definimos comprobaciones de estado y especificamos el comando de inicio del contenedor.

Verifique que el nuevo Dockerfile se creó correctamente:

cat rhel9-automated.dockerfile

Debería ver el contenido completo del Dockerfile que demuestra cómo los conceptos tradicionales de automatización Kickstart se traducen a despliegues RHEL modernos basados en contenedores.

Validar la Configuración del Contenedor y Construir la Imagen

En este paso, validará su Dockerfile personalizado y construirá la imagen del contenedor RHEL. Este proceso es similar a la validación de un archivo Kickstart con ksvalidator, pero utiliza la validación integrada de Docker durante el proceso de construcción. Docker verificará la sintaxis e intentará ejecutar cada instrucción, proporcionando retroalimentación inmediata sobre cualquier problema.

Primero, asegúrese de estar en el directorio del proyecto donde se encuentra su Dockerfile:

cd ~/project

Antes de construir, realicemos una verificación básica de la sintaxis examinando la estructura del Dockerfile. Docker proporciona una forma de validar la sintaxis básica sin construir:

docker build --no-cache --progress=plain -f rhel9-automated.dockerfile -t rhel9-test:validation . --target ""

Sin embargo, la validación más efectiva es construir realmente la imagen. Si hay errores de sintaxis o problemas con los comandos, Docker los informará durante el proceso de construcción. Tenga en cuenta que usamos la bandera --allowerasing con dnf install para manejar los conflictos de paquetes entre curl y curl-minimal que existen en la imagen UBI9 base:

docker build -t rhel9-automated:latest -f rhel9-automated.dockerfile .

Debería ver la salida que muestra cada paso del proceso de construcción:

[+] Building 45.2s (12/12) FINISHED
 => [internal] load build definition from rhel9-automated.dockerfile
 => => transferring dockerfile: 1.23kB
 => [internal] load .dockerignore
 => => transferring context: 2B
 => [internal] load metadata for docker.io/redhat/ubi9:latest
 => [1/8] FROM docker.io/redhat/ubi9:latest@sha256:...
 => [2/8] RUN dnf update -y &&     dnf install -y --allowerasing         httpd         curl         tar         gzip &&     dnf clean all &&     rm -rf /var/cache/dnf
 => [3/8] RUN useradd -u 1001 -m -s /bin/bash labex &&     echo "labex:labex" | chpasswd
 => [4/8] RUN sed -i 's/Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf &&     chown -R labex:labex /var/log/httpd /var/run/httpd
 => [5/8] RUN echo '#!/bin/bash' > /start.sh &&     echo 'echo "RHEL Container started on $(date)" > /var/www/html/index.html' >> /start.sh &&     echo 'echo "<h1>RHEL 9 Container</h1><p>Deployed via automated configuration</p>" >> /var/www/html/index.html' >> /start.sh &&     echo 'exec /usr/sbin/httpd -D FOREGROUND' >> /start.sh &&     chmod +x /start.sh
 => [6/8] USER labex
 => exporting to image
 => => exporting layers
 => => writing image sha256:a1b2c3d4e5f6...
 => => naming to docker.io/library/rhel9-automated:latest

Si la construcción se completa con éxito, significa que la sintaxis de su Dockerfile es correcta y todos los comandos se ejecutaron correctamente. Es posible que vea algunos mensajes de advertencia sobre la configuración regional y la gestión de suscripciones durante el proceso de construcción; estos son normales para los contenedores UBI y no afectan la funcionalidad.

Verifique que la imagen se haya creado:

docker images rhel9-automated

Debería ver su imagen recién construida:

REPOSITORY       TAG       IMAGE ID       CREATED          SIZE
rhel9-automated  latest    a1b2c3d4e5f6   2 minutes ago    280MB

Ahora, probemos el contenedor para asegurarnos de que funciona como se espera. Ejecute el contenedor en modo desasociado:

docker run -d --name rhel9-test -p 8080:8080 rhel9-automated:latest

Verifique si el contenedor se está ejecutando:

docker ps

Debería ver su contenedor en la lista:

CONTAINER ID   IMAGE                     COMMAND      CREATED         STATUS         PORTS                    NAMES
a1b2c3d4e5f6   rhel9-automated:latest   "/start.sh"  30 seconds ago  Up 30 seconds  0.0.0.0:8080->8080/tcp   rhel9-test

Pruebe el servicio web haciendo una solicitud al contenedor:

curl http://localhost:8080

Debería ver la salida HTML de su contenedor RHEL automatizado:

RHEL Container started on Wed Jul 22 14:30:15 UTC 2024
<h1>RHEL 9 Container</h1><p>Deployed via automated configuration</p>

Finalmente, limpie deteniendo y eliminando el contenedor de prueba:

docker stop rhel9-test
docker rm rhel9-test

Su configuración del contenedor RHEL se ha validado y probado con éxito, lo que demuestra las capacidades de despliegue automatizado.

Crear un Script de Despliegue Automatizado

En este paso, creará un script de automatización que demuestra cómo desplegar contenedores RHEL de forma consistente y repetida. Este script cumple el mismo propósito que el uso de archivos Kickstart para la automatización de VM, pero está adaptado para despliegues RHEL en contenedores. El script se encargará de la construcción de la imagen, el despliegue del contenedor y la verificación básica del estado.

Primero, asegúrese de estar en el directorio de su proyecto:

cd ~/project

Cree un script de automatización de despliegue que imite las capacidades de automatización que lograría con Kickstart y virt-install:

nano deploy-rhel-container.sh

Agregue el siguiente contenido para crear un script de despliegue completo:

#!/bin/bash

## Script de Despliegue Automatizado de Contenedores RHEL
## Este script demuestra la automatización del despliegue de RHEL basado en contenedores
## Similar a la automatización de Kickstart para VM, pero para contenedores

set -e ## Salir ante cualquier error

## Variables de configuración
IMAGE_NAME="rhel9-automated"
IMAGE_TAG="latest"
CONTAINER_NAME="rhel9-production"
HOST_PORT="8080"
CONTAINER_PORT="8080"
DOCKERFILE="rhel9-automated.dockerfile"

## Códigos de color para la salida
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' ## Sin Color

## Función para imprimir salida coloreada
print_status() {
  echo -e "${BLUE}[INFO]${NC} $1"
}

print_success() {
  echo -e "${GREEN}[SUCCESS]${NC} $1"
}

print_warning() {
  echo -e "${YELLOW}[WARNING]${NC} $1"
}

print_error() {
  echo -e "${RED}[ERROR]${NC} $1"
}

## Función para verificar si Docker se está ejecutando
check_docker() {
  print_status "Verificando la disponibilidad de Docker..."
  if ! docker info > /dev/null 2>&1; then
    print_error "Docker no se está ejecutando o no es accesible"
    exit 1
  fi
  print_success "Docker está disponible"
}

## Función para construir la imagen
build_image() {
  print_status "Construyendo la imagen del contenedor RHEL..."
  if [ ! -f "$DOCKERFILE" ]; then
    print_error "Dockerfile '$DOCKERFILE' no encontrado"
    exit 1
  fi

  docker build -t "${IMAGE_NAME}:${IMAGE_TAG}" -f "$DOCKERFILE" .
  print_success "Imagen '${IMAGE_NAME}:${IMAGE_TAG}' construida con éxito"
}

## Función para detener y eliminar el contenedor existente
cleanup_existing() {
  print_status "Verificando la existencia de un contenedor..."
  if docker ps -a | grep -q "$CONTAINER_NAME"; then
    print_warning "Deteniendo y eliminando el contenedor existente '$CONTAINER_NAME'"
    docker stop "$CONTAINER_NAME" > /dev/null 2>&1 || true
    docker rm "$CONTAINER_NAME" > /dev/null 2>&1 || true
  fi
}

## Función para desplegar el contenedor
deploy_container() {
  print_status "Desplegando el contenedor RHEL..."
  docker run -d \
    --name "$CONTAINER_NAME" \
    -p "${HOST_PORT}:${CONTAINER_PORT}" \
    --restart unless-stopped \
    "${IMAGE_NAME}:${IMAGE_TAG}"

  print_success "Contenedor '$CONTAINER_NAME' desplegado con éxito"
}

## Función para verificar el despliegue
verify_deployment() {
  print_status "Verificando el despliegue del contenedor..."

  ## Esperar a que el contenedor se inicie
  sleep 5

  ## Verificar si el contenedor se está ejecutando
  if ! docker ps | grep -q "$CONTAINER_NAME"; then
    print_error "El contenedor no se está ejecutando"
    docker logs "$CONTAINER_NAME"
    exit 1
  fi

  ## Verificar si el servicio web está respondiendo
  print_status "Probando el servicio web..."
  for i in {1..10}; do
    if curl -s "http://localhost:${HOST_PORT}" > /dev/null; then
      print_success "El servicio web está respondiendo"
      break
    fi
    if [ $i -eq 10 ]; then
      print_error "El servicio web no responde después de 10 intentos"
      exit 1
    fi
    sleep 2
  done
}

## Función para mostrar la información del despliegue
show_deployment_info() {
  print_success "=== Despliegue del Contenedor RHEL Completado ==="
  echo "Nombre del Contenedor: $CONTAINER_NAME"
  echo "Imagen: ${IMAGE_NAME}:${IMAGE_TAG}"
  echo "Mapeo de Puertos: ${HOST_PORT}:${CONTAINER_PORT}"
  echo "URL de Acceso: http://localhost:${HOST_PORT}"
  echo ""
  print_status "Estado del Contenedor:"
  docker ps | grep "$CONTAINER_NAME"
  echo ""
  print_status "Contenido de Ejemplo:"
  curl -s "http://localhost:${HOST_PORT}" | head -2
}

## Proceso principal de despliegue
main() {
  echo "=== Despliegue Automatizado del Contenedor RHEL ==="
  echo "Este script automatiza el despliegue del contenedor RHEL"
  echo "Similar a la automatización de Kickstart para instalaciones tradicionales"
  echo ""

  check_docker
  build_image
  cleanup_existing
  deploy_container
  verify_deployment
  show_deployment_info

  print_success "El despliegue automatizado del contenedor RHEL se completó con éxito!"
}

## Manejar los argumentos del script
case "${1:-deploy}" in
  "deploy" | "")
    main
    ;;
  "cleanup")
    print_status "Limpiando el despliegue..."
    cleanup_existing
    docker rmi "${IMAGE_NAME}:${IMAGE_TAG}" 2> /dev/null || true
    print_success "Limpieza completada"
    ;;
  "status")
    docker ps | grep "$CONTAINER_NAME" || print_warning "Contenedor no en ejecución"
    ;;
  *)
    echo "Uso: $0 [deploy|cleanup|status]"
    echo "  deploy  - Construir y desplegar el contenedor RHEL (por defecto)"
    echo "  cleanup - Detener el contenedor y eliminar la imagen"
    echo "  status  - Mostrar el estado del contenedor"
    exit 1
    ;;
esac

Guarde el archivo y salga de nano (Ctrl+X, luego Y, luego Enter).

Comprender la Estructura del Script de Despliegue

Antes de ejecutar el script, comprendamos cómo funciona este script de automatización. Esta sección proporciona una explicación detallada de cada componente, lo que facilita que los principiantes comprendan los conceptos de scripting de shell y automatización de contenedores.

Encabezado del Script y Manejo de Errores

#!/bin/bash
set -e ## Salir ante cualquier error
  • #!/bin/bash: Esto se llama "shebang" - le dice al sistema que use el shell Bash para ejecutar este script
  • set -e: Esto hace que el script salga inmediatamente si algún comando falla, asegurando que el script se detenga en el primer error en lugar de continuar con un estado potencialmente roto

Variables de Configuración

## Variables de configuración
IMAGE_NAME="rhel9-automated"
IMAGE_TAG="latest"
CONTAINER_NAME="rhel9-production"
HOST_PORT="8080"
CONTAINER_PORT="8080"
DOCKERFILE="rhel9-automated.dockerfile"

Estas variables definen todos los parámetros clave para nuestro despliegue. Al colocarlos en la parte superior, podemos modificar fácilmente la configuración del despliegue sin cambiar la lógica del script. Esto es similar a cómo los archivos Kickstart usan parámetros de configuración.

Sistema de Salida Amigable para el Usuario

## Códigos de color para la salida
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' ## Sin Color

## Función para imprimir salida coloreada
print_status() {
  echo -e "${BLUE}[INFO]${NC} $1"
}

Esto crea un sistema de registro profesional con salida coloreada:

  • \033[0;31m: Códigos de escape ANSI para colores (31 = rojo, 32 = verde, etc.)
  • echo -e: La bandera -e habilita la interpretación de escapes de barra invertida para colores
  • $1: Se refiere al primer argumento pasado a la función

Funciones Principales de Despliegue

1. Verificación del Entorno Docker

check_docker() {
  print_status "Verificando la disponibilidad de Docker..."
  if ! docker info > /dev/null 2>&1; then
    print_error "Docker no se está ejecutando o no es accesible"
    exit 1
  fi
  print_success "Docker está disponible"
}
  • docker info > /dev/null 2>&1: Ejecuta docker info y redirige tanto la salida (>) como los errores (2>&1) a /dev/null (los descarta)
  • !: Niega el resultado - si docker info falla (devuelve un valor distinto de cero), la condición se vuelve verdadera
  • Esto es equivalente a verificar si la virtualización está disponible en los despliegues tradicionales de VM

2. Función de Construcción de Imagen

build_image() {
  print_status "Construyendo la imagen del contenedor RHEL..."
  if [ ! -f "$DOCKERFILE" ]; then
    print_error "Dockerfile '$DOCKERFILE' no encontrado"
    exit 1
  fi

  docker build -t "${IMAGE_NAME}:${IMAGE_TAG}" -f "$DOCKERFILE" .
  print_success "Imagen '${IMAGE_NAME}:${IMAGE_TAG}' construida con éxito"
}
  • [ ! -f "$DOCKERFILE" ]: Verifica si el Dockerfile NO existe (! niega, -f verifica la existencia del archivo)
  • docker build -t: Crea una imagen de contenedor con una etiqueta (nombre:versión)
  • Esto reemplaza el proceso de instalación tradicional desde medios ISO

3. Función de Limpieza

cleanup_existing() {
  print_status "Verificando la existencia de un contenedor..."
  if docker ps -a | grep -q "$CONTAINER_NAME"; then
    print_warning "Deteniendo y eliminando el contenedor existente '$CONTAINER_NAME'"
    docker stop "$CONTAINER_NAME" > /dev/null 2>&1 || true
    docker rm "$CONTAINER_NAME" > /dev/null 2>&1 || true
  fi
}
  • docker ps -a | grep -q: Enumera todos los contenedores y busca silenciosamente nuestro nombre de contenedor
  • || true: Asegura que el comando siempre tenga éxito (devuelve 0) incluso si el contenedor no existe
  • Esto evita conflictos con despliegues existentes

4. Despliegue del Contenedor

deploy_container() {
  print_status "Desplegando el contenedor RHEL..."
  docker run -d \
    --name "$CONTAINER_NAME" \
    -p "${HOST_PORT}:${CONTAINER_PORT}" \
    --restart unless-stopped \
    "${IMAGE_NAME}:${IMAGE_TAG}"

  print_success "Contenedor '$CONTAINER_NAME' desplegado con éxito"
}
  • -d: Ejecuta el contenedor en modo desasociado (segundo plano)
  • -p "${HOST_PORT}:${CONTAINER_PORT}": Mapea el puerto del host al puerto del contenedor
  • --restart unless-stopped: Reinicia automáticamente el contenedor si se detiene (excepto paradas manuales)
  • \: Carácter de continuación de línea para comandos de varias líneas

5. Verificación del Estado

verify_deployment() {
  print_status "Verificando el despliegue del contenedor..."

  ## Esperar a que el contenedor se inicie
  sleep 5

  ## Verificar si el contenedor se está ejecutando
  if ! docker ps | grep -q "$CONTAINER_NAME"; then
    print_error "El contenedor no se está ejecutando"
    docker logs "$CONTAINER_NAME"
    exit 1
  fi

  ## Verificar si el servicio web está respondiendo
  print_status "Probando el servicio web..."
  for i in {1..10}; do
    if curl -s "http://localhost:${HOST_PORT}" > /dev/null; then
      print_success "El servicio web está respondiendo"
      break
    fi
    if [ $i -eq 10 ]; then
      print_error "El servicio web no responde después de 10 intentos"
      exit 1
    fi
    sleep 2
  done
}
  • {1..10}: Expansión de llaves de Bash - crea la secuencia 1, 2, 3... 10
  • curl -s: Modo silencioso de solicitud HTTP
  • break: Sale del bucle temprano cuando el servicio responde
  • Esto implementa un mecanismo de reintento con tiempo de espera

Interfaz de Línea de Comandos

case "${1:-deploy}" in
  "deploy" | "")
    main
    ;;
  "cleanup")
    print_status "Limpiando el despliegue..."
    cleanup_existing
    docker rmi "${IMAGE_NAME}:${IMAGE_TAG}" 2> /dev/null || true
    print_success "Limpieza completada"
    ;;
  "status")
    docker ps | grep "$CONTAINER_NAME" || print_warning "Contenedor no en ejecución"
    ;;
  *)
    echo "Uso: $0 [deploy|cleanup|status]"
    echo "  deploy  - Construir y desplegar el contenedor RHEL (por defecto)"
    echo "  cleanup - Detener el contenedor y eliminar la imagen"
    echo "  status  - Mostrar el estado del contenedor"
    exit 1
    ;;
esac
  • ${1:-deploy}: Expansión de parámetros - usa $1 (primer argumento) o "deploy" como predeterminado
  • Declaración case: Similar a switch/case en otros lenguajes
  • ;;: Termina cada rama del caso
  • $0: Se refiere al nombre del script en sí

Esto crea un script versátil que se puede usar para múltiples operaciones, de manera similar a cómo los administradores de sistemas usan diferentes herramientas para el despliegue, el mantenimiento y la supervisión.

Haga que el script sea ejecutable:

chmod +x deploy-rhel-container.sh

Ahora ejecute el script de despliegue automatizado para ver el proceso de automatización completo:

./deploy-rhel-container.sh

Debería ver la salida que muestra el proceso de despliegue completo:

=== Despliegue Automatizado del Contenedor RHEL ===
Este script automatiza el despliegue del contenedor RHEL
Similar a la automatización de Kickstart para instalaciones tradicionales

[INFO] Verificando la disponibilidad de Docker...
[SUCCESS] Docker está disponible
[INFO] Construyendo la imagen del contenedor RHEL...
[SUCCESS] Imagen 'rhel9-automated:latest' construida con éxito
[INFO] Verificando la existencia de un contenedor...
[INFO] Desplegando el contenedor RHEL...
[SUCCESS] Contenedor 'rhel9-production' desplegado con éxito
[INFO] Verificando el despliegue del contenedor...
[INFO] Probando el servicio web...
[SUCCESS] El servicio web está respondiendo
[SUCCESS] === Despliegue del Contenedor RHEL Completado ===
Nombre del Contenedor: rhel9-production
Imagen: rhel9-automated:latest
Mapeo de Puertos: 8080:8080
URL de Acceso: http://localhost:8080

Pruebe las diferentes opciones del script:

./deploy-rhel-container.sh status

Recorrido de la Ejecución del Script

Cuando ejecuta el script, ejecuta la siguiente secuencia automáticamente:

1. Fase de Validación del Entorno

El script primero verifica si Docker está disponible y es accesible. Esto es crucial porque el despliegue de contenedores requiere un entorno Docker en funcionamiento, de manera similar a cómo el despliegue de VM requiere un hipervisor en funcionamiento.

2. Fase de Construcción de la Imagen

El script construye una nueva imagen de contenedor a partir de su Dockerfile. Este proceso:

  • Lee el rhel9-automated.dockerfile
  • Descarga la imagen UBI9 base si aún no está presente
  • Ejecuta cada instrucción en el Dockerfile
  • Crea una nueva imagen etiquetada como rhel9-automated:latest

3. Fase de Limpieza

Antes de desplegar, el script verifica y elimina cualquier contenedor existente con el mismo nombre. Esto asegura un despliegue limpio sin conflictos de nombres.

4. Fase de Despliegue

El script crea e inicia el nuevo contenedor con:

  • Modo desasociado: El contenedor se ejecuta en segundo plano
  • Mapeo de puertos: El puerto del host 8080 se mapea al puerto del contenedor 8080
  • Política de reinicio: El contenedor se reinicia automáticamente si se detiene inesperadamente
  • Contenedor con nombre: Fácil identificación y gestión

5. Fase de Verificación

El script realiza comprobaciones de estado para asegurar un despliegue exitoso:

  • Verificación del estado del contenedor: Verifica que el contenedor se esté ejecutando
  • Verificación de la disponibilidad del servicio: Prueba la respuesta del servicio HTTP
  • Mecanismo de reintento: Intenta hasta 10 veces con intervalos de 2 segundos
  • Detección automática de fallos: Sale con error si la verificación falla

6. Fase de Visualización de la Información

Finalmente, el script muestra información completa del despliegue, incluidos los detalles del contenedor, las URL de acceso y el contenido de ejemplo.

Ejemplos de Uso Práctico

Puede usar este script de varias maneras:

Despliegue normal:

./deploy-rhel-container.sh
## o explícitamente
./deploy-rhel-container.sh deploy

Verificar el estado del despliegue:

./deploy-rhel-container.sh status

Limpiar recursos:

./deploy-rhel-container.sh cleanup

Ver la ayuda del script:

./deploy-rhel-container.sh help

Beneficios sobre los Métodos Tradicionales

Este enfoque de automatización proporciona varias ventajas en comparación con los despliegues tradicionales de Kickstart + VM:

  1. Velocidad: El inicio del contenedor es típicamente 10-100x más rápido que el arranque de la VM
  2. Eficiencia de recursos: Los contenedores comparten el kernel del host, usando menos memoria y CPU
  3. Consistencia: El mismo contenedor se ejecuta de forma idéntica en diferentes entornos
  4. Escalabilidad: Fácil de crear múltiples instancias o escalar horizontalmente
  5. Portabilidad: Puede ejecutarse en cualquier sistema con Docker instalado
  6. Control de versiones: Las imágenes de contenedor se pueden versionar y almacenar en registros

Este script de automatización demuestra cómo los despliegues RHEL modernos basados en contenedores pueden lograr el mismo nivel de automatización y consistencia que las instalaciones tradicionales de VM basadas en Kickstart, pero con los beneficios adicionales de la contenedorización, como un despliegue más rápido, una mejor utilización de los recursos y una escalabilidad más fácil en los entornos de nube modernos.

Resumen

En este laboratorio, exploró el enfoque moderno para automatizar los despliegues de Red Hat Enterprise Linux (RHEL) 9 utilizando contenedores Docker e imágenes base universales (UBI) de Red Hat. Aprendió que, si bien los despliegues tradicionales de RHEL se basaban en archivos Kickstart y máquinas virtuales, los entornos nativos de la nube modernos utilizan cada vez más RHEL en contenedores a través de imágenes UBI como redhat/ubi9.

Practicó la traducción de los conceptos tradicionales de Kickstart a la automatización de contenedores mediante la creación de Dockerfiles personalizados que definen la configuración del sistema, la instalación de paquetes, la gestión de usuarios y la configuración de servicios. En lugar de usar ksvalidator para los archivos Kickstart, aprendió a validar las configuraciones de los contenedores a través del proceso de construcción de Docker, que proporciona retroalimentación inmediata sobre la sintaxis y los errores de ejecución.

Finalmente, creó un script de automatización completo que demuestra el despliegue de contenedores de extremo a extremo, de forma similar al uso de virt-install con archivos Kickstart para la automatización de VM. Este enfoque proporciona el mismo nivel de automatización y consistencia que los métodos tradicionales, al tiempo que ofrece los beneficios de la contenedorización: un despliegue más rápido, una mejor utilización de los recursos, portabilidad y una escalabilidad más sencilla en los entornos de nube modernos.