En el tema anterior arrancabas contenedores de nginx o de debian sin preguntarte mucho de dónde
salían. Salen de una imagen: la plantilla con los archivos y el programa. En este tema la
imagen es la protagonista: cómo se llama, qué versión es, qué lleva dentro, cómo se le pone un
nombre propio, cómo se borra sin dejar el servidor a medias y cómo se lleva a una máquina que no
sale a internet.
Los ejercicios pasan en el servidor de pruebas de El Diario, un periódico digital. Su web, su
gestor de contenidos y su análisis de visitas son imágenes propias (periodico/...), hechas sobre
las oficiales.
El nombre de una imagen
Una imagen se nombra con su repositorio y su etiqueta, separados por dos puntos:
nginx:1.27-alpine es el repositorio nginx con la etiqueta 1.27-alpine (nginx 1.27, sobre
Alpine Linux). Lo completo sería docker.io/library/nginx:1.27-alpine: el registro (Docker Hub,
docker.io), el espacio de las imágenes oficiales (library) y lo demás. Si no pones etiqueta,
Docker pone latest.
docker pull baja una imagen sin arrancar nada:
tecnico@srv-pruebas:~$ docker pull nginx:1.27-alpine 1.27-alpine: Pulling from library/nginx f18232174bc9: Pull complete 61ca4f733c80: Pull complete b464cfdf2a63: Pull complete d7e507024086: Pull complete 81bd8ed7ec67: Pull complete 197eb75867ef: Pull complete 34a64644b756: Pull complete 39c2ddfd6010: Pull complete Digest: sha256:65645c7bb6a0661892a8b03b89d0743208a18dd2f3f17a54ef4b76fb8e2f2a10 Status: Downloaded newer image for nginx:1.27-alpine docker.io/library/nginx:1.27-alpine
Cada línea con un código es una capa (enseguida vemos qué son). El digest es la huella de la imagen: si alguien cambia un solo byte, el digest cambia. Si la vuelves a pedir y ya la tienes al día, no baja nada:
tecnico@srv-pruebas:~$ docker pull nginx:1.27-alpine 1.27-alpine: Pulling from library/nginx Digest: sha256:65645c7bb6a0661892a8b03b89d0743208a18dd2f3f17a54ef4b76fb8e2f2a10 Status: Image is up to date for nginx:1.27-alpine docker.io/library/nginx:1.27-alpine
Si la etiqueta no existe, el registro lo dice; y si el repositorio no existe (o es privado), no te deja bajarlo:
tecnico@srv-pruebas:~$ docker pull nginx:9.99 Error response from daemon: manifest for nginx:9.99 not found: manifest unknown: manifest unknown
Ejercicio
Una versión fija
La hemeroteca del periódico tiene que ir siempre con la misma versión de nginx: la 1.27, la de Alpine (nginx:1.27-alpine). Bájala y arranca con ella el contenedor hemeroteca.
Preparando la máquina…
Las imágenes que tienes: docker images
tecnico@srv-pruebas:~$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE python 3.11-slim d3846bce6e97 5 days ago 133MB python 3.12-slim 414a398990af 5 days ago 128MB nginx 1.27-alpine 6769dc3a703c 17 months ago 48.2MB
- IMAGE ID: su identificador. Dos etiquetas con el mismo id son la misma imagen.
- CREATED: cuándo la hizo quien la publica (no cuándo la bajaste tú).
- SIZE: lo que ocupa descomprimida.
Con un nombre detrás, solo las de ese repositorio (docker images python); con --digests, el
digest de cada una; con -q, solo los ids.
Por dentro: las capas
Una imagen no es un bloque: es una pila de capas, cada una con los cambios de un paso de su construcción (instalar algo, copiar un archivo). Las capas se comparten: si dos imágenes empiezan igual, esa parte se baja y se guarda una sola vez. Mira lo que pasa al bajar la segunda versión de Python:
tecnico@srv-pruebas:~$ docker pull python:3.11-slim 3.11-slim: Pulling from library/python 6b37362b3da7: Already exists f64163c1b799: Pull complete 295f1967d045: Pull complete 48355dfcbf9e: Pull complete Digest: sha256:bab1b7ef4b450c81002278d035eff85ebe394ae94df904f7a3ba14f7e16e487b Status: Downloaded newer image for python:3.11-slim docker.io/library/python:3.11-slim
La primera capa (el Debian de la base) ya estaba: Already exists. docker history enseña los
pasos de una imagen, del último al primero, con lo que ocupa cada uno:
tecnico@srv-pruebas:~$ docker history python:3.12-slim IMAGE CREATED CREATED BY SIZE COMMENT 414a398990af 5 days ago CMD ["python3"] 0B buildkit.dockerfile.v0 <missing> 5 days ago RUN /bin/sh -c set -eux; for src in idle3 p… 0B buildkit.dockerfile.v0 <missing> 5 days ago RUN /bin/sh -c set -eux; savedAptMark="$(a… 36.8MB buildkit.dockerfile.v0 <missing> 5 days ago ENV PYTHON_SHA256=c2c4321961fab0fb999d66e0ce… 0B buildkit.dockerfile.v0 <missing> 5 days ago ENV PYTHON_VERSION=3.12.15 0B buildkit.dockerfile.v0 <missing> 5 days ago ENV GPG_KEY=7169605F62C751356D054A26A821E680… 0B buildkit.dockerfile.v0 <missing> 5 days ago RUN /bin/sh -c set -eux; apt-get update; a… 12MB buildkit.dockerfile.v0 <missing> 5 days ago ENV LANG=C.UTF-8 0B buildkit.dockerfile.v0 <missing> 5 days ago ENV PATH=/usr/local/bin:/usr/local/sbin:/usr… 0B buildkit.dockerfile.v0 <missing> 2 weeks ago # debian.sh --arch 'amd64' out/ 'trixie' '@1… 78.8MB debuerreotype 0.17
Los pasos de 0B no añaden archivos: cambian la configuración (ENV, CMD). <missing> no es un
error: esas capas no tienen un id propio en tu máquina (se bajaron como parte de la imagen). Lo
que trae la imagen también está en docker image inspect, que da su configuración entera en JSON;
con -f eliges un dato:
tecnico@srv-pruebas:~$ docker image inspect -f '{{.Config.Env}}' python:3.12-slim [PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin LANG=C.UTF-8 GPG_KEY=7169605F62C751356D054A26A821E680E5FA6305 PYTHON_VERSION=3.12.15 PYTHON_SHA256=c2c4321961fab0fb999d66e0cecf521c2ab3994c7992873ea99e306c1094fd5a]
Y siempre queda preguntárselo al programa, en un contenedor de usar y tirar:
tecnico@srv-pruebas:~$ docker run --rm python:3.12-slim python --version Python 3.12.15
Ejercicio
¿Qué trae esta imagen?
El equipo de datos pregunta con qué versión de Python viene su imagen, periodico/analitica:1.0. Averígualo y apúntala (solo el número, como 3.10.4) en python.txt, en tu carpeta.
Preparando la máquina…
Etiquetas propias: docker tag
docker tag le pone otro nombre a una imagen que ya tienes. No copia nada: es la misma imagen
con dos etiquetas (fíjate en el IMAGE ID):
tecnico@srv-pruebas:~$ docker tag nginx:1.27-alpine periodico/web:2.3
tecnico@srv-pruebas:~$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE python 3.11-slim d3846bce6e97 5 days ago 133MB python 3.12-slim 414a398990af 5 days ago 128MB nginx 1.27-alpine 6769dc3a703c 17 months ago 48.2MB periodico/web 2.3 6769dc3a703c 17 months ago 48.2MB
Es lo que hacen los equipos para ordenarse: las versiones de lo suyo (periodico/web:2.3,
2.4…) y etiquetas con significado, como estable o produccion, que se mueven a la versión
que toque. Una etiqueta solo puede estar en una imagen: si la pones en otra, se va de la primera.
Ejercicio
Etiquetas propias
La versión 2.3 de la web del periódico es la buena. Ponle también la etiqueta estable (periodico/web:estable), para que todos sepan cuál usar.
Preparando la máquina…
Borrar imágenes: docker rmi
docker rmi (o docker image rm) borra una etiqueta. Si a la imagen le quedan otras, solo se
quita esa (Untagged); si era la última, se borra la imagen y las capas que nadie más usa
(Deleted):
tecnico@srv-pruebas:~$ docker rmi periodico/web:2.3 Untagged: periodico/web:2.3
Una imagen que usa algún contenedor no se borra, aunque el contenedor esté parado:
tecnico@srv-pruebas:~$ docker rmi nginx:1.26-alpine Error response from daemon: conflict: unable to remove repository reference "nginx:1.26-alpine" (must force) - container 9328e219070e is using its referenced image 42ce3d3585d4
Primero se borra el contenedor (docker rm) y luego la imagen:
tecnico@srv-pruebas:~$ docker rmi nginx:1.26-alpine Untagged: nginx:1.26-alpine Untagged: nginx@sha256:1eadbb07820339e8bbfed18c771691970baee292ec4ab2558f1453d26153e22d Deleted: sha256:42ce3d3585d47518cb0c1ef4bd3d8a65c1edfcbbfd423eda86990a83f378b111 Deleted: sha256:80b3029b6869e6a8366b719476de8cf8d375befde2d48ab75b0797d929a46da3 …
Ejercicio
No me deja borrarla
Sobra la versión vieja del gestor de contenidos, periodico/cms:3.0. Pero docker rmi da error: hay un contenedor parado que la usa (cms-viejo). Bórralos los dos.
Preparando la máquina…
Las colgadas y la limpieza
Cuando una etiqueta pasa a otra imagen (al bajar una versión nueva de latest, al cargar una con
el mismo nombre), la vieja se queda sin etiqueta: es una imagen colgada (dangling), y sale
como <none>:
tecnico@srv-pruebas:~$ docker images -f dangling=true REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> 83b2b6703a62 12 months ago 7.39MB <none> <none> 42ce3d3585d4 20 months ago 47.2MB
Nadie las puede pedir por su nombre: ocupan disco sin servir para nada. docker image prune las
borra (pregunta antes; con -f, sin preguntar):
tecnico@srv-pruebas:~$ docker image prune -f Deleted Images: deleted: sha256:83b2b6703a620bf2e001ab57f7adc414d891787b3c59859b1b62909e48dd2242 deleted: sha256:0b44b2151d78267ab6f2c76208c3be18688f49b2b0afd6852a9533f2cce121c5 deleted: sha256:42ce3d3585d47518cb0c1ef4bd3d8a65c1edfcbbfd423eda86990a83f378b111 … Total reclaimed space: 54.58MB
docker system df dice cuánto ocupa todo lo de Docker, y cuánto se podría liberar. Cuenta cada
capa una vez, aunque la compartan varias imágenes:
tecnico@srv-pruebas:~$ docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 4 0 56.02MB 56.02MB (100%) Containers 0 0 0B 0B Local Volumes 0 0 0B 0B Build Cache 0 0 0B 0B
Ejercicio
Imágenes colgadas
El disco del servidor de pruebas se está llenando. Hay imágenes colgadas (<none>, sin etiqueta): bórralas, y solo esas. Las que tienen etiqueta se usan, aunque ahora no haya ningún contenedor con ellas.
Preparando la máquina…
Sin internet: docker save y docker load
Muchos servidores no salen a internet, por seguridad. Ahí docker pull no llega al registro:
tecnico@srv-diario:~$ docker pull nginx:1.27-alpine Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
Las imágenes viajan entonces en un archivo. En una máquina que sí la tiene, docker save guarda la
imagen (con todas sus capas y su etiqueta) en un .tar:
tecnico@srv-pruebas:~$ docker save -o web.tar nginx:1.27-alpine
Se copia el archivo al otro servidor (con scp, un disco…) y allí docker load la carga, capa a
capa, con su etiqueta:
tecnico@srv-diario:~$ docker load -i web.tar 08000c18d16d: Loading layer 8.121MB/8.121MB d71eae0084c1: Loading layer 4.511MB/4.511MB c56f134d3805: Loading layer 3.584kB/3.584kB e244aa659f61: Loading layer 4.608kB/4.608kB b8d7d1d22634: Loading layer 2.56kB/2.56kB 811a4dbbf4a5: Loading layer 5.12kB/5.12kB 947e805a4ac7: Loading layer 7.168kB/7.168kB 0d853d50b128: Loading layer 36.98MB/36.98MB Loaded image: nginx:1.27-alpine
Es la misma imagen, con el mismo id. Lo único que no lleva es el digest del registro (no vino de él).
Ejercicio
Llega en un archivo
Este servidor no sale a internet: docker pull no sirve. El proveedor ha dejado la versión nueva del gestor de contenidos en /srv/entregas/cms-3.1.tar. Cárgala en Docker.
Preparando la máquina…
Los registros
Docker Hub es el registro de serie, pero no el único: las empresas tienen los suyos (el de GitHub, el de su nube, uno propio). En Docker Hub hay dos clases de repositorios:
- Los oficiales (
nginx,python,postgres): sin nombre delante, mantenidos por Docker y por quien hace el programa. - Los de usuarios y empresas (
ana/app,periodico/web): con su nombre delante. Pueden ser públicos o privados.
Para subir una imagen (docker push) hay que entrar antes en el registro (docker login) y tener
permiso en ese repositorio; si no, el registro lo rechaza (denied: requested access to the resource is denied). Las imágenes propias de El Diario no están en ningún registro público: solo
en sus servidores.
Resumen
| Orden | Para qué |
|---|---|
docker pull repo:etiqueta |
bajar una imagen (sin etiqueta, latest) |
docker images |
las que tienes (-f dangling=true: las colgadas) |
docker history imagen |
sus capas, con lo que ocupa cada paso |
docker image inspect imagen |
su configuración (-f para un dato) |
docker tag origen destino |
ponerle otra etiqueta (es la misma imagen) |
docker rmi imagen |
quitar una etiqueta, y la imagen si era la última |
docker image prune |
borrar las colgadas (-a: todas las que no se usan) |
docker system df |
lo que ocupa Docker |
docker save -o x.tar imagen / docker load -i x.tar |
llevar imágenes en un archivo |