No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Curso de Docker

Curso de Docker

Guido Vilariño

Guido Vilariño

Aprovechando el caché de capas para estructurar correctamente tus imágenes

21/33
Recursos

Aportes 71

Preguntas 35

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Conclusiones
Lo que conclui de esta clase es que siempre que nuestra aplicaion tenga dependencias independientemente de la tecnologia (node: npm, python: pip, php:composer) podemos serar en dos capas la intalacion de las dependencias del codigo de la aplicaion per se
Ejemplo con python

Evitar escribir todo el path para montar el bind mount

docker run --rm -p 3000:3000 -v $(pwd)/index.js:/usr/src/index.js platziapp

Comandos:
$ docker build platziapp . (creo la imagen local)
$ docker run --rm -p 3000:3000 -v pathlocal/index.js:pathcontenedor/index.js platziapp (corro un contenedor y monto el archivo index.js para que se actualice dinámicamente con nodemon que está declarado en mi Dockerfile)

La clave está en estructurar nuestro Dockerfile de manera de que primero se copien todas las dependencias y posteriormente nuestro código fuente, que es el mas suceptible a cambios.

A mí no se me actualiza automáticamente el archivo (estoy usando Windows)

Hice una imagen de docker para typescript. En resumen, copia e instala las dependencias, después hace build y copia las variables de entorno (.env), de último ejecutar el resultado de build. Estoy amando este curso y también a docker, no esperaba que me gustara tanto 😃

Solución para Windows si no les anda:

  1. Modificar el archivo “Dockerfile”:
CMD ["npx", "nodemon", "-L", "index.js"]
  1. Ir a la consola de Windows (Powershell / cmd) y tirar la build de vuelta:
$ docker build -t platziapp . 
  1. Luego en la consola tiramos esta linea de comando:
$ docker run -v C:\Users\Mahaka\Documents\GitHub\DockerPlatzi\docker\index.js:/usr/src/index.js -p 3000:3000 platziapp

Reemplazar por su usuario y la ruta de donde hicieron el git clone

De esta forma me anduvo a mi. Documentación de donde lo saque: LINK

– vamos a usar un repositorio en github

mkdir platzi && cd platzi
git clone https://github.com/platzi/docker
cd docker
nano Dockerfile

#####Dockerfile#####
FROM node:12

COPY [".", “/usr/src/”]

WORKDIR /usr/src

RUN npm install

EXPOSE 3000

CMD [“node”, “index.js”]
####################

docker build -t platziapp .
docker image ls
docker run --rm -p 3000:3000 platziapp

– usando cache
nano Dockerfile

#####Dockerfile#####
FROM node:12

COPY [“package.json”, “package-lock.json”, “/usr/src/”]

WORKDIR /usr/src

RUN npm install

COPY [".", “/usr/src/”]

EXPOSE 3000

CMD [“node”, “index.js”]
####################

docker build -t platziapp .

– probamos cambiando el codigo en index.js, cambiando de BOOM a PUM
nano index.js
docker build -t platziapp .

– queremos que nuestro contenedor se actualice cada vez que cambiamos codigo en index.js, vamos a usar un proceso propio de NODE

nano Dockerfile

#####Dockerfile#####
FROM node:14

COPY [“package.json”, “package-lock.json”, “/usr/src/”]

WORKDIR /usr/src

RUN npm install

COPY [".", “/usr/src/”]

EXPOSE 3000

CMD [“npx”, “nodemon”, “index.js”]
####################

docker build -t platziapp .

– Para no hacer un rebuild
docker run --rm -p 3000:3000 -v /root/platzi/docker/index.js:/usr/src/index.js platziapp

Si corren Docker en Windows utilicen el Flag “-L” en su CMD de su Dockerfile para que se actualicen los cambios que se realicen en el index.js si en caso tengan problemas …

CMD ["npx", "nodemon", "-L", "index.js"]    

En windows hay un inconveniente al momento de hacer el bind-mount, no se sincroniza en si y crea un carpeta alterna que termina en ;C alguien pudo solucionarlo?

Un pequeño aporte para quien tenga la misma duda que yo tuve:
El --rm hace que Docker elimine automáticamente el contenedor cuando sale del mismo.
Una joya esta clase! Este debe ser sencillamente uno de los mejores cursos que tomé en Platzi.

  • En docker, cuando se vuelve a ejecutar el comando build del dockerfile, este usa su cache sobre las capas que no han sufrido cambios, optimizando la reconstrucción de la imagen.
  • En nuestro caso podemos optimizar nuestro dockerfile de la siguiente manera. Copiando sólo los archivos necesarios para la instalación de dependencias y el resto de archivos al final.
