Docker馃敆
El proyecto Docker te permitir谩 la creaci贸n de entornos de construcci贸n y/o ejecuci贸n de c贸digo fuente o procesos a partir del uso de im谩genes y contenedores.
Una imagen suele ser un sistema operativo (basado en GNU/Linux) y el contenedor puede ser desde un proceso (un interprete de comandos, un servidor de HTTP o un sistema gestor de bases de datos) hasta una aplicaci贸n web o una aplicaci贸n de escritorio.
Mientras que una imagen es obtenida y/o publicada en Docker Hub, un contenedor es creado de manera local.
驴Qu茅 es Docker?
Docker es una plataforma de software que le permite crear, probar e implementar aplicaciones r谩pidamente. Docker empaqueta software en unidades estandarizadas llamadas contenedores que incluyen todo lo necesario para que el software se ejecute, incluidas bibliotecas, herramientas de sistema, c贸digo y tiempo de ejecuci贸n. - AWS Amazon
Docker (software)
Docker es un proyecto de c贸digo abierto que automatiza el despliegue de aplicaciones dentro de contenedores de software, proporcionando una capa adicional de abstracci贸n y automatizaci贸n de virtualizaci贸n de aplicaciones en m煤ltiples sistemas operativos. - Wikipedia
Una excelente introducci贸n a Docker por parte de Peter McKee hablando de im谩genes, contenedores, red, e inclusive Docker Hub:
Instalaci贸n馃敆
-
En el caso de usar Microsoft Windows o macOS te ser谩 necesario la instalaci贸n de Docker Desktop as铆 como la instalaci贸n de otros programas (virtualizadores) seg煤n sea el caso.
-
En GNU/Linux te ser谩 necesario hacer uso del gestor de paquetes de tu distribuci贸n para la instalaci贸n del paquete docker.
La instalaci贸n de Docker incluye a Docker Compose.
Imagen馃敆
Se har谩 uso de dos im谩genes ofrecidas en Docker Hub, ambas im谩genes corresponden a distribuciones del sistema operativo GNU/Linux:
- Alpine Linux: versi贸n 3.13
- Debian: versi贸n 10
Para obtener (pull) dichas im谩genes se ejecuta lo siguiente en la l铆nea de comandos:
[nihilipster@localhost:~]$ docker image pull alpine:3.13.2
[nihilipster@localhost:~]$ docker image pull debian:10.8
Importante
- Es recomendable obtener las 煤ltimas versiones disponibles as铆 como siempre ser explicitos en la versi贸n usada.
- Es posible obtener tantas im谩genes como sean necesarias desde Docker Hub tomando en cuenta su espacio.
- Es posible borrar una imagen mientras ning煤n contenedor se encuentre haciendo uso de ella.
Contenedor馃敆
Mientras que una imagen es obtenida de Docker Hub, un contenedor es creado (create) de manera local a partir de una imagen previamente obtenida. Es posible crear tantos contenedores como sean necesarios a partir de una misma imagen tomando en cuenta el espacio usado en disco duro por cada contenedor. Por otro lado, es posible crear-iniciar-detener-borrar un contenedor sin afectar la imagen a partir del cual fue creado.
El interprete de comandos sh (Bourne Shell)馃敆
Para la creaci贸n de un contenedor a partir de la imagen de Alpine Linux:
[nihilipster@localhost:~]$ docker container create --name alpine-sh --tty --interactive alpine:3.13.2
Para obtener una lista de contenedores y su estado (STATUS):
[nihilipster@localhost:~]$ docker container ls -a
CONTAINER ID IMAGE COMMAND STATUS PORTS NAMES
xxxxxxxxxxxx alpine:3.13.2 "sh" Created alpine-sh
Para iniciar un contenedor:
[nihilipster@localhost:~]$ docker container start --attach --interactive alpine-sh
Por el ejemplo abordado al iniciar el contenedor se obtendr谩 un interprete de comandos de Alpine Linux llamado
sh
(Bourne Shell):
/ # env
HOSTNAME=yyyyyyyyyyyyyy
SHLVL=1
HOME=/root
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
/ # whoami
root
/ # cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.13.2
PRETTY_NAME="Alpine Linux v3.13"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://bugs.alpinelinux.org/"
/ # exit
Al salir de sh
se puede observar que el contenedor se ha detenido:
[nihilipster@localhost:~]$ docker container ls -a
CONTAINER ID IMAGE COMMAND STATUS PORTS NAMES
xxxxxxxxxxxx alpine:3.13.2 "/bin/sh" Exited (0) 2 minutes ago alpine-sh
El interprete de comandos Bash (GNU Bash)馃敆
Se procede de manera similar al ejemplo dado con Alpine Linux haciendo modificaciones donde sea necesario tomando
en cuenta que el interprete de comandos en Debian es bash
(GNU Bash).
[nihilipster@localhost:~]$ docker container create --name debian-bash --tty --interactive debian:10.8
[nihilipster@localhost:~]$ docker container start --attach --interactive debian-bash
root@zzzzzzzzzzzzzzz:/# env
HOSTNAME=zzzzzzzzzzzzzzz
PWD=/
HOME=/root
TERM=xterm
SHLVL=1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
_=/usr/bin/env
root@zzzzzzzzzzzzzzz:/# whoami
root
root@zzzzzzzzzzzzzzz:/# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
Informaci贸n
sh
tambi茅n est谩 disponible en Debian pero realmente se trata dedash
(Debian Almquist Shell).
El sistema operativo GNU/Linux馃敆
En los anteriores interpretes de comandos fueron usados los comandos env
, whoami
y cat
. Para aprender
otros comandos disponibles pero sobre todo para familiarizarse con el sistema operativo y su interprete de
comandos tienes los siguientes recursos:
- Learning the Shell.
- Ryans Tutorials, Linux Tutorial: solo las secciones 1, 2, 3, 5, 7, 8, 9, 10, 11 y 14.
Algunos comandos abordados en los anteriores recursos no est谩n disponibles en las im谩genes de Alpine Linux y
Debian; tal es el caso de tree
, vim
, ps
, file
, entre otros tantos. Es posible instalarlos en caso de ser
necesario.
Advertencia
Existen otros tantos proyectos-terminos asociados a Docker, tal es el caso de Docker Compose, Docker Swarm, Kubernetes, DevOps, Continuous Integration, Continuous Delivery, Continuous Deployment, etc. por lo que ser谩 importante concentrarse solo en aquello que por el momento sea necesario.
Las siguientes presentaciones por parte de Wendy Fabela puede ser de tu interes para contextualizar a Docker.
Paquetes en Alpine Linux y Debian馃敆
Las im谩genes de Alpine Linux y Debian disponibles en Docker Hub no cuentan con varios paquetes por lo que es necesario hacer uso de sus gestores de paquetes dentro de los distintos contenedores que podamos crear.
Para lo siguiente se ejemplificar谩 con la instalaci贸n del editor de texto Nano, el cual no forma parte de las im谩genes de ambos sistemas operativos.
Informaci贸n
Las im谩genes de los sistemas operativos solo integran lo m谩s b谩sico e indispensable para su ejecuci贸n, esto se hace principalmente para reducir su tama帽o-peso por lo que aprender a su administraci贸n es clave para brindar mayor seguridad tanto al contenedor como aquello que le integremos.
Alpine Linux馃敆
Se ofrece https://pkgs.alpinelinux.org/packages para la b煤squeda de paquetes. Por ejemplo ingresando nano, seleccionando v13.3, x86_64 y dando click al bot贸n de Search se obtiene un resultado con el paquete de Nano disponible.
Por otro lado, en la l铆nea de comandos, dentro de alg煤n contenedor basado en la imagen de Alpine Linux podemos
hacer uso del gestor de paquetes apk
:
[nihilipster@localhost:~]$ docker container start --attach --interactive alpine-sh
/ # which nano
/ #
/ # apk update
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/community/x86_64/APKINDEX.tar.gz
v3.13.2-105-g4e9e4fc875 [https://dl-cdn.alpinelinux.org/alpine/v3.13/main]
v3.13.2-106-g54cefe59f4 [https://dl-cdn.alpinelinux.org/alpine/v3.13/community]
OK: 13878 distinct packages available
/ # apk search nano
nano-doc-5.4-r1
plasma-nano-5.20.5-r0
nano-5.4-r1
nano-syntax-5.4-r1
/ # apk add nano
(1/4) Installing libmagic (5.39-r0)
(2/4) Installing ncurses-terminfo-base (6.2_p20210109-r0)
(3/4) Installing ncurses-libs (6.2_p20210109-r0)
(4/4) Installing nano (5.4-r1)
Executing busybox-1.32.1-r3.trigger
OK: 13 MiB in 18 packages
/ # which nano
/usr/bin/nano
Por un lado se ha actualizado la lista de paquetes disponibles con apk update
, posteriormente se ha buscado a
Nano con apk search
y finalmente se ha instalado con apk add
. Por otro lado como puedes observar which
no
encuentra a nano
en el PATH
sin embargo una vez instalado indica su ubicaci贸n en /usr/bin/nano
.
Finalmente, podr谩s hacer uso del editor de texto Nano solo en este contenedor haciendo uso del comando nano
.
Debian馃敆
Se ofrece https://www.debian.org/distrib/packages para la b煤squeda de paquetes. Por ejemplo, ingresando nano, seleccionando Package names only, stable y dando click al bot贸n de Search se obtiene un resultado con el paquete de Nano disponible.
Por otro lado, en la l铆nea de comandos, dentro de alg煤n contenedor basado en la imagen de Debian podemos hacer
uso del gestor de paquetes apt
:
[nihilipster@localhost:~]$ docker container start --attach --interactive debian-bash
root@yyyyyyyyyyyy:/# which nano
root@yyyyyyyyyyyy:/#
root@yyyyyyyyyyyy:/# apt-get update
Get:1 http://security.debian.org/debian-security buster/updates InRelease [65.4 kB]
Hit:2 http://deb.debian.org/debian buster InRelease
Get:3 http://deb.debian.org/debian buster-updates InRelease [51.9 kB]
Fetched 117 kB in 1s (136 kB/s)
Reading package lists... Done
root@yyyyyyyyyyyy:/# apt-cache search '^nano$'
nano - small, friendly text editor inspired by Pico
root@yyyyyyyyyyyy:/# apt-get install nano
Reading package lists... Done
Building dependency tree
Reading state information... Done
nano is already the newest version (3.2-3).
0 upgraded, 0 newly installed, 0 to remove and 1 not upgraded.
root@yyyyyyyyyyyy:/# which nano
/bin/nano
Por un lado se ha actualizado la lista de paquetes disponibles con apt-get update
, posteriormente se ha buscado a Nano con apt-cache search
y finalmente se ha instalado con apt-get install
. Por otro lado, como puedes
observar which
no encuentra a nano
en el PATH
sin embargo una vez instalado indica su ubicaci贸n en
/bin/nano
.
Finalmente, podr谩s hacer uso del editor de texto Nano solo en este contenedor haciendo uso del comando nano
.
Importante
A煤n cuando el comando usualmente usado en Debian es apt
por cuestiones del uso de Docker y la
programaci贸n/automatizaci贸n de paquetes se recomienda hacer uso de apt-get
y apt-cache
para la
administraci贸n de paquetes en Debian
Creaci贸n de im谩genes de Docker.馃敆
Uno de los aspectos interesantes de Docker es la creaci贸n de im谩genes a partir de una imagen pre existente. Por ejemplo, podr铆as crear una imagen en base a GNU/Linux en la cual automatizar la instalaci贸n de programas/bibliotecas as铆 como su configuraci贸n para poder crear contenedores de alguna aplicaci贸n de usuario.
Lo anteriormente mencionado se ejemplificar谩 creando una imagen para una aplicaci贸n de usuario en la l铆nea de comandos usando Java 11.
Aplicaci贸n de usuario馃敆
El c贸digo fuente para la aplicaci贸n de usuario haciendo uso de Java 11 es el siguiente, Main.java
:
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Main {
public static void main(String[] args) {
var ubicacionArchivo = "/etc/os-release";
var contenidoArchivo = "";
try {
contenidoArchivo = Files.readString(Paths.get(ubicacionArchivo), StandardCharsets.UTF_8);
} catch (IOException e) {
System.out.println("[Clase Main] Error en la lectura de '" + ubicacionArchivo + "'");
System.err.println("[Clase Main] Excepci贸n atrapada '" + e + "'");
System.exit(1);
}
System.out.println("|---------------------------------");
System.out.println("| Contenido de " + ubicacionArchivo);
System.out.println("|---------------------------------");
System.out.println(contenidoArchivo);
System.out.println("|---------------------------------");
}
}
Definici贸n de imagen馃敆
Para definir una imagen har谩s uso de un archivo Dockerfile
en el cual (usando un conjunto de directivas o nem贸nicos) definir谩s la imagen pre existente desde la cual
se construir谩 (build) una nueva imagen as铆 como las instrucciones necesarias para copiar y compilar el
c贸digo fuente de la aplicaci贸n de usuario en la imagen.
Importante
El archivo Dockerfile
debe estar en la misma carpeta que Main.java
.
-
Dockerfile para Alpine Linux:
FROM alpine:3.13.2 LABEL description="Aplicaci贸n en la l铆nea de comandos con Java 11" ENV APP_DIR="/app" ENV JAVA_HOME="/usr/lib/jvm/default-jvm" ENV PATH="$JAVA_HOME/bin:$PATH" WORKDIR "$APP_DIR" RUN apk update --quiet --no-cache RUN apk add --quiet --no-cache openjdk11-jdk COPY Main.java "$APP_DIR"/ RUN javac Main.java CMD ["java", "Main"]
-
Dockerfile para Debian:
FROM debian:10.8 LABEL description="Aplicaci贸n en la l铆nea de comandos con Java 11" ENV APP_DIR="/app" ENV JAVA_HOME="/usr/lib/jvm/java-11-openjdk-amd64" ENV PATH="$JAVA_HOME/bin:$PATH" WORKDIR "$APP_DIR" RUN apt-get update --quiet --assume-yes RUN apt-get install --quiet --assume-yes openjdk-11-jdk COPY Main.java "$APP_DIR"/ RUN javac Main.java CMD ["java", "Main"]
Construcci贸n de nueva imagen馃敆
Como siguiente paso es necesario que te encuentres en la misma carpeta donde se encuentran los archivos
Dockerfile
y Main.java
para que ejecutes la opci贸n build de Docker, dando un nombre (--tag
) a la nueva
imagen:
-
Construcci贸n de nueva imagen a partir de Alpine Linux:
[nihilipster@localhost:~]$ docker build --tag java11-app:0.1.0 . Sending build context to Docker daemon ... Step 1/11 : FROM alpine:3.13.2 ... Step 2/11 : LABEL description="Aplicaci贸n en la l铆nea de comandos con Java 11" ... ... ... Successfully tagged java11-app:0.1.0
-
Construcci贸n de nueva imagen a partir de Debian:
[nihilipster@localhost:~]$ docker build --tag java11-app:0.1.0 . Sending build context to Docker daemon 7.168kB Step 1/11 : FROM debian:10.8 ... Step 2/11 : LABEL description="Aplicaci贸n en la l铆nea de comandos con Java 11" ... ... ... Successfully tagged java11-app:0.1.0
Al terminar la ejecuci贸n de alguno de ellos uno puedes observa la nueva imagen creada, prestando atenci贸n en la diferencia de sus tama帽os (SIZE):
[nihilipster@localhost:~]$ docker image ls -a
REPOSITORY TAG IMAGE ID SIZE
java11-app 0.1.0 xxxxxxxxxx ???MB
Advertencia
Se debe de tomar en cuenta que solo es posible tener una imagen con un nombre en especifico (--tag
) dado
que en los anteriores casos se est谩 usando el mismo nombre (java11-app:0.1.0
) para la creaci贸n de la nueva
imagen.
Creaci贸n de nuevo contenedor馃敆
Para la creaci贸n de un nuevo contenedor haciendo uso de la imagen recientemente creada ejecuta lo siguiente, seg煤n el caso:
[nihilipster@localhost:~]$ docker container create --name app01 --tty --interactive java11-app:0.1.0
Podr谩s observar la creaci贸n del nuevo contenedor mediante:
[nihilipster@localhost:~]$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
xxxxxxxxxxxx java11-app:0.1.0 "java Main" 3 minutes ago Created app01
Ejecuci贸n o inicio del contenedor馃敆
Para que inicialices el nuevo contenedor:
-
Inicializaci贸n de nuevo contenedor en base a Alpine Linux:
[nihilipster@localhost:~]$ docker container start --attach --interactive app01 |-------------------------------- | Contenido de /etc/os-release |-------------------------------- NAME="Alpine Linux" ... ... ... BUG_REPORT_URL="https://bugs.alpinelinux.org/" |--------------------------------
-
Inicializaci贸n de nuevo contenedor en base a Debian:
[nihilipster@localhost:~]$ docker container start --attach --interactive app01 |-------------------------------- | Contenido de /etc/os-release |-------------------------------- PRETTY_NAME="Debian GNU/Linux 10 (buster)" ... ... ... BUG_REPORT_URL="https://bugs.debian.org/" |--------------------------------
Una vez que obtengas lo programado en Main.java
observar谩s que el contenedor se encuentra detenido:
[nihilipster@localhost:~]$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
xxxxxxxxxxxx java11-app:0.1.0 "java Main" 7 minutes ago Exited (0) 24 seconds ago app01
Reutilizaci贸n de im谩genes馃敆
Algo muy importante de observar de los contenedores creados es su tama帽o (SIZE), en el caso de Alpine Linux se obtuvo un contenedor de ~200MB mientras que para Debian uno de ~900MB.
Ante la anterior observaci贸n es muy recomendable que busques una imagen base que ya contenga lo necesario para que tu imagen-contenedor tenga un tama帽o m谩s peque帽o.
En el caso particular que se ha planteado ya existen im谩genes especificas para aplicaciones basadas en Java por
lo que no es necesario hacer uso de Alpine Linux o Debian y despu茅s instalar (apk
/apt-get
) el JDK en ellos:
- adoptopenjdk: https://hub.docker.com/_/adoptopenjdk
- openjdk: https://hub.docker.com/_/openjdk
- azul: https://hub.docker.com/u/azul
Analiza las secciones How to use this Image en los anteriores enlaces para comprender este 煤ltimo punto.
Por otro lado tambi茅n es posible encontrar im谩genes base para:
- Otros sistemas operativos:
- CentOS: https://hub.docker.com/_/centos
- fedora: https://hub.docker.com/_/fedora
- Windows: https://hub.docker.com/_/microsoft-windows
- Lenguajes de programaci贸n:
- C/C++ con GCC: https://hub.docker.com/_/gcc
- C# y ASP (.Net): https://hub.docker.com/_/microsoft-dotnet
- F#: https://hub.docker.com/_/fsharp
- PHP: https://hub.docker.com/_/php
- Python: https://hub.docker.com/_/python
- Ruby: https://hub.docker.com/_/ruby
- Node.js: https://hub.docker.com/_/node
- Sistemas Gestores de Bases de Datos:
- MariaDB: https://hub.docker.com/_/mariadb
- MySQL: https://hub.docker.com/_/mysql
- MongoDB:https://hub.docker.com/_/mongo
- PostgreSQL: https://hub.docker.com/_/postgres
- Redis: https://hub.docker.com/_/redis
- Cassandra: https://hub.docker.com/_/cassandra
- CouchDB: https://hub.docker.com/_/couchdb
- Aplicaciones o servidores:
- nginx: https://hub.docker.com/_/nginx
- httpd: https://hub.docker.com/_/httpd
- Drupal: https://hub.docker.com/_/drupal
- Joomla: https://hub.docker.com/_/joomla
- Sonarqube: https://hub.docker.com/_/sonarqube
- Solr: https://hub.docker.com/_/solr
- Odoo: https://hub.docker.com/_/odoo
- Jenkins: https://registry.hub.docker.com/_/jenkins/
Te recomiendo la excelente presentaci贸n, con consejos pr谩cticos para la creaci贸n de un Dockerfile
, por parte de
Tibor Vass y Sebastiaan van Stijn hablando sobre environments, minimal im谩genes, tags, cache, as铆 como
multi-stage images:
Red en Docker.馃敆
Un contenedor en Docker puede tener comunicaci贸n de red mediante drivers de red (subsistemas de comunicaci贸n de Docker) ya integrados en Docker o bien ofrecidos mediante plugins por terceros.
El driver de red bridge permite la comunicaci贸n entre contenedores dentro de la misma computadora o instancia de Docker. Docker conecta un contenedor a un bridge ya activado por default .
Para ejemplificar la comunicaci贸n con un servicio o proceso en un contenedor se har谩 uso del protocolo de red Echo.
Java: EchoServer & EchoClient馃敆
-
EchoServer.java
/* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Oracle or the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import java.net.*; import java.io.*; public class EchoServer { public static void main(String[] args) throws IOException { if (args.length != 1) { System.err.println("Usage: java EchoServer <port number>"); System.exit(1); } int portNumber = Integer.parseInt(args[0]); try ( ServerSocket serverSocket = new ServerSocket(Integer.parseInt(args[0])); Socket clientSocket = serverSocket.accept(); PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); BufferedReader in = new BufferedReader( new InputStreamReader(clientSocket.getInputStream())); ) { String inputLine; while ((inputLine = in.readLine()) != null) { out.println(inputLine); } } catch (IOException e) { System.out.println("Exception caught when trying to listen on port " + portNumber + " or listening for a connection"); System.out.println(e.getMessage()); } } }
-
EchoClient.java
/* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Oracle or the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import java.net.*; import java.io.*; public class EchoServer { public static void main(String[] args) throws IOException { if (args.length != 1) { System.err.println("Usage: java EchoServer <port number>"); System.exit(1); } int portNumber = Integer.parseInt(args[0]); try ( ServerSocket serverSocket = new ServerSocket(Integer.parseInt(args[0])); Socket clientSocket = serverSocket.accept(); PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); BufferedReader in = new BufferedReader( new InputStreamReader(clientSocket.getInputStream())); ) { String inputLine; while ((inputLine = in.readLine()) != null) { out.println(inputLine); } } catch (IOException e) { System.out.println("Exception caught when trying to listen on port " + portNumber + " or listening for a connection"); System.out.println(e.getMessage()); } } }
Informaci贸n
La implementaci贸n en Java ha sido obtenida de Reading from and Writing to a Socket.
Dockerfile馃敆
FROM adoptopenjdk:11.0.10_9-jre-hotspot
LABEL description="EchoServer"
LABEL source="https://docs.oracle.com/javase/tutorial/networking/sockets/readingWriting.html"
ENV APP_DIR="/app"
ENV ECHO_PORT="7"
EXPOSE "$ECHO_PORT"
WORKDIR "$APP_DIR"
COPY EchoServer.class "$APP_DIR"/
CMD ["bash", "-c", "java EchoServer $ECHO_PORT"]
Importante
- El archivo
Dockerfile
se encontrar谩 en la misma carpeta que los archivosEchoClient.java
yEchoServer.java
. - La imagen usada es el JRE, mas no es JDK, del proyecto AdoptOpenJDK por lo que solo se puede ejecutar c贸digo de Java en dicho contenedor.
- La compilaci贸n del cliente y del servidor del protocolo de red Echo se hace desde el sistema anfitri贸n
(el sistema donde se haya instalado y se ejecute a Docker):
javac EchoCliente.java
javac EchoServer.java
- Solo el servidor
EchoServer.class
es copiado (COPY) en el contenedor. - La ejecuci贸n del cliente
EchoCliente
es llevado a cabo dentro del sistema anfitri贸n.
Imagen馃敆
Puedes obtener primero la imagen de Docker:
[nihilipster@localhost:~]$ docker image pull adoptopenjdk:11.0.10_9-jre-hotspot
11.0.10_9-jre-hotspot: Pulling from library/adoptopenjdk
...
...
...
Status: Downloaded newer image for adoptopenjdk:11.0.10_9-jre-hotspot
docker.io/library/adoptopenjdk:11.0.10_9-jre-hotspot
Para despu茅s crear una imagen a partir de esta:
[nihilipster@localhost:~]$ docker image build --tag echo-server:0.1.0 .
Sending build context to Docker daemon 15.36kB
...
...
...
Successfully built xxxxxxxxxxxx
Successfully tagged echo-server:0.1.0
Contenedor馃敆
Finalmente se crea un contenedor en base a la nueva imagen echo-server:0.1.0:
[nihilipster@localhost:~]$ docker container create --name echo-server --publish 127.0.0.1:1234:7 \
--tty --interactive echo-server:0.1.0
Importante
- En el archivo
Dockerfile
se ha expuesto (EXPOSE) el puerto TCP #7 para la comunicaci贸n externa hac铆a el servidor del protocolo de red Echo. - Mediante
--publish
se ha establecido un redireccionamiento (o binding) del socket127.0.0.1:1234
al puerto TCP #7. Lo anterior con la finalidad de que al establecer una conexi贸n con el anfitri贸n (127.0.0.1
) en el puerto TCP #1234 dicha conexi贸n realmente sea al puerto TCP #7 del contenedor.
Ejecuci贸n馃敆
Inicializa el contenedor recientemente creado:
[nihilipster@localhost:~]$ docker container start --attach --interactive echo-server
Importante
La terminal quedar谩 bloqueada ya que el servidor del protocolo de red Echo est谩 en ejecuci贸n dentro del contenedor.
Acceso馃敆
En otra terminal ejecuta el cliente del protocolo de red Echo indicando el servidor al cual ha de conectarse:
[nihilipster@localhost:~]$ java EchoClient 127.0.0.1 1234
Importante
La terminal quedar谩 bloqueada ya que espera que escribas algo y aprietes la tecla de Enter.
Como resultado notar谩s que todo aquello que escribas en el cliente ser谩 reenviado por el servidor precedido por
la palabra echo:
, por ejemplo:
[nihilipster@localhost:~]$ java EchoClient 127.0.0.1 1234
隆Hola, mundo!
echo: 隆Hola, mundo!
Una vez que detengas el cliente (Ctrl + C
o Ctrl + D
en el emulador de terminal) tambi茅n se detendr谩 el
servidor-contenedor.
Ruby: echo_server & echo_client馃敆
-
echo_server.rb
# frozen_string_literal: true # Copyright (c) 2021 Antonio Hern谩ndez Blas <https://nihilipster.dev> # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. require 'socket' # Server class EchoServer def self.main(port) echo_socket = TCPServer.new(port) connection = echo_socket.accept begin while (line = connection.gets) message = line.chomp connection.puts message break if message.empty? end rescue SystemExit, Interrupt exit 1 end connection.close end end EchoServer.main(ARGV[0])
-
echo_client.rb
# frozen_string_literal: true # Copyright (c) 2021 Antonio Hern谩ndez Blas <https://nihilipster.dev> # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. require 'socket' # ECHO client class EchoClient def self.main(host, port) echo_socket = TCPSocket.open(host, port) begin while (line = $stdin.gets) message = line.chomp echo_socket.puts message $stdout.puts "echo: #{echo_socket.gets.chomp}" break if message.empty? end rescue SystemExit, Interrupt exit 1 end echo_socket.close end end EchoClient.main(ARGV[0], ARGV[1])
Dockerfile馃敆
FROM ruby:2.7.4-bullseye
LABEL description="echo_server"
LABEL source="https://rosettacode.org/wiki/Echo_server#Ruby"
ENV APP_DIR="/app"
ENV ECHO_PORT="7"
EXPOSE "$ECHO_PORT"
WORKDIR "$APP_DIR"
COPY echo_server.rb "$APP_DIR"/
CMD ["bash", "-c", "ruby echo_server.rb $ECHO_PORT"]
Importante
- El archivo
Dockerfile
se encontrar谩 en la misma carpeta que los archivosecho_server.rb
yecho_client.rb
. - La imagen usada es de Ruby YARV, la imagen oficial de Ruby en Docker Hub, por lo que es posible llevar
a cabo la instalaci贸n de otras gemas de ser necesario mediante
gem
. - Solo el servidor
echo_server.rb
es copiado (COPY) en el contenedor. - La ejecuci贸n del cliente
echo_client.rb
es llevado a cabo dentro del sistema anfitri贸n.
Imagen馃敆
Puedes obtener primero la imagen de Docker:
[nihilipster@localhost:~]$ docker image pull ruby:2.7.4-bullseye
ruby:2.7.4-bullseye: Pulling from library/ruby
...
...
...
Status: Downloaded newer image for ruby:2.7.4-bullseye
docker.io/library/ruby:2.7.4-bullseye
Para despu茅s crear una imagen a partir de esta:
[nihilipster@localhost:~]$ docker image build --tag echo-server:0.1.0 .
Sending build context to Docker daemon 15.36kB
...
...
...
Successfully built xxxxxxxxxxxx
Successfully tagged echo-server:0.1.0
Contenedor馃敆
Finalmente se crea un contenedor en base a la nueva imagen echo-server:0.1.0:
[nihilipster@localhost:~]$ docker container create --name echo-server --publish 127.0.0.1:1234:7 \
--tty --interactive echo-server:0.1.0
Importante
- En el archivo
Dockerfile
se ha expuesto (EXPOSE) el puerto TCP #7 para la comunicaci贸n externa hac铆a el servidor del protocolo de red Echo. - Mediante
--publish
se ha establecido un redireccionamiento (o binding) del socket127.0.0.1:1234
al puerto TCP #7. Lo anterior con la finalidad de que al establecer una conexi贸n con el anfitri贸n (127.0.0.1
) en el puerto TCP #1234 dicha conexi贸n realmente sea al puerto TCP #7 del contenedor.
Ejecuci贸n馃敆
Inicializa el contenedor recientemente creado:
[nihilipster@localhost:~]$ docker container start --attach --interactive echo-server
Importante
La terminal quedar谩 bloqueada ya que el servidor del protocolo de red Echo est谩 en ejecuci贸n dentro del contenedor.
Acceso馃敆
En otra terminal ejecuta el cliente del protocolo de red Echo indicando el servidor al cual ha de conectarse:
[nihilipster@localhost:~]$ ruby echo_client.rb 127.0.0.1 1234
Importante
La terminal quedar谩 bloqueada ya que espera que escribas algo y aprietes la tecla de Enter.
Como resultado notar谩s que todo aquello que escribas en el cliente ser谩 reenviado por el servidor precedido por
la palabra echo:
, por ejemplo:
[nihilipster@localhost:~]$ ruby echo_client.rb 127.0.0.1 1234
隆Hola, mundo!
echo: 隆Hola, mundo!
Una vez que detengas el cliente (Ctrl + C
o Ctrl + D
en el emulador de terminal) tambi茅n se detendr谩 el
servidor-contenedor.
Docker Hub馃敆
Repositorio馃敆
Es posible compartir una imagen construida, haciendo uso de un registro de im谩genes, siendo Docker Hub el m谩s conocido.
Para lo siguiente es necesario crear una cuenta de usuario (<Docker ID>
) en Docker Hub y
acceder a https://hub.docker.com/repository/create para crear un nuevo repositorio (imagen remota).
El formulario obtenido es rellenado teniendo en cuenta lo siguiente:
- Name: nombre del repositorio (imagen remota).
- Description: descripci贸n del repositorio (imagen remota).
- Visibility: visibilidad p煤blica o privada.
En este caso podr铆a ser:
- Name:
echo-server
- Description:
Echo server in Ruby
- Visibility:
public
Al finalizar estar谩s en el dashboard del repositorio:
https://hub.docker.com/repository/docker/<Docker ID>/echo-server
.
Informaci贸n
El perfil del repositorio (https://hub.docker.com/r/<Docker ID>/echo-server
) cuenta con un Readme vacio por
default pero es posible modificarlo accediendo al dashboard del repositorio.
Publicaci贸n馃敆
Para publicar la imagen local al repositorio (imagen remota) es necesario cambiar la etiqueta de la imagen local:
[nihilipster@localhost:~]$ docker tag echo-server:0.1.0 <Docker ID>/echo-server:0.1.0
Autentificarse ante el registro de im谩genes (por default es Docker Hub) haciendo uso de la cuenta de usuario
(<Docker ID>
):
[nihilipster@localhost:~]$ docker login --username <Docker ID>
Password:
Login Succeeded
Y finalmente publicar la imagen local al repositorio:
docker push <Docker ID>/echo-server:tagname
The push refers to repository [docker.io/<USUARIO>/echo-server]
34381271ebba: Pushed
a214018272ff: Pushed
0bc5e3a10491: Mounted from library/ruby
7b095a612410: Mounted from library/ruby
65be50d09676: Mounted from library/ruby
21abb8089732: Mounted from library/ruby
9889ce9dc2b0: Mounted from library/ruby
21b17a30443e: Mounted from library/ruby
05103deb4558: Mounted from library/ruby
a881cfa23a78: Mounted from library/ruby
0.1.0: digest: sha256:4d6dfe4edca0970abf10d3af575ac3ad4c56551703563c440dd736b9cad16123 size: 2418
Alternativas馃敆
Algunas alternativas, publicas y/o privadas, a Docker Hub son:
- Alibaba Cloud Container Registry
- Amazon Elastic Container Registry
- Azure Container Registry
- CentOS Container Registry
- Container Registry
- Dist Container Registry
- Fedora Container Registry
- GitHub Container Registry
- GitLab Container Registry
- Google Cloud Container Registry
- IBM Cloud Container Registry
- JFrog Container Registry
- Mirantis Secure Registry
- Nexus Repository
- Oracle Cloud Infrastructure Container Registry
- openSUSE Container Registry
- Red Hat Quay.io
- Scaleway Container Registry
Mientras que algunas aplicaciones para crear un registro son Harbor y Portus.
Almacenamiento en Docker馃敆
Un contenedor en Docker puede tener un espacio para el almacenamiento de datos mediante drivers de almacenamiento (subsistemas de almacenamiento de Docker) ya integrados en Docker o bien ofrecidos mediante plugins por terceros.
Por default un contenedor puede almacenar datos dentro de si mismo (tal es el caso cuando se instalan paquetes mediante un gestor de paquetes) pero en otras ocasiones se busca compartir datos entre el anfitri贸n (la computadora donde est谩 en ejecuci贸n el contenedor o la instancia de Docker) y el contenedor o bien entre varios contenedores.
Vol煤menes馃敆
Un volumen es un almacenamiento (archivo o carpeta) controlado por Docker.
Para listar los vol煤menes creados y disponibles en Docker:
[nihilipster@localhost:~]$ docker volume ls
DRIVER VOLUME NAME
Para crear un nuevo volumen indicando su nombre, shared01 como ejemplo:
[nihilipster@localhost:~]$ docker volume create shared01
shared01
[nihilipster@localhost:~]$ docker volume ls
DRIVER VOLUME NAME
local shared01
Para determinar la carpeta que retiene los datos del volumen se inspecciona el volumen:
[nihilipster@localhost:~]$ docker volume inspect shared01
[
{
...
"Driver": "local",
...
"Mountpoint": "/var/lib/docker/volumes/shared01/_data",
"Name": "shared01",
...
...
}
]
Puede observarse que aquellos datos almacenados por un contenedor en el volumen shared01 ser谩n realmente
almacenados en la carpeta /var/lib/docker/volumes/shared01/_data
(Mountpoint) del sistema operativo
anfitri贸n.
Importante
Puesto que el sistema anfitri贸n puede ser GNU/Linux, Microsoft Windows o macOS es importante considerar la ruta o ubicaci贸n de archivos y carpetas en ellos. En este ejemplo se est谩 haciendo uso del sistema operativo GNU/Linux por lo que se obtiene ese tipo de ruta en Mountpoint.
Para poner a disposici贸n (montar) un volumen en un contenedor se indica esto al momento de crear al contenedor:
[nihilipster@localhost:~]$ docker container create --name alpine-shared01 --tty --interactive \
--mount source=shared01,target=/shared01 alpine:3.13.2
La opci贸n usada es --mount
con la cual se indica que el volumen shared01 ser谩 montado o puesto a
disposici贸n del contenedor en la carpeta (target) /shared01
dentro del contenedor.
Importante
Puesto que el contenedor es creado a partir de la imagen de Alpine Linux es importante
conocer el sistema operativo GNU/Linux en especifico el uso de su interprete de comandos as铆 como de los
comandos necesarios para manipular archivos y carpetas en 茅l (pwd
, ls
, mkdir
, cd
, cat
, etc).
Finalmente se podr谩 observar como los archivos creados en el contenedor son accesibles por el anfitri贸n una vez
que el contenedor es iniciado (docker container start --attach --interactive alpine-shared01
):
Importante
Observar que antes de llevar a cabo lo siguiente el volumen estar谩 vac铆o.
-
En el contenedor:
/ # ls -l /shared01 total 0 / # echo "隆Hola, mundo!" > /shared01/hola.txt / # ls -l /shared01 total 4 -rw-r--r-- 1 root root 31 Feb 3 01:18 hola.txt / #
-
En el anfitri贸n:
[nihilipster@localhost:~]$ ls -l /var/lib/docker/volumes/shared01/_data total 4 -rw-r--r-- 1 root root 31 Feb 2 19:18 hola.txt [nihilipster@localhost:~]$ cat /var/lib/docker/volumes/shared01/_data/hola.txt 隆Hola, mundo!
Importante
Puesto que el sistema anfitri贸n puede ser GNU/Linux, Microsoft Windows o macOS es necesario que ajustes esta secci贸n seg煤n sea tu caso.
Bind mounts馃敆
Un bind mount es un almacenamiento (archivo o carpeta) disponible al contenedor desde el mismo sistema operativo anfitri贸n sin la intervenci贸n de Docker por lo que su ruta o ubicaci贸n puede ser decidida por uno y no por Docker.
Suponiendo que se tenga en el anfitri贸n la carpeta /tmp/shared01
o bien C:\shared01
, seg煤n sea el caso, se
puede crear el contenedor de la siguiente forma:
[nihilipster@localhost:~]$ docker container create --name alpine-shared01 --tty --interactive \
--mount type=bind,source=/tmp/shared01,target=/shared01 alpine:3.13.2
La opci贸n usada es --mount
con la cual se indica que el bind mount /tmp/shared01
ser谩 montado o puesto a
disposici贸n del contenedor en la carpeta (target) /shared01
dentro del contenedor.
Advertencia
Es necesario que el bind mount ya exista previa creaci贸n del contenedor, de no ser as铆 se obtendr谩 el error bind source path does not exist.
Finalmente se podr谩 observar como los archivos creados en el contenedor son accesibles por el anfitri贸n una vez
que el contenedor es iniciado (docker container start --attach --interactive alpine-shared01
):
Importante
Observar que antes de llevar a cabo lo siguiente el bind mount estar谩 vac铆o.
-
En el contenedor:
/ # ls -l /shared01/ total 0 / # echo "隆Hola, mundo!" > /shared01/hola.txt / # ls -l /shared01 total 4 -rw-r--r-- 1 root root 31 Feb 3 01:18 hola.txt / #
-
En el anfitri贸n:
[nihilipster@localhost:~]$ ls -l /tmp/shared01/ total 4 -rw-r--r-- 1 root root 31 Feb 3 08:00 hola.txt [nihilipster@localhost:~]$ cat /tmp/shared01/hola.txt 隆Hola, mundo!
Importante
Puesto que el sistema anfitri贸n puede ser GNU/Linux, Microsoft Windows o macOS es necesario que ajustes esta secci贸n seg煤n sea tu caso.
Servidor HTTP en Docker (contenido est谩tico)馃敆
Un Servidor de HTTP o Servidor Web puede exponer dos tipos de contenidos hac铆a un Cliente de HTTP o Cliente Web: est谩tico y/o din谩mico.
El contenido est谩tico es todo aquel recurso accedido por el Cliente HTTP mediante un URL y que previamente ha sido creado y depositado en alguna carpeta a disposici贸n del Servidor de HTTP, por lo que el Servidor de HTTP solo se encarga de entregar dicho recurso al Cliente de HTTP. Ejemplos de contenido est谩tico pueden ser archivos de im谩genes (JPEG, PNG, GIF, etc), archivos de audio (MP3, OGG, FLAC, etc), documentos de ofim谩tica (DOCX, XLSX, PDF, etc), archivos de v铆deo (AVI, WAV, MP4, etc) as铆 como archivos de texto plano (TXT, HTML, CSS, CSV, JSON, XML, etc).
darkhttpd馃敆
Dockerfile馃敆
A partir de la imagen de Alpine Linux se definen dos variables de entorno (ENV
): una para indicar el puerto
TCP en el cual estar谩 expuesto el servidor web y otra para indicar la carpeta que se expondr谩 al exterior
(conocida como carpeta ra铆z) por el servidor web.
FROM alpine:3.13.2
LABEL description="Sitio web estatico con darkhttpd"
ENV HTTP_PORT 80
ENV HTTP_DIR /srv/www
EXPOSE "$HTTP_PORT"
WORKDIR "$HTTP_DIR"
RUN apk add darkhttpd
RUN mkdir -p "$HTTP_DIR"
CMD ["sh", "-c", "darkhttpd $HTTP_DIR --port $HTTP_PORT"]
El servidor web que usar谩s, como ejemplo, ser谩 darkhttpd. darkhttpd
es un
servidor web muy b谩sico en comparaci贸n con otros servidores web. El primero argumento indica la carpeta ra铆z
mientras que --port
indica el puerto TCP a usar en espera de conexiones.
Imagen馃敆
Construye la imagen con el nombre darkhttpd
y la etiqueta 0.1.0
:
[nihilipster@localhost:~]$ docker build --tag darkhttpd:0.1.0 .
Contenedor馃敆
Crea un nuevo contenedor en base a la imagen recientemente creada:
[nihilipster@localhost:~]$ docker container create --name darkhttpd01 --tty --interactive \
--publish 127.0.0.1:8080:80 --mount type=bind,source=/tmp/www,target=/srv/www darkhttpd:0.1.0
El contenedor creado hace un redireccionamiento del puerto TCP 8080 del anfitri贸n al puerto TCP 80 del
contenedor. Por otro lado se est谩 poniendo a disposici贸n del contenedor la carpeta /tmp/www
como bind mount
en la carpeta /srv/www
la cual fue establecida como carpeta ra铆z en el archivo Dockerfile
.
Importante
Ya que el anfitri贸n puede ser Windows, macOS o GNU/Linux es importante que consideres que carpeta est谩s usando para bind mount.
Ejecuci贸n馃敆
Inicia el contenedor:
[nihilipster@localhost:~]$ docker container start --attach --interactive darkhttpd01
Acceso馃敆
Podr谩s acceder al servidor web con un cliente web, como por ejemplo un navegador web, haciendo uso del UR: http://127.0.0.1:8080.
Contenido馃敆
Para corroborar que todo est谩 funcionando puedes crear contenido est谩tico dentro del bind mount: /tmp/www
Importante
Ya que el anfitri贸n puede ser Windows, macOS o GNU/Linux es importante que consideres que carpeta est谩s usando para bind mount.
mini_httpd馃敆
Dockerfile馃敆
A partir de la imagen de Alpine Linux se definen dos variables de entorno (ENV
): una para indicar el puerto
TCP en el cual estar谩 expuesto el servidor web y otra para indicar la carpeta que se expondr谩 al exterior
(conocida como carpeta ra铆z) por el servidor web.
FROM alpine:3.13.2
LABEL description="Sitio web estatico con mini_httpd"
ENV HTTP_PORT 80
ENV HTTP_DIR /srv/www
EXPOSE "$HTTP_PORT"
WORKDIR "$HTTP_DIR"
RUN apk add mini_httpd
RUN mkdir -p "$HTTP_DIR"
CMD ["sh", "-c", "mini_httpd -p $HTTP_PORT -d $HTTP_DIR -T UTF-8 -D -M 0"]
El servidor web que usar谩s, como ejemplo, ser谩 mini_httpd.
mini_httpd
es un servidor web muy b谩sico en comparaci贸n con otros servidores web. Los argumentos -p
y -d
sirven para establecer el puerto TCP y la carpeta ra铆z respectivamente.
Imagen馃敆
Construye la imagen con el nombre mini_httpd
y la etiqueta 0.1.0
:
[nihilipster@localhost:~]$ docker build --tag mini_httpd:0.1.0 .
Contenedor馃敆
Crea un nuevo contenedor en base a la imagen recientemente creada:
[nihilipster@localhost:~]$ docker container create --name mini_httpd01 --tty --interactive \
--publish 127.0.0.1:8080:80 --mount type=bind,source=/tmp/www,target=/srv/www mini_httpd:0.1.0
El contenedor creado hace un redireccionamiento del puerto TCP 8080 del anfitri贸n al puerto TCP 80 del
contenedor. Por otro lado se est谩 poniendo a disposici贸n del contenedor la carpeta /tmp/www
como bind mount
en la carpeta /srv/www
la cual fue establecida como carpeta ra铆z en el archivo Dockerfile
.
Importante
Ya que el anfitri贸n puede ser Windows, macOS o GNU/Linux es importante que consideres que carpeta est谩s usando para bind mount.
Ejecuci贸n馃敆
Inicia el contenedor:
[nihilipster@localhost:~]$ docker container start --attach --interactive mini_httpd01
Acceso馃敆
Podr谩s acceder al servidor web con un cliente web, como por ejemplo un navegador web, haciendo uso del UR: http://127.0.0.1:8080.
Contenido馃敆
Para corroborar que todo est谩 funcionando puedes crear contenido est谩tico dentro del bind mount: /tmp/www
Importante
Ya que el anfitri贸n puede ser Windows, macOS o GNU/Linux es importante que consideres que carpeta est谩s usando para bind mount.
lighttpd馃敆
Dockerfile馃敆
A partir de la imagen de Alpine Linux se definen dos variables de entorno (ENV
): una para indicar el puerto
TCP en el cual estar谩 expuesto el servidor web y otra para indicar la carpeta que se expondr谩 al exterior
(conocida como carpeta ra铆z) por el servidor web.
FROM alpine:3.13.2
LABEL description="Sitio web estatico con lighttpd"
ENV HTTP_PORT 80
ENV HTTP_DIR /srv/www
EXPOSE "$HTTP_PORT"
WORKDIR "$HTTP_DIR"
RUN apk add lighttpd
RUN mkdir -p "$HTTP_DIR"
# Se configura la carpeta raiz:
RUN sed -i "s|^var.basedir.*|var.basedir = \"$HTTP_DIR\"|" /etc/lighttpd/lighttpd.conf
RUN sed -i "s|^server.document-root.*|server.document-root = var.basedir|" /etc/lighttpd/lighttpd.conf
# Se activa el listado del contenido de carpetas:
RUN sed -i "s|^# dir-listing.activate.*|dir-listing.activate = \"enable\"|" /etc/lighttpd/lighttpd.conf
RUN sed -i "s|^# dir-listing.hide-dotfiles.*|dir-listing.hide-dotfiles = \"enable\"|" /etc/lighttpd/lighttpd.conf
# Se configura el puerto TCP:
RUN sed -i "s|^# server.port.*|server.port = \"$HTTP_PORT\"|" /etc/lighttpd/lighttpd.conf
CMD ["sh", "-c", "lighttpd -f /etc/lighttpd/lighttpd.conf -D"]
El servidor web que usar谩s, como ejemplo, ser谩 lighttpd.
Imagen馃敆
Construye la imagen con el nombre lighttpd
y la etiqueta 0.1.0
:
[nihilipster@localhost:~]$ docker build --tag lighttpd:0.1.0 .
Contenedor馃敆
Crea un nuevo contenedor en base a la imagen recientemente creada:
[nihilipster@localhost:~]$ docker container create --name lighttpd01 --tty --interactive \
--publish 127.0.0.1:8080:80 --mount type=bind,source=/tmp/www,target=/srv/www lighttpd:0.1.0
El contenedor creado hace un redireccionamiento del puerto TCP 8080 del anfitri贸n al puerto TCP 80 del
contenedor. Por otro lado se est谩 poniendo a disposici贸n del contenedor la carpeta /tmp/www
como bind mount
en la carpeta /srv/www
la cual fue establecida como carpeta ra铆z en el archivo Dockerfile
.
Importante
Ya que el anfitri贸n puede ser Windows, macOS o GNU/Linux es importante que consideres que carpeta est谩s usando para bind mount.
Ejecuci贸n馃敆
Inicia el contenedor:
[nihilipster@localhost:~]$ docker container start --attach --interactive lighttpd01
Acceso馃敆
Podr谩s acceder al servidor web con un cliente web, como por ejemplo un navegador web, haciendo uso del UR: http://127.0.0.1:8080.
Contenido馃敆
Para corroborar que todo est谩 funcionando puedes crear contenido est谩tico dentro del bind mount: /tmp/www
IMPORTANTE: ya que el anfitri贸n puede ser Windows, macOS o GNU/Linux es importante que consideres que carpeta est谩s usando para bind mount.
thttpd馃敆
Advertencia
El servidor thttpd utiliza como scripts de CGI los archivos ejecutables encontrados en la carpeta r谩iz por lo que su uso en Windows (como anfitri贸n) no es el esperado como servidor de contenido est谩tico. Lo siguiente queda como referencia.
Dockerfile馃敆
A partir de la imagen de Alpine Linux se definen dos variables de entorno (ENV
): una para indicar el puerto
TCP en el cual estar谩 expuesto el servidor web y otra para indicar la carpeta que se expondr谩 al exterior
(conocida como carpeta ra铆z) por el servidor web.
FROM alpine:3.13.2
LABEL description="Sitio web estatico con thttpd"
ENV HTTP_PORT 80
ENV HTTP_DIR /srv/www
EXPOSE "$HTTP_PORT"
WORKDIR "$HTTP_DIR"
RUN apk add thttpd
RUN mkdir -p "$HTTP_DIR"
CMD ["sh", "-c", "thttpd -p $HTTP_PORT -d $HTTP_DIR -T UTF-8 -D -M 0 -l -"]
El servidor web que usar谩s, como ejemplo, ser谩 thttpd. thttpd
es un
servidor web muy b谩sico en comparaci贸n con otros servidores web. Los argumentos -p
y -d
sirven para
establecer el puerto TCP y la carpeta ra铆z respectivamente.
Imagen馃敆
Construye la imagen con el nombre thttpd
y la etiqueta 0.1.0
:
[nihilipster@localhost:~]$ docker build --tag thttpd:0.1.0 .
Contenedor馃敆
Crea un nuevo contenedor en base a la imagen recientemente creada:
[nihilipster@localhost:~]$ docker container create --name thttpd01 --tty --interactive \
--publish 127.0.0.1:8080:80 --mount type=bind,source=/tmp/www,target=/srv/www thttpd:0.1.0
El contenedor creado hace un redireccionamiento del puerto TCP 8080 del anfitri贸n al puerto TCP 80 del
contenedor. Por otro lado se est谩 poniendo a disposici贸n del contenedor la carpeta /tmp/www
como bind mount
en la carpeta /srv/www
la cual fue establecida como carpeta ra铆z en el archivo Dockerfile
.
Importante
Ya que el anfitri贸n puede ser Windows, macOS o GNU/Linux es importante que consideres que carpeta est谩s usando para bind mount.
Ejecuci贸n馃敆
Inicia el contenedor:
[nihilipster@localhost:~]$ docker container start --attach --interactive thttpd01
Acceso馃敆
Podr谩s acceder al servidor web con un cliente web, como por ejemplo un navegador web, haciendo uso del UR: http://127.0.0.1:8080.
Contenido馃敆
Para corroborar que todo est谩 funcionando puedes crear contenido est谩tico dentro del bind mount: /tmp/www
Importante
Ya que el anfitri贸n puede ser Windows, macOS o GNU/Linux es importante que consideres que carpeta est谩s usando para bind mount.
Servidor HTTP en Docker (contenido din谩mico)馃敆
Un Servidor de HTTP o Servidor Web puede exponer dos tipos de contenidos hac铆a un Cliente de HTTP o Cliente Web: est谩tico y/o din谩mico.
El contenido din谩mico es todo aquel recurso accedido por el Cliente HTTP mediante un URL y que es generado por parte del Servidor de HTTP haciendo uso de alg煤n lenguaje de programaci贸n por lo que el Servidor de HTTP se encarga de atender la conexi贸n con el cliente mientras que el lenguaje de programaci贸n procesa la solicitud y genera una respuesta al cliente. Ejemplos de contenido din谩mico pueden ser archivos de im谩genes (JPEG, PNG, GIF, etc), archivos de audio (MP3, OGG, FLAC, etc), documentos de ofim谩tica (DOCX, XLSX, PDF, etc), archivos de v铆deo (AVI, WAV, MP4, etc) as铆 como archivos de texto plano (TXT, HTML, CSS, CSV, JSON, XML, etc) generados de manera din谩mica por el lenguaje de programaci贸n usado.
Java (JavaServer Pages & Apache Tomcat)馃敆
Dockerfile馃敆
A partir de la imagen de Apache Tomcat se definen dos variables de
entorno (ENV
): una para indicar el puerto TCP en el cual estar谩 expuesto el servidor web y otra para indicar
la carpeta en la cual residir谩 la aplicaci贸n web.
FROM tomcat:9.0.20-jre8-alpine
LABEL description="P谩gina web din谩mica generada con JavaServer Pages (JSP) en Apache Tomcat"
ENV HTTP_PORT 80
ENV APP_DIR "/usr/local/tomcat/webapps/ROOT"
EXPOSE "$HTTP_PORT"
WORKDIR "$APP_DIR"
# Se configura el puerto TCP para el servidor web Coyote integrado en Apache Tomcat:
RUN sed -i "s|port=\"8080\"|port=\"80\"|" /usr/local/tomcat/conf/server.xml
CMD ["sh", "-c", "catalina.sh run"]
Imagen馃敆
Construye la imagen con el nombre tomcat
y la etiqueta 0.1.0
:
[nihilipster@localhost:~]$ docker build --tag tomcat:0.1.0 .
Contenedor馃敆
Crea un nuevo contenedor en base a la imagen recientemente creada:
[nihilipster@localhost:~]$ docker container create --name tomcat01 \
--tty --interactive --publish 127.0.0.1:8080:80 \
--mount type=bind,source=/tmp/ROOT,target=/usr/local/tomcat/webapps/ROOT tomcat:0.1.0
El contenedor creado hace un redireccionamiento del puerto TCP 8080 del anfitri贸n al puerto TCP 80 del
contenedor. Por otro lado se est谩 poniendo a disposici贸n del contenedor la carpeta /tmp/ROOT
como bind mount
en la carpeta /usr/local/tomcat/webapps/ROOT
la cual fue establecida como la carpeta de la aplicaci贸n web
en el archivo Dockerfile
.
Importante
Ya que el anfitri贸n puede ser Windows, macOS o GNU/Linux es importante que consideres que carpeta est谩s usando para bind mount.
Aplicaci贸n Web馃敆
Dentro de la carpeta /tmp/ROOT
crea el archivo index.jsp
con el siguiente contenido:
<%--
-- JavaServer Pages (JSP)
-- https://es.wikipedia.org/wiki/JavaServer_Pages
--
-- La Directiva page, establece lo siguiente:
--
-- * language: lenguaje de programaci贸n a usar embebido en este archivo JSP: java
-- * contenType: tipo de contenido que generar谩 este archivo JSP: text/html
-- * pageEncoding: codificaci贸n de car谩cteres a usar para este archivo JSP: UTF-8
--
-- JSP forza la creaci贸n e inicio de una sesi贸n (JSESSIONID) con el cliente (navegador web).
-- Si se quiere desactivar esta car谩cteristica se establece el atributo session a false en la
-- directiva page.
--
-- <%@
-- page session="false"
-- language="java"
-- %>
--
-- Un JSP tiene acceso a varios objetos globales u objetos implicitos:
--
-- * HttpServletRequest request
-- * HttpServletResponse response
-- * HttpSession session
-- * ServletContext application
-- * ServletConfig config
--%>
<%@
page language="java"
contentType="text/html;charset=UTF-8"
pageEncoding="UTF-8"
%>
<%--
-- Importaci贸n de clases de Java
--%>
<%@
page import="java.util.List"
import="java.util.ArrayList"
import="java.util.Arrays"
import="java.util.Enumeration"
import="java.util.Date"
import="java.util.Locale"
import="java.util.Properties"
import="java.text.SimpleDateFormat"
import="java.io.File"
%>
<%--
-- Scriptlet: sentencias de c贸digo Java embebido/incrustado en los elementos est谩ticos del
-- documento (por ejemplo HTML/XML).
-- https://es.wikipedia.org/wiki/JavaServer_Pages#Scriptlets
--%>
<%!
/*
* Definici贸n de un m茅todo privado en este archivo JSP
*/
private List<Double> generarNumerosPseudoAleatorios(int cantidad) {
List<Double> numeros = new ArrayList<>();
if (cantidad <= 0) {
return numeros;
}
for (int i = 0; i < cantidad; i++) {
numeros.add(Math.random());
}
return numeros;
}
%>
<%--
-- Declaraci贸n e inicializaci贸n de variables globales:
--%>
<%
String titulo = "隆Bienvenid@!";
SimpleDateFormat formatoFecha = new SimpleDateFormat("EEEE d 'de' MMMM 'del' yyyy", new Locale("es", "MX"));
String fecha = formatoFecha.format(new Date());
SimpleDateFormat formatoHora = new SimpleDateFormat("H:mm:ss a", new Locale("es", "MX"));
String hora = formatoHora.format(new Date());
List<Double> numerosPseudoAleatorios = generarNumerosPseudoAleatorios(5);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><%= titulo %></title>
<link rel="stylesheet" href="https://www.w3.org/StyleSheets/Core/Modernist" type="text/css" />
</head>
<body>
<main class="container">
<h1><%= titulo %></h1>
<p>Fecha y hora actual del servidor: <%= fecha + ", " + hora %></p>
<h2>N煤meros pseudo-aleatorios</h2>
<ol>
<%
for (Double numero : numerosPseudoAleatorios) {
%>
<li><code><%= numero %></code></li>
<%
}
%>
</ol>
<h2>Entorno de ejecuci贸n</h2>
<dl>
<%
/*
* Informaci贸n encontrada en el entorno de ejecuci贸n
* (Contenedor de Servlets o Servidor de Aplicaciones).
*/
Properties propiedades = System.getProperties();
Object[] llaves = propiedades.keySet().toArray();
Arrays.sort(llaves);
for (int i = 0; i < llaves.length; i++) {
String llave = (String)llaves[i];
String valor = (String)propiedades.get(llave);
%>
<dt><em><%= llave %></em></dt>
<dd><code><%= valor %></code></dd>
<%
}
%>
</dl>
<h2>HTTP - Solicitud</h2>
<dl>
<dt><em>request.getCharacterEncoding()</em></dt>
<dd><code><%=request.getCharacterEncoding()%></code></dd>
<dt><em>request.getContentType()</em></dt>
<dd><code><%=request.getContentType()%></code></dd>
<dt><em>request.getLocale()</em></dt>
<dd><code><%=request.getLocale()%></code></dd>
<dt><em>request.getProtocol()</em></dt>
<dd><code><%=request.getProtocol()%></code></dd>
<dt><em>request.getRemoteAddr()</em></dt>
<dd><code><%=request.getRemoteAddr()%></code></dd>
<dt><em>request.getRemoteHost()</em></dt>
<dd><code><%=request.getRemoteHost()%></code></dd>
<dt><em>request.getScheme()</em></dt>
<dd><code><%=request.getScheme()%></code></dd>
<dt><em>request.getServerName()</em></dt>
<dd><code><%=request.getServerName()%></code></dd>
<dt><em>request.getServerPort</em></dt>
<dd><code><%=request.getServerPort()%></code></dd>
<dt><em>request.isSecure</em></dt>
<dd><code><%=request.isSecure()%></code></dd>
<dt><em>request.getAuthType()</em></dt>
<dd><code><%=request.getAuthType()%></code></dd>
<dt><em>request.getContextPath()</em></dt>
<dd><code><%=request.getContextPath()%></code></dd>
<dt><em>request.getMethod()</em></dt>
<dd><code><%=request.getMethod()%></code></dd>
<dt><em>request.getPathInfo()</em></dt>
<dd><code><%=request.getPathInfo()%></code></dd>
<dt><em>request.getPathTranslated()</em></dt>
<dd><code><%=request.getPathTranslated()%></code></dd>
<dt><em>request.getQueryString()</em></dt>
<dd><code><%=request.getQueryString()%></code></dd>
<dt><em>request.getRemoteUser()</em></dt>
<dd><code><%=request.getRemoteUser()%></code></dd>
<dt><em>request.getRequestedSessionId()</em></dt>
<dd><code><%=request.getRequestedSessionId()%></code></dd>
<dt><em>request.getRequestURI()</em></dt>
<dd><code><%=request.getRequestURI()%></code></dd>
<dt><em>request.getRequestURL.toString()</em></dt>
<dd><code><%= request.getRequestURL().toString() %></code></dd>
<dt><em>request.getServletPath()</em></dt>
<dd><code><%= request.getServletPath() %></code></dd>
</dl>
<h2>HTTP - Cabeceras de la solicitud</h2>
<dl>
<%
/*
* Informaci贸n enviada por el cliente y encontrada dentro de la solicitud.
*/
Enumeration<String> cabeceras = request.getHeaderNames();
while (cabeceras.hasMoreElements()) {
String llave = (String)cabeceras.nextElement();
String valor = request.getHeader(llave);
%>
<dt><em><%= llave %></em></dt>
<dd><code><%= valor %></code></dd>
<%
}
%>
</dl>
</main>
</body>
</html>
Importante
Ya que el anfitri贸n puede ser Windows, macOS o GNU/Linux es importante que consideres que carpeta est谩s usando para bind mount.
Ejecuci贸n馃敆
Inicia el contenedor:
[nihilipster@localhost:~]$ docker container start --attach --interactive tomcat01
Acceso馃敆
Podr谩s acceder al servidor web con un cliente web, como por ejemplo un navegador web, haciendo uso del UR: http://127.0.0.1:8080.
Contenido馃敆
Para corroborar que todo est谩 funcionando puedes hacer peque帽as modificaciones al archivo index.jsp
y ver los
efectos de dichas ediciones en el navegador web.
Importante
Ya que el anfitri贸n puede ser Windows, macOS o GNU/Linux es importante que consideres que carpeta est谩s usando para bind mount.
Cliente HTTP en Docker馃敆
Existen distintos clientes HTTP disponibles para distintas plataformas o sistemas operativos, siendo un navegadores web el m谩s conocido y de m谩s amplio uso
Lynx y Curl馃敆
Para ejemplificar otros clientes HTTP se har谩 uso de lynx y cURL, ambas aplicaciones en la l铆nea de comandos.
El nodo cliente ser谩 un contenedor de Alpine Linux con lynx
y curl
como clientes HTTP y direcci贸n IP
10.2.3.4
.
El nodo servidor ser谩 un contenedor de Apline Linux con thttpd
como servidor HTTP y direcci贸n IP
10.5.6.7
.
Red virtual en Docker馃敆
Para tener un mayor control sobre la configuraci贸n y comunicaci贸n entre los nodos cliente-servidor en Docker se crear谩 una red virtual usando el controlador bridge.
[nihilipster@localhost:~]$ docker network create --driver bridge --subnet 10.0.0.0/8 --gateway 10.0.0.1 \
cliente-servidor-http
Puedes obtener la lista de redes en Docker mediante docker network ls
:
[nihilipster@localhost:~]$ docker network ls
NETWORK ID NAME DRIVER SCOPE
xxxxxxxxxxxx bridge bridge local
xxxxxxxxxxxx cliente-servidor-http bridge local
xxxxxxxxxxxx host host local
xxxxxxxxxxxx none null local
Puedes obtener informaci贸n sobre la subred y la puerta de salida de una red en particular mediante
docker network inspect cliente-servidor-http
por ejemplo:
[
{
"Name": "cliente-servidor-http",
...
"Driver": "bridge",
...
"Subnet": "10.0.0.0/8",
"Gateway": "10.0.0.1"
...
}
]
La red se llama cliente-servidor-http y su subred es 10.0.0.0/8
con puerta de salida 10.0.0.1
. Para
determinar el rango de direcciones IP disponibles en dicha subred puedes hacer uso de
http://jodies.de/ipcalc, introduciendo 10.0.0.0
en Address y 8
en Netmask
para finalmente prestar atenci贸n a los valores de HostMin y HostMax cuando des click al bot贸n Calculate.
Nodo Cliente馃敆
Dockerfile馃敆
FROM alpine:3.13.2
LABEL description="Cliente de HTTP"
ENV HOME="/root"
ENV DESCARGAS="$HOME/Descargas"
WORKDIR "$DESCARGAS"
RUN apk add lynx
RUN apk add curl
CMD ["sh"]
Creaci贸n de la imagen馃敆
[nihilipster@localhost:~]$ docker build --tag cliente-http:0.1.0 .
Creaci贸n del contenedor馃敆
[nihilipster@localhost:~]$ docker container create --name cliente-http01 --tty --interactive \
--mount type=bind,source=/tmp/Descargas,target=/root/Descargas --network cliente-servidor-http \
--ip 10.2.3.4 cliente-http:0.1.0
Importante
Observa que se hace uso de un bind mount, /tmp/Descargas
, por lo que es importante que consideres su
ubicaci贸n en base al anfitri贸n que uses.
Ejecuci贸n del contenedor馃敆
[nihilipster@localhost:~]$ docker container start --attach --interactive cliente-http01
Nodo servidor馃敆
Dockerfile馃敆
FROM alpine:3.13.2
LABEL description="Servidor de HTTP"
ENV HTTP_PORT 80
ENV HTTP_DIR /srv/www
EXPOSE "$HTTP_PORT"
WORKDIR "$HTTP_DIR"
RUN apk add thttpd
RUN mkdir -p "$HTTP_DIR"
COPY www/* ./
RUN find ./ -type f -exec chmod 644 {} \;
CMD ["sh", "-c", "thttpd -p $HTTP_PORT -d $HTTP_DIR -T UTF-8 -D -M 0 -l -"]
Contenido est谩tico馃敆
En la misma carpeta donde se encuentra el archivo Dockerfile
(para el nodo servidor) crea la carpeta www
y
en ella el archivo index.html
con el siguiente contenido:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8"/>
<title>Inicio</title>
</head>
<body>
<h1>隆Bienvenid@!</h1>
</body>
</html>
Creaci贸n de la imagen馃敆
[nihilipster@localhost:~]$ docker build --tag servidor-http:0.1.0 .
Creaci贸n del contenedor馃敆
[nihilipster@localhost:~]$ docker container create --name servidor-http01 --tty --interactive \
--network cliente-servidor-http --ip 10.5.6.7 servidor-http:0.1.0
Ejecuci贸n del contenedor馃敆
[nihilipster@localhost:~]$ docker container start --attach --interactive servidor-http01
Comunicaci贸n de nodos馃敆
Estando en el nodo cliente puedes acceder al nodo servidor mediante lynx
con el comando
lynx http://10.5.6.7
, de igual manera puedes descargar al cliente el archivo index.html
encontrado en el
nodo servidor mediante el comando curl http://10.5.6.7/index.html --output hola.txt
observando que en la
carpeta /root/Descargas
se crear谩 el archivo hola.txt
.
Tambi茅n te ser谩 posible ejecutar:
lynx https://nihilipster.dev
curl http://nihilipster.dev --output nihilipster.dev.txt
Referencias de comandos馃敆
Podr谩s encontrar las siguientes referencias para trabajar con Docker:
Seguridad馃敆
OWASP provee una referencia de errores y sugerencias para mejorar la seguridad en el uso de Docker, im谩genes y contenedores en Docker Security Cheat Sheet