Puertos, servicios y acceso a contenedores
1. Servicios dentro de un contenedor #
Hasta ahora hemos utilizado principalmente contenedores Linux interactivos.
Sin embargo, Docker se utiliza habitualmente para ejecutar servicios como:
1Nginx 2Apache 3MySQL 4PostgreSQL 5MongoDB 6Redis
Estos servicios suelen escuchar en determinados puertos.
Por ejemplo:
1Nginx → puerto 80 2MySQL → puerto 3306
El problema es que el puerto del contenedor no es directamente el mismo puerto de nuestro ordenador.
Por eso necesitamos realizar un mapeo de puertos.
2. Puertos del host y del contenedor #
Imaginemos un servidor Nginx.
Dentro del contenedor Nginx escucha en:
1Puerto 80
Pero nosotros queremos acceder desde nuestro ordenador.
Podemos hacer que:
1ORDENADOR CONTENEDOR 2Puerto 33 ───────→ Puerto 80
De esta forma podremos acceder mediante:
1http://localhost:33
3. Publicar puertos #
Docker permite publicar los puertos de un contenedor principalmente mediante:
1-P
y:
1-p
Existe una diferencia importante entre ambos.
4. Publicación automática: -P #
La opción:
1-P
en mayúscula permite que Docker asigne automáticamente puertos disponibles en el equipo anfitrión.
Por ejemplo:
1docker run -dP nginx
También podríamos escribir:
1docker run -d -P nginx
5. ¿Qué significa -d? #
La opción:
1-d
significa:
1detached
Hace que el contenedor se ejecute en segundo plano.
Sin -d, la terminal puede quedar asociada directamente al proceso del contenedor.
Con:
1docker run -dP nginx
Nginx queda funcionando en segundo plano y recuperamos inmediatamente nuestra consola.
6. Comprobar el contenedor #
Después de ejecutar:
1docker run -dP nginx
podemos comprobarlo con:
1docker ps
Podremos encontrar una salida similar a:
1CONTAINER ID IMAGE STATUS PORTS 2abc123 nginx Up ... 0.0.0.0:32769->80/tcp
La parte importante es:
132769 -> 80
Esto significa:
1HOST CONTENEDOR 232769 ───────→ 80
Por tanto, accederíamos desde el navegador mediante:
1http://localhost:32769
7. Inconveniente de -P #
Con:
1docker run -dP nginx
Docker decide automáticamente qué puerto utilizar en nuestra máquina.
Esto resulta cómodo, pero el puerto podría ser diferente cada vez.
Por ejemplo:
132768 232769 332770
Normalmente resulta más práctico decidir nosotros qué puerto queremos utilizar.
Para eso utilizamos:
1-p
8. Publicación manual: -p #
La opción:
1-p
en minúscula permite indicar manualmente el puerto del host y el puerto del contenedor.
La sintaxis es:
1docker run -p <puerto_host>:<puerto_contenedor> <imagen>
Por ejemplo:
1docker run -p 33:80 nginx
Esto significa:
1Puerto 33 del ordenador 2 ↓ 3Puerto 80 del contenedor
9. Ejecutar Nginx en segundo plano #
Normalmente queremos ejecutar un servidor web como servicio en segundo plano.
Utilizamos:
1docker run -dp 33:80 nginx
Este comando combina:
1-d
ejecución en segundo plano.
y:
1-p 33:80
mapeo de puertos.
10. Interpretar docker run -dp 33:80 nginx #
El comando:
1docker run -dp 33:80 nginx
podemos interpretarlo así:
1docker run 2 ↓ 3crear y arrancar el contenedor 4 5-d 6 ↓ 7ejecutar en segundo plano 8 9-p 33:80 10 ↓ 11puerto 33 del host → puerto 80 del contenedor 12 13nginx 14 ↓ 15imagen utilizada
11. Probar Nginx #
Ejecutamos:
1docker run -dp 33:80 nginx
Después abrimos el navegador:
1http://localhost:33
Deberíamos ver la página inicial de Nginx.
12. Comprobar el mapeo #
Ejecutamos:
1docker ps
En la columna:
1PORTS
podremos encontrar algo como:
10.0.0.0:33->80/tcp
Esto indica:
1puerto 33 del host → puerto 80 del contenedor
13. Otro ejemplo #
Podemos utilizar el puerto 8080 de nuestro ordenador:
1docker run -dp 8080:80 nginx
Entonces accederemos mediante:
1http://localhost:8080
Nginx sigue escuchando internamente en:
180
pero nosotros hemos decidido utilizar externamente:
18080
14. Podemos tener varios Nginx #
Una de las ventajas de Docker es poder ejecutar varios contenedores de una misma imagen.
Por ejemplo:
1docker run -dp 8080:80 nginx
y:
1docker run -dp 8081:80 nginx
Tendríamos:
1localhost:8080 2 ↓ 3Nginx contenedor 1 4 5 6localhost:8081 7 ↓ 8Nginx contenedor 2
Ambos contenedores utilizan internamente el puerto 80.
15. ¿Podemos usar el mismo puerto dos veces? #
No podemos tener dos servicios distintos escuchando simultáneamente en el mismo puerto del host.
Por ejemplo:
1docker run -dp 33:80 nginx
Si el puerto 33 ya está ocupado, otro:
1docker run -dp 33:80 nginx
producirá un error.
Podríamos utilizar otro puerto:
1docker run -dp 34:80 nginx
16. Poner nombre al servidor Nginx #
Podemos combinar lo aprendido anteriormente.
Por ejemplo:
1docker run -d -p 33:80 --name mi-nginx nginx
O:
1docker run -dp 33:80 --name mi-nginx nginx
Ahora podremos utilizar:
1docker stop mi-nginx
1docker start mi-nginx
1docker inspect mi-nginx
17. Práctica con Nginx #
Ejecuta:
1docker run -dp 80:80 --name servidor-web nginx
Comprueba:
1docker ps
Accede desde el navegador:
1http://localhost
Después detén el servidor:
1docker stop servidor-web
Comprueba:
1docker ps
Y:
1docker ps -a
Finalmente vuelve a arrancarlo:
1docker start servidor-web
Y prueba de nuevo:
1http://localhost
18. docker exec #
Una vez que tenemos un contenedor funcionando, en muchas ocasiones queremos ejecutar un comando dentro de él.
Para ello utilizamos:
1docker exec
La sintaxis general es:
1docker exec <contenedor> <comando>
19. Ejecutar un comando dentro del contenedor #
Por ejemplo, si tenemos:
1mi-nginx
podemos ejecutar:
1docker exec mi-nginx ls
Docker ejecutará:
1ls
dentro del contenedor.
20. Obtener una shell con docker exec #
También podemos obtener una shell interactiva dentro de un contenedor que ya está funcionando.
Utilizamos:
1docker exec -it <contenedor> bash
Por ejemplo:
1docker exec -it mi-nginx bash
Ahora veremos algo similar a:
1root@abc123:/#
Estamos trabajando dentro del contenedor Nginx.
21. docker exec frente a docker attach #
En el bloque anterior utilizamos:
1docker attach
Ahora tenemos:
1docker exec -it
No hacen exactamente lo mismo.
docker attach #
Se conecta al proceso principal que ya está ejecutándose en el contenedor.
1docker attach miDebian
docker exec #
Crea y ejecuta un nuevo proceso dentro de un contenedor existente.
Por ejemplo:
1docker exec -it mi-nginx bash
Para entrar en contenedores que ejecutan servicios, normalmente resulta muy útil:
1docker exec -it
22. Ejemplo con Nginx #
Arrancamos:
1docker run -dp 80:80 --name mi-nginx nginx
Después obtenemos una shell:
1docker exec -it mi-nginx bash
Dentro podemos ejecutar:
1ls
1cd /usr/share/nginx/html
1ls
Ahí encontraremos los archivos de la página web de Nginx.
23. Modificar el index.html #
Dentro del contenedor podríamos instalar un editor.
Por ejemplo:
1apt update
Después:
1apt install nano
Accedemos a:
1cd /usr/share/nginx/html
Editamos:
1nano index.html
Guardamos los cambios.
Después podemos actualizar:
1http://localhost
y veremos el nuevo contenido.
24. Ver los puertos publicados: docker port #
Docker dispone del comando:
1docker port
para consultar los puertos publicados de un contenedor.
La sintaxis es:
1docker port <contenedor>
Por ejemplo:
1docker port mi-nginx
Podríamos obtener:
180/tcp -> 0.0.0.0:33
Esto significa:
1CONTENEDOR HOST 280 → 33
25. Ejemplo práctico de docker port #
Creamos:
1docker run -dp 4000:80 --name web nginx
Consultamos:
1docker port web
Obtendremos información indicando que:
180/tcp
está publicado en:
14000
Podremos acceder mediante:
1http://localhost:4000
26. Resumen de -P y -p #
-P #
1docker run -dP nginx
Docker selecciona automáticamente el puerto del host.
Ejemplo:
132769 → 80
-p #
1docker run -dp 33:80 nginx
Nosotros seleccionamos el puerto.
133 → 80
Una forma fácil de recordarlo:
1-P → Puerto automático 2 3-p → Puerto indicado por nosotros
27. Creación de un contenedor MySQL #
Docker también permite ejecutar servidores de bases de datos.
Vamos a crear un contenedor MySQL.
Primero descargamos la imagen:
1docker pull mysql
Después crearemos el contenedor.
28. Ejecutar MySQL #
Podemos utilizar:
1docker run -d \ 2 -p 3306:3306 \ 3 --name mysql \ 4 -e MYSQL_ROOT_PASSWORD=Ad1234 \ 5 mysql
En una única línea:
1docker run -d -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=Ad1234 mysql
29. Explicar el comando MySQL #
Tenemos:
1docker run
Crea un nuevo contenedor.
1-d
Ejecuta MySQL en segundo plano.
1-p 3306:3306
Publica:
1Puerto host: 3306 2Puerto contenedor: 3306
MySQL utiliza normalmente el puerto:
13306
1--name mysql
Pone al contenedor el nombre:
1mysql
1-e
permite definir una variable de entorno.
En este caso:
1MYSQL_ROOT_PASSWORD
1MYSQL_ROOT_PASSWORD=Ad1234
establece la contraseña del usuario root de MySQL.
30. Comprobar MySQL #
Ejecutamos:
1docker ps
Deberíamos encontrar:
1mysql
en ejecución.
También podemos consultar:
1docker port mysql
31. Ver los logs de MySQL #
Un servicio puede tardar unos segundos en inicializarse.
Podemos consultar sus mensajes mediante:
1docker logs mysql
Esto resulta especialmente útil para comprobar:
- Si MySQL ha arrancado.
- Si existe algún error.
- Si la configuración es correcta.
32. Acceder al cliente MySQL #
Podemos utilizar docker exec para ejecutar directamente el cliente MySQL dentro del contenedor.
Ejecutamos:
1docker exec -it mysql mysql -uroot -p
Nos pedirá la contraseña.
Introducimos la contraseña configurada anteriormente.
Después veremos:
1mysql>
Ya estamos dentro del servidor MySQL.
33. ¿Qué hace este comando? #
Tenemos:
1docker exec -it mysql mysql -uroot -p
Primera parte:
1docker exec -it mysql
significa:
1ejecutar interactivamente un comando 2dentro del contenedor llamado mysql
Segunda parte:
1mysql -uroot -p
es el comando que ejecutamos dentro del contenedor.
Significa:
1abrir el cliente MySQL 2con el usuario root 3solicitando contraseña
34. Primeras operaciones en MySQL #
Una vez dentro:
1mysql>
podemos crear una base de datos:
1CREATE DATABASE cebem;
Mostrar las bases de datos:
1SHOW DATABASES;
Seleccionarla:
1USE cebem;
Crear una tabla:
1CREATE TABLE profesor ( 2 id INT NOT NULL AUTO_INCREMENT, 3 nombre VARCHAR(20), 4 PRIMARY KEY (id) 5);
35. Insertar información #
Podemos insertar:
1INSERT INTO profesor(nombre) 2VALUES ('Pepe');
Y consultar:
1SELECT * FROM profesor;
36. Salir de MySQL #
Podemos ejecutar:
1exit;
Volveremos a nuestra terminal.
El contenedor seguirá ejecutándose.
Podemos comprobarlo:
1docker ps
37. Parar MySQL #
Podemos detenerlo:
1docker stop mysql
Comprobamos:
1docker ps
38. Volver a arrancarlo #
Utilizamos:
1docker start mysql
39. Reiniciar MySQL #
También podemos utilizar:
1docker restart mysql
40. Volver a conectarnos #
Ejecutamos:
1docker exec -it mysql mysql -uroot -p
Podemos comprobar que la base de datos creada sigue existiendo:
1SHOW DATABASES;