paint-brush
Una guía simplificada para la "Dockerazition" de Ruby y Rails con la aplicación React Front-End por@forison
347 lecturas
347 lecturas

Una guía simplificada para la "Dockerazition" de Ruby y Rails con la aplicación React Front-End

por Addo Boakye Forison13m2024/08/04
Read on Terminal Reader

Demasiado Largo; Para Leer

La dockerización implica dos conceptos clave: imágenes y contenedores. Las imágenes sirven como planos de contenedores y contienen toda la información necesaria para crear un contenedor. Un contenedor es una instancia en tiempo de ejecución de una imagen, que comprende la imagen misma, un entorno de ejecución e instrucciones en tiempo de ejecución. En este artículo, proporcionaremos una guía práctica para acoplar sus aplicaciones Rails y React en detalle.
featured image - Una guía simplificada para la "Dockerazition" de Ruby y Rails con la aplicación React Front-End
Addo Boakye Forison HackerNoon profile picture
0-item
1-item

Dockerizar su Ruby on Rails con una aplicación front-end de React puede mejorar drásticamente su flujo de trabajo de desarrollo y su proceso de implementación. Al crear un entorno estandarizado para su aplicación, garantiza un comportamiento coherente en las diferentes etapas de desarrollo, pruebas, producción e incluso en diferentes sistemas. De hecho, está diseñado para minimizar los problemas relacionados con las diferencias del sistema. Esta guía lo guiará a través de los pasos esenciales para que su aplicación Rails y React funcione sin problemas en contenedores Docker.

Docker al rescate

¿Por qué Dockerizar una aplicación?

  • Coherencia en todos los entornos :
    • Docker garantiza que la aplicación se ejecute de la misma manera independientemente de dónde se implemente, ya sea en la máquina de un desarrollador, un entorno de prueba o un servidor de producción. Esta coherencia se logra al contener todas las dependencias y configuraciones.


  • Gestión de dependencias :
    • Los contenedores Docker incluyen todas las dependencias necesarias para que se ejecute la aplicación. Esto significa que las variaciones en las bibliotecas del sistema o las dependencias faltantes en diferentes sistemas no afectan la funcionalidad de la aplicación.


  • Aislamiento :
    • Los contenedores Docker se ejecutan de forma aislada entre sí y del sistema host. Este aislamiento evita conflictos entre diferentes aplicaciones y sus dependencias en el mismo sistema.


  • Portabilidad :
    • Los contenedores Docker se pueden mover y ejecutar fácilmente en cualquier sistema que admita Docker, ya sea una máquina local, un servicio en la nube o un servidor dedicado. Esto hace que la aplicación sea muy portátil y flexible en términos de implementación.


NB: se requiere conocimiento de la sintaxis de Docker


La dockerización implica dos conceptos clave: imágenes y contenedores. Las imágenes sirven como planos para contenedores y contienen toda la información necesaria para crear un contenedor, incluidas las dependencias y las configuraciones de implementación. Un contenedor es una instancia en tiempo de ejecución de una imagen, que comprende la imagen misma, un entorno de ejecución e instrucciones en tiempo de ejecución. Docker en general establece un estándar para el envío de software.


Para explicar Docker con una analogía simple: piense en los contenedores como los contenedores de envío en un patio, las imágenes como los elementos colocados dentro de estos contenedores y el buque de envío como el sistema sobre el cual se ejecutan los contenedores.


Siempre que configura y construye su aplicación, ciertas configuraciones del entorno son necesarias. Por ejemplo, no puede ejecutar una aplicación Rails sin un entorno Ruby instalado en su sistema. De manera similar, no puede ejecutar una aplicación React sin Node.js y no puede instalar paquetes de React sin un administrador de paquetes de Node como npm o Yarn , etc.


Dado que el contenedor se ejecuta de forma aislada del sistema del usuario, haremos que todos estos paquetes estén disponibles en nuestro contenedor tal como lo habríamos hecho si lo hubiéramos creado directamente en nuestro sistema, por lo tanto, el contenedor actuará como un sistema en él. propio, como una máquina virtual. Existen diferencias entre Docker y la máquina virtual, pero este ejemplo es solo para explicarlo más.


Ahora, sigamos adelante y dockericemos la aplicación Rails. Para hacer esto, necesitaremos tres archivos en nuestra aplicación Rails: un Dockerfile , un docker-compose.yml y un bin/docker-entrypoint . Examinemos cada uno de estos archivos en detalle.


