Si desarrolla activamente una aplicación, usando Docker, puede simplificar su flujo de trabajo y el proceso de implementación de su aplicación para producción. El trabajo con contenedores en tareas de desarrollo tiene los siguientes beneficios:
A través de este tutorial, verá la forma de configurar un entorno de desarrollo para una aplicación de Node.js usando Docker. Creará dos contenedores: uno para la aplicación de Node y otro para la base de datos de MongoDB, con Docker Compose. Debido a que esta aplicación funciona con Node y MongoDB, nuestra configuración realizará lo siguiente:
Al finalizar este tutorial, contará con una aplicación de información sobre tiburones en funcionamiento en contenedores de Docker:
Para seguir este tutorial, necesitará lo siguiente:
sudo
y un firewall activo. Para obtener información sobre cómo configurarlos, consulte esta guía de configuración inicial para servidores.El primer paso para crear esta configuración será clonar el código del proyecto y modificar su archivo package.json
, que incluye las dependencias del proyecto. Añadiremos nodemon
a devDependencies
del proyectoy especificaremos que lo utilizaremos durante el desarrollo. Ejecutar la aplicación con nodemon
garantiza que se reiniciará automáticamente cuando realice cambios en su código.
Primero, clone el repositorio nodejs-mongo-mongoose
desde la cuenta de GitHub de la comunidad de DigitalOcean. Este repositorio incluye el código de la configuración descrita en el artículo Cómo integrar MongoDB con su aplicación de Node, en el que se explica la manera de integrar una base de datos de MongoDB con una aplicación de Node existente usando Mongoose.
Clone el repositorio en un directorio llamado node_project
:
- git clone https://github.com/do-community/nodejs-mongo-mongoose.git node_project
Diríjase al directorio node_project
:
- cd node_project
Abra el archivo package.json
del proyecto usando nano
o su editor favorito:
- nano package.json
Debajo de las dependencias del proyecto y encima de la llave de cierre, cree un nuevo objeto devDependencies
que incluya nodemon
:
...
"dependencies": {
"ejs": "^2.6.1",
"express": "^4.16.4",
"mongoose": "^5.4.10"
},
"devDependencies": {
"nodemon": "^1.18.10"
}
}
Guarde y cierre el archivo cuando haya terminado de editar.
Una vez que se implemente el código del proyecto y se modifiquen sus dependencias, podrá proceder a refactorizar el código para un flujo de trabajo en contenedor.
Modificar nuestra aplicación para un flujo de trabajo en contenedores implica hacer que nuestro código sea más modular. Los contenedores ofrecen portabilidad entre entornos, y nuestro código debería reflejar esto manteniendo un nivel de disociación lo más alto posible respecto del sistema operativo subyacente. A fin de lograr esto, refactorizaremos nuestro código para hacer un mayor uso de la propiedad process.env de Node, que muestra un objeto con información sobre su entorno de usuario en el tiempo de ejecución. Podemos usar este objeto en nuestro código para asignar de forma dinámica información de la configuración en el tiempo de ejecución con variables de entorno.
Comenzaremos con apps.js
, nuestro punto de entrada principal para la aplicación. Abra el archivo:
- nano app.js
Dentro, verá una definición para una constante port
, además de una función listen
que utiliza esta constante para especificar el puerto en el que la aplicación escuchará.
...
const port = 8080;
...
app.listen(port, function () {
console.log('Example app listening on port 8080!');
});
Redefiniremos la constante port
para permitir la asignación dinámica en el tiempo de ejecución usando el objeto process.env
. Realice los siguientes cambios en la definición de la constante y la función listen
:
...
const port = process.env.PORT || 8080;
...
app.listen(port, function () {
console.log(`Example app listening on ${port}!`);
});
Con nuestra nueva definición de la constante, port
se asigna de forma dinámica usando el valor transmitido en el tiempo de ejecución o 8080
. De modo similar, reescribimos la función listen
para que use un literal de plantilla que interpolará el valor del puerto al escuchar conexiones. Debido a que asignaremos nuestros puertos en otra parte, estas revisiones evitarán que debamos revisar continuamente este archivo a medida que nuestro entorno cambie.
Una vez que finalice la edición, guarde y cierre el archivo.
A continuación, modificaremos la información de conexión de nuestra base de datos para eliminar cualquier credencial de configuración. Abra el archivo db.js
, que contiene esta información:
- nano db.js
Actualmente, el archivo hace lo siguiente:
mongoose.connect
.Para obtener más información sobre el archivo, consulte el paso 3 de Cómo integrar MongoDB con su aplicación de Node.
Nuestro primer paso para modificar el archivo será redefinir las constantes que incluyan información confidencial. Actualmente, estas constantes tendrán este aspecto:
...
const MONGO_USERNAME = 'sammy';
const MONGO_PASSWORD = 'your_password';
const MONGO_HOSTNAME = '127.0.0.1';
const MONGO_PORT = '27017';
const MONGO_DB = 'sharkinfo';
...
En vez de realizar una codificación rígida de esta información, puede usar el objeto process.env
a fin de capturar los valores del tiempo de ejecución para estas constantes: Modifique el bloque para que tenga este aspecto:
...
const {
MONGO_USERNAME,
MONGO_PASSWORD,
MONGO_HOSTNAME,
MONGO_PORT,
MONGO_DB
} = process.env;
...
Guarde y cierre el archivo cuando haya terminado de editar.
En este punto, habrá modificado db.js
para que funcione con las variables de entorno de su aplicación, pero aún necesita una forma de pasar estas variables a su aplicación. Crearemos un archivo .env
con valores que pueda pasar a su aplicación en el tiempo de ejecución.
Abra el archivo:
- nano .env
Este archivo incluirá la información que eliminó de db.js
: el nombre de usuario y la contraseña para la base de su aplicación, además del ajuste del puerto y el nombre de la base de datos. Recuerde actualizar el nombre de usuario, la contraseña y el nombre de la base de datos que se muestran aquí con su propia información:
MONGO_USERNAME=sammy
MONGO_PASSWORD=your_password
MONGO_PORT=27017
MONGO_DB=sharkinfo
Tenga en cuenta que eliminamos el ajuste de host que originalmente aparecía en db.js
. Ahora definiremos nuestro host a nivel del archivo de Docker Compose, junto con información adicional sobre nuestros servicios y contenedores.
Guarde y cierre este archivo cuando concluya la edición.
Debido a que su archivo .env
contiene información confidencial, le convendrá asegurarse de que se incluya en los archivos .dockerignore
y .gitignore
de su proyecto para que no realice copias al control de su versión o a los contenedores.
Abra su archivo .dockerignore
:
- nano .dockerignore
Añada la siguiente línea a la parte inferior del archivo:
...
.gitignore
.env
Guarde y cierre el archivo cuando haya terminado de editar.
El archivo .gitignore
de este repositorio ya incluye .env,
pero verifique que esté allí:
- nano .gitignore
...
.env
...
En este punto, habrá extraído correctamente la información confidencial del código de su proyecto y tomado medidas para controlar la forma y la ubicación en que se copia esta información. Ahora, podrá aportar más solidez al código de conexión de su base de datos a fin de optimizarlo para un flujo de trabajo en contenedor.
Nuestro siguiente paso será hacer que el método de conexión de nuestra base de datos sea más sólido añadiendo código que gestione los casos en los que nuestra aplicación no se conecte con nuestra base de datos. Sumar este nivel de resistencia al código de su aplicación es una práctica recomendada cuando se trabaja con contenedores usando Compose.
Abra db.js
para editarlo:
- nano db.js
Verá el código que añadimos antes, junto con la constante url
para la URI de conexión de Mongo y el método connect
de Mongoose:
...
const {
MONGO_USERNAME,
MONGO_PASSWORD,
MONGO_HOSTNAME,
MONGO_PORT,
MONGO_DB
} = process.env;
const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;
mongoose.connect(url, {useNewUrlParser: true});
Actualmente, nuestro método connect
acepta una opción que indica a Mongoose que utilice el nuevo analizador de URL de Mongo. Añadiremos algunas opciones más a este método para definir parámetros para intentos de reconexión. Podemos hacer esto creando una constante options
que incluya la información pertinente, además de usar la opción del nuevo analizador de URL. En sus constantes de Mongo, añada la siguiente definición para una constante options
:
...
const {
MONGO_USERNAME,
MONGO_PASSWORD,
MONGO_HOSTNAME,
MONGO_PORT,
MONGO_DB
} = process.env;
const options = {
useNewUrlParser: true,
reconnectTries: Number.MAX_VALUE,
reconnectInterval: 500,
connectTimeoutMS: 10000,
};
...
La opción reconnectTries
indica a Mongoose que siga intentando establecer conexión indefinidamente, mientras que reconnectInterval
define el período entre los intentos de conexión en milisegundos. connectTimeoutMS
define 10 segundos como el período que el controlador de Mongo esperará antes de que falle el intento de conexión.
Ahora podemos usar la nueva constante options
en el método connect
de Mongoose para ajustar nuestra configuración de conexión de Mongoose. También añadiremos una promesa para manejar los posibles errores de conexión.
En este momento, el método conn
ect de Mongoose tiene este aspecto:
...
mongoose.connect(url, {useNewUrlParser: true});
Elimine el método connect
existente y sustitúyalo por el siguiente código, que incluye la constante options
y una promesa:
...
mongoose.connect(url, options).then( function() {
console.log('MongoDB is connected');
})
.catch( function(err) {
console.log(err);
});
En caso de que la conexión se realice correctamente, nuestra función registrará un mensaje correspondiente; de lo contrario, aplicará catch
al error y lo registrará para que podamos resolverlo.
El archivo terminado tendrá este aspecto:
const mongoose = require('mongoose');
const {
MONGO_USERNAME,
MONGO_PASSWORD,
MONGO_HOSTNAME,
MONGO_PORT,
MONGO_DB
} = process.env;
const options = {
useNewUrlParser: true,
reconnectTries: Number.MAX_VALUE,
reconnectInterval: 500,
connectTimeoutMS: 10000,
};
const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;
mongoose.connect(url, options).then( function() {
console.log('MongoDB is connected');
})
.catch( function(err) {
console.log(err);
});
Guarde y cierre el archivo cuando concluya la edición.
Con esto, habrá añadido resistencia al código de su aplicación para gestionar los casos en los cuales fuera posible que esta no pudiera establecer conexión con su base de datos. Una vez establecido este código, puede proceder a definir sus servicios con Compose.
Una vez refactorizado su código, estará listo para escribir el archivo docker-compose.yml
con las definiciones de su servicio. Un servicio en Compose es un contenedor en ejecución y las definiciones del servicio, que incluirá en su archivo docker-compose.yml
, contienen información sobre cómo se ejecutará cada imagen del contenedor. La herramienta Compose le permite definir varios servicios para crear aplicaciones en diferentes contenedores.
Antes de definir nuestros servicios, sin embargo, añadiremos una herramienta a nuestro proyecto llamada wait-for
para garantizar que nuestra aplicación solo intente establecer conexión con nuestra base de datos una vez que las tareas de inicio de esta última se completen. Esta secuencia de comandos utiliza netcat
para determinar, mediante un sondeo, si un host y puerto específicos aceptan conexiones TCP o no. Usarla le permite controlar los intentos que su aplicación realiza para establecer conexión con su base de datos determinando, mediante una prueba, si la base de datos está lista o no para aceptar conexiones.
Aunque Compose le permite especificar dependencias entre los servicios usando la opción depends_on
, esta orden se basa más en el hecho que el contenedor se ejecute o no que en el hecho de que esté preparado. Usar depends_on
no será la mejor opción para nuestra configuración, pues queremos que nuestra aplicación se conecte solo cuando las se completen tareas de la base de datos, incluida la de añadir usuario y contraseña a la base de datos de autenticación de admin
. Para obtener más información sobre cómo usar wait-for
y otras herramientas para controlar la orden de inicio, consulte las recomendaciones pertinentes en la documentación de Compose.
Abra un archivo llamado wait-for.sh
:
- nano wait-for.sh
Pegue el siguiente código en el archivo para crear la función de sondeo:
#!/bin/sh
# original script: https://github.com/eficode/wait-for/blob/master/wait-for
TIMEOUT=15
QUIET=0
echoerr() {
if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi
}
usage() {
exitcode="$1"
cat << USAGE >&2
Usage:
$cmdname host:port [-t timeout] [-- command args]
-q | --quiet Do not output any status messages
-t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout
-- COMMAND ARGS Execute command with args after the test finishes
USAGE
exit "$exitcode"
}
wait_for() {
for i in `seq $TIMEOUT` ; do
nc -z "$HOST" "$PORT" > /dev/null 2>&1
result=$?
if [ $result -eq 0 ] ; then
if [ $# -gt 0 ] ; then
exec "$@"
fi
exit 0
fi
sleep 1
done
echo "Operation timed out" >&2
exit 1
}
while [ $# -gt 0 ]
do
case "$1" in
*:* )
HOST=$(printf "%s\n" "$1"| cut -d : -f 1)
PORT=$(printf "%s\n" "$1"| cut -d : -f 2)
shift 1
;;
-q | --quiet)
QUIET=1
shift 1
;;
-t)
TIMEOUT="$2"
if [ "$TIMEOUT" = "" ]; then break; fi
shift 2
;;
--timeout=*)
TIMEOUT="${1#*=}"
shift 1
;;
--)
shift
break
;;
--help)
usage 0
;;
*)
echoerr "Unknown argument: $1"
usage 1
;;
esac
done
if [ "$HOST" = "" -o "$PORT" = "" ]; then
echoerr "Error: you need to provide a host and port to test."
usage 2
fi
wait_for "$@"
Guarde y cierre el archivo cuando termine de añadir el código.
Haga que la secuencia de comandos sea ejecutable:
- chmod +x wait-for.sh
A continuación, abra el archivo docker-compose.yml
:
- nano docker-compose.yml
Primero defina el servicio de la aplicación nodejs
agregando el siguiente código al archivo:
version: '3'
services:
nodejs:
build:
context: .
dockerfile: Dockerfile
image: nodejs
container_name: nodejs
restart: unless-stopped
env_file: .env
environment:
- MONGO_USERNAME=$MONGO_USERNAME
- MONGO_PASSWORD=$MONGO_PASSWORD
- MONGO_HOSTNAME=db
- MONGO_PORT=$MONGO_PORT
- MONGO_DB=$MONGO_DB
ports:
- "80:8080"
volumes:
- .:/home/node/app
- node_modules:/home/node/app/node_modules
networks:
- app-network
command: ./wait-for.sh db:27017 -- /home/node/app/node_modules/.bin/nodemon app.js
La definición del servicio nodejs
incluye las siguientes opciones:
build
: define las opciones de configuración, incluido el context
y dockerfile
, que se aplicarán cuando Compose cree la imagen de la aplicación. Si desea utilizar una imagen existente de un registro como Docker Hub, podría utilizar la instrucción image
como alternativa, con información sobre su nombre de usuario, repositorio y etiqueta de imagen.
context
: esto define el contexto de compilación para la compilación de la imagen; en este caso, el directorio del proyecto actual.
dockerfile
: esto especifica el Dockerfile
del directorio actual de su directorio como el archivo que Compose usará para complilar la imagen de la aplicación. Para obtener más información sobre este archivo, consulte Cómo crear una aplicación de Node.js con Docker.
image
y container_name
: aplican nombres a la imagen y al contenedor.
restart
: define la política de reinicio. El valor predeterminado es no
, pero configuramos el contenedor para reiniciarse a menos que se detenga.
env_file
: indica a Compose que deseamos añadir variables de entorno de un archivo llamado .env
, ubicado en nuestro contexto de compilación.
environment
: esta opción le permite añadir los ajustes de conexión de Mongo que definió en el archivo .env
. Tenga en cuenta que no fijaremos NODE_ENV
en development
, ya que éste es el comportamiento predeterminado de Express si NODE_ENV
no se configura. Cuando procedamos con la producción, podrá fijarlo en production
para permitir el almacenamiento de vistas en caché y recibir menos mensajes de error confusos. Observe, además, que especificamos el contenedor de la base de datos db
como host, como se explicó en el paso 2.
ports
: asigna el puerto 80
del host al puerto 8080
del contenedor.
volumes
: incluiremos dos tipos de montajes aquí:
/home/node/app
del contenedor. Esto facilitará un desarrollo rápido, ya que cualquier cambio que realice a su código de host se completará de inmediato en el contenedor.node_modules
. Cuando Docker ejecute la instrucción npm install
que se indica en el Dockerfile
de la aplicación, npm
creará en el contenedor un nuevo directorio node_modules
en el que se incluirán los paquetes necesarios para ejecutar la aplicación. El montaje de enlace que acabamos de crear ocultará, sin embargo, este directorio node_modules
recién creado. Debido a que node_modules
en el host está vacío, el bind asignará un directorio vacío al contenedor, con lo cual se anulará el nuevo directorio node_modules
y se evitará el inicio de nuestra aplicación. El volumen llamado node_modules
resuelve este problema haciendo que persista el contenido del directorio /home/node/app/node_modules
y montándolo en el contenedor, con lo cual se ocultará el enlace.Tenga en cuenta lo siguiente cuando utilice este enfoque:
node_modules
del contenedor en el host y este directorio será propiedad de root
, ya que el volumen nombrado fue creado por Docker.node_modules
preexistente en el host, anulará el directorio node_modules
creado en el contenedor. Para configuración que estamos creando en este tutorial, se supone que no dispone de un directorio node_modules
preexistente y que no trabajará con npm
en su host. Esto se ajusta a un enfoque de doce factores para el desarrollo de la aplicación, que minimiza las dependencias entre los entornos de ejecución.networks
: especifica que nuestro servicio de aplicación se unirá a la red app-network
, que definiremos al final del archivo.
command
: esta opción le permite establecer el comando que debería ejecutarse cuando Compose ejecute la imagen. Tenga en cuenta que con esto se anulará la instrucción CMD
que establecimos en el Dockerfile
de nuestra aplicación. En este caso, ejecutaremos la aplicación usando la secuencia de comandos wait-for
que sondeará el servicio db
en el puerto 27017
para probar si el servicio de la base de datos está listo o no. Una vez que esta prueba se realice, la secuencia de comandos ejecutará el comando que establecimos, /home/node/app/node_modules/.bin/nodemon app.js
, para iniciar la aplicación con nodemon
. Esto garantizará que cualquier cambio futuro que realicemos en nuestro código se recargue sin que debamos reiniciar la aplicación.
A continuación, cree el servicio db
agregando el siguiente código debajo de la definición del servicio de la aplicación:
...
db:
image: mongo:4.1.8-xenial
container_name: db
restart: unless-stopped
env_file: .env
environment:
- MONGO_INITDB_ROOT_USERNAME=$MONGO_USERNAME
- MONGO_INITDB_ROOT_PASSWORD=$MONGO_PASSWORD
volumes:
- dbdata:/data/db
networks:
- app-network
Algunos de los ajustes que definimos para el servicio nodejs
seguirán siendo los mismos, pero también realizamos los siguientes cambios en las definiciones de image
, environment
y volumes
:
image
: para crear este servicio, Compose extraerá la imagen de Mongo 4.1.8-xenial
de Docker Hub. Fijaremos una versión concreta para evitar posibles conflictos futuros a medida que la imagen de Mongo cambie. Para obtener más información sobre la fijación de la versiones, consulte la documentación de Docker en Prácticas recomendadas de Dockerfile.MONGO_INITDB_ROOT_USERNAME
, MONGO_INITDB_ROOT_PASSWORD
: la imagen de mongo
pone estas variables de entorno a disposición para que pueda modificar la inicialización de la instancia de su base de datos. MONGO_INITDB_ROOT_USERNAME
y MONGO_INITDB_ROOT_PASSWORD
crean juntos un usuario root
en la base de datos de autenticación admin
y verifican que la autenticación esté habilitada cuando se inicie el contenedor. Configuramos MONGO_INITDB_ROOT_USERNAME
y MONGO_INITDB_ROOT_PASSWORD
usando los valores de nuestro archivo .env
, que pasamos al servicio db
usando la opción env_file
. Hacer esto significa que nuestro usuario de la aplicación sammy
será un usuario root
en la instancia de la base de datos, con acceso a todos los privilegios administrativos y operativos de esa función. Cuando trabaje en producción, le convendrá crear un usuario de aplicación dedicado con privilegios de alcance correspondiente.
<$>[note]
Nota: Tenga en cuenta que estas variables no se aplicarán si inicia el contenedor con un directorio de datos existente implementado.
<$>dbdata:/data/db
: el volumen llamado dbdata
preservará los datos almacenados en /data/db
, el directorio de datos predeterminado de Mongo. Esto garantizará que no pierda datos en los casos en los que detenga o elimine contenedores.También agregamos el servcio db
a la red app-network
con la opción networks
.
Como paso final, añada las definiciones de volumen y red al final del archivo:
...
networks:
app-network:
driver: bridge
volumes:
dbdata:
node_modules:
La red de puente definida por el usuario app-network
permite la comunicación entre nuestros contenedores, ya que están en el mismo host de demonio de Docker. Esto agiliza el tráfico y la comunicación dentro de la aplicación, ya que abre todos los puertos entre contenedores en la misma red de puente y, al mismo tiempo, no expone ningún puerto al exterior. Por lo tanto, nuestros contenedores db
y nodejs
pueden comunicarse entre sí y solo debemos exponer el puerto 80
para el acceso de front-end a la aplicación.
Nuestra clave volumes
de nivel nivel superior define dbdata
y node_modules
de los volúmenes. Cuando Docker crea volúmenes, el contenido de estos se almacena en una parte del sistema de archivos host, /var/ib/docker/volume/
, que Docker administra. El contenido de cada volumen se almacena en un directorio en /var/lib/docker/volume/
y se monta en cualquier contenedor que utilice el volumen. De esta forma, los datos de la información sobre tiburones que nuestros usuarios crearán persistirán en el volumen dbdata
, incluso si eliminamos y volvemos a crear el contenedor db
.
El archivo docker-compose.yml
terminado tendrá este aspecto:
version: '3'
services:
nodejs:
build:
context: .
dockerfile: Dockerfile
image: nodejs
container_name: nodejs
restart: unless-stopped
env_file: .env
environment:
- MONGO_USERNAME=$MONGO_USERNAME
- MONGO_PASSWORD=$MONGO_PASSWORD
- MONGO_HOSTNAME=db
- MONGO_PORT=$MONGO_PORT
- MONGO_DB=$MONGO_DB
ports:
- "80:8080"
volumes:
- .:/home/node/app
- node_modules:/home/node/app/node_modules
networks:
- app-network
command: ./wait-for.sh db:27017 -- /home/node/app/node_modules/.bin/nodemon app.js
db:
image: mongo:4.1.8-xenial
container_name: db
restart: unless-stopped
env_file: .env
environment:
- MONGO_INITDB_ROOT_USERNAME=$MONGO_USERNAME
- MONGO_INITDB_ROOT_PASSWORD=$MONGO_PASSWORD
volumes:
- dbdata:/data/db
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
dbdata:
node_modules:
Guarde y cierre el archivo cuando haya terminado de editar.
Una vez implementadas las definiciones de su servicio, estará listo para iniciar la aplicación.
Una vez implementado su archivo docker-compose.yml
, puede crear sus servicios con el comando docker-compose up
. También puede comprobar que sus datos persisitirán deteniendo y eliminando sus contenedores con docker-compose down
.
Primero, compile las imágenes del contenedor y cree los servicios ejecutando docker-compose up
con el indicador -d
, que luego ejecutará los contenedores nodejs
y db
en segundo plano.
- docker-compose up -d
Verá un resultado que confirmará la creación de sus servicios:
Output...
Creating db ... done
Creating nodejs ... done
También puede obtener información más detallada sobre los procesos de inicio mostrando el resultado del registro de los servicios:
- docker-compose logs
Si todo se inició de forma correcta, verá algo similar a esto:
Output...
nodejs | [nodemon] starting `node app.js`
nodejs | Example app listening on 8080!
nodejs | MongoDB is connected
...
db | 2019-02-22T17:26:27.329+0000 I ACCESS [conn2] Successfully authenticated as principal sammy on admin
También puede verificar el estado de sus contenedores con docker-compose ps
:
- docker-compose ps
Verá un resultado que indicará que sus contenedores están en ejecución:
Output Name Command State Ports
----------------------------------------------------------------------
db docker-entrypoint.sh mongod Up 27017/tcp
nodejs ./wait-for.sh db:27017 -- ... Up 0.0.0.0:80->8080/tcp
Una vez que los servicios estén en ejecución, podrá visitar http://your_server_ip
en el navegador. Verá una página de aterrizaje similar a esta:
Haga clic en el botón Get Shark Info. Verá una página con un formulario de entrada en el que podrá introducir un nombre del tiburón y una descripción del carácter general de este:
En el formulario, agregue un tiburón que elija. A los efectos de esta demostración, añadiremos Megalodon Shark
en el campo Shark Name y Ancient
en el campo Shark Character:
Haga clic en el botón Submit. Visualizará una página con la siguiente información sobre tiburones que se le mostrará de nuevo:
Como paso final, podemos hacer una prueba para verificar que los datos que acaba de introducir persistan si elimina el contenedor de su base de datos.
Cuando regrese a su terminal, escriba el siguiente comando para detener y eliminar sus contenedores y su red:
- docker-compose down
Tenga en cuenta que no incluiremos la opción --volumes
; por lo tanto, no se eliminará nuestro volumen dbdata
.
El siguiente resultado confirma que se eliminaron sus contenedores y su red:
OutputStopping nodejs ... done
Stopping db ... done
Removing nodejs ... done
Removing db ... done
Removing network node_project_app-network
Vuelva a crear los contenedores:
- docker-compose up -d
Ahora, vuelva al formulario de información de tiburones:
Introduzca un nuevo tiburón que elija. Usaremos Whale Shark
y Large
:
Una vez que haga clic en Submit, verá que se agregó el nuevo tiburón a la colección de tiburones de su base de datos sin pérdida de datos que ya introdujo:
Su aplicación ahora se ejecuta en los contenedores de Docker con la persistencia de datos y la sincronización de códigos habilitadas.
Siguiendo este tutorial, creó una configuración de desarrollo para su aplicación de Node usando contenedores de Docker. Hizo que su proyecto fuera más modular y portátil mediante la extracción de información confidencial y la desvinculación del estado de su aplicación del código de esta. También configuró un archivo docker-compose.yml
estándar que podrá revisar a medida que sus necesidades y requisitos de desarrollo cambien.
A medida que realice desarrollos, es posible que le interese aprender más sobre cómo diseñar aplicaciones para flujos de trabajo en contenedores y de Cloud Native. Consulte Crear aplicaciones para Kubernetes y Modernizar aplicaciones para Kubernetes para obtener más información sobre estos temas.
Para obtener más información sobre el código utilizado en este tutorial, consulte Cómo crear una aplicación de Node.js con Docker y Cómo integrar MongoDB con su aplicación de Node. Para obtener información sobre cómo implementar una aplicación de Node con un proxy inverso de Nginx usando contenedores, consulte Cómo proteger una aplicación de Node.js en contenedor con Nginx, Let´s Encrypt y Docker Compose.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!