Docker En Rails - Parte 1
Published: 2022-09-08 01:26:52

Tengo tiempo escuchando acerca de Docker (en realidad años), actualmente puedo decir que se como ejecutar algunos comandos para correr aplicaciones sin problemas, sin embargo si me llegan a preguntar cosas como ¿que es una imagen?, ¿que es un contenedor?, ¿como es que se puede agregar Docker a una aplicación?, sinceramente me quedaría en blanco.

Por lo tanto durante esta serie de posts que estaré  creando a lo largo de unas cuantas semanas planeo adentrarme a su conocimiento y funcionamiento, todo esto con la finalidad de aprender y compartir como me fue en el camino de conocer esta gran herramienta que desde mi punto de vista debe ser un **"must to have"** si te encuentras en el desarrollo de software.
Así que a ti que estás leyendo  esto que si aprecias algún error o detalle házmelo saber con la finalidad de actualizar todos estos posts. Estoy empezando en este proceso de aprender Docker y puede que durante el proceso escriba una que otra **tarugada**, por lo tanto ahí te encargo.

Toda la información que vaya a estar publicando de acuerdo a este tema (Docker) estara basado en información de terceros que recopile y estudie de diversas fuentes, por lo que las siguientes entradas a recursos se van a estar actualizando según progrese en el camino.
* Libros:
  * [Docker for rails developers]
