Instalar Rails 5 y Postgres usando Docker
Referencia :
- https://blog.codeship.com/running-rails-development-environment-docker/ He hecho el ejercicio y modoficado los archivos que esta excelente guía propone para hacerlo funcionar en mi entorno de trabajo.
- Estoy ejecutando este tutorial en Mac OS Sierra V 10.12.5
- Para mas tutoriales interesantes sobre Docker visita :
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"]
# "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"
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"
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
Mejoramos el docker-compose.yml
Agregamos el volume con :
volumes:
- .:/app
- .:/app
Incorporamos Postgres, como un nuevo service en docker-compose.yml
postgres:
image: postgres:9.4
ports:
- "5432"
image: postgres:9.4
ports:
- "5432"
Y vinculamos el service app: con el postgres: agregando al final del service app lo siguiente
links:
- postgres
- 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
# 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
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
$ 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