FROM node:10
COPY ["package.json","package-lock.json","/usr/src"]
WORKDIR /usr/src
RUN npm install
COPY [".","/usr/src"]
EXPOSE 3000
CMD ["node","index.js"]

Este curso no pasa de moda y es genial… el tiempo y el ritmo como habla el profesor lo hacen todo muy agradable y fácil de entender… ojalá ese curso fuera obligatorio para los nuevos profesores de cómo se debe hablar al enseñar … Si Escuela de Desarrollo Web … es con tigo

Se puede simplificar la linea 3 y evitar tener que escribir

COPY ["package.json", "package-lock.json","/usr/src/"]

por:

# esto le dira que me copie todos los archivos que empiecen por package, seguido de lo que sea y termine en .json 
COPY ["package*.json", "/usr/src/"]

Si no quieren que el build mount pise los archivos y directorios que estan en el contenedor tambien pueden hacer un archivo .dockerignore y agregar los directorios que no quieres que se sobre-escriban por ejemplo:

.dockerignore:

node_modules

asi aun que tu escribas:

docker run -v .:/usr/src platziApp

node_modules jamas se sobre escribira

(windows)Sino les hace el cambio coloquen

CMD [“npx”, “nodemon”,"-L", “index.js”]

luego hacen el build
y lo de dan run en el CMD

Me estuve volviendo loca por un error que me salía 😰, aquí se los comparto por si alguien lo tiene.
El error era el siguiente:

[internal] load metadata for docker.io/library/node:14:
failed to solve with frontend dockerfile.v0: failed to create LLB definition: failed to authorize: rpc error: code = Unknown desc = failed to fetch oauth token: Get https://auth.docker.io/token?scope=repository%3Alibrary%2Fnode%3Apull&service=registry.docker.io: dial tcp: lookup auth.docker.io on 172.18.13.209:53: read udp 172.18.13.220:34231->172.18.13.209:53: i/o timeout

Leí algunas soluciones pero aún así no podía resolverlo 🙁, cambié todo lo que sugerían en las soluciones, pero aún así no podía.
Al final, la manera en que lo resolví fue reiniciando la computadora 👀

Layer cache: considera cada uno de los layers cuando intentamos construir una nueva, si queremos construir un layer que ya existe, docker se da cuenta y no la crea sino la asocia, haciendonos ganar tiempo

Problema: Cuando estamos en desarrollo constantemente estamos cambiando código y el problema es que debe reconstruir todo de vuelta. Pasa cuando el dockerfile no esta bien estructurado.

Solución: restructurar e dockerfile

FROM node:12

# copiar solo los archivos que se necesitan para el npm
COPY ["package.json","package-lock.json", "/usr/src/"]

# como hacer cd 
WORKDIR /usr/src

RUN npm install

# copiar todos los archivos desde build a esa ruta, como ya pasamos dos archivos package json ya no se volveran a pasar
# optimizaremos el tiempo 
COPY [".", "/usr/src/"]

# permitir que el puerto sea vinculable, se pueda acceder al contenedor mediante ese puerto
EXPOSE 3000

# comando a ejecutarse
CMD ["node", "index.js"]

Cómo hacer para no hacer build cada vez que realicemos cambios en nuestro código?

Objetivo: compartir nuestro volumen para que sea el mismo que el del contenedor.

docker run --rm -p 3000:3000 -v $(pwd)/index.js:/usr/src/index.js platziapp

Si a alguien se le presenta este error:
docker: Error response from daemon: driver failed programming external connectivity on endpoint naughty_chatterjee (19bb768bda0afe678c2cc686493eba1c2646784029806bbb9abc1e4b384d24d3): Bind for 0.0.0.0:3000 failed: port is already allocated.

Tienen que parar el contenedor anterior. Asegurense de eliminar el contenedor anterior que se lanzó antes de lanzar uno nuevo que use el mismo puerto.

La leccion es:
Copia hasta el ultimo los recursos que son mas propensos a cambiar.
Despues copia los que comunmente no se cambian, por ejemplo las dependencias no cambian tan rapido como si lo hace tu codigo.

para que aproveches el sistema de cache de docker

¿Al hacer una imagen con nuestro código fuente, no afecta que estemos cambiando nuestro código por el desarrollo a la hora de montar los contenedores?

Ejemplo hago mi imagen para desarrollar una app, pero cuando avanzo en el desarrollo que pasa con lo que hice?