NB: se requiere conocimiento de la sintaxis de Docker

archivo acoplable

Dockerfile es un modelo para crear un contenedor Docker. Contiene una serie de instrucciones que Docker utiliza para crear una imagen, que luego se puede utilizar para ejecutar contenedores. Analicemos un Dockerfile para una aplicación Ruby on Rails y React:

. Imagen base

 ARG RUBY_VERSION=3.1.4 FROM ruby:$RUBY_VERSION
  • ARG RUBY_VERSION=3.1.4 : define un argumento de compilación denominado RUBY_VERSION con un valor predeterminado de 3.1.4 . Esto se puede anular en el momento de la compilación.


  • FROM ruby:$RUBY_VERSION : utiliza la imagen base ruby con la versión especificada por RUBY_VERSION . Esto configura el contenedor con el tiempo de ejecución de Ruby. Tal como mencioné anteriormente, para ejecutar una aplicación Rails, necesitas tener Ruby instalado.

2. Instalar dependencias

 RUN apt-get update -qq && \ apt-get install -y build-essential libvips bash bash-completion libffi-dev tzdata postgresql curl && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man
  • apt-get update -qq : actualiza la lista de paquetes de los repositorios, con -qq para una salida silenciosa.


  • apt-get install -y ... : Instala varios paquetes:
    • build-essential : paquetes esenciales para crear software (como GCC).

    • libvips : Biblioteca para procesamiento de imágenes.

    • bash , bash-completion : Bash Shell y su autocompletado.

    • libffi-dev : biblioteca de interfaz de funciones externas.

    • tzdata : datos de zona horaria.

    • postgresql : Cliente de base de datos PostgreSQL.

    • curl : Herramienta para transferir datos desde URL.


  • apt-get clean : limpia el repositorio local de archivos de paquetes recuperados.


  • rm -rf /var/lib/apt/lists/ /usr/share/doc /usr/share/man : Elimina listas de paquetes y documentación para reducir el tamaño de la imagen.

3. Instale Node.js y Yarn

 RUN curl -fsSL https://deb.nodesource.com/setup_current.x | bash - && \ apt-get install -y nodejs && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ apt-get update && \ apt-get install -y yarn
  • curl -fsSL https://deb.nodesource.com/setup_current.x | bash - : Descarga y ejecuta el script de instalación de NodeSource para instalar Node.js.


  • apt-get install -y nodejs : Instala Node.js.


  • curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - : Agrega la clave Yarn GPG para verificar sus paquetes.


  • echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list : agrega el repositorio de Yarn a la lista de fuentes.


  • apt-get update && apt-get install -y yarn : actualiza la lista de paquetes e instala Yarn.

4. Variables de entorno

 ENV NODE_OPTIONS=--openssl-legacy-provider
  • ENV NODE_OPTIONS=--openssl-legacy-provider : establece una variable de entorno para habilitar la compatibilidad con OpenSSL heredado para Node.js.

5. Establecer directorio de trabajo

 WORKDIR /rails
  • WORKDIR /rails : establece el directorio de trabajo para instrucciones posteriores en /rails .

6. Construir argumentos y variables de entorno

 ARG RAILS_ENV ENV RAILS_ENV=$RAILS_ENV
  • ARG RAILS_ENV : define un argumento de compilación llamado RAILS_ENV para especificar el entorno Rails (como development , test , production ).


  • ENV RAILS_ENV=$RAILS_ENV : establece la variable de entorno RAILS_ENV en el valor del argumento de compilación.

7. Instale gemas de aplicaciones

 COPY Gemfile Gemfile.lock ./ RUN bundle install
  • COPY Gemfile Gemfile.lock ./ : Copia Gemfile y Gemfile.lock al directorio de trabajo.


  • RUN bundle install : Instala las gemas Ruby especificadas en el Gemfile .

8. Instalar dependencias de front-end

 COPY package.json yarn.lock ./ RUN yarn install --frozen-lockfile
  • COPY package.json yarn.lock ./ : Copia el package.json y yarn.lock al directorio de trabajo.


  • RUN yarn install --frozen-lockfile : Instala las dependencias de front-end usando Yarn, asegurándose de que use las versiones exactas en yarn.lock .

