Docker

¿Que es docker? 

Docker es un entorno virtual que corre de forma paralela al sistema operativo, el cual se usa principalmente para ejecutar entornos de programación. Docker esta conformado por imagenes y contenedores.

¿Que es una imagen? 

Una imagen es una plantilla que se usa para crear contenedores. Contiene lo necesario para que un contenedor funcione.

¿Que es un contenedor?

Un contenedor es una instancia de imagen siendo ejecutada, es basicamente un sistema operativo de bajos recursos ejecutandose en segundo plano, pero con la diferencia que usa el kernel del anfitrión y solo empaquetando las aplicaciones para su uso; es una forma de virtualizacion distinta a las maquinas virtuales, las cuales en sus imagenes vienen empaquetados tanto las aplicaciones como el kernel a utilizar. 

Docker Desktop

Docker Desktop es una maquina virtual, la cual se encuentra optimizada y corre en linux, la cual permite: 

- Ejecutar containers.
- Acceder a la red, tanto interna como externa.

Contiene las herramientas Docker Compose, CLI (command line interface), etc...; Corre en cualquier sistema operativo. Es de vital importancia instalarla para poder trabajar con Docker. Podemos ingresar en docker hub para indagar las imagenes que podemos descargar para usar de forma predeterminada en docker desktop.

Comandos utiles 

-> docker images 
Permite listar las imagenes descargadas. (Repository, Tag, Image ID, Created, Size)

-> docker pull <imageName:version> 
Permite descargar una imagen en su ultima version,... un ejemplo seria -> docker pull node la cual descarga la ultima version de la imagen de node. si queremos especificar la version agregamos dos puntos ":" y escribimos la version como ejemplo -> docker pull node:18 

Si el comando de docker pull genera alguna clase de error como el siguiente: 


Se puede solucionar con el siguiente comando 

-> docker pull --platform <platform> <imageName:version> 
La plataforma se debe consultar en el caso del chip M1 de apple es: "linux/x86_64"

-> docker image rm <imageName:tag>
Permite borrar imagenes de docker, el tag es necesario cuando tienes varias imagenes que se llamen igual, de resto no es necesario. 

Para crear un contenedor se debe tener una imagen previamente descargada. 

-> docker create <imageName> // -> docker container create <imageName>
Nos permite crear un contenedor teniendo en base el nombre de la imagen que se proporcione

-> docker ps
Nos devuelve en una tabla los contenedores que actualmente estan corriendo ( Container Id, Image, Command, Created, Status, Ports, Names), este comando no muestra los contenedores que no esten corriendo, para visualizar los que no estan corriendo en adicion a los que si estan corriendo se agrega "-a" al final del comando -> docker ps -a

-> docker stop <conatinerId>
Detiene un contenedor que se esta ejecutando

-> docker rm <nameContainer>
Elimina el contenedor que tiene por nombre nameContainer

-> docker create --name <nameContainer> <imageName>
Permite crear un contenedor con un nombre asignado teniendo en base la imagen que se proporcione

-> docker create -p<portHost:portContainer> --name <nameContainer> <imageName>

Permite crear un contenedor con un nombre asignado teniendo en base la imagen que se proporcione y adicional enlaza un puerto fisico con uno del contenedor.

-> docker create -p<portContainer> --name <nameContainer> <imageName>
Permite crear un contenedor con un nombre asignado teniendo en base la imagen que se proporcione y adicional enlaza un puerto fisico con uno del contenedor pero con la diferencia que el puerto del anfitrion es seleccionado de forma aleatoria.


-> docker logs <nameContainer>
Muestra los ultimos logs del contenedor,.. si queremos que se quede escuchando los logs se le agrega la particula --follow por ejemplo -> docker logs --follow <nameContainer>

-> docker run <imageName>
    --- Este comando busca la imagen,... si no la encuentra la descarga,.. 
    --- Crea un contenedor
    --- Inicia un contenedor
    --- Queda ejecutando el contenedor como si se hubiera agregado la particula --follow, si no quiere que se quede el log abierto se agrega la particula "-d" asi:  
    -> docker run -d <imageName>

-> docker run --name <containerName> -p<portHost:portContainer> -d <imageName>
Es una union de todos los comandos anteriores; cada vez que ejecutamos docker run creamos un contenedor distinto.

-> docker run --name <containerName> -p<portHost:portContainer> -e MONGO_INITDB_ROOT_USERNAME=<userName> -e MONGO_INITDB_ROOT_PASSWORD=<userPass> mongo
Este es un ejemplo para crear un contenedor basado en la imagen de mongo, la cual es necesario agregar usuario y contraseña, cada vez que se quiera agregar una variable de entorno se coloca antes de la variable la particula -e

-> docker create -p<portHost:portContainer> --name <containerName> --network <redName> -e MONGO_INITDB_ROOT_USERNAME=<userName> -e MONGO_INITDB_ROOT_PASSWORD=<userPass> mongo
Este es un ejemplo para crear un contenedor basado en la imagen de mongo, la cual es necesario agregar usuario y contraseña, cada vez que se quiera agregar una variable de entorno se coloca antes de la variable la particula -e adicional se agrega una vinculacion a una red para comunicar tanto este contenedor como otro creado por medio de Dockerfile

-> docker network ls
Lista todas las redes en docker

-> docker network create <redName>
Crea una red en docker

-> docker network rm <redName>
Elimina una red en docker

-> docker build -t <containerName:tag> <route>
Crear un contenedor en base a un archivo Dockerfile con el nombre, un tag y la ruta donde se encuentra el código de la aplicación 

Tomar aplicación y pasarla a un contenedor 

