Diferencia entre revisiones de «Contenedores»

De Wiki de Sistemas Operativos
Saltar a: navegación, buscar
(Paso 11: Crear nuestra propia imagen docker)
(Paso 11: Crear nuestra propia imagen de contenedor)
 
(No se muestran 84 ediciones intermedias de 4 usuarios)
Línea 1: Línea 1:
En esta práctica aprenderemos a utilizar [https://es.wikipedia.org/wiki/Docker_(software) docker] para desplegar contenedores.
+
En esta práctica aprenderemos a utilizar [https://es.wikipedia.org/wiki/Podman podman] para desplegar contenedores.
  
= Paso 1: Instalar docker =
+
= Paso 1: Instalar podman =
  
Vamos a añadir un nuevo repositorio, ya que docker no está en los repositorios
+
Para instalar el paquete oficial:
oficiales:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
sudo apt update
+
apt install podman
sudo apt install docker.io
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Para ver si está todo bien y se ha instalado correctamente, comprobaremos que el
+
podman es un clon de '''docker''.
servicio está activo:
+
 
 +
Si añade un usuario 'test' a su sistema con:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
sudo service docker status
+
adduser test
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Debería mostrar algo similar a lo siguiente:
+
recuerde hacer:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
● docker.service - Docker Application Container Engine
+
loginctl enable-linger test
  Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
+
systemctl start --user dbus
  Active: active (running) since Mon 2019-08-26 09:41:40 UTC; 37s ago
 
    Docs: https://docs.docker.com
 
Main PID: 3630 (dockerd)
 
    Tasks: 8
 
  CGroup: /system.slice/docker.service
 
          └─3630 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Pulsamos la tecla 'q' para salir.
+
para evitar un warning que se muestra al ejecutar '''podman''' como usuario.
  
Si el servicio aparece inactivo, puedes lanzarlo con:
+
= Paso 2: Repositorio de imágenes de contenedores DockerHub =
  
<syntaxhighlight lang="bash">
+
Docker ofrece un servicio de nube denominado ''DockerHub'' que puede ser empleado como red social para compartir tus imágenes de Podman. En ''DockerHub'' existen además imágenes de contenedores preconfiguradas de software, muchas de ellas oficiales (ofrecidas por el propio fabricante del software) que se podrán emplear como base para construir nuevas imágenes adaptadas a nuestras necesidades.
sudo service docker start
 
</syntaxhighlight>
 
  
= Paso 2: Ejecutar docker con nuestro usuario =
+
Podremos realizar búsquedas en este repositorio ''DockerHub'' puedes emplear el siguiente comando:
 
 
Para no necesitar sudo al utilizar docker, añadiremos a nuestro usuario al grupo
 
docker:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
sudo usermod -aG docker ubuntu
+
podman search docker.io/library/hello-world
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Para que el cambio tenga efecto, tendremos que cerrar la sesión de nuestro
+
Para descargarnos la imagen de ''hello-world'' podemos usar la orden ''pull'':
usuario y abrirla de nuevo. Podemos hacerlo fácilmente pulsando CTRL + D y
 
volviendo a insertar nuestras credenciales.
 
 
 
 
 
= Paso 3: Repositorios: dockerHub y otros =
 
 
 
DockerHub es el repositorio de imágenes por defecto que utiliza docker, donde
 
existen imágenes preconfiguradas y listas para utilizar, entre ellas tenemos
 
imágenes oficiales de debian, postgresql, python, node, nginx, ...
 
 
 
Podremos realizar búsquedas en este repositorio con el siguiente comando:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker search hello-world
+
podman pull docker.io/library/hello-world
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Veamos las diferencias que existen a la hora de traernos una imagen (pull), hacer login y subir una imagen
+
También podemos publicar imágenes propias, esto require '''registro de usuario''' en la nube de ''DockerHub'', lo que '''no''' es obligatorio para la realización de esta práctica. Para subir una imagen, hay que validarse como usuario en la nube de ''DockerHub'':
(push).
 
 
 
Los comandos de login o de subir imagen no los utilizaremos en esta práctica,
 
pero los mencionaremos:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker pull IMAGEN
+
podman login docker.io
docker login
 
docker push IMAGEN
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Si utilizamos el repositorio privado https://laboratorio-docker.com, sería:
+
Tras introducir tu usuario y contraseña, puedes comenzar a publicar tus propias imágenes.
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker pull https://laboratorio-docker.com/IMAGEN
+
podman push docker.io/USUARIO/MI_IMAGEN
docker login https://laboratorio-docker.com
 
docker push https://laboratorio-docker.com/IMAGEN
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
Este paso es '''opcional''', sólo en caso de que se quieran subir imágenes de contenedores a la nube de docker.io.
  
 
= Paso 4: Comprobar imágenes en nuestra máquina =
 
= Paso 4: Comprobar imágenes en nuestra máquina =
Línea 91: Línea 61:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker images
+
podman images
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Si lo hacemos, no encontrará ninguna, vamos a descargarnos la imagen hello-world
+
Inicialmente, no tenemos imágenes en almacenamiento, podemos descargarnos la imagen oficial de Debian 13 (Trixie):
del repositorio oficial, y después volvemos a realizar el comando:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker pull hello-world
+
podman pull docker.io/library/debian
docker images
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Ahora si, ya debería de aparecernos la imagen hello-world.
+
Ahora si, ya debería de aparecernos la imagen ''debian''.
  
Comentar también que cada imagen puede tener varios tags, por ejemplo, la imagen
+
Comentar también que cada imagen puede tener varias etiquetas, por ejemplo, la imagen Debian 12 (Bookworm), cuando la hemos visto en el listado de imágenes, venía con el tag latest, que es el tag que se descarga por defecto, pero nosotros podemos especificar otro, por ejemplo:
hello-world, cuando la hemos visto en el listado de imágenes, venía con el tag
 
latest, que es el tag que se descarga por defecto, pero nosotros podemos
 
especificar otro, por ejemplo:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker pull hello-world:linux
+
podman pull docker.io/library/debian:bookworm
docker images
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Ahora tendremos dos imágenes con diferente tag, que serían como las diferentes
+
Para traernos la versión de la imagen de Debian 12 ''Bookworm''.
versiones de cada imagen.
 
  
 +
Ahora tendremos dos imágenes con diferente etiqueta, que serían como las diferentes versiones de cada imagen.
  
= Paso 5: Crear un contenedor =
+
= Paso 5: Lanzar un contenedor =
  
Un contenedor no es más que una imagen de docker ejecutándose, sería similar a
+
Un contenedor no es más que una imagen de podman ejecutándose, sería similar a
 
una máquina virtual, aunque mucho más liviano.
 
una máquina virtual, aunque mucho más liviano.
  
Línea 127: Línea 91:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run hello-world
+
podman run hello-world
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Línea 145: Línea 109:
 
     to your terminal.
 
     to your terminal.
  
To try something more ambitious, you can run an Ubuntu container with:
+
To try something more ambitious, you can run an Debian container with:
  $ docker run -it ubuntu bash
+
  $ podman run -it debian bash
  
 
Share images, automate workflows, and more with a free Docker ID:
 
Share images, automate workflows, and more with a free Docker ID:
Línea 157: Línea 121:
 
Al crear los contenedores utilizando el comando 'run', tenemos varias opciones:
 
Al crear los contenedores utilizando el comando 'run', tenemos varias opciones:
  
== Paso 5.1: Ejecutar en segundo plano (-d) ==
+
* Lanzar una terminal en el contenedor en modo interactivo
 +
* Lanzar en segundo plano y conectarnos posteriormente al contenedor
 +
 
 +
== Paso 5.1: Lanzar una terminal en el contenedor en modo interactivo (-ti) ==
 +
 
 +
Para este ejemplo vamos a utilizar otra imagen diferente, en este caso vamos a utilizar una imagen de debian.
 +
 
 +
Vamos a lanzar un contenedor y ejecutar una terminal en el que se va a ejecutar el programa '''bash''' que me ofrece un interprete de órdenes:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run -d hello-world
+
podman run -ti debian bash
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Nos mostrará el id del contenedor y se ejecutará en segundo plano, por lo que la
+
La opción ''-t'' indica que se crea un terminal en el contenedor. Y la opción ''-i'' indica que el contenedor se ejecuta en modo interactivo.
salida que antes obtuvimos, ahora no se muestra. Para poder ver esta salida,
+
 
podemos utilizar el comando logs y el id mostrador anteriormente:
+
Al acceder al contenedor de ''debian'' nos aparece un ''hash'' en el prompt de la shell, que identifica a la instancia del contenedor (es valor es similar al que muestra la orden ''podman container ls'').
 +
 
 +
Para salir del contenedor, escribimos 'exit' o pulsamos ''CTRL + D''
 +
 
 +
== Paso 5.2 Lanzar en segundo plano (-d) ==
 +
 
 +
Otro ejemplo, con la imagen de Debian:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker logs 2ec1daae4676a4e84dc04fd91399c1dfe92119544ff12ee307991fe573d3db64
+
podman run -dti debian
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
que muestra un hash que identifica de forma única el contenedor lanzado:
  
== Paso 5.2: Ejecutar una terminal en el contenedor al iniciar (-ti) ==
+
<syntaxhighlight lang="bash">
 +
2ec1daae4676a4e84dc04fd91399c1dfe92119544ff12ee307991fe573d3db64
 +
</syntaxhighlight>
  
Para este ejemplo vamos a utilizar otra imagen diferente, en este caso vamos a utilizar una imagen de ubuntu:
+
Mediante el comando ''attach'' puedo entrar al contenedor:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker pull ubuntu
+
podman attach 2ec1daae4676
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Vamos a lanzar un contenedor y ejecutar una terminal en el que se va a ejecutar el programa '''bash''' que me ofrece un interprete de órdenes:
+
Para salir, pulsamos ''CTRL + P'' seguido de ''CTRL + Q''.
 +
 
 +
De manera similar, puedo lanzar en segundo plano la imagen de contenedor de ''hello-world'':
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run -ti ubuntu bash
+
podman run -d hello-world
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Ahora deberíamos de estar dentro del contenedor que está ejecutando una imagen
+
Y consultar los logs:
alpine, y podremos realizar varios comandos y ver el contenido, por ejemplo:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
pwd
+
podman logs b67fae3312bc321
ls
 
mkdir hello
 
ls
 
...
 
 
</syntaxhighlight>
 
</syntaxhighlight>
 
Para terminar, escribimos 'exit' o pulsamos 'CTRL + D'
 
  
 
== Paso 5.3: Añadir variables de entorno a un contenedor ==
 
== Paso 5.3: Añadir variables de entorno a un contenedor ==
Línea 207: Línea 182:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run -ti -e TEST=test alpine ash
+
podman run -ti -e TEST=test debian bash
echo $TEST
 
exit
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Hemos creado una variable de entorno que le hemos pasado al contenedor, esto es
+
Ahora, desde el contenedor podemos comprobar el valor de la variable de entorno ''$TEST''.
muy utilizado ya que las imágenes son genéricas y utilizan las variables de
 
entornos para poder modificar su funcionamiento, por ejemplo, si ejecutamos una
 
imagen con una base de datos postgres, necesitaremos darle el nombre de la base
 
de datos, el nombre de usuario y la contraseña. Todo esto se hace pasándole a la
 
imágen las variables de entorno.
 
  
 +
<syntaxhighlight lang="bash">
 +
echo $TEST
 +
test
 +
</syntaxhighlight>
  
= Paso 6: Visualizar contenedores =
+
= Paso 6: Listar contenedores en ejecución =
  
Hemos estado haciendo pruebas y ejecutando contenedores en el paso anterior,
+
Hemos estado haciendo pruebas y ejecutando contenedores en el paso anterior, vamos a ver donde se encuentran estos contenedores que hemos ejecutado, y después veremos algunas opciones más del comando run.
vamos a ver donde se encuentran estos contenedores que hemos ejecutado, y
 
después veremos algunas opciones más del comando run.
 
  
 
Tenemos dos opciones para ver los contenedores:
 
Tenemos dos opciones para ver los contenedores:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker container ls -a
+
podman container ls -a
 
</syntaxhighlight>
 
</syntaxhighlight>
  
ó la versión corta:
+
o la versión corta:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker ps -a
+
podman ps -a
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Línea 242: Línea 212:
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
 
CONTAINER ID        IMAGE              COMMAND            CREATED            STATUS                      PORTS              NAMES
 
CONTAINER ID        IMAGE              COMMAND            CREATED            STATUS                      PORTS              NAMES
e2bde5f5500c        alpine             "ash"              6 minutes ago      Exited (0) 2 seconds ago                        pensive_sammet
+
e2bde5f5500c        debian             "bash"              6 minutes ago      Exited (0) 2 seconds ago                        pensive_sammet
544ad27dbc3c        alpine             "ash"              7 minutes ago      Exited (0) 7 minutes ago                        serene_elgamal
+
544ad27dbc3c        debian             "bash"              7 minutes ago      Exited (0) 7 minutes ago                        serene_elgamal
52281a79c8d4        debian              "bash"              9 minutes ago      Exited (0) 8 minutes ago                        elegant_snyder
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
En la información veremos que el contenedor tiene el estado exited, eso quiere
+
En la información veremos que el contenedor tiene el estado exited, eso quiere decir que no se está ejecutando y ya ha finalizado. Vamos a hacer una prueba para ver un contendor ejecutándose:
decir que no se está ejecutando y ya ha finalizado. Vamos a hacer una prueba
 
para ver un contendor ejecutándose:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run -d alpine sleep 30
+
podman run -d debian sleep 30
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Con el comando sleep 30 esperamos 30 segundos hasta que termine el comando, así
+
Con el comando sleep 30 esperamos 30 segundos hasta que termine el comando, asíque durante esos 30 segundos, el contenedor estará ejecutándose, veámoslo:
que durante esos 30 segundos, el contenedor estará ejecutándose, veámoslo:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker ps -a
+
podman ps -a
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
 
CONTAINER ID        IMAGE              COMMAND            CREATED            STATUS                      PORTS              NAMES
 
CONTAINER ID        IMAGE              COMMAND            CREATED            STATUS                      PORTS              NAMES
eacceb27d52d        alpine             "sleep 30"          12 seconds ago      Up 11 seconds                                  sharp_pasteur
+
eacceb27d52d        debian             "sleep 30"          12 seconds ago      Up 11 seconds                                  sharp_pasteur
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Vamos a ver unas pocas de opciones más del comando run, las cuales podremos
+
Vamos a ver alguna opciones más de la orden ''run''.
comprobar visualizando el contenedor:
 
 
 
  
== Paso 6.1: Poner un nombre al contenedor (--name) ==
+
== Paso 6.1: Dar un nombre al contenedor (--name) ==
  
Por defecto, docker creará automáticamente un nombre como hemos visto en las
+
Por defecto, podman creará automáticamente un nombre como hemos visto en las salidas del comando ''podman ps -a''. Podemos establecer el nombre del contenedor que queramos con la opción ''--name'':
salidas del comando 'docker ps -a', vamos a editar nosotros ese nombre:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run -d --name my_alpine alpine
+
podman run -ti --name mi_debian debian
docker ps -a
 
 
</syntaxhighlight>
 
</syntaxhighlight>
 
  
 
== Paso 6.2: Eliminar contenedor cuando termine (--rm) ==
 
== Paso 6.2: Eliminar contenedor cuando termine (--rm) ==
Línea 286: Línea 247:
 
Vamos a mezclar todo lo visto anteriormente:
 
Vamos a mezclar todo lo visto anteriormente:
  
* Correr en segundo plano (-d)
+
* Lanzar en segundo plano (-d)
 
* Ejecutar contenedor durante 30 segundos (sleep 30)
 
* Ejecutar contenedor durante 30 segundos (sleep 30)
 
* Dar un nombre a la imagen (--name)
 
* Dar un nombre a la imagen (--name)
Línea 292: Línea 253:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run -d --rm --name bye-bye alpine sleep 30
+
podman run -d --rm --name bye-bye debian sleep 30
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Antes de que pasen 30 segundos, veamos que el contenedor existe:
+
Antes y una vez pasados los 30 segundos, podemos comprobar que el contenedor ha desaparecido.
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker ps -a
+
podman ps -a
 
</syntaxhighlight>
 
</syntaxhighlight>
 
Una vez pasado los 30 segundos, ejecutamos de nuevo:
 
 
<syntaxhighlight lang="bash">
 
docker ps -a
 
</syntaxhighlight>
 
 
Veremos que el contenedor ha desaparecido.
 
 
  
 
= Paso 7: Parar y eliminar contenedores =
 
= Paso 7: Parar y eliminar contenedores =
  
Los contenedores podemos pararlos o eliminarlos, veamos como hacerlo. Antes que
+
Para parar contenedores podemos usar el ID o su nombre:
nada, borraremos todos los contenedores que estén terminados, para ello:
 
 
 
<syntaxhighlight lang="bash">
 
docker container prune
 
docker ps -a
 
</syntaxhighlight>
 
 
 
Ya lo hemos dejado todo limpio para seguir, ahora vamos a crear un contenedor,
 
utilizando un comando de linux que no termina, para que así se quede
 
ejecutándose el contenedor infinitamente:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run -d --name my_container alpine ping 0.0.0.0
+
podman stop my_container
docker ps -a
+
podman stop e4901956f108
 +
podman ps -a
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Vamos a pararlo (podemos utilizar el nombre dado o el id):
+
Una vez hemos comprobado que han terminado su ejecución, podemos eliminar los ficheros resultantes de su ejecución:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker stop my_container
+
podman container rm my_container
docker stop e4901956f108
 
docker ps -a
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Veremos que ya ha terminado, y ahora vamos a eliminarlo, pero solo este
+
Para borrar todos los contenedores ya finalizados
contenedor, no como previamente que eliminamos todos. Lo mismo que para pararlo,
 
podemos utilizar el nombre o el id.
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker container rm my_container
+
podman container prune
docker container rm my_container
 
docker ps -a
 
 
</syntaxhighlight>
 
</syntaxhighlight>
 
Veremos que ya no tenemos el contenedor y está correctamente eliminado.
 
 
  
 
= Paso 8: Conectarnos a un contenedor que se está ejecutando en segundo plano =
 
= Paso 8: Conectarnos a un contenedor que se está ejecutando en segundo plano =
  
Vamos a ejecutar de nuevo un contenedor que no termine, utilizando el comando
+
Vamos a ejecutar de nuevo un contenedor que no termine:
ping:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run -d --name to_attach alpine ping 0.0.0.0
+
podman run -d -ti --name mi-contenedor debian bash
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Línea 363: Línea 296:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker attach to_attach
+
podman attach mi-contenedor
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Veremos el comando ping ejecutándose, para terminar, hacemos un 'CTRL + C', y
+
Veremos la orden bash ejecutándose, para terminar, hacemos un 'CTRL + C', y ahora, veremos que ha pasado con el contenedor:
ahora, veremos que ha pasado con el contenedor:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker ps -a
+
podman ps -a
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Línea 377: Línea 309:
 
finalizado.
 
finalizado.
  
 +
''Nota:'' Para salir del contenedor '''sin detenerlo''' hacemos 'CTRL + P' seguido 'CTRL + Q'
  
= Paso 9: Ejecutar en un contenedor otro comando =
+
= Paso 9: Ejecutar un comando dentro de un contenedor en ejecución =
  
 
Vamos a ver otresta vez como ejecutar un comando en un contenedor que ya está
 
Vamos a ver otresta vez como ejecutar un comando en un contenedor que ya está
Línea 384: Línea 317:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run -d --name to_exec alpine ping 0.0.0.0
+
podman run -d -ti --name mi-contenedor debian bash
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Ahora, vamos a ejecutar un comando en ese contenedor. El comando exec es similar
+
Ahora, vamos a ejecutar un comando en ese contenedor con el nombre ''mi-contenedor''.
al comando run, pero para ejecutar un comando dentro de un contenedor:
+
El comando exec es similar al comando run, pero para ejecutar un comando dentro de un contenedor:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker exec -ti to_exec ash
+
podman exec -ti mi-contenedor ls
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Ahora estamos dentro del contenedor creado anteriormente, vamos a comprobar que
+
Para redirigir la salida a un fichero en el anfitrión:
tenemos un proceso que está ejecutando el comando ping:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
ps -a
+
podman exec -ti mi-contenedor ls > x.txt
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Aquí veremos en el listado de procesos que hay un proceso ping ejecutándose.
+
Para redirigir la salida a un fichero ''dentro'' del contenedor, hacemos:
  
Ahora vamos a salirnos del contenedor, escribiendo 'exit' o 'CTRL + D', y
+
<syntaxhighlight lang="bash">
comprobemos el estado del contenedor:
+
podman exec -ti mi-contenedor sh -c "ls > x.txt"
 +
</syntaxhighlight>
 +
 
 +
También es posible ejecutar comandos con tuberías:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker ps -a
+
podman exec -ti mi-contenedor sh -c "ls -la | grep ^d"
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Ahora veremos que el contenedor se sigue ejecutando, ya que está el comando ping
+
= Paso 10: Persistencia en contenedores =
en funcionamiento, no como en el paso anterior.
+
 
 +
Al hacer ''exit'' y salir de un contenedor, se pierden todos los cambios que hemos realizado. Los
  
 +
<syntaxhighlight lang="bash">
 +
podman run -d -ti --name mi-ejemplo debian bash
 +
</syntaxhighlight>
  
= Paso 10: Persistencia en contenedores =
+
Ahora, vamos a crear una carpeta en el contenedor y comprobar que esa carpeta existe:
 +
 
 +
<syntaxhighlight lang="bash">
 +
podman exec mi-ejemplo mkdir test
 +
podman exec mi-ejemplo ls
 +
</syntaxhighlight>
  
Vamos a ver que los contenedores no mantienen los datos por defecto, solo nos
+
Veremos que la carpeta existe, pero, ¿qué ocurre si para el contenedor?
dan un servicio pero los datos NO son persistentes. Creemos un contenedor que
 
vamos a dejar ejecutándose:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run -d --name to_expire alpine ping 0.0.0.0
+
podman container stop mi-ejemplo
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Ahora, vamos a crear una carpeta en el contenedor y comprobar que esa carpeta
+
Y volvemos a lanzarlo:
existe:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker exec to_expire mkdir test
+
podman container rm mi-ejemplo
docker exec to_expire ls
+
podman run -d -ti --name mi-ejemplo debian bash
 +
podman exec mi-ejemplo ls
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Veremos que la carpeta existe, pero, ¿qué ocurre si eliminamos el contedor y
+
Podemos comprobar que la carpeta creada anteriormente, no existe.
volvemos a crear uno?
+
 
 +
¿Qué podemos hacer para mantener la modificaciones realizadas sobre un contenedor?
 +
 
 +
== Paso 10.1: Crear una imagen derivada de la imagen base ==
 +
 
 +
Es posible crear una imagen derivada, con modificaciones, a partir de una imagen existente mediante la orden '''commit'''.
 +
 
 +
Por ejemplo, si queremos una imagen ''debian'' que incluya el programa ''ping'' ya instalado, tendríamos que lanzar un contenedor a partir de la imagen ''ubuntu'':
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker container stop to_expire
+
podman run -d -ti debian bash
docker container rm to_expire
 
docker run -d --name to_expire alpine ping 0.0.0.0
 
docker exec to_expire ls
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Podemos comprobar que la carpeta creada anteriormente, no existe si el
+
Suponiendo que el contenido está identificado con el ID 56ef5b312334
contenedor termina. Si quisíeramos mantener una persistencia de datos, tenemos
 
varias opciones:
 
  
 +
Instalamos el paquete ping:
  
== Paso 10.1: Mantener la persistencia cambiando la imagen base ==
+
<syntaxhighlight lang="bash">
 +
podman exec 56ef5b312334 apt -y install ping
 +
</syntaxhighlight>
  
Repetimos los pasos anteriores, pero antes de parar el contenedor, vamos a
+
Generamos la imagen derivada con el nombre ''ubuntu-con-ping'':
guardar el estado del contener en la imagen:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run -d --name to_save alpine ping 0.0.0.0
+
podman commit 56ef5b312334 ubuntu-con-ping
docker exec to_save mkdir test
 
docker commit to_save alpine
 
docker stop to_save
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Ahora, vamos a para el contenedor y ejecutar uno nuevo para probar que los datos
+
Ya podemos para nuestro contendor:
han persistido:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run -d --name to_save_v2 alpine ping 0.0.0.0
+
podman stop 56ef5b312334
docker exec to_save_v2 ls
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
Y lanzar un nuevo contenedor a partir de la imagen ''debian-con-ping'':
  
== Paso 10.2: Mantener la persistencia creando volúmenes ==
+
<syntaxhighlight lang="bash">
 +
podman run -d -ti debian-con-ping bash
 +
</syntaxhighlight>
 +
 
 +
== Paso 10.2: Mantener la persistencia mediante volúmen ==
 +
 
 +
Otra opción para mantener los datos es montar un volumen al ejecutar el contenedor.
  
La otra opción para mantener los datos es montar un volumen al ejecutar el
+
Primero crearemos una carpeta que hará de volumen en nuestra máquina, que será la que luego montemos para podman:
contenedor. Primero crearemos una carpeta que hará de volumen en nuestra
 
máquina, que será la que luego montemos para docker:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
mkdir /home/ubuntu/volumen
+
mkdir /home/debian/volumen
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Línea 486: Línea 432:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run --rm -ti -v /home/ubuntu/volumen:/volumen:rw alpine ash
+
podman run --rm -ti -v /home/debian/volumen:/volumen:rw debian bash
 
mkdir /volumen/test
 
mkdir /volumen/test
 
touch /volumen/test/file
 
touch /volumen/test/file
Línea 504: Línea 450:
 
nuestra máquina y el contenedor de forma sencilla.
 
nuestra máquina y el contenedor de forma sencilla.
  
 
+
= Paso 11: Crear nuestra propia imagen de contenedor =
= Paso 11: Crear nuestra propia imagen docker =
 
  
 
Para crear una imagen de un contenedor con una aplicación de Python hug, creamos en primer lugar la carpeta que contendrá los ficheros que nos permiten crear la imagen.
 
Para crear una imagen de un contenedor con una aplicación de Python hug, creamos en primer lugar la carpeta que contendrá los ficheros que nos permiten crear la imagen.
Línea 517: Línea 462:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
FROM ubuntu
+
FROM debian
 
 
ENV USERNAME="username"
 
  
RUN apt-get update
+
RUN apt -y update
RUN apt-get -y install python3 python3-pip
+
RUN apt -y upgrade
 +
RUN apt -y install python3-hug
 
RUN mkdir /app
 
RUN mkdir /app
RUN pip3 install hug
 
 
COPY endpoint.py /app
 
COPY endpoint.py /app
 
WORKDIR /app
 
WORKDIR /app
 
CMD hug -f endpoint.py
 
CMD hug -f endpoint.py
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
Alternativamente, puedes crear un [[Creando imagen propia usando Ubuntu de base|Dockerfile empleando la imagen de Ubuntu]] como base en lugar de Alpine.
  
 
Y añadimos el fichero ''endpoint.py'' que emplea el framework Python hug con el contenido siguiente:
 
Y añadimos el fichero ''endpoint.py'' que emplea el framework Python hug con el contenido siguiente:
Línea 546: Línea 491:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker build -t app:v1 -f Dockerfile .
+
podman build -t app:v1 -f Dockerfile
 
</syntaxhighlight>
 
</syntaxhighlight>
 
Nota: Si te quedas sin espacio en la máquina virtual, recuerda que puedes redimensionar [[Sistemas_de_archivos#Paso_9:_Redimensionar_tama.C3.B1o_del_disco_virtual_de_imagen_Ubuntu_cloud|la imagen de Ubuntu Cloud]].
 
  
 
Vamos a explicar para que sirve cada línea:
 
Vamos a explicar para que sirve cada línea:
Línea 557: Línea 500:
 
* RUN: para ejecutar comandos, ya sea para crear una carpeta, instalar dependencias o cualquier otra opción que necesitemos
 
* RUN: para ejecutar comandos, ya sea para crear una carpeta, instalar dependencias o cualquier otra opción que necesitemos
 
* COPY: para copiar datos desde nuestra máquina a la imagen
 
* COPY: para copiar datos desde nuestra máquina a la imagen
* WORKDIR: para cambiar el directorio de trabajo
+
* WORKDIR: para cambiar el directorio de trabajo (lo crea si no existe)
 
* CMD: este comando será ejecutado por defecto al iniciar un contenedor a partir de esta imagen
 
* CMD: este comando será ejecutado por defecto al iniciar un contenedor a partir de esta imagen
  
Esto construirá una imagen docker basada en python:alpine, en la cual hemos
+
Esto construirá una imagen podman basada en python:alpine, en la cual hemos
 
guardado nuestra pequeña aplicación y se va a ejecutar cuando ejecutemos un
 
guardado nuestra pequeña aplicación y se va a ejecutar cuando ejecutemos un
 
contenedor basado en esa imagen. Para comprobar que la imagen se ha creado
 
contenedor basado en esa imagen. Para comprobar que la imagen se ha creado
Línea 567: Línea 510:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker images
+
podman images
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Línea 575: Línea 518:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run --name my-app --rm -d -p 8001:8000 app:v1
+
podman run --name my-app --rm -d -p 8001:8000 app:v1
 +
</syntaxhighlight>
 +
 
 +
''Nota:'' podman supone que la redirección de puerto es TCP, para una redirección de puertos UDP, puedes usar:
 +
 
 +
<syntaxhighlight lang="bash">
 +
... -p 8001:8000/udp
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Línea 591: Línea 540:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker exec -ti my-app ash
+
podman exec -ti my-app ash
 
echo $USERNAME
 
echo $USERNAME
 
</syntaxhighlight>
 
</syntaxhighlight>
Línea 599: Línea 548:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker run --rm -ti -e USERNAME=me app:v1 ash
+
podman run --rm -ti -e USERNAME=me app:v1 ash
 
echo $USERNAME
 
echo $USERNAME
 
</syntaxhighlight>
 
</syntaxhighlight>
Línea 608: Línea 557:
 
= Paso 12: Eliminar imágenes =
 
= Paso 12: Eliminar imágenes =
  
Veremos que después de todas las pruebas que hemos estado haciendo, tenemos
+
Para borrar una imagen, puede hacer:
muchas imágenes, y algunas de las cuales no nos servirán o no las utilizaremos,
 
así que podemos borrarlas para ahorrar espacio.
 
 
 
Al igual que con los contenedores, tenemos una opción para borrar imágenes que
 
no se utilicen:
 
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker image prune
+
podman image rm hello-world
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Esto borrará imágenes intermedias que se utilizan a veces para construir
+
= Paso 13: Ejercicios =
nuestras imágenes o imágenes que hemos intentado construir y nos han fallado.
 
  
La otra opción para borrar imágenes una a una, sería utilizando el comando
+
== Ejercicio 1: Image derivada de Debian con el programa sl ==
docker rmi y utilizar el nombre de la imagen o el id. Si esta es la salida de
+
 
'docker images':
+
Lance un contenedor a partir de una imagen de Debian, instale el programa sl, ejecute sl (desde fuera del contenedor) y detenga el contenedor.
 +
 
 +
== Ejercicio 2  ==
 +
 
 +
== Ejercicio 3: Variante de httpd ==
 +
 
 +
Construya una imagen ''httpd-hola-mundo'' a partir de la imagen ''httpd''. El fichero de index.html de la carpeta htdocs/ tiene que mostrar el mensaje "hola mundo".
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
REPOSITORY          TAG                IMAGE ID            CREATED            SIZE
+
podman pull httpd
app                v1                  18609c517d32        14 minutes ago      109MB
 
python              alpine              39fb80313465        23 hours ago        98.7MB
 
debian              latest              85c4fd36a543        13 days ago        114MB
 
hello-world        latest              fce289e99eb9        7 months ago        1.84kB
 
hello-world        linux              fce289e99eb9        7 months ago        1.84kB
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Podemos eliminar las imágenes de hello-world:
+
Edita el fichero Dockerfile:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker rmi hello-world
+
nano Dockerfile
 
</syntaxhighlight>
 
</syntaxhighlight>
  
ó
+
Añada este contenido:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker rmi fce289e99eb9
+
FROM httpd
 +
 
 +
COPY index.html htdocs/index.html
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
Edita el fichero index.html:
  
= Paso 13: Varios docker a la vez (docker-compose) =
+
<syntaxhighlight lang="bash">
 +
nano index.html
 +
</syntaxhighlight>
  
Antes de comenzar, vamos a parar todos los contenedores que tengamos abiertos,
+
Añada este contenido:
para dejar el entorno de docker limpio, que nos vendrá bien para esta parte.
 
  
Cuando queremos ejecutar varios contenedores a la vez y que estén conectados
+
<syntaxhighlight lang="bash">
entre ellos fácilmente, utilizaremos docker-compose, donde con un fichero de
+
<html>hola mundo</html>
configuración simple en yaml, tendremos toda la configuración de lo que vamos a
+
</syntaxhighlight>
ejecutar.
 
  
Primero vamos a instalar docker-compose:
+
Construye la imagen:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
sudo apt install docker-compose
+
podman build -t mihttpd -f Dockerfile
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Ahora veamos un pequeño ejemplo donde explicaremos todos los detalles para crear
+
Ahora vamos a crear un contenedor de nuestra imagen:
un docker-compose, en este caso, el nombre por defecto de los ficheros suele ser
+
 
docker-compose.yml, y el contenido será similar a:
+
<syntaxhighlight lang="bash">
 +
podman run --name mihttpd -d -p 8080:80 mihttpd
 +
</syntaxhighlight>
  
 +
Ahora vamos a probar que funciona nuestra imagen y nuestro código:
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
version: '3'
+
curl -X GET http://localhost:8080
 +
</syntaxhighlight>
  
services:
+
Tiene que salir por pantalla esto:
  web:
+
<syntaxhighlight lang="bash">
    container_name: web
+
<html>hola mundo</html>
    restart: always
 
    build:
 
      context: .
 
    ports:
 
      - "8000:8000"
 
    volumes:
 
      - /home/ubuntu/volume:/volumen:rw
 
    environment:
 
      USERNAME: test
 
  web2:
 
    container_name: web2
 
    build:
 
      dockerfile: Dockerfile
 
      context: .
 
    depends_on:
 
      - web
 
    command: touch web2
 
  web3:
 
    container_name: web3
 
    restart: on-failure
 
    image: pstauffer/curl
 
    depends_on:
 
      - web
 
    command: curl -X GET web:8000/welcome?username=web3
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
En el docker-compose definimos diferentes servicios a ejecutar, en nuestro caso
+
== Ejercicio 4: aplicación flask ==
hemos iniciado tres servicios diferentes, web, web2 y web3:
+
 
 +
Flask es un framework python para implementar webs. Cree una imagen "miapp-flask" a partir de la imagen de "python":
 +
 
 +
* Instale flask mediante: pip install flask
 +
* Cree la carpeta "app"
 +
* Establezca la variable FLASK_APP a "hello.py"
 +
* Añada el fichero "hello.py"
 +
* Establezca el directorio de trabajo a "/app"
 +
 
 +
El fichero hello.py contiene un "hola mundo" para Flask:
 +
 
 +
<syntaxhighlight lang="python">
 +
from flask import Flask
 +
app = Flask(__name__)
 +
 
 +
@app.route("/")
 +
def hello():
 +
    return "Hello World!"
  
El primer servicio, web:
+
if __name__ == "__main__":
 +
    app.run()
 +
</syntaxhighlight>
  
* container_name: para darle un nombre por defecto al contenedor cuando se cree
+
Solución con alpine:
* restart: pueden ser:
 
** "no": si la máquina termina, no se vuelve a iniciar (opción por defecto)
 
** always: siempre que el contenedor termine, intenta iniciarse de nuevo
 
** on-failure: solo intenta reiniciarse si el contenedor termina con fallo
 
** unless-stopped: solo reinicia el contenedor si el usuario es el que lo termina
 
* Utilizará el fichero Dockerfile creado en el paso 11 para generar la imagen a
 
  usar.
 
* Expondrá el puerto 8000 del contenedor en el 8000 de nuestra máquina
 
* Montará un volumen, se hace de forma similar a la línea de comandos
 
* Creará una variable de entorno
 
  
El segundo servicio, web2:
+
<syntaxhighlight lang="bash">
 +
FROM python:alpine
  
* Utilizará el fichero Dockerfile también, la diferencia entre este y el primer
+
RUN mkdir /app
  servicio, es que si el nombre del Dockerfile cambia, tendremos que hacerlo de
+
RUN pip install flask
  esta segunda forma, la primera por defecto solo buscará el fichero Dockerfile
+
ENV FLASK_APP="app/hello.py"
* depends_on hará que para ejecutar este servicio, su dependencia tenga ya que
+
COPY hello.py
  estar iniciada
+
WORKDIR /
* Ejecutaremos un comando el cual sustituirá al comando de la imagen
+
CMD flask run --host=0.0.0.0
 +
</syntaxhighlight>
  
El tercer servicio, web3:
+
Solución con Ubuntu:
  
* Utilizará la imagen ostauffer/curl que es un imagen mínima que contiene el
+
<syntaxhighlight lang="bash">
  comando curl
+
FROM ubuntu:bionic
* restart: en este caso, hasta que el comando no se ejecute correctamente, se
+
 
  seguirá reiniciando el contenedor
+
RUN apt-get update
* depends_on igual que el servicio 2, dependerá del servicio 1
+
RUN apt-get -y install python python-pip wget
* Ejecutaremos un comando para llamar desde el servicio 3 al servicio 1
+
RUN pip install Flask
 +
ENV FLASK_APP="app/hello.py"
 +
RUN mkdir /app
 +
COPY hello.py /app
 +
CMD flask run --host=0.0.0.0
 +
</syntaxhighlight>
  
 +
== Ejercicio 5: mysql ==
  
== Paso 13.1: Construir docker-compose ==
+
'''EN LA MÁQUINA VIRTUAL:'''
  
En el caso de existir servicios que tengan Dockerfiles, esto hará que se
+
mkdir miapp
contruyan previamente, como hacer un docker build de cada uno de los servicios
+
cd miapp
que contenga un Dockerfile:
+
podman pull mysql
 +
nano Dockerfile
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker-compose build
+
FROM mysql
 +
ENV MYSQL_ROOT_PASSWORD="lacontraseñaqueyoquiera"
 +
RUN mkdir /app
 +
WORKDIR /app
 +
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Con esto se generarán las imágenes necesarias para ejecutar todos los
+
CTRL+O , ENTER Y CTRL+X (para guardar Dockerfile y salir)
servicios.
 
  
 +
podman build -ti mrfdocker -f Dockerfile
 +
podman  run --name mymrf --rm -p 8001:3306 mrfdocker
 +
docker images
  
== Paso 13.2: Iniciar docker-compose ==
+
'''EN LA TERMINAL DEL HOST:'''
  
Para iniciar todos los servicios, ejecutaremos:
+
''Instalación de mysql:''
 +
 
 +
apt install mysql-client-core-5.7
 +
apt-get install mysql-server
 +
service mysql start
 +
 
 +
''Para entrar:''
 +
 
 +
mysql -u root -p -P 8001
 +
 
 +
Una vez dentro de msql:
 +
 
 +
mysql> show databases;
 +
 
 +
''Para salir:''
 +
 
 +
exit
 +
 
 +
== Ejercicio 6: python pyramid ==
 +
 
 +
Pyramid es un framework python para implementar webs. Cree una imagen "miapp-pyramid":
 +
 
 +
* Emplee la imagen de debian como referencia, instale los paquetes python3 y python3-pyramid.
 +
* Cree la carpeta "app"
 +
* Añada el fichero "hello.py"
 +
* Establezca el directorio de trabajo a "/app"
 +
* La aplicación se lanza con la orden: python3 hello.py
 +
* Compruebe que funciona con curl, la ruta a la web es http://127.0.0.1:8000/hello, suponiendo que ha empleado el puerto 8000 para exponer el servicio.
 +
 
 +
El fichero hello.py contiene un "hola mundo" para Pyramid:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker-compose up -d
+
from wsgiref.simple_server import make_server
 +
from pyramid.config import Configurator
 +
from pyramid.response import Response
 +
 
 +
def hello_world(request):
 +
    print('Request inbound!')
 +
    return Response('Podman works with Pyramid!')
 +
 
 +
if __name__ == '__main__':
 +
    config = Configurator()
 +
    config.add_route('hello', '/')
 +
    config.add_view(hello_world, route_name='hello')
 +
    app = config.make_wsgi_app()
 +
    server = make_server('0.0.0.0', 6543, app)
 +
    server.serve_forever()
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Después de esto podremos ver el logs de todos los servicios:
+
Este programa recibe peticiones en el puerto 6543.
 +
 
 +
== Ejercicio 7 ==
 +
 
 +
Cree una imagen derivada de Ubuntu, instale el paquete apache2, php y libapache2-mod-php.
 +
Active el módulo de php para apache2 mediante la orden:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker-compose logs -f
+
a2enmod php
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Aquí veremos que el servicio 3 ha conseguido llamar correctamente al servicio 1.
+
Cree la carpeta /var/www/php.
  
Ahora veremos como docker-compose ha creado los contenedores:
+
Cree el fichero index.php
  
<syntaxhighlight lang="bash">
+
<syntaxhighlight lang="php">
docker ps -a
+
<?php
 +
Print "Hello, World!";
 +
?>
 
</syntaxhighlight>
 
</syntaxhighlight>
  
La salida será similar a la siguiente:
+
y copielo a /var/www/php/.
 +
 
 +
Cree el fichero 000-default.conf y copielo a /etc/apache2/sites-enabled/
 +
 
 +
Dicho fichero contiene.
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
CONTAINER ID        IMAGE              COMMAND                  CREATED            STATUS                    PORTS                    NAMES
+
<VirtualHost *:80>
219a4118244c        pstauffer/curl      "curl -X GET web:800…"   6 seconds ago       Exited (0) 3 seconds ago                            web3
+
  DocumentRoot /var/www/php
c97e894cb3ae        ubuntu_web2        "touch web2"            6 seconds ago       Exited (0) 4 seconds ago                            web2
+
 
f35d034204fc        ubuntu_web          "/bin/sh -c 'hug -f …"   6 seconds ago      Up 5 seconds              0.0.0.0:8000->8000/tcp  web
+
   <Directory /var/www/php/>
 +
      Options Indexes FollowSymLinks MultiViews
 +
      AllowOverride All
 +
       Order deny,allow
 +
       Allow from all
 +
  </Directory>
 +
 
 +
  ErrorLog ${APACHE_LOG_DIR}/error.log
 +
   CustomLog ${APACHE_LOG_DIR}/access.log combined
 +
</VirtualHost>
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Aquí vemos varios detalles:
+
Tiene que lanzar apache con la orden: apachectl -D FOREGROUND
  
* El nombre que le hemos dado en el docker-compose ha funcionado correctamente
+
Tras crear la imagen, láncela mapeando el puerto 8888 al 80, pruebe que puede acceder a http://127.0.0.1:8888/php/ mediante curl
* Vemos que los comandos son los correctos también
 
* web2 está parado por que la política de reinicio es apagar cuando se termine
 
  de ejecutar un comando
 
* web 3 está parado por que el comando ha terminado con un salida correcta
 
  
Vamos a comprobar ahora que en el servicio web está todo correcto:
+
Solución:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker exec -ti web ash
+
FROM ubuntu:latest
echo $USERNAME
+
 
ls /volumen
+
RUN apt-get update
exit
+
RUN apt-get install -y tzdata
 +
RUN apt-get install -y apache2
 +
RUN apt-get install -y php
 +
RUN apt-get install -y libapache2-mod-php
 +
RUN a2enmod php7.2
 +
COPY index.php /var/www/php
 +
COPY 000-default.conf /etc/apache2/sites-enabled/ 
 +
CMD apachectl -D FOREGROUND
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Podemos comprobar que tanto cambiar la variable de entorno como crear un
+
Y para lanzarlo:
volumen ha funcionado correctamente.
 
  
 +
podman run --name my-app --rm -d -p 8001:8000 app:v1
  
== Paso 13.3: Parar docker-compose ==
+
y para probarlo:
  
Para parar todos los servicios:
+
curl -X GET http://127.0.0.1:8888/php/
 +
 
 +
== Ejercicio 8 ==
 +
 
 +
Instale el paquete ''netcat-traditional'' en una imagen de contenedor de ''ubuntu''. Lance la orden:
 +
 
 +
nc -u -l -p 8080
 +
 
 +
en el contenedor. Asegúrese de crear una redirección de puertos de 9999 desde el ''host'' al puerto 8080 en el contenedor.
 +
 
 +
Desde fuera del contenedor, pruebe a conectarse con:
 +
 
 +
nc -u 127.0.0.1 9999
 +
 
 +
== Ejercicio 9 ==
 +
 
 +
Cree una imagen derivada de "ubuntu" con un Dockerfile que incluya soporte de python y lance el siguiente código en Python:
 +
 
 +
<syntaxhighlight lang="python">
 +
from http.server import BaseHTTPRequestHandler, HTTPServer
 +
import time
 +
 
 +
hostName = "0.0.0.0"
 +
serverPort = 8080
 +
 
 +
class MyServer(BaseHTTPRequestHandler):
 +
    def do_GET(self):
 +
        self.send_response(200)
 +
        self.send_header("Content-type", "text/html")
 +
        self.end_headers()
 +
        self.wfile.write(bytes("<html><head><title>Welcome!</title></head>", "utf-8"))
 +
        self.wfile.write(bytes("<body>", "utf-8"))
 +
        self.wfile.write(bytes("<p>This is an example web server.</p>", "utf-8"))
 +
        self.wfile.write(bytes("</body></html>", "utf-8"))
 +
 
 +
if __name__ == "__main__":       
 +
    webServer = HTTPServer((hostName, serverPort), MyServer)
 +
    print("Server started http://%s:%s" % (hostName, serverPort))
 +
 
 +
    try:
 +
        webServer.serve_forever()
 +
    except KeyboardInterrupt:
 +
        pass
 +
 
 +
    webServer.server_close()
 +
    print("Server stopped.")
 +
</syntaxhighlight>
 +
 
 +
Llame a su imagen "python-http-server". Lance una instancia de la imagen "python-http-server" mapeando el puerto 9999 al puerto 8888/tcp del contenedor. Compruebe con:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker-compose down
+
curl http://127.0.0.1:9999/
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Comprobamos:
+
que muestre la página HTML que ofrece el servidor, que debería ser:
  
 
<syntaxhighlight lang="bash">
 
<syntaxhighlight lang="bash">
docker ps -a
+
<html><head><title>Welcome!</title></head><body><p>This is an example web server.</p></body></html>
 
</syntaxhighlight>
 
</syntaxhighlight>
 
Vemos que han desaparecido todos los contenedores.
 
  
  
<!--
+
= Anexo =
= Paso 12: Minikube: versión reducida de Kubernetes =
 
  
Minikube es una versión reducida de Kubernetes para poder ejecutar todo en la
+
* Cómo usar [[Podman compose]]
misma máquina y no necesitar 3 nodos como necesita Kubernetes.
 

Revisión actual del 14:37 16 dic 2025

En esta práctica aprenderemos a utilizar podman para desplegar contenedores.

Paso 1: Instalar podman

Para instalar el paquete oficial:

apt install podman

podman es un clon de 'docker.

Si añade un usuario 'test' a su sistema con:

adduser test

recuerde hacer:

loginctl enable-linger test
systemctl start --user dbus

para evitar un warning que se muestra al ejecutar podman como usuario.

Paso 2: Repositorio de imágenes de contenedores DockerHub

Docker ofrece un servicio de nube denominado DockerHub que puede ser empleado como red social para compartir tus imágenes de Podman. En DockerHub existen además imágenes de contenedores preconfiguradas de software, muchas de ellas oficiales (ofrecidas por el propio fabricante del software) que se podrán emplear como base para construir nuevas imágenes adaptadas a nuestras necesidades.

Podremos realizar búsquedas en este repositorio DockerHub puedes emplear el siguiente comando:

podman search docker.io/library/hello-world

Para descargarnos la imagen de hello-world podemos usar la orden pull:

podman pull docker.io/library/hello-world

También podemos publicar imágenes propias, esto require registro de usuario en la nube de DockerHub, lo que no es obligatorio para la realización de esta práctica. Para subir una imagen, hay que validarse como usuario en la nube de DockerHub:

podman login docker.io

Tras introducir tu usuario y contraseña, puedes comenzar a publicar tus propias imágenes.

podman push docker.io/USUARIO/MI_IMAGEN

Este paso es opcional, sólo en caso de que se quieran subir imágenes de contenedores a la nube de docker.io.

Paso 4: Comprobar imágenes en nuestra máquina

Para ver las imágenes que tenemos en nuestra máquina, utilizaremos el comando:

podman images

Inicialmente, no tenemos imágenes en almacenamiento, podemos descargarnos la imagen oficial de Debian 13 (Trixie):

podman pull docker.io/library/debian

Ahora si, ya debería de aparecernos la imagen debian.

Comentar también que cada imagen puede tener varias etiquetas, por ejemplo, la imagen Debian 12 (Bookworm), cuando la hemos visto en el listado de imágenes, venía con el tag latest, que es el tag que se descarga por defecto, pero nosotros podemos especificar otro, por ejemplo:

podman pull docker.io/library/debian:bookworm

Para traernos la versión de la imagen de Debian 12 Bookworm.

Ahora tendremos dos imágenes con diferente etiqueta, que serían como las diferentes versiones de cada imagen.

Paso 5: Lanzar un contenedor

Un contenedor no es más que una imagen de podman ejecutándose, sería similar a una máquina virtual, aunque mucho más liviano.

Para crear un contenedor, utilizaremos una imagen, en este caso, la imagen hello-world. Hacemos lo siguiente:

podman run hello-world

Esto nos mostrará el siguiente mensaje si todo está correcto:

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Debian container with:
 $ podman run -it debian bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

Al crear los contenedores utilizando el comando 'run', tenemos varias opciones:

  • Lanzar una terminal en el contenedor en modo interactivo
  • Lanzar en segundo plano y conectarnos posteriormente al contenedor

Paso 5.1: Lanzar una terminal en el contenedor en modo interactivo (-ti)

Para este ejemplo vamos a utilizar otra imagen diferente, en este caso vamos a utilizar una imagen de debian.

Vamos a lanzar un contenedor y ejecutar una terminal en el que se va a ejecutar el programa bash que me ofrece un interprete de órdenes:

podman run -ti debian bash

La opción -t indica que se crea un terminal en el contenedor. Y la opción -i indica que el contenedor se ejecuta en modo interactivo.

Al acceder al contenedor de debian nos aparece un hash en el prompt de la shell, que identifica a la instancia del contenedor (es valor es similar al que muestra la orden podman container ls).

Para salir del contenedor, escribimos 'exit' o pulsamos CTRL + D

Paso 5.2 Lanzar en segundo plano (-d)

Otro ejemplo, con la imagen de Debian:

podman run -dti debian

que muestra un hash que identifica de forma única el contenedor lanzado:

2ec1daae4676a4e84dc04fd91399c1dfe92119544ff12ee307991fe573d3db64

Mediante el comando attach puedo entrar al contenedor:

podman attach 2ec1daae4676

Para salir, pulsamos CTRL + P seguido de CTRL + Q.

De manera similar, puedo lanzar en segundo plano la imagen de contenedor de hello-world:

podman run -d hello-world

Y consultar los logs:

podman logs b67fae3312bc321

Paso 5.3: Añadir variables de entorno a un contenedor

Utilizaremos la imagen anterior, y vamos a añadir una variable de entorno llamada TEST que contenga el valor 'test'. A parte, también ejecutaremos la terminal como antes, para comprobar con el comando echo, que la variable de entorno está creada correctamente:

podman run -ti -e TEST=test debian bash

Ahora, desde el contenedor podemos comprobar el valor de la variable de entorno $TEST.

echo $TEST
test

Paso 6: Listar contenedores en ejecución

Hemos estado haciendo pruebas y ejecutando contenedores en el paso anterior, vamos a ver donde se encuentran estos contenedores que hemos ejecutado, y después veremos algunas opciones más del comando run.

Tenemos dos opciones para ver los contenedores:

podman container ls -a

o la versión corta:

podman ps -a

Ambas hacen lo mismo, y debería de mostrarnos una salida similar a la siguiente:

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
e2bde5f5500c        debian              "bash"               6 minutes ago       Exited (0) 2 seconds ago                        pensive_sammet
544ad27dbc3c        debian              "bash"               7 minutes ago       Exited (0) 7 minutes ago                        serene_elgamal

En la información veremos que el contenedor tiene el estado exited, eso quiere decir que no se está ejecutando y ya ha finalizado. Vamos a hacer una prueba para ver un contendor ejecutándose:

podman run -d debian sleep 30

Con el comando sleep 30 esperamos 30 segundos hasta que termine el comando, asíque durante esos 30 segundos, el contenedor estará ejecutándose, veámoslo:

podman ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
eacceb27d52d        debian              "sleep 30"          12 seconds ago      Up 11 seconds                                   sharp_pasteur

Vamos a ver alguna opciones más de la orden run.

Paso 6.1: Dar un nombre al contenedor (--name)

Por defecto, podman creará automáticamente un nombre como hemos visto en las salidas del comando podman ps -a. Podemos establecer el nombre del contenedor que queramos con la opción --name:

podman run -ti --name mi_debian debian

Paso 6.2: Eliminar contenedor cuando termine (--rm)

Vamos a mezclar todo lo visto anteriormente:

  • Lanzar en segundo plano (-d)
  • Ejecutar contenedor durante 30 segundos (sleep 30)
  • Dar un nombre a la imagen (--name)
  • Eliminar contenedor cuando termine (--rm)
podman run -d --rm --name bye-bye debian sleep 30

Antes y una vez pasados los 30 segundos, podemos comprobar que el contenedor ha desaparecido.

podman ps -a

Paso 7: Parar y eliminar contenedores

Para parar contenedores podemos usar el ID o su nombre:

podman stop my_container
podman stop e4901956f108
podman ps -a

Una vez hemos comprobado que han terminado su ejecución, podemos eliminar los ficheros resultantes de su ejecución:

podman container rm my_container

Para borrar todos los contenedores ya finalizados

podman container prune

Paso 8: Conectarnos a un contenedor que se está ejecutando en segundo plano

Vamos a ejecutar de nuevo un contenedor que no termine:

podman run -d -ti --name mi-contenedor debian bash

Ahora, vamos a conectarnos a este contenedor que está ejecutándose en segundo plano:

podman attach mi-contenedor

Veremos la orden bash ejecutándose, para terminar, hacemos un 'CTRL + C', y ahora, veremos que ha pasado con el contenedor:

podman ps -a

Lo veremos parado, por que lo que hemos hecho ha sido conectarnos al contenedor y parar el comando que se estaba ejecutando, así que ahora tenemos el contenedor finalizado.

Nota: Para salir del contenedor sin detenerlo hacemos 'CTRL + P' seguido 'CTRL + Q'

Paso 9: Ejecutar un comando dentro de un contenedor en ejecución

Vamos a ver otresta vez como ejecutar un comando en un contenedor que ya está ejecutándose:

podman run -d -ti --name mi-contenedor debian bash

Ahora, vamos a ejecutar un comando en ese contenedor con el nombre mi-contenedor. El comando exec es similar al comando run, pero para ejecutar un comando dentro de un contenedor:

podman exec -ti mi-contenedor ls

Para redirigir la salida a un fichero en el anfitrión:

podman exec -ti mi-contenedor ls > x.txt

Para redirigir la salida a un fichero dentro del contenedor, hacemos:

podman exec -ti mi-contenedor sh -c "ls > x.txt"

También es posible ejecutar comandos con tuberías:

podman exec -ti mi-contenedor sh -c "ls -la | grep ^d"

Paso 10: Persistencia en contenedores

Al hacer exit y salir de un contenedor, se pierden todos los cambios que hemos realizado. Los

podman run -d -ti --name mi-ejemplo debian bash

Ahora, vamos a crear una carpeta en el contenedor y comprobar que esa carpeta existe:

podman exec mi-ejemplo mkdir test
podman exec mi-ejemplo ls

Veremos que la carpeta existe, pero, ¿qué ocurre si para el contenedor?

podman container stop mi-ejemplo

Y volvemos a lanzarlo:

podman container rm mi-ejemplo
podman run -d -ti --name mi-ejemplo debian bash
podman exec mi-ejemplo ls

Podemos comprobar que la carpeta creada anteriormente, no existe.

¿Qué podemos hacer para mantener la modificaciones realizadas sobre un contenedor?

Paso 10.1: Crear una imagen derivada de la imagen base

Es posible crear una imagen derivada, con modificaciones, a partir de una imagen existente mediante la orden commit.

Por ejemplo, si queremos una imagen debian que incluya el programa ping ya instalado, tendríamos que lanzar un contenedor a partir de la imagen ubuntu:

podman run -d -ti debian bash

Suponiendo que el contenido está identificado con el ID 56ef5b312334

Instalamos el paquete ping:

podman exec 56ef5b312334 apt -y install ping

Generamos la imagen derivada con el nombre ubuntu-con-ping:

podman commit 56ef5b312334 ubuntu-con-ping

Ya podemos para nuestro contendor:

podman stop 56ef5b312334

Y lanzar un nuevo contenedor a partir de la imagen debian-con-ping:

podman run -d -ti debian-con-ping bash

Paso 10.2: Mantener la persistencia mediante volúmen

Otra opción para mantener los datos es montar un volumen al ejecutar el contenedor.

Primero crearemos una carpeta que hará de volumen en nuestra máquina, que será la que luego montemos para podman:

mkdir /home/debian/volumen

Ahora vamos a montar la carpeta al ejecutar el contenedor, lo hacemos con la opción -v, la cual tiene 3 campos separados por ':':

  1. El volumen en nuestra máquina
  2. Donde se montará el volumen dentro del contenedor
  3. Opciones de mmontaje, por ejemplo rw (read and write) o ro (read only)
podman run --rm -ti -v /home/debian/volumen:/volumen:rw debian bash
mkdir /volumen/test
touch /volumen/test/file
exit

Una vez nos salgamos del contenedor, podemos ver que en nuestra máquina están los datos:

ls /home/ubuntu/volumen/
ls /home/ubuntu/volumen/test

La próxima vez que ejecutemos un contenedor, si montamos ese volumen, los datos estarán ahí, además esta forma tiene el beneficio de compartir datos entre nuestra máquina y el contenedor de forma sencilla.

Paso 11: Crear nuestra propia imagen de contenedor

Para crear una imagen de un contenedor con una aplicación de Python hug, creamos en primer lugar la carpeta que contendrá los ficheros que nos permiten crear la imagen.

mkdir miapp
cd miapp

Definimos un fichero Dockerfile para definir la imagen:

FROM debian

RUN apt -y update
RUN apt -y upgrade
RUN apt -y install python3-hug
RUN mkdir /app
COPY endpoint.py /app
WORKDIR /app
CMD hug -f endpoint.py

Alternativamente, puedes crear un Dockerfile empleando la imagen de Ubuntu como base en lugar de Alpine.

Y añadimos el fichero endpoint.py que emplea el framework Python hug con el contenido siguiente:

import hug

@hug.get('/welcome')
def welcome(username="unknown"):
    """ Say welcome to username """
    return "Welcome " + username

Este fichero es un ejemplo de uso de Python hug. Si hacemos una petición a /welcome?username="LSO", esto nos devolverá el mensaje "Welcome LSO".

Una vez tengamos los dos ficheros creados en nuestra máquina virtual, podemos construir nuestra imagen:

podman build -t app:v1 -f Dockerfile

Vamos a explicar para que sirve cada línea:

  • FROM: servirá para basarnos en una imagen existente, en este caso, una imagen de python alpine, que contiene python y no ocupa mucho espacio
  • ENV: para crear variables de entorno
  • RUN: para ejecutar comandos, ya sea para crear una carpeta, instalar dependencias o cualquier otra opción que necesitemos
  • COPY: para copiar datos desde nuestra máquina a la imagen
  • WORKDIR: para cambiar el directorio de trabajo (lo crea si no existe)
  • CMD: este comando será ejecutado por defecto al iniciar un contenedor a partir de esta imagen

Esto construirá una imagen podman basada en python:alpine, en la cual hemos guardado nuestra pequeña aplicación y se va a ejecutar cuando ejecutemos un contenedor basado en esa imagen. Para comprobar que la imagen se ha creado correctamente, listamos las imagenes, y debería de aparecernos una imagen con nombre 'app' y tag 'v1':

podman images

Ahora vamos a crear un contenedor de nuestra imagen, y vamos a añadir una nueva opción, -p 8001:8000. Esta opción hará que el puerto interno 8000 del contenedor sea expuesto en el puerto 8001 de nuestra máquina:

podman run --name my-app --rm -d -p 8001:8000 app:v1

Nota: podman supone que la redirección de puerto es TCP, para una redirección de puertos UDP, puedes usar:

... -p 8001:8000/udp

Ahora vamos a probar que funciona nuestra imagen y nuestro código. En nuestra máquina haremos:

curl -X GET http://localhost:8001/welcome?username=LSO

Comprobaremos que la salida del comando curl, es "Welcome LSO".

Antes de terminar, vamos a comprobar otro pequeño detalle que añadimos en nuestra imagen, la variable de entorno USERNAME, vamos a comprobar que funciona:

podman exec -ti my-app ash
echo $USERNAME

Funciona correctamente, pero al ejecutar el contenedor, podemos cambiar esta variable de entorno como vimos en uno de los pasos anteriores:

podman run --rm -ti -e USERNAME=me app:v1 ash
echo $USERNAME

Esto nos servirá para tener opciones por defecto y que el usuario pueda cambiarlo a su antojo, como por ejemplo contraseñas u otros detalles.

Paso 12: Eliminar imágenes

Para borrar una imagen, puede hacer:

podman image rm hello-world

Paso 13: Ejercicios

Ejercicio 1: Image derivada de Debian con el programa sl

Lance un contenedor a partir de una imagen de Debian, instale el programa sl, ejecute sl (desde fuera del contenedor) y detenga el contenedor.

Ejercicio 2

Ejercicio 3: Variante de httpd

Construya una imagen httpd-hola-mundo a partir de la imagen httpd. El fichero de index.html de la carpeta htdocs/ tiene que mostrar el mensaje "hola mundo".

podman pull httpd

Edita el fichero Dockerfile:

nano Dockerfile

Añada este contenido:

FROM httpd

COPY index.html htdocs/index.html

Edita el fichero index.html:

nano index.html

Añada este contenido:

<html>hola mundo</html>

Construye la imagen:

podman build -t mihttpd -f Dockerfile

Ahora vamos a crear un contenedor de nuestra imagen:

podman run --name mihttpd -d -p 8080:80 mihttpd

Ahora vamos a probar que funciona nuestra imagen y nuestro código:

curl -X GET http://localhost:8080

Tiene que salir por pantalla esto:

<html>hola mundo</html>

Ejercicio 4: aplicación flask

Flask es un framework python para implementar webs. Cree una imagen "miapp-flask" a partir de la imagen de "python":

  • Instale flask mediante: pip install flask
  • Cree la carpeta "app"
  • Establezca la variable FLASK_APP a "hello.py"
  • Añada el fichero "hello.py"
  • Establezca el directorio de trabajo a "/app"

El fichero hello.py contiene un "hola mundo" para Flask:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()

Solución con alpine:

FROM python:alpine

RUN mkdir /app
RUN pip install flask
ENV FLASK_APP="app/hello.py"
COPY hello.py
WORKDIR /
CMD flask run --host=0.0.0.0

Solución con Ubuntu:

FROM ubuntu:bionic

RUN apt-get update
RUN apt-get -y install python python-pip wget
RUN pip install Flask
ENV FLASK_APP="app/hello.py"
RUN mkdir /app
COPY hello.py /app
CMD flask run --host=0.0.0.0

Ejercicio 5: mysql

EN LA MÁQUINA VIRTUAL:

mkdir miapp
cd miapp
podman pull mysql
nano Dockerfile
FROM mysql
ENV MYSQL_ROOT_PASSWORD="lacontraseñaqueyoquiera"
RUN mkdir /app
WORKDIR /app

CTRL+O , ENTER Y CTRL+X (para guardar Dockerfile y salir)

podman build -ti mrfdocker -f Dockerfile
podman  run --name mymrf --rm -p 8001:3306 mrfdocker
docker images

EN LA TERMINAL DEL HOST:

Instalación de mysql:

apt install mysql-client-core-5.7
apt-get install mysql-server
service mysql start

Para entrar:

mysql -u root -p -P 8001

Una vez dentro de msql:

mysql> show databases;

Para salir:

exit

Ejercicio 6: python pyramid

Pyramid es un framework python para implementar webs. Cree una imagen "miapp-pyramid":

  • Emplee la imagen de debian como referencia, instale los paquetes python3 y python3-pyramid.
  • Cree la carpeta "app"
  • Añada el fichero "hello.py"
  • Establezca el directorio de trabajo a "/app"
  • La aplicación se lanza con la orden: python3 hello.py
  • Compruebe que funciona con curl, la ruta a la web es http://127.0.0.1:8000/hello, suponiendo que ha empleado el puerto 8000 para exponer el servicio.

El fichero hello.py contiene un "hola mundo" para Pyramid:

from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response

def hello_world(request):
    print('Request inbound!')
    return Response('Podman works with Pyramid!')

if __name__ == '__main__':
    config = Configurator()
    config.add_route('hello', '/')
    config.add_view(hello_world, route_name='hello')
    app = config.make_wsgi_app()
    server = make_server('0.0.0.0', 6543, app)
    server.serve_forever()

Este programa recibe peticiones en el puerto 6543.

Ejercicio 7

Cree una imagen derivada de Ubuntu, instale el paquete apache2, php y libapache2-mod-php. Active el módulo de php para apache2 mediante la orden:

a2enmod php

Cree la carpeta /var/www/php.

Cree el fichero index.php

<?php 
Print "Hello, World!";
?>

y copielo a /var/www/php/.

Cree el fichero 000-default.conf y copielo a /etc/apache2/sites-enabled/

Dicho fichero contiene.

<VirtualHost *:80>
  DocumentRoot /var/www/php

  <Directory /var/www/php/>
      Options Indexes FollowSymLinks MultiViews
      AllowOverride All
      Order deny,allow
      Allow from all
  </Directory>

  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Tiene que lanzar apache con la orden: apachectl -D FOREGROUND

Tras crear la imagen, láncela mapeando el puerto 8888 al 80, pruebe que puede acceder a http://127.0.0.1:8888/php/ mediante curl

Solución:

FROM ubuntu:latest

RUN apt-get update
RUN apt-get install -y tzdata
RUN apt-get install -y apache2
RUN apt-get install -y php
RUN apt-get install -y libapache2-mod-php
RUN a2enmod php7.2
COPY index.php /var/www/php
COPY 000-default.conf /etc/apache2/sites-enabled/  
CMD apachectl -D FOREGROUND

Y para lanzarlo:

podman run --name my-app --rm -d -p 8001:8000 app:v1

y para probarlo:

curl -X GET http://127.0.0.1:8888/php/

Ejercicio 8

Instale el paquete netcat-traditional en una imagen de contenedor de ubuntu. Lance la orden:

nc -u -l -p 8080

en el contenedor. Asegúrese de crear una redirección de puertos de 9999 desde el host al puerto 8080 en el contenedor.

Desde fuera del contenedor, pruebe a conectarse con:

nc -u 127.0.0.1 9999

Ejercicio 9

Cree una imagen derivada de "ubuntu" con un Dockerfile que incluya soporte de python y lance el siguiente código en Python:

from http.server import BaseHTTPRequestHandler, HTTPServer
import time

hostName = "0.0.0.0"
serverPort = 8080

class MyServer(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        self.wfile.write(bytes("<html><head><title>Welcome!</title></head>", "utf-8"))
        self.wfile.write(bytes("<body>", "utf-8"))
        self.wfile.write(bytes("<p>This is an example web server.</p>", "utf-8"))
        self.wfile.write(bytes("</body></html>", "utf-8"))

if __name__ == "__main__":        
    webServer = HTTPServer((hostName, serverPort), MyServer)
    print("Server started http://%s:%s" % (hostName, serverPort))

    try:
        webServer.serve_forever()
    except KeyboardInterrupt:
        pass

    webServer.server_close()
    print("Server stopped.")

Llame a su imagen "python-http-server". Lance una instancia de la imagen "python-http-server" mapeando el puerto 9999 al puerto 8888/tcp del contenedor. Compruebe con:

curl http://127.0.0.1:9999/

que muestre la página HTML que ofrece el servidor, que debería ser:

<html><head><title>Welcome!</title></head><body><p>This is an example web server.</p></body></html>


Anexo