Hola chicos, dejo una solución para un problema que no encontré en los comentarios:
Trabajando en Windows 10 al ejecutar el comando para crear bind mount en GIT BASH, siempre me generaba una carpeta con nombre “index.js;C”, pero al ejecutar el mismo comando desde CMD me toma bien el index.js y lo actualiza.
Los comandos utilizado fue:
GIT BASH-CMD: docker run --rm -p 3000:3000 -v “/c/Users/kevin/Platzi Docker/docker/index.js”:/usr/src/index.js platziapp
Dockerfile: CMD [“npx”, “nodemon”, “-L”, “index.js”]
Espero les sirva 😃

Una pequeña observación, no sé a que es debido, pero nodemon no está recogiendo los cambios en el fichero index.js, no se el motivo exacto Guido, pero para solucionarlo, hice los siguiente:
— Dockerfile —
CMD [“npm”,“run”, “nodemon”]

— package.json —
“nodemon”: “npx nodemon -L index.js”

… y mirando en la documentación de nodemon, dice esto al respecto del -L flag
In some networked environments (such as a container running nodemon reading across a mounted drive), you will need to use the legacyWatch: true which enables Chokidar’s polling.
Via the CLI, use either --legacy-watch or -L for short:

Interesante la utilización de la cache, queda de parte de cada quien saber que necesita para realizar cambios frecuentes o no.

Joder no me había dado cuenta de todas las imágenes que tengo y que si no pones el -t para asignarle un tag sale lo siguiente

Necesitaba esta clase para fortalecer lo visto anteriormente. Genial!

npx: installed 33 in 6.537s \[nodemon] 3.0.1 \[nodemon] to restart at any time, enter `rs` \[nodemon] watching path(s): \*.\* \[nodemon] watching extensions: js,mjs,cjs,json \[nodemon] starting `node index.js` internal/modules/cjs/loader.js:934 throw err; ^ Error: Cannot find module 'express' Require stack: \- /usr/src/index.js at Function.Module.\_resolveFilename (internal/modules/cjs/loader.js:931:15) at Function.Module.\_load (internal/modules/cjs/loader.js:774:27) at Module.require (internal/modules/cjs/loader.js:1003:19) at require (internal/modules/cjs/helpers.js:107:18) at Object.\<anonymous> (/usr/src/index.js:1:17) at Module.\_compile (internal/modules/cjs/loader.js:1114:14) at Object.Module.\_extensions..js (internal/modules/cjs/loader.js:1143:10) at Module.load (internal/modules/cjs/loader.js:979:32) at Function.Module.\_load (internal/modules/cjs/loader.js:819:12) at Function.executeUserEntryPoint \[as runMain] (internal/modules/run\_main.js:75:12) { code: 'MODULE\_NOT\_FOUND', requireStack: \[ '/usr/src/index.js' ] } \[nodemon] app crashed - waiting for file changes before starting...

Usar CMD ["npx", "nodemon", "-L", "index.js"] en el docker file

RESUMEN: A la hora de instalar dependencias, debemos separar el copiado de los archivos de referencia de la instalación (como package.json o requirements.txt, los cuales irían antes de la ejecución de npm install o pip install) del copiado del resto de los archivos de la app (los cuales irían despues de la instalación de las dependencias).
De esta manera nos ahorramos la instalación de dependencias cada vez que cambiamos algo de la app, a excepción de cuando lo que cambian son los archivos de referencia.

Si están en Linux para usar el directorio actual en consola pueden hacerlo de esta y no hacer largo el comando

docker run --rm -p 3000:3000  -v $({pwd})/index.js:/usr/src/index.js platziapp

al correr el contenedor en windows puesde usar cd para no tener que escribir la ruta completa de tu directorio
ejemplo

 docker run --rm -p 3000:3000 -v cd:/usr/src platziapp

