Instalar Rails 5 y Postgres usando Docker

Referencia :

Requisitos :

  • Haber instalado ruby versión 2.2 como mínimo en tu terminal
  • Haber instalado Docker en tu estación de trabajo
  • Debes tener instalado the Command Line Developer Tools para XCode con comando  $ xcode-select --install

Hacer una app en mi estación de trabajo

Instalar la versión más reciente de rails y bundle
$ gem list --local  # Verifica que versiones de Gems tienes instalada en tu computador localmente
$ gem install rails bundle # instala versiones vigentes de rails y bundle
$ gem list --local  # Verifica que versiones de Gems tienes instalada en tu computador localmente
Crear una App base de Rails, instalar y verificar sus gems
$ rails new demo # crea una aplicación base
$ cd demo
$ bundle install # instala las gems del Gemfile
$ bundle exec rake test # Verifica que no existan errores en la instalación de Gems
$ bundle exec rails server # Inicializa Rails, puedes visitar en tu navegador http://localhost:3000

Convertir la App creada a que pueda ser Dockerizada (usada con Docker)

Crear un Dockerfile en tu carpeta de la App con los siguientes datos
cd FROM ruby:2.2
MAINTAINER galindo@untaldouglas.info
# Install apt based dependencies required to run Rails as
# well as RubyGems. As the Ruby image itself is based on a
# Debian image, we use apt-get to install those.
RUN apt-get update && apt-get install -y \
 build-essential \
 nodejs
# Configure the main working directory. This is the base
# directory used in any further RUN, COPY, and ENTRYPOINT
# commands.
RUN mkdir -p /app
WORKDIR /app
# Copy the Gemfile as well as the Gemfile.lock and install
# the RubyGems. This is a separate step so the dependencies
# will be cached unless changes to one of those two files
# are made.
COPY Gemfile Gemfile.lock ./
RUN gem install bundler && bundle install --jobs 20 --retry 5
# Copy the main application.
COPY . ./
# Expose port 3000 to the Docker host, so we can access it
# from the outside.
EXPOSE 3000
# The main command to run when the container starts. Also
# tell the Rails dev server to bind to all interfaces by
# default.
CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]
Crear nuestra image usando el Dockerfile recien editado con
$ docker build -t demo . # Crea la image llamada demo, no olvidar el punto(.) al final

Verificamos que las gems se hallan instalado sin problema en el container.
$  docker run -it demo bundle exec rake test # Ejecutamos en el Container un test con rake
Verificamos el container ejecutado interactivamente con
$ docker run -itP demo # Iniciar un container de manera interactiva en base a nuestra image demo
Aca algunas explicaciones de los comandos ejecutados :
  • docker run   ejecuta tareas en el Container Docker, se utiliza para tareas de ejecución única muy útiles en desarrollo.
  • El parametro  -itP  hace que el Container inicializado sea interactivo, y que cualquier Port no comprometido del Desktop (Host) se habilite para la instancia container(Client) que se está ejecutando
  • Si no especificamos ningún comando a ejecutar con el container, entonces se ejecutan los comandos definidos en la sentencia CMD del Dockerfile (CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"])
En otra tab de la terminal verificamos el container ejecutándose y sus datos de configuración (ID del container, port expuesto, tiempo de estar ejecutandose) con que fué creado con
  • $ docker ps
)Para verificar desde navegador la aplicación ejecutandose en el container debes visitar :
  • http://localhost:[NUM PORT USADO POR CONTAINER]
  • Si no te funciona es porque Docker no se esta ejecutando localmente (por ejemplo desde windows o Mac),  entonces debes encontrar la IP que se le asignó al container automaticamente cuando se comenzó a ejecutar con el comando :  $ docker-machine ip “${DOCKER_MACHINE_NAME}” # Usando el nombre de tu container.   y Luego visitas esa ip con el port en el navegador, ejemplo en mi caso  $ docker-machine ip ${upbeat_raman} # Docker asigna Nombres cómicos y originales a los Containers cuando no agregas el --name opttion  respectivo para asignarlo al momento de usar docker run