Para que nuestra aplicación se ejecute en un contenedor debemos crear en la raiz de los archivos un archivo llamado "Dockerfile"

Lineas utiles dentro de un Dockerfile 

/////////////////////
FROM <imageName:tag> // Crea el contenedor desde la imagen y la version dada

RUN mkdir -p /home/app // Es una ruta dentro del contenedor donde va a estar el codigo fuente de la aplicacion

COPY  . /home/app //Permite acceder a los archivos del sistema anfitrion y pegarlo en el destino

EXPOSE 3000 

CMD ["node", "<ruta>"] //Ejemplo ["/home/app/index.js"] en el caso de una aplicación en node
/////////////////////

Docker Compose 

Se agrega un archivo en la raiz del proyecto junto al Dockerfile llamado docker-compose.yml,.... esto es un ejemplo para vincular dos contenedores en una misma red, uno de la aplicacion y otro de una db en base a mongodb

/////////////////////
version: "<version-docker-compose>"
services:
    <containerName1>:
        build: .
        ports: 
            - "<portHost:portContainer>" //usualmente 300 pero puede ser otro
            - "<portHost2:portContainer2>"
        links: 
            - <containerName2>
    <containerName2>:
        image: mongo
        ports:
            - "<portHostDb:portContainerDb>" //usualmente 27017 pero puede ser otro
        environment:
            - MONGO_INITDB_ROOT_USERNAME=<userName>
            - MONGO_INITDB_ROOT_PASSWORD=<userPass>
//////////////////

Teniendo los dos archivos se usa el comando 

-> docker compose up
Construye los contenedores y los corre

-> docker compose down
Remueve los contenedores y las redes creadas con docker compose

-> docker compose -f <nameDockerFile>.yml up
el -f es para indicar que el archivo dockerfile es distinto al que usualmente usa indicando su nombre con la extension .yml 

Volumenes

Cuando ejecutamos el docker compose down o eliminamos un contenedor toda la información que este dentro de los contenedores se elimina, esto se soluciona con los volumenes los cuales están guardados en el sistema operativo anfitrión, hay tres tipos.

- Anonimos: Solo se indica la ruta
- De anfitrion o host
- Nombrado

Se ajusta en docker-compose.yml al final del archivo los volumenes en el containerName2 son solo ejemplos, se selecciona el que mas se adapte a la necesidad.

///////////////////////////////////////
version: "<version-docker-compose>"
services:
    <containerName1>:
        build: .
        ports: 
            - "<portHost:portContainer>" //usualmente 300 pero puede ser otro
            - "<portHost2:portContainer2>"
        links: 
            - <containerName2>
    <containerName2>:
        image: mongo
        ports:
            - "<portHostDb:portContainerDb>" //usualmente 27017 pero puede ser otro
        environment:
            - MONGO_INITDB_ROOT_USERNAME=<userName>
            - MONGO_INITDB_ROOT_PASSWORD=<userPass>
        volumes:
            - <volumenName>: /data/db //dirección por defecto de mongodb
            <volumenName>: /var/lib/mysql //dirección por defecto de mysql
            <volumenName>: /var/lib/postgresql/data //dirección por defecto de postgres
 volumes:
    <volumenName>:
///////////////////////////////////////

De esta forma persisten los archivos asi se eliminen los contenedores y al subirlos nuevamente

DockerFile.dev

Se puede agilizar el desarrollo configurando un distinto entorno de programación que escuche los cambios en los archivos de desarrollo. Se crea el archivo Dockerfile.dev, copiando y pegando el mismo código del Dockerfile

/////////////////////
FROM <imageName:tag> // Crea el contenedor desde la imagen y la version dada

RUN npm i -g nodemon // Herramienta para detectar cambios
RUN mkdir -p /home/app // Es una ruta dentro del contenedor donde va a estar el codigo fuente de la aplicacion

WORKDIR /home/app. //Vamos a estar trabajando en esa ruta

COPY  . /home/app //Permite acceder a los archivos del sistema anfitrión y pegarlo en el destino (ya no es necesario este comando en este archivo)

EXPOSE 3000 

CMD ["nodemon", "<archivo>"] //ya no es necesario la ruta
/////////////////////

Creado este archivo se crea uno docker-compose-dev.yml

///////////////////////////////////////
version: "<version-docker-compose>"
services:
    <containerName1>:
        build: 
            context: .
            dockerfile: Dockerfile.dev. // Indicamos el archivo Dockerfile que va a usar para construir el contenedor
        ports: 
            - "<portHost:portContainer>" //usualmente 300 pero puede ser otro
            - "<portHost2:portContainer2>"
        links: 
            - <containerName2>
        volumes:
            - .:/home/app. //De esta forma enlazamos lo que hacemos para que se actualice de forma dinamica en el contenedor
    <containerName2>:
        image: mongo
        ports:
            - "<portHostDb:portContainerDb>" //usualmente 27017 pero puede ser otro
        environment:
            - MONGO_INITDB_ROOT_USERNAME=<userName>
            - MONGO_INITDB_ROOT_PASSWORD=<userPass>
        volumes:
            - <volumenName>: /data/db //dirección por defecto de mongodb
            - <volumenName>: /var/lib/mysql //dirección por defecto de mysql
            - <volumenName>: /var/lib/postgresql/data //dirección por defecto de postgres
 volumes:
    <volumenName>:
///////////////////////////////////////

se usa el comando  -> docker compose -f docker-compose-dev.yml up

De esta forma cuando modificamos el archivo se actualiza automaticamente el contenedor sin necesidad de subir y bajar contenedores

Enlaces de interes:

Comentarios

Entradas populares de este blog