Quiero aportar con algo y es la documentación de docker, ahi también explican todo esto
(https://docs.docker.com/language/nodejs/build-images/)

Dato curioso:
el comando

EXPOSE 3000

Solo sirve como documentacion para que lo usuario de la imagen tengan referencia. Es por eso que cuando corre un contenedor sige usando

-p 3000:3000

Psdata : Mi primer aporte en platzi

Al principio no sabía para que era necesario hacer el bind del index.js si ya se supone que en el build de la imagen se copiaban todos los archivos incluyendo el index.js

Pero no recordaba que era porque ahora se estaba corriendo nodemon y nodemon le hace es watch al index.js pero conforme se vaya actualizando en la maquina local el index.js dentro del container debería cambiar y para eso es el bind.

Aprovechando el caché de capas para estructurar correctamente tus imágenes
Comandos:
$ docker build -t platziapp . (creo la imagen local)
$ docker run --rm -p 3000:3000 -v pathlocal/index.js:pathcontenedor/index.js platziapp (corro un contenedor y monto el archivo index.js para que se actualice dinámicamente con nodemon que está declarado en mi Dockerfile)

Si no comprenden bien como funciona la estructura de Dockerfile les recomiendo que programen en python porque depende de la posición del codigo que se va a ejecutar el programa

Al usar las imagenes docker como una herramienta del proseso de desarrollo nos encontramos con el problema de que las capas son inmutables, pero nuestro código cambia constantemente, por lo que es recomendable reorganizar el Dockerfile de tal forma que las capas que menos cambios tengan sean las primeras y el codigo que cambie constantemente esté en las ultimas capas o aprovechar el manejo de volumenes

Realice la prueba de este clase y obtengo este log:

pero el problema es que al recargar el navegador no me toma el nuevo cambio de mi index.js

tengo un error en windows:
docker: Error response from daemon: Ports are not available: listen tcp 0.0.0.0:3000: bind: Intento de acceso a un socket no permitido por sus permisos de acceso.
time=“2020-11-07T16:07:59-06:00” level=error msg=“error waiting for container: context canceled”

Si están usando Windows y no detecta el cambio en index.js, cambien la ultima línea de Dockerfile por:
CMD [“npx”, “nodemon”, “–legacy-watch”, “index.js”]

cómo fue el atajo con pwd para no escribir todo el path? 9:47

interesante, el uso de bind mount, puede ahorrar builds, guardando cambios y publicandolos a la app

Una de las herramientas que nos da docker para agilizar el tiempo de trabajo, es que considera a cada uno de los layers cada vez que intentamos construir una nueva (layer cache). Es decir, si tiene que crear una nueva layer, pero ya existe en el sistema y no ha sufrido cambios, no la crea y utiliza esa. Pero si la tiene que recrear, va a invalidar las siguientes capaz también, por lo que el orden y la forma de armar el dockerfile puede influir mucho en esto. Una optimización para el dockerfile del repo sería: ```txt FROM node:12 COPY ["package.json", "package-lock.json", "/usr/src/"] WORKDIR /usr/src RUN npm install COPY [".", "/usr/src/"] # No vuelve a copiar los .json anteriores EXPOSE 3000 CMD ["node", "index.js"] ```Con esto, si cambiamos el codigo y rebuildeamos, solo a va rebuildear desde la capa del segundo COPY, y nos evitamos reinstalar dependencias. Se puede hacer también que el contenedor esté atento a los cambios del código sin tener que rebuildear, esto es muy útil para desarrollar, pero el cambio necesario depende mucho del entorno de desarrollo. Por ejemplo, para node, se utiliza nodemon, pero si desarrollaramos con fastapi, por ejemplo, el cambio sería otro. Para el caso del proyecto en node, solo haría falta cambiar la línea de CMD por la siguiente: `CMD ["npx", "nodemon", "inde.js"]` Despues de buildear, al correr el contenedor debemos ejecutar el comando run con el flag `-v` y el value `<path/to/the/project/index.js>:/usr/src/index.js` (esto solo bindea el archivo index.js, pero para el caso sirve el ejemplo)
Hola Estoy tratando de levantar el servicio con las modificaciones al DockerFile, pero aun así me tira este error., pero cuando no aplico el "Volumen" no falla. me faltara algo ? ```js $ docker run --rm -p 3000:3000 -v /home/{userName}/baseDatosExpimental/docker/index.js:/usr/src/index.js platziapp docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "/home/{userName}/baseDatosExpimental/docker/inde x.js" to rootfs at "/usr/src/index.js": mount /home/{userName}/baseDatosExpimental/docker/index.js:/usr/src/index.js (via /proc/self/fd/9), flags: 0x5000: not a directory: unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host pa th exists and is the expected type. ```
**error con monitorización** no se estresen con los que tienen **Mac M1** , la capa/el cambio: CMD \["npx","nodemon","index.js"] no funciona debido a la arquitectura ARM64.

Excelentes clases, hay teoria y practica.
Me encanta el curso

Les comparto el resumen de la clase

#Dockerfile
FROM node:12

#COPIAMOS INICIALMENTE LOS ARCHIVOS .json para aprovechar el sistema de capas y
#evitar que la imagen se invalide cada vez al hacer un build cambiando el index.js
COPY ["package.json", "package-lock.json", "/usr/src/"]

#Creamos nuestro directorio de trabajo
WORKDIR /usr/src

#Instalamos las dependencias
RUN npm install

#copiamos el resto de nuestros archivos al directorio de trabajo
COPY [".", "/usr/src/"]

#Exponemos el puerto 3000 de nuestro contenedor
EXPOSE 3000

#Nodemon , quedara atento a cualquier cambio
CMD ["npx", "nodemon", "-L", "index.js"]
#FIN Dockerfile

#Luego para crear la imagen basada en este docker file es con el siguiente comando
docker build -t platziapp .

#... Esperamos el build

#Luego para correr el contenedor con el siguiente comando.
docker run -d --rm -p 3000:3000 -v <path>\index.js:/usr/src/index.js --name app platziapp
#-d -> (detached)
#--rm -> (remove) eliminar el contenedor inmediatamente despues se pare el contenedor
#-p -> (publish) <PUERTO_HOST>:<PUERTO_CONTENEDOR> 
#-v -> (bind mount) <HOST_PATH>:<CONTAINER_PATH>

#Con la configuracion de nuestro docker file 
#y el bind mount apuntando al archivo index.js, cada vez que se haga un cambio
#en el mismo , nodemos se encargara de reiniciar el server y servir los nuevos cambios en 
#el contenedor

optimizar dockerfile, para evitar que haga procesos innecesarios cuando se cambia codigo de nuestra imagen.

Para Windows me funcionó reemplazar el pwd por %cd% quedando la línea de comando así:

docker run --rm -p 3000:3000 -v %cd%/index.js:/usr/src/index.js platziapp

Si les lanza un error referente al puerto, recuerden detener el contenedor que esté escuchando el puerto 3000 con el comando:

docker stop nombre_contenedor

Este curso envejece como el vino

Me di cuenta de que al momento de correr el build, docker mismo dice que esos pasos están cacheados

Hola!!, esta genial el curso pero a consideración de quien lo vea para el hotreload de nodemon es necesario usar command prompt en windows, en mi caso no detecto la variable de entorno ${PWD} asi que toco ponerla la ruta a mano, luego si es necesario dirigir al archivo ````index.js``` tanto en el host como en el contenedor, espero a alguien le sea util

En Ubuntu también tuve que usar -L como parametro para que haga restart en los cambios.

Recuerden en Settings compartir el directorio donde tienen el código

El orden de las instrucciones en el Docker File afecta en el uso del Cache Build, los archivos utilizados son utilizados en cada capa o generados no afectan.

A pesar de que existen librerias como watchdog/watchmedo que reflejan la funcionalidad de nodemon en Python, este último tambien permite monitorear y re-ejecutar una aplicación .py

nodemon hello.py
[nodemon] starting `python hello.py`

woaaaa magia.

Que hay bandita! Pues estuve todo el día intentando resolver el problema de nodemon en Windows, intenté varias cosas pero no fue hasta que eliminé las imágenes sin tag (por lo que investigué las “pendientes”) y volví a buildear el proyecto y ya me dejó. Tengo entendido entonces que estamos trabajando un proyecto en un entorno preacondicionado por nosotros como lo es el de este proyecto. Grandes avances!!! Cualquier cosa comenten!!! Saludos ^^ Así quedó el docker file:

FROM node:14

COPY ["package.json", "package-lock.json", "/usr/src/"]

WORKDIR /usr/src

RUN npm install

COPY [".", "/usr/src/"]

EXPOSE 3000

CMD ["npx", "nodemon", "-L", "index.js"]

En Linux también funciona el comando que usa el profesor

`pwd`

Solo deben tener la terminal Zsh con Oh-My-Zsh

hice la prueba con la versión que tengo de docker y ya utiliza el cache cuando se cambia la version de Node en el Dockerfile, al parecer ya mejoro esa parte.

Excelente contenido, muy interesante para los desarrolladores.

Puede haber una forma mas rapida de hacer el build. Para ello exportamos la variable de entorno:

export DOCKER_BUILDKIT=1

Luego hacemos el build.

Mas info aca

Si alguno de ustedes tuvo el siguiente error

docker: Error response from daemon: driver failed programming external connectivity on endpoint intelligent_mestorf (482c90a64f90008147499f38fd655c15ba2db4c5df81a6a6d12cbcde2b04a9d9): Bind for 0.0.0.0:3000 failed: port is already allocated.

al ejecutar este comando

sudo docker run --rm -p 3000:3000 -v $(pwd)/index.js:/usr/src/index.js platziapp

sigue los siguientes pasos, en linux

sudo lsof -i -P -n | grep LISTEN
sudo kill -9 PIDs  (ex. sudo kill -9 51175 51182)
sudo service docker restart 

spoiler alert: esos problemas los soluciona nuestra amigo docker-compose

Entendido

Comando . para la carpeta docker/

docker run --rm -p 3000:3000 -v (pwd)/index.js:/usr/src/index.js platziapp

optimización en el proceso de construcción de aplicación

Buena clase

😎