Algunas Mejoras al Dockerfile y entorno …..
Usar un archivo .dockerignore para especificar que files son excluidos y no son transferidos al Container durante su build.  Esto nos ayuda a optimizar el rendimiento en la construcción y arranques de containers.  Crear en la carpeta el archivo .dockerignore con esta propuesta :
.git*
db/*.sqlite3
db/*.sqlite3-journal
log/*
tmp/*
Dockerfile
README.rdoc
Usar bundle exec en Entrypoint del Dockerimage para evitar tener que estarlo agregando en cada ejecución de containers;  agregar al Dockerfile antes del último CMD  :
# Configure an entry point, so we don't need to specify
# "bundle exec" for each of our commands.
ENTRYPOINT ["bundle", "exec"]
Si necesitas en algún momento modificar esta configuración inicial de bundle exec lo puedes hacer así :
docker run -it demo "rake test"
docker run -it --entrypoint="" demo "ls -la"
Si necesitas en algún momento modificar esta configuración inicial de bundle exec lo puedes
Si quisieras agregar otros Locales configuration a tu container lo puedes hacer instalando primero los paquetes requeridos, regenerando los locales y configurando variables locales de entorno.  Agrega al Dockerfile :
# Install apt based dependencies required to run Rails as
# well as RubyGems. As the Ruby image itself is based on a
# Debian image, we use apt-get to install those.
RUN apt-get update && apt-get install -y \
 build-essential \
 locales \
 nodejs
# Use en_US.UTF-8 as our locale
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

A continuación vamos a incorporar Postgres a la instalación y usaremos para ello Docker-compose, asegurate de tenerlo instalado.  

Agregar docker-compose y Postgres

Agregar un docker-compose.yml  file a tu carpeta con :
app:
 build: .
 command: rails server -p 3000 -b '0.0.0.0'
 volumes:
   - .:/app
 ports:
   - "3000:3000"

Construimos los containers de docker-compose (es como una receta de cocina para infraestructura con containers)
# docker-compose build # Construye el container a partir de la image, se tardará dependiendo red
# docker-compose up  # inicia el container, puedes visitar tu instalación en http://localhost:3000

Mejoramos el docker-compose.yml

Agregamos el volume con :
volumes:
   - .:/app
Incorporamos Postgres, como un nuevo service en docker-compose.yml
postgres:
 image: postgres:9.4
 ports:
   - "5432"
Y vinculamos el service app:  con el postgres:  agregando al final del service app lo siguiente
links:
   - postgres

El archivo final de docker-compose.yml queda así :
# Service web server
app:
 build: .
 # Eliminamos record de web-server que se ejecutó antes por container en pids
 command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
 volumes:
   - .:/app
 ports:
   - "3000:3000"
 links:
   - postgres

# Service database server
postgres:
 image: postgres:9.4
 ports:
   - "5432"

Para acceder a la database desde nuestra app rails, usaremos las variables de entorno de Docker para los container linked con el comando
$ docker-compose build # Reconstruimos el container para aplicar los cambios hechos.
$ docker-compose run app env # Vemos todas las variables de entorno que se nos han creado
Busca principalmente estas variables :
POSTGRES_PORT_5432_TCP_ADDR=172.17.0.2
POSTGRES_PORT_5432_TCP_PORT=5432


Con estos valores podemos modificar el config/database.yml de la app rails y lograr la conexión. Así :
# dag configuración para usar postgres en lugar de mysql
# se debe haber agregado pg en Gemfile
default: &default
 adapter: postgresql
 encoding: unicode
 pool: 5
 timeout: 5000
 username: postgres
 # please see the update below about using hostnames to
 # access linked services via docker-compose
 host: <%= ENV['POSTGRES_PORT_5432_TCP_ADDR'] %>
 port: <%= ENV['POSTGRES_PORT_5432_TCP_PORT'] %>
# dag
Cambiar el Gemfile para utilizar la Gem del conector de Postgres en lugar de sqlite3 editando
# dag Ya no se utilizará
# gem 'sqlite3'
# dag
# dag utilizaremos postgres
gem 'pg'
# dag

Cada vez que se modifican el Gemfile se debe re-build la image en la que se basa el service App de Rails.  
$ docker-compose build # Reconstruimos el container para aplicar los cambios hechos.
$ docker-compose up -d
$ docker-compose run app rake db:create #
$ docker-compose run app rake db:migrate

El config/database.yml debe quedar mas o menos así :
default: &default
 adapter: postgresql
 encoding: unicode
 pool: 5
 timeout: 5000
 username: postgres
 host: postgres
 port: 5432
development:
 <<: *default
 database: app_development
test:
 <<: *default
 database: app_test
production:
 <<: *default
 database: app_production

Visitamos http://localhost:3000  y hecho !!
Cerramos los containers con
$ docker-compose down

Validemos lo que hemos hecho con otra App

Replicaremos lo que hemos hecho en otra carpeta para verificar la configuración creada en los Archivos Dockerfile,  docker-compose.yml  y  .dockerignore

Paso 1 : Inicializamos una app Rails desde tu carpeta de proyectos desarrollo
$ rails new demo2 # crea una aplicación base
$ cd demo2
$ bundle install # instala las gems del Gemfile
$ bundle exec rake test # Verifica que no existan errores en la instalación de Gems
$ bundle exec rails server # Inicializa Rails, puedes visitar en tu navegador http://localhost:3000
Paso 2 : Copiamos los archivos Dockerfile, docker-compose.yml y .dockerignore, o si ya sabes como lo subes en un Git repository y los clonas.
Paso 3 : Editas el config/database.yml así :
default: &default
 adapter: postgresql
 encoding: unicode
 pool: 5
 timeout: 5000
 username: postgres
 host: postgres
 port: 5432
development:
 <<: *default
 database: app_development
test:
 <<: *default
 database: app_test
production:
 <<: *default
 database: app_production
Paso 4 :  Editas el Gemfile para que incorpore Postgres en lugar de  sqlite3
# dag Ya no se utilizará
# gem 'sqlite3'
# dag
# dag utilizaremos postgres
gem 'pg'
# dag
Paso 5 :  Construyes y levantas con docker-compose
$ docker-compose up --build
Paso 6 :  La aplicación dará error en su ejecución porque las bases de datos no están creadas
$ docker-compose run app rake db:create
$ docker-compose run app rake db:migrate
Paso 6 : Levantar/Ejecutar los servicios nuevamente
$ docker-compose up
Paso 7 : Verificar en tu navegador,  Exito !!!  Si tienes preguntas, estoy a tus ordenes dandole seguimiento a los comentarios del Post.

Conclusiones

  • Docker es solo una de las formas en que puedes usar Ruby on Rails,  tiene en mi opinión muchas ventajas que nos facilita de una manera agil, y segura el enviar nuestro producto a entornos de producción diversos, manteniendo nuestro entorno de desarrollo lo más exacto al entorno real de producción.
  • No cargas tu computador con una serie de bibliotecas y confusiones de versiones,  una App un entorno de trabajo; sencillo, elegante y facil de gestionar.
  • Ayuda a mantener los recursos de tu equipo slim,  es decir,  no tienes que guardar las images, ni los containers que no ocupas(solo los containers que son volumes con datos, esos sí) y puedes bajar el tamaño de tu disco.

Opciones a seguir

Usar comando commit de docker así :
En mi caso específico ejecutaré $docker ps # para conocer ID de mi container y luego
$ docker commit -a "galindo@untaldouglas.info" -m "Docker con Rails V5 y Postgres 9.4" 3b8ff749c73c untaldouglas/rails5pg:v1
$ docker images # debe aparecer tu nueva image
$ docker run untaldouglas/rails5pg:v1 # iniciar un container con tu image
$ docker attach {containerID}  # para ingresar a tu container ejecutandose.
$ docker exec -it <container-id> bash


Pendientes :
  • Crear volumes para editar tu trabajo con tools de tu desktop actualizando la image.


En próximos post compartiremos la creación y edición de una App en rails sencilla para que veas el workflow de trabajo, luego haremos una excursión sobre como enviar nuestra app a la nube a un entorno de producción usando herramientas diversas como Docker cloud, Kubernetes,  y servicios como Google Cloud y AWS.











Comments

Popular posts from this blog

Guía de instalación y configuración de Elixir Phoenix en Linux Pop 21 o Ubuntu 20.04

Instalar Frappe y ErpNext usando Docker developer mode en Linux y Mac

Configurar entorno de desarrollo para Django y Postgres con VSCode plugins