Docker Documentation
Docker Documentation
md 2024-11-22
Contenedor
Se crea a partir de una imagen
Las imagenes se pueden descargar de DockerHub, se conecta automaticamente.
Agregar nombre de la imagen y crear contenedor, le agregaremos como nombre "hello world"
docker images
docker ps
docker ps -a
Docker Hub
Sitio Web del repositorio
Suscripciones a Docker
Precios
Limitaciones a nivel de cuenta. Se puede trabajar de manera gratuita pero tendra sus limitaciones.
1 / 123
01-primer-contenedor.md 2024-11-22
Creo el contenedor
Comando Docker ps
docker ps -l: el último utilizado
docker ps -n 4: los últimos 4 utilizados
docker ps --help: ayuda con el comando
docker ps -a -q: saca solo el id de todos los contenedores, tambien funciona docker ps -aq
docker ps -af "name=gallant_antonelli": filtrar de todos los contenedores los que tengan el nombre
"gallant_antonelli"
Nombre a Contenedores
Se le pone el nombre ubuntu2 a la imagen ubuntu creando el contenedor ubuntu2, para tener un acceso
personalizado y no generado por defecto por docker.
Modo Interactivo
Se ingresa directo al contenedor y no lo termina, esto es muy útil en el caso de SO como Ubuntu, Fedora, etc
En algunos sistemas operativos es necesario agregar bash al final, esto debido a que sino no puede acceder a
la imagen. Para salir del contenedor se puede realizar de dos formas:
2 / 123
01-primer-contenedor.md 2024-11-22
Se arrancaría con docker start nombredelcontenedor, se puede empezar y parar con el id (solo se
necesitan las 4 primeras letras)
De esta manera el contenedor se queda en ejecución y no me hemos entrado en ningun entorno interactivo.
No todos los contenedores pueden funcionar en modo background, si el contenedor no esta preparado para
ejecutarse en modo background este se terminará.
Una forma de ponerlos en modo background es utilizarlos en modo interactivo: docker run --name
fedora4 -d -it fedora, de esta manera se logra iniciar el contenedor y este no se termina.
Tags o Etiquetas
Etiquetas para dar algún sentido a la imagen, normalmente se le coloca la versión.
docker rm 4780
En este caso 4780 se refiere a los 4 primeros números del id del contenedor a borrar
3 / 123
01-primer-contenedor.md 2024-11-22
No se pueden borrar las imagenes que esten contenidas dentro de un contenedor. Primero se debe
borrar su contenedor asociado
Comando Exec
Ejecución de comandos con los contenedores. Enfocado a contenedores interactivos y en background.
Me retorna la fecha
Comando Attach
Asociar la entrada o la salida para poder acceder de manera facil
Si el contenedor es de ubuntu y tiene asociada una bash, nos permitira asociarnos a la bash (la salida).
4 / 123
01-primer-contenedor.md 2024-11-22
Con el docker logs puedo ver que esta sacando por pantalla el contenedor, ya que se ejecuta en modo
background pero no vemos nada, con el comando podemos ver lo que esta sacando. Mostrando todo lo que
esta haciendo
Para poder mostrar los datos resumidos en los ultimos 10, podemos usar
Docker Top
Permite averiguar cual es el proceso que mas esta consumiendo dentro del contenedor.
Docker stats
Permite ver información del contenedor. Nombre, uso de CPU, uso de memoria, limite, i/o red.
Docker Inspect
Recuperar información de una imagen o un contenedor a nivel de sus propiedades
Debido a que sale mucha información y queda mas comodo guardarlo en un archivo para visualizarlo
con mas calma
Docker system
Cuenta con 4 opciones:
5 / 123
01-primer-contenedor.md 2024-11-22
Docker cp
Como podemos copiar ficheros/archivos entre un contenedor y el sistema operativo.
Local al Contenedor
#Revisar archivo
docker exec -it ubuntu10 bash
cd /tmp
ls -l ejemplo.txt
cat ejemplo.txt # visualizar archivo
Contenedor a Local
docker cp ubunuto10:/tmp/ejemplo.txt .
# . : ubicación actual
# Revisar archivo
ls -l eje*
cat ejemplo.txt
Variables
Pasando argumentos a los contenedores
6 / 123
01-primer-contenedor.md 2024-11-22
Verificar
Multiples variables
Ejemplo: MariaDB
MariaDB es un entorno que nos pide variables para funcionar, en este caso si no se las enviamos nos saltara
un error.
Se ejecuta pero se cierra debido a que no tiene los parámetros para poder funcionar correctamente. Si
revisamos los logs me dice lo siguiente:
7 / 123
01-primer-contenedor.md 2024-11-22
Ejemplo: Crear una base de datos llamada db1 con el usuario usu1
show databases;
select user from mysql.user;
Bases de datos:
Usuarios:
MYSQL_ROOT_PASSWORD=contra
MYSQL_USER=usu1
8 / 123
01-primer-contenedor.md 2024-11-22
MYSQL_DATABASE=db1
MYSQL_PASSWORD=contra1
Verificación de resultados
Bases de datos:
Redes
9 / 123
01-primer-contenedor.md 2024-11-22
Docker implementa sus propias redes virtuales para dar soporte a los distintos contenedores que queremos
lanzar
Introducción
Trabajar con puertos
Creación de redes
Enlazar contenedores
Configurandolo
Archivo nuevo:
<html>
<body>
<h1>Hello world</h1>
<p>web page created with apache container using docker</p>
<p>Instructor: Apasoft Training</p>
</body>
</html>
10 / 123
01-primer-contenedor.md 2024-11-22
Guardo con Ctrl+O confirmo y luego Ctrl+X y me salgo. Vuelvo a cargar la página en el navegador y tengo:
Pagina web
Vamos a poner una página web ya diseñada para presentarla en el navegador desde un contenedor de
apache. Primero movemos la información a la ubicación del apache.
Me sale lo siguiente:
about.html
contact.html
css
gallery.html
images
index.html
js
testimonial.html
Una vez se cargue la página del navegador se tendra la nueva página web:
11 / 123
01-primer-contenedor.md 2024-11-22
Puerto automatico Si deseo que docker se encargue de colocar el puerto, necesito usar el siguiente
comando
Lo que nos arroja: 'map[3306/tcp:{}]' Comprobando que es el puerto 3306 por lo que ahora si podriamos
usar el comando y asignarle un puerto o que este se asigne automaticamente.
Redes en Docker
Docker mantiene una arquitectura por debajo que permite gestionar las distintas redes que podemos usar
dentro de docker para conectarlas a un contenedor.
Con el comando docker network podemos obtener información sobre las redes y objetos que tenemos.
Listar redes
docker network ls
Obtenemos lo siguiente:
12 / 123
01-primer-contenedor.md 2024-11-22
redes bridge: redes privadas de la maquina que se puedan conectar a traves de la red fisica al exterior.
Red default sino le decimos lo contrario.
redes host: todos los contenedores de esa red solo pueden dialogar con el host principal, no se pueden
ver entre si. Para contenedores autonomos e independientes
redes none: con un driver null, es decir, un contenedor sin red.
podemos ver las IPAddress del contenedor y vemos que es de tipo Bridge
Podemos ver los contenedores asociados, sus subredes y algunas opciones asociadas a la red.
Debido a que le metodo bridge los mantiene conectados dentro de la misma red, podemos observar las redes
de los contenedores.
13 / 123
01-primer-contenedor.md 2024-11-22
Obteniendo lo siguiente:
Comprobar puertos:
Sino tenemos clara la información de la imagen respecto a puertos o algunos detalles extras, podemos
acceder a su detalle mediante:
14 / 123
01-primer-contenedor.md 2024-11-22
Donde podemos ver el parámetro ExposedPorts mostrandonos el puerto que tiene la imagen.
creación:
Docker recomienda que creemos nuestras propias redes, ya que los contenedores de la red van a ver sus
puertos de manera automatica entre si.
Revisamos su red
15 / 123
01-primer-contenedor.md 2024-11-22
De igual forma se enlaza a la misma red y la pone la siguiente subred, es decir, el contenedor ubuntazo tiene
la red 172.18.0.2 y el contenedor nginx4 tiene la red 172.18.0.3.
Tambien podemos asociar los contenedores a la red mediante el comando docker network.
Lo que hace es conectar el contenedor ubuntazo a la red2 ya creada. Por lo cual ahora si inspeccionamos el
contenedor vemos que tiene 2 redes, la red1 y la red2. Lo que puede conllevar a un trabajo con multiples
redes.
16 / 123
01-primer-contenedor.md 2024-11-22
Obteniendo lo siguiente:
Arrancando desde la IP 172.28.10.0, la cual fue la que prestablecimos como el inicio de las subredes con el
parametro --ip-range. Ahora si vuelvo a crear otro contenedor y enlazarlo a la red le pondra la siguiente
dirección IP 172.28.10.1.
Mostrando lo siguiente
Enlazar contenedores
17 / 123
01-primer-contenedor.md 2024-11-22
con docker ps -aq obtengo los id's de todos los contenedores y si usamos
Ejemplo:
Luego con el comando cat /etc/hosts en cualquiera de las consolas de los contenedores podemos
observar el IP y con el comando ping dirección_IP verificamos su conexión.
de tal manera que nos conectamos a b1 y le asignamos el alias maquina3 de tal manera que obtenemos lo
siguiente con el comando para revisar su IP
donde tenemos su IP propia sino tambien el enlace contra la maquina definida b1. Ahora si hacemos un ping
obtenemos:
18 / 123
01-primer-contenedor.md 2024-11-22
Sin embargo si en la máquina b1 tratamos de hacer ping b1 ya no funciona debido a que este tipo de enlace
es unidireccional por tal motivo deberíamos poner toda la dirección ip
# servidor
docker run -d --name mysql_server -p 3100:3306 -e MYSQL_ROOT_PASSORD=contra --
network red1 mysql
# cliente
docker run -d --name mysql_client -p 3101:3306 -e MYSQL_ROOT_PASSORD=contra --
network red1 mysql
# Verificar
docker inspect network red1
prueba... Docker crea una especie de DNS para que los contenedores se localicen entre si a traves del nombre.
obteniendo:
de tal manera que no es necesario usar la dirección del host sino directamente el nombre en una red
personalizada con los contenedores
19 / 123
01-primer-contenedor.md 2024-11-22
Se realizara la creación de un contenedor de mysql y a este le conectaremos un wordpress que creara su base
de datos en el mysql. Luego nos conectaremos mediante el navegador al wordpress (internamente usa
apache).
Si verificamos en los registros con docker logs wp1 evidenciamos su funcionamiento y luego nos queda
verificar en el navegador:
20 / 123
01-primer-contenedor.md 2024-11-22
El cual nos redirige a una página para la instalación del wordpress. Una vez instalado podemos revisar
rapidamente dentro del navegador iniciando sesión con las credenciales o mediante la consola:
21 / 123
01-primer-contenedor.md 2024-11-22
Redes que nos permiten que un contenedor funcione al mismo nivel de la maquina en la que se encuentra. Es
una red que no esta aislada de la maquina real, sino que hace parte de la misma.
No tiene IPv4 ni IPv6, lo que indica que el contenedor esta compartiendo el mismo namespace, en el mismo
ambito de red de la maquina.
Con el comando anterior revisando tampoco nos ofrece una IP, pero si revisamos directamente el puerto que
ofrece apache nos muestra que funciona.
Volúmenes
Almacenamiento en Docker
22 / 123
01-primer-contenedor.md 2024-11-22
Volúmenes: permite persistir información dentro de una zona gestionada por docker, dentro de una
docker area dentro de un fichero del computador
bind mount: similar a un enlace directo a un directorio, montar un directorio real que apunte a uno del
contenedor
tmpfs mounts/named Pipes: montajes en memoria, cuando no necesitamos persistir la información,
es decir, si el contenedor muere, tambien se va la información. dos tipos: tmpfs (Linux) y named pipes
(Windows)
observamos el directorio del volumen /datos. Este estará enlazado al directorio en la ruta del volumen.
Podemos comprobar esto revisando el nombre del volumen
Información de volúmenes
docker volume ls
Información de un volumen
23 / 123
01-primer-contenedor.md 2024-11-22
verificamos el volumen dentro de windows con su identificación. Para acceder a esta carpeta compartida de
wsl es necesario acceder manualmente ya que no se muestra normalmente.
Crear volúmen
24 / 123
01-primer-contenedor.md 2024-11-22
cd datos/
touch prueba.txt
y si revisamos el volumen
cd datos/
ls
y observamos el archivo prueba.txt, y podemos asociar al mismo volumen pero referenciando un volumen
enlazado y no el original
En este caso referenciamos a ubuntu5 que esta referenciando los volumenes de ubuntu4 por tal motivo
podemos observar el volumen con sus datos dentro en el directorio datos/ en la consola de ubuntu6.
Si borramos todos los contenedores asociados al volumen, el volumen quedaria disaciado y no podriamos
utilizarlo, tendria que coger la información del volumen y traspasarla al nuevo volumen para evitar este
inconveniente.
Eliminar volumen
Bind mounts
Montaje en el cual este enlazado a un directorio local en el equipo por fuera de docker.
En este caso enlazamos la ruta del directorio con un directorio dentro del contenedor. Ahora si en el equipo
creamos un archivo dentro del directorio directorio_bind_mount.
25 / 123
01-primer-contenedor.md 2024-11-22
Los directorios sino existen los crea (se deben tener permisos de creación)
Donde podemos evidenciar la información puesta en el archivo prueba.txt visto desde el contenedor.
Que nos dice que es de tipo bind, su fuente, su destino, lectura-escritura y otras propiedades mas.
TMPFS mounts
Crea almacenamiento en memoria mientras creo y uso el contenedor, si se borra el contenedor se borra la
información del contenedor. Pero si yo lo detengo y lo vuelvo a arrancar la información sigue estando, debido
a una capa de escritura que contiene el contenedor. Esto lo podemos probar en la siguiente imagen
26 / 123
01-primer-contenedor.md 2024-11-22
En el cual creamos un directorio dir1/ de tipo tmpfs y otro dir2/ sin ser tmpfs, en ambos creamos archivos
de texto, ahora si paramos y volvemos a arrancar el contenedor tenemos lo siguiente
27 / 123
01-primer-contenedor.md 2024-11-22
Observamos que los archivos dentro de dir2/ aun continuan existiendo pero los archivos dentro de dir1/ ya
no se encuentran. Han sido borrados.
Imágenes
Una imágen en Docker son una serie de capas de tipo lectura.
Algunas imagenes traen algunas configuraciones y caracteristicas por defecto, a manera de ejemplo usaremos
la imagen de ubuntu
Podemos ver las diferencias de la imagen con sus modificaciones con el comando diff
28 / 123
01-primer-contenedor.md 2024-11-22
Donde las que son A nos indican una adición, C una modificación y D una eliminación.
mi_ubuntu puede tener una etiqueta y esta basada en el contenedor ubuntu1, comprobamos con
docker images
Recordando que mi_ubuntu parte de ubuntu1 y ubuntu1 fue modificado para poder usar wget, con esto
mismo podriamos verificar su funcionalidad
Algunas de ellas tienen mas capas que otras, como por ejemplo owncloud/server tiene lo siguiente:
29 / 123
01-primer-contenedor.md 2024-11-22
donde tiene diferentes capas con una encriptación en concreto, por lo cual las imagenes parten de mas
imagenes en las cuales se van apilando y creando una serie de capas para tener una imagen mas compleja
que me permita trabajar con las caracteristicas que deseo.
evidenciamos 0 bytes de escritura ya que no lo hemos modificado y 78.1 Megabytes de lectura de la imagen
original, esto quiere decir que si creamos varias imagenes de ubuntu estos contenedores creados leeran de la
imagen que ya esta instalada en el sistema y no generaran mas peso innecesario en la maquina.
Lo que indica que ya tiene 42 MB en su capa de escritura y sigue leyendo de la capa de las imagenes, sin
embargo acá ya suma el base con el modificado. Tambien podemos mirar el total de los contenedores con -a
cd /var/lib/docker
ls -l
30 / 123
01-primer-contenedor.md 2024-11-22
#directorio image
Donde el overlay2 es el driver de almacenamiento por defecto con los ficheros que forman parte de todos
los contenedores, tambien en una carpeta anterior tenemos containers
donde tenemos los contenedores. Sin embargo, se pierde un control de los cambios y no es personalizable, es
decir, que permita crear imagenes desde cero y no apartir de otros contenedores
Dockerfile
Un fichero de instrucciones que le indica a Docker como queremos construir una imagen.
FROM ubuntu
La imagen padre puede ser scratch (imagen ligera sin sistema), o alguna imagen en concreto
31 / 123
01-primer-contenedor.md 2024-11-22
En este caso se le coloca la bandera -y debido a que no permite la interactividad con el usuario, entonces por
defecto ya le especificamos el Si para que continue con la instalación de python3 en este caso.
Ahora para correr la imagen nos movemos a la ubicación y ejecutamos docker build
-t indica una etiqueta que le agregaremos a la imagen, el . indica que es en la ubicación actual.
Se va retornando la serie de pasos que va ejecutando. Ahora si revisamos las imagenes con docker images
Revisamos que si construyo la imagen. Esto luego deberiamos subirlo a nuestro dockerhub para poder
utilizarlo desde la nube, aunque deberiamos cambiar el nombre segun la nomenclatura especifica. Ejecutamos
la imagen para ver si cuenta con python3
Comando history
Nos indica los cambios que se han ejecutado en una imagen en concreto, si lo usamos con la imagen recien
creada obtenemos
32 / 123
01-primer-contenedor.md 2024-11-22
Donde vemos que el toma la imagen de ubuntu que ya habia sido descargada con anterioridad y sobre esa
agrega lo que le pedimos de modificaciones para crear la imagen deseada.
&& creara una sola capa del conjunto de las dos instrucciones, crea un echo 1.0 en un dichero /etc/version
sino existe lo crea, y luego instala una serie de funcionalidades, la \ indica que continuara en la siguiente
linea, para evitar lineas tan extensas. Ahora lo ejecutamos...
Comando CMD
Nos permite indicar el comando por defecto del contenedor, luego de arrancado el contenedor, el CMD se va a
ejecutar para indicarle el comando por defecto. Solo puede haber un CMD dentro de un Dockerfile, es
decir, pueden existir varias lineas con el CMD pero solo va a valer el último.
FROM ubuntu
RUN apt-get update
RUN apt-get install -y python3
RUN echo 1.0 >> /etc/version && apt-get install -y git \
&& apt-get install -y iputils-ping
CMD echo "Welcome to this container"
lo cual retorna Welcome to this container y se cierra. Si realizamos el siguiente cambio CMD
["echo","Welcome to this contaner"] reemplazando toda la linea de CMD por la anterior permite
ejecutar con exec y no como shell, por lo cual es recomendado ya que no depende de una shell.
33 / 123
01-primer-contenedor.md 2024-11-22
Si realizamos el cambio del CMD por CMD /bin/bash y denuevo ejecutamos todo otra vez al final obtenemos
lo que indica que cuando va a ejecutar esa linea primero llama a /bin/bash para ejecutar un bash y luego lo
vuelve a ejecutar bin/bash, lo cual no es correcto del todo ya que esta llamando una bash desde una shell
Se recomienda usar el comando JSON para llamar a nuestro comando de la siguiente forma
FROM ubuntu
RUN apt-get update
RUN apt-get install -y python3
RUN echo 1.0 >> /etc/version && apt-get install -y git \
&& apt-get install -y iputils-ping
CMD ["/bin/bash"]
Retornando lo siguiente:
Comando ENTRYPOINT
Ejecuta un comando cuando arrancamos el contenedor, a diferencia del CMD nos permite ejecutar este
comando siempre, mientras que con el comando CMD esto no pasa.
34 / 123
01-primer-contenedor.md 2024-11-22
FROM ubuntu
RUN apt-get update
RUN apt-get install -y python3
RUN echo 1.0 >> /etc/version && apt-get install -y git \
&& apt-get install -y iputils-ping
ENTRYPOINT ["/bin/bash"]
y ejecutamos
Nos retorna un error, este añade el comando que le ponemos y al final no puede ejecutar el comando. Sin
embargo, este tema de añadir los comandos nos permite añadir argumentos enviados desde la consola al
momento de ejecutarlo
FROM ubuntu
RUN apt-get update
RUN apt-get install -y python3
RUN echo 1.0 >> /etc/version && apt-get install -y git \
&& apt-get install -y iputils-ping
ENTRYPOINT ["df"]
y si ejecutamos añadiendo -h
Lo que indica que se ejecuto el comando df -h y no solo el df pero acá al momento de añadirse el comando
se formó un comando que si entiende la shell por lo que no retorno error.
35 / 123
01-primer-contenedor.md 2024-11-22
ENTRYPOINT y CMD
Un entrypoint y un cmd.pero se pueden poner juntos? Si. Ejemplo, un contenedor que cuando se ejecute
haga algo de manera obligatoria y cosas por defecto que pondriamos en el cmd.
FROM ubuntu
RUN apt-get update
RUN apt-get install -y python3
RUN echo 1.0 >> /etc/version && apt-get install -y git \
&& apt-get install -y iputils-ping
ENTRYPOINT ["ping","-c","3"]
CMD ["localhost"]
El anterior comando dice que enviara 3 paquetes con el comando ping y en el CMD los parametros
predeterminados que se le pasaran al comando ENTRYPOINT, ejecutamos y obtenemos
Donde vemos que si queremos le podemos colocar o no la dirección a la cual hacer ping usando el
parametro de CMD de manera opcional.
Sobreescribir entrypoint
Obteniendo lo siguiente:
36 / 123
01-primer-contenedor.md 2024-11-22
Comando WORKDIR
Nos permite determinar el directorio de trabajo para otras directivas/comandos como e.j. RUN, ENTRYPOINT,
COPY, ADD, etc
FROM ubuntu
RUN apt-get update
RUN apt-get install -y python3
RUN echo 1.0 >> /etc/version && apt-get install -y git \
&& apt-get install -y iputils-ping
RUN mkdir /datos
WORKDIR /datos
RUN touch f1.txt
RUN mkdir /datos1
WORKDIR /datos1
RUN touch f2.txt
ENTRYPOINT ["/bin/bash"]
Donde nos posiciona directamente en /datos1, ademas de tambien crear /datos y ambas con sus archivos
respectivos.
COMANDO COPY-ADD
FROM ubuntu
RUN apt-get update
RUN apt-get install -y python3
RUN echo 1.0 >> /etc/version && apt-get install -y git \
&& apt-get install -y iputils-ping
##WORKDIR##
RUN mkdir /datos
WORKDIR /datos
RUN touch f1.txt
RUN mkdir /datos1
WORKDIR /datos1
RUN touch f2.txt
37 / 123
01-primer-contenedor.md 2024-11-22
##COPY##
COPY index.html .
COPY app.log /datos
##ENTRYPOINT##
ENTRYPOINT ["/bin/bash"]
Vemos que se han movido correctamente los archivos al destino seleccionado, en este caso el . hace
referencia a /datos1 ya que es el ultimo sitio que se posiciona debido al WORKDIR.
ADD
FROM ubuntu
RUN apt-get update
RUN apt-get install -y python3
RUN echo 1.0 >> /etc/version && apt-get install -y git \
&& apt-get install -y iputils-ping
##WORKDIR##
RUN mkdir /datos
WORKDIR /datos
RUN touch f1.txt
RUN mkdir /datos1
WORKDIR /datos1
RUN touch f2.txt
##COPY##
COPY index.html .
COPY app.log /datos
##ADD##
ADD docs docs
ADD f* /datos/
ADD f.tar .
38 / 123
01-primer-contenedor.md 2024-11-22
##ENTRYPOINT##
ENTRYPOINT ["/bin/bash"]
ADD y COPY son bastante similares, una diferencia es que ADD permite el paso de ficheros .tar (ficheros
empaquetados), este contiene archivos de f1 a f5. Tambien permite extraer contenido de URL.
En este caso el trata al archivo .tar como un directorio y por lo demas realiza los movimientos de los
archivos.
MANEJO DE VARIABLES
Usando el comando ENV seguido de la definición de la variable, ademas de poderlos usar internamente
definidos en el Dockerfile. Añadiendo lo siguiente antes del comando ENTRYPOINT al anterior archivo
Dockerfile
##ENV##
ENV dir=/data dir1=/data1
RUN mkdir $dir && mkdir $dir1
Lo ejecutamos y obtenemos
39 / 123
01-primer-contenedor.md 2024-11-22
Donde vemos los directorios /data y /data1, Ademas de poderlo revisar dentro del contenedor
##ENV##
ENV dir=/data dir1=/data1
RUN mkdir $dir && mkdir $dir1
ENV TEXTO="Ejemplo de texto"
Ejecutamos y obtenemos:
Pero si queremos modificar la variable directamente desde el arranque del contenedor debemos usar la
bandera -e
Obteniendo
40 / 123
01-primer-contenedor.md 2024-11-22
Obtenemos
No realiza cambios ya que ya se ha ejecutado el paso de ejecutar el directorio (sigue creando el directorio
/data1), sin embargo si modifica el valor de la variable cuando revisamos en el ambiente del contenedor.
##ENV##
ENV dir=/data dir1=/data1
RUN mkdir $dir
ENV TEXTO="Ejemplo de texto"
Ya que cuento con la creación del directorio en el CMD ya en la parte escribible del contenedor y no antes. Y le
envío como argumento un valor a dir1
Obtenemos que el directorio /ejemplazo si se creo y el directorio anterior /data1 no. Ya que cuando se
efectuo el comando CMD recurrio al argumento enviado por consola.
41 / 123
01-primer-contenedor.md 2024-11-22
mkdir $dir1
ls -l /
##ENV##
ENV dir=/data dir1=/data1
RUN mkdir $dir
ENV TEXTO="Ejemplo de texto"
ADD crear_dir.sh .
# permisos
RUN chmod +x /datos1/crear_dir.sh
# ejecución
CMD /datos1/crear_dir.sh
42 / 123
01-primer-contenedor.md 2024-11-22
Evidenciando que se creo el directorio /textos y nos muestra la salida de acuerdo a la ejecución del script
43 / 123
01-primer-contenedor.md 2024-11-22
Comando ARG
Directiva que sirve para poner variables, con la diferencia de que no es necesario poner un valor para las
variables dentro del Dockerfile
##WORKDIR##
RUN mkdir /datos
WORKDIR /datos
RUN touch f1.txt
RUN mkdir /datos1
WORKDIR /datos1
RUN touch f2.txt
##COPY##
COPY index.html .
COPY app.log /datos
##ADD##
ADD docs docs
ADD f* /datos/
ADD f.tar .
##ENV##
ENV dir=/data dir1=/data1
RUN mkdir $dir && mkdir $dir1
ENV TEXTO="Ejemplo de texto"
44 / 123
01-primer-contenedor.md 2024-11-22
##ARG##
ARG dir2
RUN mkdir $dir2
##ENTRYPOINT##
ENTRYPOINT ["/bin/bash"]
Obligatorio pasar el parametro dir2 sino retorna un error al momento de construir la imagen
Obtenemos lo siguiente
Creamos un script con adduser $user_docker donde ejecutara el comando adduser y recibira la variable
user_docker
##ARG##
ARG dir2
RUN mkdir $dir2
ARG user
ENV user_docker $user
ADD add_user.sh /datos1/
RUN chmod +x /datos1/add_user.sh
RUN /datos1/add_user.sh
Notar que ARG no enlaza entre el contenedor y el dockerfile, por lo que no importa si la declaramos como
user o como user_docker como se define en el script, de esta forma le enviamos al comando ENV para
enlazarla con la variable del script.
45 / 123
01-primer-contenedor.md 2024-11-22
Comando EXPOSE
Permite la exposición de puertos para poder usarse publicamente (se debe seguir usando la opción -p), de tal
manera que sirve de guia al momento de construir el Dockerfile El script entrypoint.sh queda:
apachectl start
/bin/bash
Y el Dockerfile queda:
##COPY##
COPY index.html .
COPY app.log /datos
##ADD##
ADD docs docs
46 / 123
01-primer-contenedor.md 2024-11-22
ADD f* /datos/
ADD f.tar .
##ENV##
ENV dir=/data dir1=/data1
RUN mkdir $dir && mkdir $dir1
ENV TEXTO="Ejemplo de texto"
##EXPOSE##
RUN apt-get install -y apache2
EXPOSE 80
ADD entrypoint.sh /datos1/
##CMD##
RUN chmod +x /datos1/entrypoint.sh
CMD /datos1/entrypoint.sh
Ejecutamos
y Obtenemos:
Nos menciona una advertencia de la IP del servidor por lo que se recomienda usar un servidor propio, sin
embargo, para probar nos sirve, ahora revisamos en la maquina en un navegador el localhost con el puerto
8080 predefinido en el Dockerfile, donde nos damos cuenta que si funcionó el enlace de los puertos con la
aplicación del contenedor
47 / 123
01-primer-contenedor.md 2024-11-22
Comando VOLUME
FROM ubuntu
RUN apt-get update
RUN apt-get install -y python3
RUN echo 1.0 >> /etc/version && apt-get install -y git \
&& apt-get install -y iputils-ping
##WORKDIR##
RUN mkdir /datos
WORKDIR /datos
RUN touch f1.txt
RUN mkdir /datos1
WORKDIR /datos1
RUN touch f2.txt
##COPY##
COPY index.html .
COPY app.log /datos
##ADD##
ADD docs docs
ADD f* /datos/
ADD f.tar .
##ENV##
ENV dir=/data dir1=/data1
RUN mkdir $dir && mkdir $dir1
ENV TEXTO="Ejemplo de texto"
##EXPOSE##
RUN apt-get install -y apache2
EXPOSE 80
48 / 123
01-primer-contenedor.md 2024-11-22
##VOLUME##
ADD paginas /var/www/html
VOLUME ["/var/www/html"]
##CMD##
RUN chmod +x /datos1/entrypoint.sh
CMD /datos1/entrypoint.sh
Donde movemos un directorio a una dirección en el contenedor y luego en esa dirección creo un volumen.
Ahora si ejecutamos el Dockerfile y creamos un contenedor basandonos en su imagen.
Y revisamos su funcionamiento
Observamos que ahora muestra el contenido del directorio que le pasamos /paginas en vez del por defecto
de apache debido a que movimos y reemplazamos el contenido que muestra apache con el contenido de
/paginas en la ruta /var/www/html. Y si revisamos los volumenes notamos un nuevo volumen. Tambien
podemos comprobar directamente el contenido del contenedor por medio de \\wsl.localhost\docker-
desktop-
data\data\docker\volumes\8e7e69962e8e690a45d1ebbfb2e7f96d30ae0e5d37fda9ef0c17d514bb5fc49
1\_data en el caso de usar wsl en Windows.
49 / 123
01-primer-contenedor.md 2024-11-22
Revisando en el navegador
Observando el mismo contenido desde otro puerto, ahora si revisamos los volumenes, notamos que no creo
un segundo volumen, lo que indica que esta apuntando al mismo volumen, lo revisamos mediante un inspect
de cada contenedor.
Volumen contenedor 2:
Volumen contenedor 1:
50 / 123
01-primer-contenedor.md 2024-11-22
Ambos contenedores cambiaron su nombre SEBAS INC. sin tener que modificar los dos sino el
contenido del wsl del volumen creado inicialmente y al que ambos contenedores apuntan.
Docker Hub
Subir imagenes a docker hub
Siguiendo algunos estandares como el nombre del usuario, a modo de ejemplo bajaremos y subiremos a
docker hub la imagen del Dockerfile
Le colocamos el nombre de usuario, en mi caso jseb99, luego iniciaremos sesión desde el CLI
docker login
51 / 123
01-primer-contenedor.md 2024-11-22
Acá nos puede pedir una URL en caso de tenerla o sino directamente intentara acceder a nuestra cuenta de
docker hub donde le ingresamos nuestras credenciales
Luego subiremos la imagen a un registro (en el que este con la sesion iniciada)
52 / 123
01-primer-contenedor.md 2024-11-22
¿Puedo etiquetar una imagen que ya existe sin necesidad de volverla a recrear? DOCKER TAG
Apartir de una imagen y contenedor que he modificado creo un commit, es decir, una imagen nueva. Y si
ahora quiero subirla a mi Dockerhub no me va a dejar.
Debido a que debe estar precedida con el nombre del usuario. Para modificarlo usaremos docker tag
53 / 123
01-primer-contenedor.md 2024-11-22
Notamos que ambas imagenes mi_apache y jseb99/mi_apache apuntan a la misma ID de la imagen, con el
mismo peso. Por lo cual no duplico la imagen sino la etiqueto, pero hace referencia a la misma imagen (su
contenido es el mismo), como un acceso directo. Ahora si realizamos un docker push ya me dejara subirla
Revisamos en docker hub, encontraremos la imagen ya publicada en nuestra cuenta, en este caso no
realizamos un login ya que estabamos iniciados recientemente.
SAVE & LOAD ¿Cómo podriamos pasar una imagen a alguna maquina externa? Mediante el comando SAVE
podemos empaquetar una imagen en un archivo .tar, entonces usaremos el siguiente comando
54 / 123
01-primer-contenedor.md 2024-11-22
Donde ubuntu_docker.tar sera el nombre de salida con la extensión .tar, Entonces si revisamos la
ubicación donde nos encontramos...tendremos el archivo empaquetado.
Lo que equivale a las capas de la imagen. Ahora si eliminamos la imagen de docker del computador docker
image rm ubuntu.
-i de input
y revisamos las imagenes cargadas docker image ls o en linux docker image ls | grep ubuntu
donde volvemos a tener la imagen con las mismas referencias anteriores (fecha, id, peso)
Docker search ¿Cómo podriamos buscar posibles imagenes que tengamos en Docker Hub? Mediante el
comando docker search, nos permitira buscar una determinada imagen dentro de docker hub
55 / 123
01-primer-contenedor.md 2024-11-22
La salida es truncada para evitar sobresaturación en la salida por la cantidad de imagenes en docker hub, este
comando muestra:
Nombre de imagen
Descripción
Estrellas
Si es oficial
Nos muestra las imagenes que subimos con anterioridad, debido a que tambien las nombramos con nuestro
nombre de usuario.
56 / 123
01-primer-contenedor.md 2024-11-22
Opciones Avanzadas
¿Cómo aprovechar los recursos para trabajar con Docker?
Memoria
Por defecto los contenedores intentan usar la máxima memoria posible, docker establece por defecto un
conjunto de prioridades para impedir que la maquina se venga abajo si tenemos mucho uso de contenedores.
salida comparativa:
Entonces todos esos procesos compiten por el espacio en memoria disponible para los recursos, en
este caso de 3.7 GB, todos los contenedores pueden usar memoria swap.
memoria swap: cuando se reclama en memoria y no hay suficiente, se baja zonas de memoria fria del
contenedor a lo que seria disco, y se recuperan si es necesario.
Uso de memoria
57 / 123
01-primer-contenedor.md 2024-11-22
--kernel-memory usa la memoria del kernel, no puede ser intercambiada por el disco, por lo que
puede colapsar la maquina. Lo minimo permitido es 6 MB.
--oom-kill-disable si existe un error out of memory el kernel mata los procesos en el contenedor,
solo deshabilitar esta opción cuando tengamos configurado la memoria mediante las opciones -m/--
memory. Si no esta configurado, el host puede correr out of memory y el kernel puede matar los
procesos del sistema para liberar memoria.
Ejemplo:
El contenedor ahora solo usa 12 MB máximo no como los 30 MB que usaba en el primer proceso mostrado
anteriormente. Ademas que en ese caso la memoria swap estaria en un valor cercano a 12 MB. Ahora si
usamos el mismo valor:
Donde en este caso la --memory-swap se desactiva ya que este valor tiene un valor igual a --memory y el
contenedor en esta condición no tendría acceso al intercambio., ademas de ver el limite de memoria que
tiene el contenedor en 256 MB. Ahora si instalamos algo dentro del contenedor
58 / 123
01-primer-contenedor.md 2024-11-22
Entonces le pedimos 2 procesos en memoria de 100 MB cada uno y que los guarde. Nos muestra lo siguiente
Vemos que la maquina usa 241 MB y esta en un 94% de uso, pero aun lo puede manejar, ahora le enviaremos
3 procesos mediante stress -m 3 --vm-bytes 100m --vm-keep lo que nos muestra
Un error debido a que la ejecución de esos procesos superan los limites permitidos.
El recurso ya no se para y sigue funcionando, en este caso si usa el total de la memoria, pero internamente
esta usando la memoria swap
Nota: El uso de memoria swap tambien es mas lento ya que usa disco realmente, sin embargo permite
que pares un proceso debido a un pico o algun elevación momentanea de uso de memoria de los
procesos.
CPU
59 / 123
01-primer-contenedor.md 2024-11-22
Por defecto cada contenedor accede a los ciclos de CPU de la maquina ilimitadamente, se pueden poner
limites a este recurso meditante:
--cpus=<value>: Especifica cuantos recursos de la CPU puede usar, si pongo 1.5 este podra usar a lo
maximo 1.5 recursos de la CPU.
--cpu-period=<value>: Especifica el periodo del cronograma CFS de la CPU, el cual es usada con una
cuota --cpu-quota. Por defecto es de 100000 microsegundos.
--cpu-quota=<value>: Cuota de CPU CFS. El número de microsegundos por --cpu-period que el
contenedor es limitado antes de cortarse.
--cpuset-cpus: Limita las CPUs o núcleos que un contenedor usa. Puede anotarse mediante - para un
rango o , para una lista. 0-3 Usara las cpus de la 1 a la 4 y 1,3 usara la segunda y cuarta CPU.
--cpu-shares: bandera que puede incrementarse o disminuirse del defecto (1024, unidad de trabajo)
peso del contenedor. Te da acceso a una mayor o menor proporción de los ciclos de CPU de la
maquina. Esto solo se activa cuando se tienen restricciones en los ciclos de CPU. Entonces cuando se
tengan ciclos de CPU activos los contenedores podran hacer uso de estos.
CPU
Ejemplo: usaremos el comando docker stats para ir revisando los recursos de la maquina, el
comando stress.
Ahora con la imagen lista podremos realizar las practicas con las limitaciones
El cual apache1 indica que como mucho consumira media CPU y apache2 indica que consumira 1 CPU y
media. Sin embargo, aun el consumo es el mismo, esto es debido a que aun no piden recursos para su
funcionamiento.
¿Que pasa si le pongo mas CPU? docker run --name apache3 --cpus=10 -d -it apache-stress Me
sale el siguiente error
60 / 123
01-primer-contenedor.md 2024-11-22
Nota: solo hace referencia al limite ya que todos los contenedores pueden usar el maximo de CPUs, es
decir, estos valores no se suman sino se refieren a los recursos de CP00U que puede usar.
Ahora si usamos el primer contenedor y lo forzamos para verificar sus limites, en este caso le pediremos 5
procesos de CPU.
Seguimos notando el limite de CPU. Mediante otra terminal forzaremos ahora el segundo contenedor
Con 3 contenedores solicitando recurso estaria de la siguiente forma, ahora el tercero soporta las 8 cpus que
mi maquina permite.
y le pido un stress de 10 procesos de cpu. Pero este no llega a pedir todo el porcentaje como vemos en la
imagen sino que tiene que nivelarse para manejar los recursos entre todos contenedores que en ese instante
estan solicitando recursos.
61 / 123
01-primer-contenedor.md 2024-11-22
Donde 1024 se refiere al total de la unidad de la cpu que podra usar, el segundo usara la mitad de potencia al
igual que el tercero y todos usaran la misma CPU. Ahora si le ponemos un stress -c 10 al primer
contenedor tendremos el siguiente uso:
El primer contenedor puede usar todo el porcentaje debido a que no compite por los recursos con los demas
contenedores. Ahora si en el segundo contenedor ponemos un stress -c 10 tenemos:
Ahora ya notamos una repartición de recursos, por ultimo le ponemos un stress -c 10 al tercer contenedor
y tenemos:
Notamos que ahora los tres compiten por los recursos y àpache1 puede llegar a un 50% de los recursos y los
demas se los reparten en un 25% cada uno. O lo mismo que el primero obtiene 1024 y los otros 2 usan 512
cada uno, repartiendose proporcionalmente los recursos de la primer CPU (CPU 0).
Ya no le especificamos las CPUs que podran usar los contenedores. Ahora si repitemos el envío de estres a los
contenedores tenemos lo siguiente, para solo el contenedor 1 tenemos:
Ahora el puede hacer uso de todas las CPUs si estan disponibles, si le enviamos ahora el segundo contenedor
tenemos:
62 / 123
01-primer-contenedor.md 2024-11-22
Ya notamos una repartición proporcional de los recursos uno en 1024 y el otro en 512, en este caso uno sobre
500 y el otro sobre 260. Si le enviamos el tercero, tenemos:
Ahora notamos que el primer contenedor esta usando alrededor de 4 CPUs y los otros 2 se reparten 2 CPUs
cada uno. Manteniendo las proporcionalidades respectivamente.
Drivers
Drivers o mecanismos que usa Docker para guardar los datos, ya sea dentro un disco o de un volumen.
Storage Drivers
La estrategia que utiliza docker para ir lo mas rapido posible es Copy-on-write (CoW) strategy, Todos los
contenedores de inicio usan los datos de las imagenes que tiene docker guardados localmente, estos difieren
es cuando se modifican los contenedores y esta modificación es lo unico que guarda docker en su capa de
escritura, al inicio docker revisa capa por capa por el archivo a actualizar, luego copia el archivo para enviarlo
a la capa superior y cualquier modificación es hecha sobre la copia de tal manera que el contenedor no puede
ver el archivo que existe en las capas inferiores.
docker info
Y obtenemos:
63 / 123
01-primer-contenedor.md 2024-11-22
On-failure (maximos intentos): rebota el contenedor si se ha caído con algún código distinto a cero.
Además podemos indicar cuantas veces reintenta el arranque.
Always: rebota el contenedor siempre cuando se para, salvo que sea una parada normal y deseada. Si
se para de forma normal solo se rebota cuando se rebota el propio demonio de docker, es decir, el
servidor.
Unless-stopped: parecida a always excepto que cuando el contenedor se para manualmente o de
cualquier otra forma no es rebotado incluso después de que arranque el demonio de Docker
No: No se rebota el contenedor de forma automatica bajo ningun concepto.
Ejemplo:
#/bin/bash
sleep 15
exit 1
FROM ubuntu
ADD parar.sh /
RUN chmod +x /parar.sh
CMD /bin/bash /parar.sh
Utilizando una imagen de ubuntu agregara el archivo de scripting al directorio /, añadimos permisos de
ejecución y luego por medio de bash ejecutara parar.sh. Ahora crearemos la imagen a partir del archivo
Dockerfile usando el siguiente comando docker build -t imagen-restart ..
Usando No:
Funcionamiento:
64 / 123
01-primer-contenedor.md 2024-11-22
Funcionamiento:
Al pararse despues de 15 segundos se vuelve a reiniciar. ¿Cómo podria verificar que rebota continuamente?
Con docker inspect t1 con t1 como el nombre del contenedor:
Donde revisando la propiedad RestartCount nos dice el número de veces que se ha reiniciado. Ahora si lo
paro manualmene con docker stop t1 tendremos:
Este ya no se reinicia pasado los 15 segundos como se tenia preestablecido. Pero si reiniciamos el demonio o
el servidor, que seria nuestro docker desktop en Windows, tendremos:
Es decir que se volvio a reiniciar el contendor automaticamente apenas reiniciamos el daemon o demonio de
docker.
65 / 123
01-primer-contenedor.md 2024-11-22
Usando Unless-stopped:
Funcionamiento:
Ahora si ejecuto docker stop t1 y a diferencia de always ejecuto un systemctl restart docker este
seguira parado. En este caso realice un reinicio manual y al revisar con un docker ps -a tendremos:
Usando On-failure:
Y si revisamos el contenedor:
Ya no reinicia y la cantidad de conteos es de 2 según el comando, esto lo revisamos con una inspección al
contenedor:
Donde notamos que despues de 2 conteos no volvio a reiniciarse. Ya no reinicia asi reiniciemos el DAEMON.
66 / 123
01-primer-contenedor.md 2024-11-22
Cuando se crea un contenedor, los datos del contenedor se guardan en ese mismo directorio.
Fichero de logs: nos muestra lo que va saliendo en el log del apache en este caso
Checkpoints que se van generando
Config.v2.json sería la configuración con la que se ha arrancado el contenedor, normalmente lo que se
ve en docker inspect
Configuración del host, tambien nos lo da el docker inspect
Resolv.conf contiene el DNS para acceder a los recursos
Información de los hosts y mounts.
67 / 123
01-primer-contenedor.md 2024-11-22
Si corremos un contenedor de cero y revisamos la información de los logs en el archivo .log podremos ver la
misma información que cuando usamos docker log y el id o nombre del contenedor.
Y si usamos un inspect sobre el contenedor tambien podriamos ver el tipo de log que estamos utillizando
Nota: al registrar todos los sucesos dentro de un contenedor, es recomendable pensar que hacer con
esa información de los logs para no sobresaturarlos de información y poder revisarlo de manera mas
apropiada.
De acuerdo a lo anterior dependera del tipo de driver que se tenga, en el caso json-file se podra modificar
el fichero daemon.json que especifica el comportamiento de la configuración general de docker. Lo que
indica que tiene propiedades que indican como se comportan el json-file.
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
68 / 123
01-primer-contenedor.md 2024-11-22
El daemon.json anterior nos muestra el tipo de log driver, el tamaño maximo y el numero maximo de archivos
para habilitar una rotación automatica del log. Ademas tambien se puede ejecutar lo mismo a traves del
propio contenedor mediante el siguiente comando:
docker run \
--log-driver json-file --log-opt max-size=10m \
alpine echo hello world
En Linux el directorio del fichero de configuración se encuentra en /etc/docker y en el caso de los Windows
se encuentra en %programdata%\docker\config\daemon.json, pero revisando lo encontre en
C:\Users\sebas\.docker. El archivo se encuentra con lo siguiente:
{
"builder": {
"gc": {
"defaultKeepStorage": "20GB",
"enabled": true
}
},
"experimental": false
}
{
"builder": {
"gc": {
"defaultKeepStorage": "20GB",
"enabled": true
}
},
"experimental": false,
"log-driver": "json-file",
"log-opt": {
69 / 123
01-primer-contenedor.md 2024-11-22
"max-size": "5m",
"max-file": "3"
}
}
Como vemos tenemos la configuración que establecimos anteriormente vista desde el docker desktop
ademas de poderlo editar desde esa misma interfaz. Ahora si iniciamos un contenedor debería tener las
configuraciones que establecimos:
Crear un segundo docker Es decir tener varios nodos DOCKER dentro de la misma maquina mientras no
impacte en el tema de puertos y demas. Correr multiples demonios
70 / 123
01-primer-contenedor.md 2024-11-22
Las siguientes opciones del daemon deben ser configuradas por cada daemon:
¿Puedo usar mi cliente docker para contectarme a un servidor docker que esta en otro sitio?
Desde un solo docker cli puedo conectarme y trabajar con otros nodos docker que esten otro sitio, incluso
con clusters de kubernetes o swarm. En docker existe el comando docker context que nos permite trabajar
con los contextos.
Docker Compose
Herramienta que nos permite crear escenarios complejos con nuestros con contenedores docker, Nos ayuda a
trabajar multiples contenedores de una manera controlada.
Docker permite el concepto de servicios, microservicios, permitia convertir una aplicación tradicional
(monolitica, db, app-server, gestor de contenidos, web-server) en un entorno de microservicios, donde se
71 / 123
01-primer-contenedor.md 2024-11-22
Este proceso se puede hacer mediante redes, volumenes, enlaces, etc. pero se vuelve muy complejo de
manejar, por tal motivo se creo docker compose, que orquesta servicios/componentes de
contenedores.
YAML
YAML es un lenguaje versátil y legible por humanos para serializar datos, que se utiliza a menudo para escribir
archivos de configuración. Contiene las instrucciones para generar un entorno multi-contenedor que son
llamados servicios.
El nombre del directorio de trabajo es importante, ya que cuando creo un docker-compose el usa el concepto
de proyecto, que hace referencia al entorno de lanzamiento a traves de docker-compose.
En este caso crearemos un directorio pr_nginx en el cual colocaremos un archivo yaml, llamado docker-
compose.yml este debe quedar asi aunque si usamos la opción -f podemos usar un nombre personalizado.
version: "3"
services:
nginx: # nombre personalizable del servicio
image: nginx # imagen hecha o build mediante dockerfile
ports: # puertos
- "80:80"
docker-compose up
Lo que me retorna los pasos realizados y un log de los sucesos dentro del orquestador:
72 / 123
01-primer-contenedor.md 2024-11-22
Tengo el contenedor activo y escuchando por el puerto 80, lo que revisaremos a continuación:
Como se ve en los pasos se muestra que crea una red, esta tambien la podemos verificar mediante docker
network ls
Vemos que creo la red pr-nginx_default para el contenedor pr-nginx-nginx-1 que podemos revisar con
un inspect sobre la red:
Ademas de poder revisar esto mediante comandos docker-compose de igual forma, en algunos casos es
mejor posicionarse sobre la ubicación del archivo de configuración para que funcione correctamente:
73 / 123
01-primer-contenedor.md 2024-11-22
Ejemplo 2:
version: "3.9"
services:
apache:
image: httpd
ports:
- "80:80"
python:
image: python
Notamos que se salio del contenedor de python, esto debido a que no lo iniciamos en modo interactivo, en
cambio apache si logro arrancar debido a que no necesita esta funcionalidad.
En lo anterior notamos este problema donde el contenedor de apache si esta corriendo mientras que el de
python se ha parado. Ademas de tambien crear una red como en el ejemplo anterior.
version: "3.9"
services:
svc-apache:
image: httpd
ports:
- "80:80"
svc-tomcat:
image: tomcat
ports:
- 8080:8080
74 / 123
01-primer-contenedor.md 2024-11-22
Mediante otra pestaña ejecutamos docker compose stop y pararemos los compose que se encuentren en
esa ubicación:
A su vez revisamos mediante docker compose ps si existe algun compose activo. Y si ejecuto docker
compose start me vuelven a encender pero no me retorna los logs, lo lanza en modo background (Con ps
podemos verificar este proceso.)
75 / 123
01-primer-contenedor.md 2024-11-22
¿Puedo yo pararlo todo? Con docker compose down no solo para los servicios, sino que borra todo.
Construir imágenes con compose Creamos un archivo Dockerfile con el siguiente contenido:
FROM ubuntu
LABEL Sebastian '[email protected]'
RUN apt-get update
RUN apt-get install -y nginx
ADD web /var/www/html
ENTRYPOINT ["/usr/sbin/nginx/","-g","daemon off;"]
EXPOSE 80
version: "3.9"
services:
web:
76 / 123
01-primer-contenedor.md 2024-11-22
build: .
image: jseb99/web:v1
container_name: web_frontal
ports:
- "80:80"
Construyeme la imagen jseb99/web:v1 a apartir del dockerfile que tengo en el directorio (.)
Una vez configurado lo anterior ya nos venimos a la ubicación del docker-compose.yml y procedemos a
ejecutarlo. Nos muestra lo siguiente:
Donde vemos que primero no encuentra la imagen, y procede a cargar la definición de la construcción del
dockerfile donde ejecuta el dockerfile y finalmente me crea la red con su contenedor. Ahora si verificamos en
el puerto expuesto (80) tenemos lo siguiente:
Tenemos la página predefinida en el directorio web/ el cual se mueve a /var/www/html que es donde usa la
imagen nginx para mostrarse en el puerto (80). Ademas de la verificación mediante el docker compose:
77 / 123
01-primer-contenedor.md 2024-11-22
¿Que pasa si lo paro? Al pararlo el ya no requerira de volver a construir la imagen, como vemos a
continuación:
La imagen ya se ha creado y al momento de bajar el docker compose y volver a crearlo este evitara pasos de
construcción de imagen y buscara primero si ya existe la imagen:
Variables
¿Cómo envío variables de entorno?
Mediante la especificación environment seguido de la definición de cada una de las variables de entorno, en
este caso tenemos el siguiente archivo docker-compose.yml:
services:
database:
image: mysql
restart: always
environment:
- MYSQL_DATABASE=db1
- MYSQL_USER=sebas
- MYSQL_PASSWORD=contra
- MYSQL_ROOT_PASSWORD=contra
En este caso restart me especifica el tipo de rebote en caso de algun error. Ahora ejecutamos el comando
docker compose up
78 / 123
01-primer-contenedor.md 2024-11-22
Nos retorna una serie de logs de los pasos que va ejecutando, ahora mediante otra pestaña podemos
comprobar el funcionamiento del contenedor:
79 / 123
01-primer-contenedor.md 2024-11-22
80 / 123
01-primer-contenedor.md 2024-11-22
Enviar variables a tráves de un fichero: ENV_FILE Cuando tengo muchas variables y estas cambian de
manera dinamica, quizas es preferible tenerlas en un fichero/archivo separado y luego anexarlas al compose.
Entonces en un nuevo directorio, creamos un archivo de configuración llamado mysql.properties en este
caso el cual contendra lo siguiente:
MYSQL_DATABASE=db1
MYSQL_USER=ironman
MYSQL_PASSWORD=contra
MYSQL_ROOT_PASSWORD=contra
services:
database:
image: mysql
restart: always
env_file:
- mysql.properties
Luego ejecutamos el comando docker compose up y mediante otra pestaña podemos verificar accediendo
al contenedor y luego al mysql:
81 / 123
01-primer-contenedor.md 2024-11-22
Donde accedimos directame con el usuario creado ironman a la base de datos y mostramos la base de datos
creada, db1 en este caso.
services:
wordpress:
image: wordpress
restart: always
ports:
- 9090:80
environment:
- WORDPRESS_DB_HOST=db-wp
- WORDPRESS_DB_USER=wp-user
- WORDPRESS_DB_PASSWORD=wp-pass
- WORDPRESS_DB_NAME=wp-db
db-wp:
image: mysql
restart: always
environment:
- MYSQL_DATABASE=wp-db
- MYSQL_USER=wp-user
- MYSQL_PASSWORD=wp-pass
- MYSQL_ROOT_PASSWORD=wp-pass
Acá tenemos dos servicios, el host de la base de datos en wordpress lo enlazamos con el servicio que
queremos usar, en este caso db-wp. Ademas de concidir el usuario, contraseña y nombre de la base de datos
para poder acceder mediante wordpress a la base de datos. Ademas el archivo compose en este caso se llamo
compose.yml que es otro formato disponible.
82 / 123
01-primer-contenedor.md 2024-11-22
Nota: Al arrancar dos servicios y uno dependa del otro primero deberíamos arrancar el servicio base
que de abasto a los demas servicios.
En este caso wordpress depende de db-wp por lo cual primero deberia arrancar db-wp. ¿Cómo podemos
solucionar este problema de manera sencilla con el compose? RTA: usamos la clausula depends_on donde
definimos los servicios de los cuales depende el servicio, de tal manera que quedaría de la siguiente manera el
compose.yml
services:
wordpress:
image: wordpress
restart: always
ports:
- 9090:80
environment:
- WORDPRESS_DB_HOST=db-wp
- WORDPRESS_DB_USER=wp-user
- WORDPRESS_DB_PASSWORD=wp-pass
- WORDPRESS_DB_NAME=wp-db
depends_on:
- db-wp
db-wp:
image: mysql
restart: always
environment:
- MYSQL_DATABASE=wp-db
- MYSQL_USER=wp-user
- MYSQL_PASSWORD=wp-pass
- MYSQL_ROOT_PASSWORD=wp-pass
Ademas notar que el depends_on es una lista, es decir, le puedo poner multiples servicios que dependan de
otra servicio. Finalmente ejecutamos el compose, en este caso en modo background:
docker compose up -d
Vemos que el servicio db-wp se inicio primero para evitar problemas y seguido de esto se creo el servicio
wordpress. Ahora si quiero ver los logs usariamos docker compose logs nombre_servicio. Ahora si
revisamos el navegador en el puerto (9090) tendremos la página de instalación de wordpress, indicando que
todo funciona correctamente:
83 / 123
01-primer-contenedor.md 2024-11-22
Ademas de que si accedemos al servicio db-wp podemos verificar el usuario y la base de datos creada:
services:
wordpress:
image: wordpress
restart: always
ports:
84 / 123
01-primer-contenedor.md 2024-11-22
- 9090:80
environment:
- WORDPRESS_DB_HOST=db-wp
- WORDPRESS_DB_USER=wp-user
- WORDPRESS_DB_PASSWORD=wp-pass
- WORDPRESS_DB_NAME=wp-db
depends_on:
- db-wp
volumes:
- /var/www/html
db-wp:
image: mysql
restart: always
environment:
- MYSQL_DATABASE=wp-db
- MYSQL_USER=wp-user
- MYSQL_PASSWORD=wp-pass
- MYSQL_ROOT_PASSWORD=wp-pass
volumes:
- /var/lib/mysql
Volumenes:
Inspeccionando un contenedor:
85 / 123
01-primer-contenedor.md 2024-11-22
Named volumes Permiten identificar de una manera mas rápida los volúmenes. Para ello definimos las rutas
mediante variables que serian sus nombres, es decir:
services:
wordpress:
image: wordpress
restart: always
ports:
- 9090:80
environment:
- WORDPRESS_DB_HOST=db-wp
- WORDPRESS_DB_USER=wp-user
- WORDPRESS_DB_PASSWORD=wp-pass
- WORDPRESS_DB_NAME=wp-db
depends_on:
- db-wp
volumes:
- wp:/var/www/html
db-wp:
image: mysql
restart: always
environment:
- MYSQL_DATABASE=wp-db
- MYSQL_USER=wp-user
- MYSQL_PASSWORD=wp-pass
- MYSQL_ROOT_PASSWORD=wp-pass
volumes:
- db:/var/lib/mysql
volumes:
wp:
db:
De manera general se recomienda usar los volumenes a nivel de todo el archivo (Como se ve al final del
archivo), de esta manera los volumenes estarán disponibles para cualquier servicio generado mediante el
compose.yml. Ahora si los ejecutamos: obtenemos los volumenes creados:
Notamos que estos volumenes han sido creados con el nombre fijado, sin embargo, lo podemos probar con
docker volume ls:
86 / 123
01-primer-contenedor.md 2024-11-22
Ademas revisando en la ruta establecida para los volumenes por docker en el equipo principal (en este caso
usando wsl) tenemos lo siguiente:
Volúmenes que enlazan un directorio del contenedor con uno de la máquina principal (host) y al no contar
tecnicamente como volume se quita de la clausula global. Quedando de la siguiente manera:
services:
wordpress:
image: wordpress
restart: always
ports:
- 9090:80
environment:
- WORDPRESS_DB_HOST=db-wp
- WORDPRESS_DB_USER=wp-user
- WORDPRESS_DB_PASSWORD=wp-pass
- WORDPRESS_DB_NAME=wp-db
depends_on:
- db-wp
volumes:
- D:\Cursos\Docker\13-docker-
compose\pr_volumenes\bind_volume\wp:/var/www/html
db-wp:
image: mysql
restart: always
87 / 123
01-primer-contenedor.md 2024-11-22
environment:
- MYSQL_DATABASE=wp-db
- MYSQL_USER=wp-user
- MYSQL_PASSWORD=wp-pass
- MYSQL_ROOT_PASSWORD=wp-pass
volumes:
- db:/var/lib/mysql
volumes:
db:
Como vemos dejamos el volúmen de la base de datos mysql db como volúmen nombrable, por tal motivo
podemos seguirlo dejando en la clausula global de volumes. Ahora lo ejecutamos con un docker compose
up -d, revisando tenemos:
Un solo volúmen, el de la base de datos que se especifico como volúmen nombrado en el archivo, pero si
revisamos la ruta en el host podemos observar lo siguiente:
88 / 123
01-primer-contenedor.md 2024-11-22
Los archivos que se usan para wordpress en docker tambien se tienen de manera local o en el host. Ahora si
revisamos en el contenedor:
Cuidado al borrar ya que los datos enlazados seguiran existiendo sino se borran en la maquina local o
el host donde se hospeden. En este caso tambien borraremos su contenido
Comprobación:
Redes
Para ello usaremos la clausula networks donde definiremos el nombre de las redes ademas de un enlace a su
servicio (en los servicios se pueden asociar multiples redes), quedando de la siguiente manera el archivo
compose.yml:
version: "3.9"
services:
svc-apache:
89 / 123
01-primer-contenedor.md 2024-11-22
image: httpd
networks:
- frontal
ports:
- 80:80
svc-tomcat:
image: tomcat
networks:
- frontal
ports:
- 8080:8080
networks:
frontal:
Vemos que crea a red pr_network_frontal predefinida anteriormente. Tambien mediante un docker
network ls podemos verificar su existencia, ahora mediante un inspect verificaremos que contenedores
tiene enlazados:
pr_network-svc-tomcat-1
pr_network-svc-apache-1
Que son los contenedores creados anteriormente, por lo cual confirma su enlace con la red especificada.
Ademas de poder asociarse a varias redes, en este caso realizaremos una modificación en el archivo
quedando de la siguiente manera:
version: "3.9"
services:
90 / 123
01-primer-contenedor.md 2024-11-22
svc-apache:
image: httpd
networks:
- frontal
ports:
- 80:80
svc-tomcat:
image: tomcat
networks:
- frontal
- middleware
ports:
- 8080:8080
networks:
frontal:
middleware:
Ahora borramos el compose anterior y ejecutamos el nuevo. Creación de las dos redes:
91 / 123
01-primer-contenedor.md 2024-11-22
Usaremos la clausula aliases para definir el alias de las redes, el archivo de configuración sera el siguiente:
services:
wordpress:
image: wordpress
restart: always
ports:
- 9090:80
environment:
- WORDPRESS_DB_HOST=db-host
- WORDPRESS_DB_USER=wp-user
- WORDPRESS_DB_PASSWORD=wp-pass
- WORDPRESS_DB_NAME=wp-db
depends_on:
- db-wp
networks:
- wp-network
db-wp:
image: mysql
restart: always
environment:
- MYSQL_DATABASE=wp-db
- MYSQL_USER=wp-user
- MYSQL_PASSWORD=wp-pass
- MYSQL_ROOT_PASSWORD=wp-pass
92 / 123
01-primer-contenedor.md 2024-11-22
networks:
wp-network:
aliases:
- db-host
networks:
wp-network:
Donde le asignamos a los dos servicios la misma red, en la segunda añadimos el alias db-host por lo cual
permitira invocar ese servicio mediante db-host o db-wp. Esto tambien lo podemos notar en la variable de
entorno de wordpress enfocada en el host de la base de datos que apunta a db-host en vez de db-wp como
estaba predefinida. Ademas podemos usar los dos como podemos apreciar en la clausula depends-on que
apunta a db-wp en vez de db-host, es decir, podemos usar una u otra.
Para que funcione este enlace deben estar los servicios dentro de la misma red. Ademas nota como
definidos uno con alias y otro sin alias (Uno lleva '-' y otro no)
Consola:
Navegador:
Ahora mediante un docker inspect pr_network_alias-db-wp-1 que fue el contenedor que le pusimos el
alias y revisamos el apartado de redes tenemos:
93 / 123
01-primer-contenedor.md 2024-11-22
db-wp
db-host
cadena de numeros
nombre de la red predefinido Que son los predefinidos en el archivo de configuración.
En este caso especial atención a db-host, ya que los otros estan predefinidos por docker.
Obteniendo:
94 / 123
01-primer-contenedor.md 2024-11-22
Notamos que ahora los nombres estan asociados a proyectazo y no a pr*network_alias como estaban
anteriormente, ahora si revisamos los servicios con docker compose ps:
Notamos que ahora no encuentra los servicios activos, esto es debido a que _docker busca los servicios con el
nombre del directorio activos y al usar la bandera no los puede encontrar*, para solucionar este inconveniente
usamos el siguiente comando:
Al usar esta flag necesitamos especificar siempre esta bandera al momento de usar comandos con
docker compose
En este caso añadimos la bandera y el nombre asociado como nombre del proyecto, en este caso proyectazo
como vimos anteriormente y ahora si obtenemos evidencia de los servicios:
Ahora si nos encontramos en otra ubicación distina al archivo de configuración podemos usar lo siguiente:
de tal manera que le indicamos la ruta del archivo del compose y mediante esta bandera -f podemos colocar
el nombre que quiera al fichero yml, solo debemos indicarle cual es el archivo facilitando muchas cosas.
Este proceso tambien lo podemos efectuar si en el archivo de configuración agregamos la clausula name que
nos permite efectuar el cambio de nombre del proyecto mediante el archivo de configuración sin tener que
enviarselo mediante comando, en este caso el archivo de configuración quedaria de la siguiente forma:
services:
wordpress:
image: wordpress
95 / 123
01-primer-contenedor.md 2024-11-22
restart: always
ports:
- 9090:80
environment:
- WORDPRESS_DB_HOST=db-host
- WORDPRESS_DB_USER=wp-user
- WORDPRESS_DB_PASSWORD=wp-pass
- WORDPRESS_DB_NAME=wp-db
depends_on:
- db-wp
networks:
- wp-network
db-wp:
image: mysql
restart: always
environment:
- MYSQL_DATABASE=wp-db
- MYSQL_USER=wp-user
- MYSQL_PASSWORD=wp-pass
- MYSQL_ROOT_PASSWORD=wp-pass
networks:
wp-network:
aliases:
- db-host
networks:
wp-network:
En este caso dejamos el nombre proyecto-docker, ahora si ejecutamos el compose con docker compose
up -d obtendremos:
Como podemos ver evidenciamos la creación de los servicios con el nombre proyecto-docker, notamos que
no necesitamos estar en el mismo directorio lo que nos permite enviarle directamente el archivo de
configuración, lo que a su vez nos permite usar otro nombre de archivo .yaml.
96 / 123
01-primer-contenedor.md 2024-11-22
Ademas notamos que no es necesario usar la bandera -f, esta solo es necesaria cuando no nos encontramos
en la ubicación del archivo de configuración, esta sirve para añadir la ruta relativa desde donde nos
encontramos hacia el archivo de configuración para indicarle a docker donde se encuentra el archivo.
Tambien podemos usar la ruta global con la bandera -f para indicarle la ubicación del archivo, como lo
podremos ver a continuación:
Sin embargo por temas de rapidez se recomienda la ruta relativa al ser mas corta y comoda de seguir.
Perfiles
Un perfil es un elemento que nos permite lanzar determinados servicios dependiendo si tengo o no activado
un perfil. Ejemplo: tengo un compose que si lo lanzo en modo desarrollo o modo producción hace una cosa u
otra. Dentro de un archivo de configuración puedo configurar los servicios para que pertenezcan a un perfil y
cuando arranquen esos componentes podre decidir que perfil quiero activar. Para ello usaremos el siguiente
archivo de configuración:
name: proyecto-docker
services:
wordpress:
image: wordpress
container_name: wordpress
restart: always
ports:
- 9090:80
97 / 123
01-primer-contenedor.md 2024-11-22
environment:
- WORDPRESS_DB_HOST=db-host
- WORDPRESS_DB_USER=wp-user
- WORDPRESS_DB_PASSWORD=wp-pass
- WORDPRESS_DB_NAME=wp-db
networks:
- wp-network
profiles:
- desarrollo
- produccion
## BASE DE DATOS DE DESARROLLO
db-wp:
image: mysql
container_name: desarrollo-bd
restart: always
environment:
- MYSQL_DATABASE=wp-db
- MYSQL_USER=wp-user
- MYSQL_PASSWORD=wp-pass
- MYSQL_ROOT_PASSWORD=wp-pass
networks:
wp-network:
aliases:
- db-host
profiles:
- desarrollo
## BASE DE DATOS DE PRODUCCIÓN
db-wp-prod:
image: mysql
container_name: produccion-bd
restart: always
environment:
- MYSQL_DATABASE=wp-db
- MYSQL_USER=wp-user
- MYSQL_PASSWORD=wp-pass
- MYSQL_ROOT_PASSWORD=wp-pass
networks:
wp-network:
aliases:
- db-host
profiles:
- produccion
networks:
wp-network:
Sino se activan los perfiles, ese servicio estara siempre activo para cualquier usuario. Ademas quitamos
la clausula de dependencia para poder probar produccion
Mediante el cual creamos perfiles de acceso a producción y desarrollo, ademas le permitimos acceder a
wordpress mediante los dos perfiles. Ahora para ejecutarlo y activar algun perfil usamos la bandera --
profile como se muestra a continuación:
98 / 123
01-primer-contenedor.md 2024-11-22
Ademas podemos notar que cuando lo apagamos necesitamos decir el perfil tambien sino no lo apaga, esto
seria con docker compose --profile desarrollo down.
Como notamos los servicios que arranca o inicia un proceso son difernetes, en este caso la base de datos
asociada al contenedor una esta definida como produccion-bd y la otra como desarrollo-bd.
Comando COMMAND
Una opción que nos permite sustituir el comando que viene por ejemplo en el dockerfile, como el CMD o el
ENTRYPOINT. Entonces para el Dockerfile usaremos lo siguiente:
FROM ubuntu
LABEL promaster "[email protected]"
RUN apt-get update
RUN apt-get install -y nginx
RUN apt-get install -y apache2
EXPOSE 80
99 / 123
01-primer-contenedor.md 2024-11-22
apache.sh:
#!/bin/bash
echo "Estoy en apache" > /var/www/html/index.html
apachectl -D FOREGROUND
nginx.sh:
#!/bin/bash
echo "Estoy en nginx" > /var/www/html/index.html
nginx -g "daemon off;"
version: "3.9"
services:
web-apache:
build: .
image: comando:latest
container_name: apache
ports:
- 8090:80
command: ["/usr/local/bin/apache.sh"]
profiles:
- apache
web-nginx:
build: .
image: comando:latest
container_name: nginx
ports:
- 8080:80
command: ["/usr/local/bin/nginx.sh"]
profiles:
- nginx
Como se ve por medio de un perfil ejecutamos un servicio u otro, en este caso usamos la clausula command
para la ejecución de dos archivos shell que iniciaran apache o nginx segun sea el caso, ademas que ambos
provienen de la misma imagen que instala ngnix y apache, ya depende de que servicio active de esta manera
solo se usara nginx o apache dependiendo de como se envien los parámetros. Usamos valores extras como los
echo para saber que servicio ejecutamos a modo de verificación. Creamos las imagenes, en este caso al ser la
misma imagen no es necesario ejecutar el otro servicio.
100 / 123
01-primer-contenedor.md 2024-11-22
Ahora con la imagen hecha, ejecutaremos el compose docker compose --profile apache up -d y si
revisamos el puerto 8090 que es en donde tengo el apache:
Obtenemos la página con la información enviada en el archivo shell, ahora si ejecutamos docker compose -
-profile nginx up -d (recordar apagar el anterior) tendremos:
services:
stress1:
image: apache-stress
cpu_count: 1
cpu_shares: 512
mem_limit: 100m
stress2:
image: apache-stress
cpu_count: 1
cpu_shares: 1024
mem_limit: 50m
El cual cuenta con una imagen utilizada anteriormente que esta basada en apache y ademas de eso contiene
stress que nos permitira simular cargas en el sistema. Seguido de eso ejecutamos el compose y revisando
mediante docker stats tenemos lo siguiente:
Indicando los limites que le hemos asignado a los servicios y consecuentemente a sus contenedores. Ahora
mediante el acceso a cada servicio y activando la simulación mediante stress -c 10 en ambos
101 / 123
01-primer-contenedor.md 2024-11-22
contenedores podemos observar como se reparten los servicios para cada contenedor
Debido a que un servicio cuenta con 1024 y otro 512 esto se reparte de la misma forma en el acceso a la CPU.
Configurar Restart
Ahora mediante la imagen realizada imagen-restart creamos el siguiente archivo de configuración:
services:
contenedor1:
image: imagen-restart
restart: unless-stopped
contenedor2:
image: imagen-restart
restart: always
contenedor3:
image: imagen-restart
restart: on-failure:2
contenedor4:
image: imagen-restart
restart: "no"
Y una vez ejecutamos el comando y vemos los contenedores podemos ver algo como lo siguiente:
Aqui notar que el contenedor tratara de funcionar pasados dos reinicios, luego ya no reiniciara. El cuarto al
primer fallo no reinicia. El primero y el segundo siempre trataran de reiniciar, en caso del primero a menos de
que lo pare manualmente seguira reiniciandose. Ahora paramos los contenedores que siguen reiniciandose
manualmente docker compose stop nombre_servicio_activo y seguido de eso reiniciamos docker. En
este caso a vuelto a arrancar el contenedor2 que es el único que estaría vivo despues de hacer un rebote o
reinicio de Docker.
Docker Registry
102 / 123
01-primer-contenedor.md 2024-11-22
Como podemos crear nuestros propios registros/repositorios de imagen, registros privados, evitar el uso de
dockerhub, interactuar y gestionar registros privados. Si queremos trabajar localmente, usaremos el grupo de
imagenes que queremos compartir y evitar el uso de dockerhub, usaremos registros privados para
desplegarlos en el lugar que usemos como medio colaborativo de manera interna (privada)
Crear un registro
Si buscamos en dockerhub registry nos ofrece una imagen que nos da la infraestructura para crear nuestro
repositorio
Exite un standard para los servidores de registro, es que normalmente escuchan por el puerto 5000 y el restar
debe estar en always.
¿Donde guarda las imagenes que se van creando? A su vez me crea un volumen para el almacenamiento:
103 / 123
01-primer-contenedor.md 2024-11-22
De acuerdo al formato estandar. host serían una maquina que tenga un DNS y que podamos acceder a
ella de manera remota.
Si revisamos un docker inspect registro notamos las ubicaciones de los montajes del volumen.
104 / 123
01-primer-contenedor.md 2024-11-22
Donde vemos que al final tenemos un directorio para los repositorios y otro para los blobs
(./images/imagenes). Si revisamos los repositorios tendremos el que subimos apache-stress:
Ahora si queremos acceder mediante el contenedor de registro tendremos que acceder mediante una shell
ya que no podremos mediante bash:
Tendremos lo siguiente:
Donde vemos que al final llegando a la ruta que nos indico en el inspect /var/lib/registry terminaremos
llegando a lo revisado en el directorio mediante wsl, donde vemos blobs y repositories.
105 / 123
01-primer-contenedor.md 2024-11-22
Lo normal es poner tambien la etiqueta con la cual lo subi, por lo cual tambien agregaremos el latest.
A la imagen que esta en el servidor localhost ¿Podriamos nosotros acceder mediante 127.0.0.1 o a traves
del nombre de la maquina? Si.
106 / 123
01-primer-contenedor.md 2024-11-22
Como vemos podemos acceder tambien mediante la IP, ya que este nombre, ahora que pasa si quiero
acceder a traves del nombre de la maquina:
Notamos que ahora nos retorna un error, debido a que nos da una respuesta HTTP a un cliente HTTPS (Sin
seguridad). En este caso debemos indicarle que confie en ese servidor. Esto podremos hacerlo mediante una
configuración en el archivo de configuración de docker, el archivo DAEMON.json.
{
"builder": {
"gc": {
"defaultKeepStorage": "20GB",
"enabled": true
}
},
"experimental": false,
"insecure-registries": ["juanmora:5000","juanmora:5001"]
}
En el cual mediante la propiedad insecure-registries agregamos las maquinas y su puerto que queremos
generar confianza.
Nota: Es importante que los nombres de los registros se configuren con el nombre de una
maquina/servidor que ofrezca esas imagenes, y que de igual donde me encuentre y el usuario pueda
acceder a ese registro en remoto. Ya que localhost sirve para probar pero en un entorno colaborativo
se haria mediante una IP/servidor en remoto.
107 / 123
01-primer-contenedor.md 2024-11-22
Por defecto el usa /var/lib/docker/volumes pero que pasa si queremos usar otra ubicación. Entonces
supodremos que queremos dejar todo en /registro_docker.
apache-stress
sha256
108 / 123
01-primer-contenedor.md 2024-11-22
Registry API
No existen comandos que nos permitan interactuar de manera sencilla con el repositorio, ya que usualmente
nos toca desplazarnos entre directorios para llegar a la información que necesitamos. Para ello tenemos el
Registry API que nos permite cierta interacción a traves de unos cuantos comandos.
Por ejemplo accedemos a un repositorio y mediante rutas en el navegador vamos buscando los datos.
Docker Swarm
Nos permite orquestar contenedores, poder configurar y gestionar contenedores para poder tener entornos
de producción complejos y de alto rendimiento. Permite que los contenedores se expandan a traves de
multiples maquinas en forma de cluster. Docker Swarm permite crear un cluster de uno o más nodos Dockers.
Esto permite disponer de "servicios" que se despliegan de forma replicada a lo largo de los nodos del cluster
Manager: gestores del cluster, podemos tener 1 o varios. Ademas de mantener el estado del cluster.
Worker: nodo encargado del trabajo, donde se despliega el contenedor a partir de una imagen y donde
se iran a ejecutar esos servicios. Normalmente se tienen varios workers
Servicios en Swarm
109 / 123
01-primer-contenedor.md 2024-11-22
Lo primero sera inicializar un swarm, y para ello necesitamos la IP por la que se quiere trabajar.
Que a su vez vemos como podemos añadir mas nodos de tipo worker a travez del join seguido de un token.
Para verificar su funcionamiento usaremos docker info, donde una parte nos mostrará si tenemos el swarm
activo o no, id del cluster, # managers, # nodos:
Otro comando que nos permite ver los nodos que en ese momento forman parte del cluster es docker node
ls.
Y el retorna el token, contra que dirección IP y contra que puerto queremos hacer el enlace.
110 / 123
01-primer-contenedor.md 2024-11-22
Docker node solo nos sirve desde el nodo 1 ya que es el cuenta con los metadatos del cluster.
Ahora como es un manager si podemos usar los comandos docker node ls, debido a que los manager se
comunican entre si compartiendo los metadatos utilizados.
Aquí podemos evidenciar que existen diferentes estados en el campo manager, entre los nodos manager
activos se dividen en dos:
La que nos indica que cuando se tiene una configuración con 2 managers, esto tiene un alto riesgo de perder
el control sobre el cluster, por tal motivo se recomienda una configuración impar de los cluster. Esto docker lo
denomina implementación de tipo raft, recomendando un número impar, para hacer que los nodos se
puedan poner de acuerdo ante el fallo del lider.
111 / 123
01-primer-contenedor.md 2024-11-22
Podemos apreciar que ahora el Leader esta en estado Unreachable y se convirtio en Leader un nodo que
estaba como Reachabler. Sin embargo si se llega a caer otro, si entrare en un conflicto, ya que tendría
problemas para gestionar los nuevos servicios o planificaciones que tuviera que hacer. Si regresamos y
arrancamos el nodo que paramos docker.
El nodo ya no se vuelve lider pero queda disponible para su alcance en caso de que pase otro paron de algun
nodo manager.
Cuando se paran dos nodos manager de tres me generará un error, para solucionarlo se deben volver
a tener los nodos manager recomendados.
Estos comandos son alias, ya que tenemos con node una serie de funcionalidades como update:
112 / 123
01-primer-contenedor.md 2024-11-22
Servicios y tareas
Servicios
Tareas
Cuando se crea un servicio lo que se hace en realidad es lanzar una o varias tareas de tipo réplica en los
nodos.
Las tareas se ejecutan de manera completamente independiente unas de otras
Ejemplo:
Replicados: Se distribuyen en los nodos necesarios (ejemplo: debe tener dos replicas)
113 / 123
01-primer-contenedor.md 2024-11-22
114 / 123
01-primer-contenedor.md 2024-11-22
Acceder a un servicio
Creamos un servicio
publish es similar al tag -p para enlaces con el contenedor, esn este caso con un servicio. Puerto 9000
en el host conecta con el puerto 80 que escucha el contenedor.
Podemos entrar con el nombre de la maquina de cualquiera de los ocho nodos va a entrar (porque publish
publica en los ocho nodos con redes overlay). En este caso tenemos 8 maquinas virtuales en un cluster en
amazon:
115 / 123
01-primer-contenedor.md 2024-11-22
Redes Overlay
Cuando revisamos las redes notamos que tenemos dos redes nuevas, docker-gwbridge y ingress que son
creadas automaticamente cuando creamos un docker-swarm.
Estas redes que son overlay estan por encima de otras como las bridge y permite que los contenedores que
funcionan dentro de esas maquinas sean accesibles desde todos los sitios.
Nota: Se necesitan obligatoriamente las dos redes docker-gwbridge e ingress. Sin una no funciona y
toca volver a crear todo.
Cuando usamos un inspect sobre la red ingress nos da (ademas de lo mismo de otras redes):
Contenedor ejecutandose
Peers: endpoints de las maquinas donde se esta interactuando La docker-gwbridge (red que
comunica los daemons entre si de las maquinas del cluster).
Las replicas son las posibilidad que yo tengo de clonar un determinado contenedor para que pueda dar
servicio por varios servidores, permitiendo mejorar el rendimiento y tener una mayor seguridad del proyecto
o aplicación.
Primero revisamos los puertos ocupados en los servicios con un service ls:
116 / 123
01-primer-contenedor.md 2024-11-22
Replicas despues de la creación Mediante el comando scale podremos subir o disminuir esas replicas
dependiendo de nuestras necesidades.
Obteniendo:
Por defecto todos los nodos participan del trabajo de las tareas, incluso si son nodos manager. Mediante el
flag --availability podemos seleccionar entre:
active
pause: deje de recibir peticiones temporalmente
drain: no reciba peticiones
Servicios Globales
A diferencia de las replicas, estos arrancan una tarea por cada uno de los servidores que tengo en el cluster
(Solo en aquellos donde tenga activa la disponibilidad)
118 / 123
01-primer-contenedor.md 2024-11-22
Ya desde el nodo en cuestión paramos el docker con sudo systemctl stop docker. Notamos que despues
de un momento identifica que el nodo se paro y para la tarea.
Modificar un servicio
Etiquetas un nodo
119 / 123
01-primer-contenedor.md 2024-11-22
Mediante la bandera label-add podemos actualizar el nombre o la etiqueta del nodo. Ademas que con
label-rm podemos remover un nombre o etiqueta existente.
Pero, ¿Donde se ven las etiquetas? para ello podemos usar docker node inspect id_nodo --pretty
Y observamos que dentro de la información del nodo encontramos la etiqueta asignada. Tambien podemos
usar otro comando, pero este nos sirve para filtrar por alguna etiqueta en particular, por ejemplo, buscaremos
los nodos que contengan rack en su etiqueta.
Vamos a utilizar una etiqueta para indicarle al docker swarm para que solo despliegue las replicas en los
nodos con dicha etiqueta
120 / 123
01-primer-contenedor.md 2024-11-22
Todos aquellos nodos con la etiqueta rack y su valor sea r1 les pondras el servicio con nginx.
Pero que pasa si le ponemos por defecto las replicas que queremos
El intentara lanzar las 6 tareas, pero se restringira en los 2 nodos que en este momento cuentan con la
etiqueta rack
Vemos que a divido de manera homogenea las replicas entre los 2 nodos. Ahora probaremos con un servicio
de tipo global, ya que estos dejaban una replica en cada uno de los nodos existentes:
En este caso evitamos la etiqueta rack con valor r1 y en todos los demas nodos se lanza el servicio.
121 / 123
01-primer-contenedor.md 2024-11-22
Si revisamos el servicio, veremos que esta corriendo pero con un mensaje de error de que no encontro un
nodo disponible para desplegarse
1. Abandone el cluster
122 / 123
01-primer-contenedor.md 2024-11-22
123 / 123