(https://pragprog.com/titles/ridocker/docker-for-rails-developers/)

## ¿Qué es Docker?
Esta es una herramienta que sirve para empaquetar y ejecutar software en pequeños entornos de pruebas (sandbox environments) conocidos como contenedores en donde se ubicara todo lo necesario para poder ejecutar nuestra aplicación.

Dado lo anterior puede surgir la pregunta ¿qué es un contenedor?, pues bien este es un entorno sandbox aislado que empaqueta todo el código y dependencias de una manera estándar; Este ambiente que proveemos cuando creamos un contenedor estara construido de varias capas con la meta de ejecutar código dentro del contenedor (una **imagen**).

Dicho lo anterior entonces en una imagen generalmente podemos configurar variables de entorno, comandos a ejecutar de algún framework o de unix, etcétera. Por lo tanto podemos definir a una imagen coloquialmente hablando como eso que nos va a servir como punto de entrada para nuestros contenedores.

Algo que debemos de tener en cuenta es la diferencia entre una máquina virtual y un contenedor.
Una máquina virtual es un sistema operativo completo funcionando de manera aislada dentro de otro sistema operativo host (el SO de nuestro equipo local), además de que cuando hablamos de una máquina virtual debemos de hacer uso de GB de nuestro equipo, memoria ram compartida, etcétera.
Un contenedor en cambio aísla el entorno de trabajo, no tiene su propio sistema operativo si no que más bien lo que hace es compartir recursos de nuestro equipo local con este.

##¿Por qué deberíamos estar utilizando Docker?
Generalmente en un equipo de desarrollo hay cambios y es algo totalmente inevitable, por lo tanto debido a estos cambios imaginemos que tenemos una gran rotación, llegando nuevos desarrolladores y cada uno de ellos debe configurar los proyectos en sus equipos; esto va a consumir tiempo debido al sistema operativo, dependencias de terceros, configuraciones, etcétera y si bien esto se lee como algo que siempre hemos estado haciendo es algo tedioso y que lamentablemente me ha tocado vivir en persona.

Aquí es cuando desde mi punto de vista siento que vale la pena aprender y utilizar Docker ya que viene a realizar una automatización de configuración e instalación a el proyecto con la finalidad de que con unos cuantos comandos ya podamos tener la aplicación ejecutándose en nuestro equipo sin detalles.

---
## Instalando Docker
Antes de proceder a adentrarnos a crear una aplicación Dockerizada necesitamos tener instalado Docker en nuestro equipo, por lo que para hacerlo podemos dirigirnos al siguiente sitio [Docker Desktop](https://docs.docker.com/desktop/) y escoger en la sección de **Download and Install** la versión que necesitemos según nuestro sistema operativo. 

Una vez que esté instalado Docker en nuestro equipo procederemos a abrir una terminal y ejecutar el siguiente comando y lo cual nos deberá arrojar lo que se muestra en la imagen posterior.

```
docker version
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bow6238in0usj263p5hk.png)

## Creando una nueva aplicación de Rails con Docker.
Para poder ejecutar un servidor de Rails en nuestro ambiente local este necesita contar con algunos requerimientos, como por ejemplos tener un intérprete de JavaScript instalado (por lo menos en la versión 6 para Rails ya en Rails 7 es otro tema), tener nuestras gemas instaladas, librerías de terceros, etcétera.

Por lo tanto empezaremos de menos a más primero conociendo cómo movernos dentro de Docker y una vez que tengamos un poco dominado conceptos y algunas características vamos a utilizar esta misma aplicación base para estar trabajando con ella en el futuro.

Procederemos entonces a crear un nuevo directorio en el lugar deseado, por ejemplo yo lo voy a crear dentro de mi escritorio con el nombre de **docker_and_rails** una vez que lo hayamos creado procederemos a entrar a el.
````
1: cd Desktop
2: mkdir docker_and_rails
3: cd docker_and_rails
```
Posteriormente vamos a iniciar una sesión interactiva en Bash con la finalidad de instalar Rails de manera adecuada, por lo tanto ejecutaremos el siguiente comando.
```
docker run -i -t --rm -v ${PWD}:/usr/src/app ruby:3.0.4-bullseye bash
```
Esto nos arrojará en terminal un output muy parecido al siguiente que enseguida vamos a explicar.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jp03wx6jfq6hvak6i8o1.png)

Primero tenemos la advertencia de que no fue posible encontrar la imagen de ruby 3.0.4 localmente y esto se debe a que no lo hemos instalado, sin embargo Docker es inteligente y sabe que debe ejecutar esta instrucción por lo tanto procede a descargar esta imagen desde las imágenes oficiales de Ruby en Docker [Ruby Images On Docker](https://hub.docker.com/_/ruby) en partes y  posteriormente después de haber descargado la imagen podremos ver que tenemos en terminal **root@0254d2520dc7** lo cual nos indica que estamos ejecutando una sesión de Bash dentro de un contenedor.

Acto seguido entraremos a el directorio que especificamos en el comando anterior para crear el nuevo proyecto de Rails.
```
root@0254d2520dc7:/# cd /usr/src/app
```
Ahora es turno de instalar dentro de este directorio la gema de Rails.
```
root@0254d2520dc7:/# gem install rails
```
Una vez que hayamos instalado la gema de Rails y todas sus dependencias hayan sido instaladas vamos a estar listos para generar nuestro proyecto.
```
root@0254d2520dc7:/# rails new theapp --skip-test --skip-bundle
```
Estamos utilizando las opciones de **skip-test - skip-bundle** debido a que posteriormente utilizaremos RSpec para configurarlo dentro de nuestro proyecto y además indicamos con este comando que no se ejecute **bundle install** después de generar nuestro proyecto.

Bueno como ahora nuestro proyecto ya fue generado es necesario recordar que estamos dentro de una sesión de Shell dentro de nuestro contenedor por lo que tendremos que salirnos con el comando **exit**.

Enseguida si ejecutamos el comando **ls** dentro del mismo directorio donde estamos (docker_and_rails) podremos apreciar que contamos con un nuevo directorio llamado **theapp** y si ingresamos a este tendremos toda la estructura básica que una aplicación de Rails necesita para poder vivir.

¿Y por qué fue que se creó este nuevo directorio en nuestro equipo local?, pues bien esto se debe a la opción **-v** dentro de en el comando **docker run** que previamente escribimos, en el lenguaje de de Docker y esta opción indica que se monte un volumen es decir compartir una porción de nuestro sistema de archivos local con el contenedor.

Por lo que **-v ${PWD}:/usr/src/app** indica montar nuestro directorio actual dentro del contenedor en **/usr/src/app**.

Cuando hablamos de montar un volumen local significa que el proyecto de Rails generado dentro del contenedor en **(/usr/src/app)** se mantiene en nuestro directorio local incluso después de que el contenedor se haya terminado. 

De esta manera todos los cambios que hagamos en nuestros archivos locales de nuestro proyecto se van a ver reflejados automáticamente dentro del contenedor.