9. Copiar el código de la aplicación

 COPY . .
  • COPY . . : Copia todo el código de la aplicación al directorio de trabajo.

10. Precompilar el código Bootsnap

 RUN bundle exec bootsnap precompile --gemfile app/ lib/
  • RUN bundle exec bootsnap precompile --gemfile app/ lib/ : Precompila el caché Bootsnap para tiempos de arranque más rápidos de la aplicación Rails. Bootsnap es una joya que acelera los tiempos de arranque de Ruby y Rails al almacenar en caché cálculos costosos.

11. Precompilar activos para producción

 RUN if [ "$RAILS_ENV" = "production" ]; then \ SECRET_KEY_BASE=1 bin/rails assets:precompile; \ fi
  • RUN if [ "$RAILS_ENV" = "production" ]; then ... : Ejecuta condicionalmente la precompilación de activos sólo si RAILS_ENV está configurado en production . Este paso es crucial para preparar los activos para un entorno de producción.

12. Guión de punto de entrada

 COPY bin/docker-entrypoint /rails/bin/ RUN chmod +x /rails/bin/docker-entrypoint
  • COPY bin/docker-entrypoint /rails/bin/ : copia un script de punto de entrada personalizado en el contenedor.


  • RUN chmod +x /rails/bin/docker-entrypoint : hace que el script del punto de entrada sea ejecutable.

13. Definir punto de entrada y comando

 ENTRYPOINT ["/rails/bin/docker-entrypoint"] EXPOSE 5000 // you can use any port of your choice CMD ["./bin/rails", "server"]
  • ENTRYPOINT ["/rails/bin/docker-entrypoint"] : establece el script del punto de entrada que se ejecutará cuando se inicie el contenedor. Este script normalmente configura el entorno, prepara la base de datos e inicia la aplicación.


  • EXPOSE 5000 : indica que el contenedor escucha en el puerto 5000. Esta es una función de documentación y no publica el puerto.


  • CMD ["./bin/rails", "server"] : especifica el comando predeterminado que se ejecutará cuando se inicia el contenedor, que es iniciar el servidor Rails.

docker-compose.yml

El archivo docker-compose.yml se utiliza para definir y ejecutar aplicaciones Docker de múltiples contenedores. Le permite configurar los servicios, redes y volúmenes de su aplicación en un solo archivo. En este caso vamos a utilizar dos servicios. Aquí está el archivo docker-compose.yml para la aplicación Rails:

1. Servicio de base de datos ( db )

 codedb: image: postgres:14.2-alpine container_name: demo-postgres-14.2 volumes: - postgres_data:/var/lib/postgresql/data command: "postgres -c 'max_connections=500'" environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} ports: - "5432:5432"
  • image: postgres:14.2-alpine : especifica la imagen de Docker que se utilizará para este servicio. En este caso, se trata de la imagen de PostgreSQL 14.2 basada en la distribución Alpine Linux. Las imágenes alpinas son conocidas por su pequeño tamaño, lo que puede ayudar a mantener bajo el tamaño general de la imagen.


  • container_name: demo-postgres-14.2 : nombra el contenedor demo-postgres-14.2 . Este nombre se utiliza para hacer referencia al contenedor en comandos y registros.


  • volumes :
    • postgres_data:/var/lib/postgresql/data: monta un volumen con nombre postgres_data en /var/lib/postgresql/data dentro del contenedor. Este directorio es donde PostgreSQL almacena sus datos, asegurando que los datos de la base de datos persistan entre reinicios del contenedor.


  • command: "postgres -c 'max_connections=500'" : anula el comando predeterminado de la imagen de PostgreSQL. Inicia PostgreSQL con una opción de configuración para aumentar el número máximo de conexiones a 500.


  • environment :
    • POSTGRES_DB: ${POSTGRES_DB} : establece el nombre de la base de datos predeterminada a crear, utilizando una variable de entorno POSTGRES_DB .

    • POSTGRES_USER: ${POSTGRES_USER} : establece el nombre de usuario predeterminado para acceder a la base de datos PostgreSQL, utilizando la variable de entorno POSTGRES_USER .

    • POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} : establece la contraseña para el usuario predeterminado, utilizando la variable de entorno POSTGRES_PASSWORD .


  • ports :
    • "5432:5432" : asigna el puerto 5432 en el host al puerto 5432 en el contenedor. Esto permite el acceso a PostgreSQL en la máquina host a través del puerto 5432.

2. Servicio de aplicación web ( demo-web )

 codedemo-web: build: context: . args: - RAILS_ENV=${RAILS_ENV} command: "./bin/rails server -b 0.0.0.0" environment: - RAILS_ENV=${RAILS_ENV} - POSTGRES_HOST=${POSTGRES_HOST} - POSTGRES_DB=${POSTGRES_DB} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - RAILS_MASTER_KEY=${RAILS_MASTER_KEY} volumes: - .:/rails - app-storage:/rails/storage depends_on: - db ports: - "3000:3000"
  • build:

    • context: . : Especifica el contexto de compilación para la imagen de Docker. En este caso, . se refiere al directorio actual. Esto significa que Docker utilizará el Dockerfile en el directorio actual para crear la imagen.
    • args :
      • RAILS_ENV=${RAILS_ENV} : pasa el argumento de compilación RAILS_ENV al proceso de compilación de Docker, lo que le permite especificar el entorno Rails (como development , test o production ).


  • command: "./bin/rails server -b 0.0.0.0" : anula el comando predeterminado de la imagen de Docker. Inicia el servidor Rails y lo vincula a todas las interfaces de red ( 0.0.0.0 ), lo cual es necesario para que se pueda acceder al servicio desde fuera del contenedor.


  • environment:

    • RAILS_ENV=${RAILS_ENV} : establece el entorno Rails dentro del contenedor utilizando la variable de entorno RAILS_ENV .

    • POSTGRES_HOST=${POSTGRES_HOST} : establece la dirección del host PostgreSQL.

    • POSTGRES_DB=${POSTGRES_DB} : establece el nombre de la base de datos.

    • POSTGRES_USER=${POSTGRES_USER} : establece el usuario de PostgreSQL.

    • POSTGRES_PASSWORD=${POSTGRES_PASSWORD} : establece la contraseña del usuario de PostgreSQL.

    • RAILS_MASTER_KEY=${RAILS_MASTER_KEY} : establece la clave maestra de Rails, que se utiliza para cifrar credenciales y otros secretos.


  • volumes :

    • .:/rails : monta el directorio actual (donde se encuentra el archivo docker-compose.yml ) en /rails dentro del contenedor. Esto le permite editar archivos en su host y reflejar esos cambios dentro del contenedor.

    • app-storage:/rails/storage : monta un volumen con nombre app-storage en /rails/storage dentro del contenedor. Normalmente se utiliza para almacenar archivos específicos de Rails, como registros, cargas y archivos en caché.


  • depends_on :

    • db : garantiza que el servicio demo-web espere a que el servicio db esté listo antes de comenzar. Docker Compose maneja el orden de inicio de los servicios según esta configuración.
  • ports:

    • "3000:3000" : asigna el puerto 3000 en el host al puerto 3000 en el contenedor. Esto le permite acceder a la aplicación Rails en la máquina host a través del puerto 3000.

    Volúmenes

     codevolumes: postgres_data: app-storage:
    • postgres_data : define un volumen con nombre postgres_data utilizado por el servicio db para conservar los datos de PostgreSQL.
    • app-storage : define un volumen app-storage con nombre utilizado por el servicio demo-web para conservar datos específicos de la aplicación, como cargas y registros.

punto de entrada bin/docker

El script bin/docker-entrypoint es una parte crucial de la configuración de Docker. Se ejecuta cuando se inicia el contenedor y normalmente maneja la configuración del entorno, la preparación de la base de datos y otras tareas de inicialización necesarias antes de iniciar la aplicación principal. Aquí hay un ejemplo de script bin/docker-entrypoint y una explicación detallada de cada parte:

Shebang y salida en caso de error

 bashCopy code#!/bin/bash set -e
  • #!/bin/bash : esta línea especifica que el script debe ejecutarse utilizando el shell Bash.


  • set -e : Esto indica al script que salga inmediatamente si algún comando devuelve un código de salida distinto de cero. Esto ayuda a garantizar que, si algún paso falla, el script detenga la ejecución, lo que puede evitar que los pasos posteriores se ejecuten en un estado no válido.


Creación o migración de bases de datos condicionales

 # If running the rails server then create or migrate existing database if [ "${*}" == "./bin/rails server" ]; then ./bin/rails db:create ./bin/rails db:prepare fi


  • if [ "${*}" == "./bin/rails servidor" ]; entonces... fi : esta declaración condicional verifica si el comando pasado al script ( "${*}" ) es ./bin/rails server . El * es un parámetro especial que contiene todos los parámetros posicionales pasados al script.


  • ./bin/rieles de base de datos

    : Si se cumple la condición, este comando intentará crear la base de datos. Es equivalente a ejecutar rails db:create , que configura la base de datos como se define en el archivo de configuración de la base de datos ( config/database.yml ).


  • ./bin/rieles de base de datos

    : Este comando ejecutará rails db:prepare , lo que garantiza que la base de datos esté configurada y migrada. Creará la base de datos si no existe y ejecutará migraciones si la base de datos ya está creada. Esta es una combinación de rails db:create y rails db:migrate .

    Ejecutando el proceso principal

     bashCopy codeexec "${@}"
    • exec "${@}" : esto reemplaza el proceso de shell actual con el comando pasado como argumentos al script. El símbolo @ contiene todos los parámetros posicionales pasados al script. Por ejemplo, si el script se llama con ./bin/rails server , esta línea ejecuta efectivamente ./bin/rails server como el proceso principal del contenedor.

Conclusión

Un Dockerfile bien diseñado es esencial para crear un entorno confiable y consistente para su aplicación Ruby on Rails y React. Al definir la imagen base, configurar variables de entorno e instalar dependencias, se asegura de que su aplicación se ejecute sin problemas en varios entornos.


Docker no solo agiliza su proceso de desarrollo sino que también mejora la confiabilidad de su aplicación en producción. Hay áreas de optimizaciones, pero esto es sólo una descripción general de cómo dockerizar la aplicación Rails.

Script completo para el Dockerfile resultante, docker-compose.yml y bin/docker-entrypoint

 ARG RUBY_VERSION=3.1.4 FROM ruby:$RUBY_VERSION # Install dependencies RUN apt-get update -qq && \ apt-get install -y build-essential libvips bash bash-completion libffi-dev tzdata postgresql curl && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man # Install Node.js and Yarn RUN curl -fsSL https://deb.nodesource.com/setup_current.x | bash - && \ apt-get install -y nodejs && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ apt-get update && \ apt-get install -y yarn # Set environment variable to enable legacy OpenSSL support ENV NODE_OPTIONS=--openssl-legacy-provider # Rails app lives here WORKDIR /rails # Set environment variable for the build ARG RAILS_ENV ENV RAILS_ENV=$RAILS_ENV # Install application gems COPY Gemfile Gemfile.lock ./ RUN bundle install # Install frontend dependencies COPY package.json yarn.lock ./ RUN yarn install --frozen-lockfile # Copy application code COPY . . # Precompile bootsnap code for faster boot times RUN bundle exec bootsnap precompile --gemfile app/ lib/ # Precompiling assets for production without requiring secret RAILS_MASTER_KEY RUN if [ "$RAILS_ENV" = "production" ]; then \ SECRET_KEY_BASE=1 bin/rails assets:precompile; \ fi # Entrypoint prepares the database. COPY bin/docker-entrypoint /rails/bin/ RUN chmod +x /rails/bin/docker-entrypoint # Use an absolute path for the entry point script ENTRYPOINT ["/rails/bin/docker-entrypoint"] # Start the server by default, this can be overwritten at runtime EXPOSE 5000 CMD ["./bin/rails", "server"]


 services: db: image: postgres:14.2-alpine container_name: demo-postgres-14.2 volumes: - postgres_data:/var/lib/postgresql/data command: "postgres -c 'max_connections=500'" environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} ports: - "5432:5432" demo-web: build: context: . args: - RAILS_ENV=${RAILS_ENV} command: "./bin/rails server -b 0.0.0.0" environment: - RAILS_ENV=${RAILS_ENV} - POSTGRES_HOST=${POSTGRES_HOST} - POSTGRES_DB=${POSTGRES_DB} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - RAILS_MASTER_KEY=${RAILS_MASTER_KEY} volumes: - .:/rails - app-storage:/rails/storage depends_on: - db ports: - "3000:3000" volumes: postgres_data: app-storage:



 #!/bin/bash set -e # If running the rails server then create or migrate existing database if [ "${*}" == "./bin/rails server" ]; then ./bin/rails db:create ./bin/rails db:prepare fi exec "${@}"