Revisando la gestión del espacio que hace Docker con sus imágenes, contenedores y ficheros.


Docker puede utilizar ficheros “Dockerfile” para generar imágenes, en base a otras imágenes de internet y aplicándole cambios.

Mientras que el fichero “Dockerfile” es un simple texto pequeño, la imágen generada puede contener megas/gigas de información.

Usaremos imágenes bajadas de internet a las cuales le aplicaremos cambios y construimos nuestras imágenes locales, las que serán un poco mas grandes que las de Internet.

Nuestras imágenes locales se pueden subir al hub de docker en Internet y conservarlas para uso privado o público.

Ese servicio nos servirá para tener un backup de una imágen que hayamos preparado con todo configurado según necesitemos.

Al subir la imágen a internet, podemos borrarla de nuestro equipo real y la próxima ves que la necesitemos la bajamos de internet, sin embargo, si esa imágen la usaremos para generar un contenedor no la podremos borrar de nuestro equipo local, porque borraría los contenedores que la usen.

Las imágenes subidas a internet, se pueden usar de otros equipos sin necesidad de regenerarla y contruir nuevos contenedores.

Comencemos bajando una imágen Ubuntu versión 17.10

# docker pull ubuntu:17.10
17.10: Pulling from library/ubuntu
d26cfb4142fa: Pull complete 
64e695836438: Pull complete 
23612a50167e: Pull complete 
0f87853aa05b: Pull complete 
196b8aba5fb6: Pull complete 
Digest: sha256:7ec155ad0aea2bdb0cc3757fc227ba019870034ab05c3bba269d1447373d0981
Status: Downloaded newer image for ubuntu:17.10

Veremos en nuestro disco que la imágen recién bajada de Ubuntu 17.10 ocupa 93.8 MB

ubuntu                  17.10               579580072367        10 days ago         93.8MB

Ahora creamos un fichero “Dockerfile” para generar una nuestra, con ssh activado.

# vi Dockerfile
FROM ubuntu:17.10

RUN apt-get update && apt-get install -y openssh-server
RUN mkdir /var/run/sshd
RUN echo 'root:screencast' | chpasswd
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd

ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile

EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]

Generamos nuestra imágen “ubussh” local.

# docker build -t ubussh .

Tenemos dos imágenes, la oficial Ubuntu 17.10 con las aplicaciones básicas y una con el SSH preparado y configurado.

Vemos la diferencia de megas (93.8 o 204 MB, 110 MB) por haber instalado y configurado openssh.

# docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
ubussh                  latest              e3ea86d084a3        4 seconds ago       204MB
ubuntu                  17.10               579580072367        10 days ago         93.8MB

Crearemos un contenedor usando la imágen con SSH (ubussh). Y dejamos abierta esa sesión. ce7aea05b590

# docker run -it ubussh /bin/bash
root@ce7aea05b590:/# 

Verificar el espacio usado hasta ahora por ese contenedor. ¿ Cómo se cual contenedor es ?

# ls /var/lib/docker/containers

Nos mostrará todos los contenedores que tenemos creados en nuestro equipo real. El último de ellos, recién creado es el que acabamos de crear, pero lo verificamos pidiendo el nombre que tiene ese contenedor (fichero hostname en Linux) y lo comparamos con el hash/nombre del servidor que tenemos corriendo. ce7aea05b590

# cat /var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc/hostname
ce7aea05b590

El espacio usado hasta ahora por este contenedor es de 36kb:

# du -h /var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc
4,0K	/var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc/checkpoints
0	/var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc/shm
36K	/var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc

Sin embargo, la imágen de usussh ocupaba 204 MB.


¿ Por qué esa diferencia ?

Docker mantiene localmente la imágen y mientras no la borremos podremos tener creados contenedores que la usen, de una manera inteligente, los ficheros existentes en esa imágen pueden ser usados por todos los contenedores que estén basados en ella, sin necesidad de copiar “N” veces los mismos ficheros.

Como ejemplo: el “bash” ocupa unos 800KB, si tenemos 5 contenedores basados en la misma imágen, nos evitamos tener 5 copias de 800KB en disco.

Ahora agregamos un fichero random de 1KB en el contenedor.

# head -c 1024 </dev/urandom > /test.txt

Al ver el espacio ocupado no veremos cambios.

# du -h /var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc
4,0K	/var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc/checkpoints
4,0K	/var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc/shm
60K	/var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc

(con el contenedor parado)

Al poner en funcionamiento el contenedor y volver a pedir el espacio usado, ahora solo consumimos 56KB.

# du -h /var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc/
4,0K	/var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc/checkpoints
0	/var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc/shm
56K	/var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc/

Curiosamente, un contenedor parado consume 60KB, pero si lo arrancamos ocupa 56KB. Lo arrancamos y nos conectamos a él.

Dentro del contenedor creamos ahora un fichero de 100KB.

# head -c 100000 </dev/urandom > /test.txt
-rw-r--r--   1 root root 1000000 Oct 30 08:42 test2.txt

El contenedor parado ocupa 60kb, aunque hemos creado un fichero de 100KB.

# du /var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc/ -h
4,0K	/var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc/checkpoints
4,0K	/var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc/shm
60K	/var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc/

¿ Dónde está el fichero que acabamos de crear (100kb) ? Docker tiene una gestión muy especial de los ficheros/objetos de cada contenedor. En este caso nuestros cambios/agregados al contenedor ce7aea05b590, están guardados en un “overlay” que también tiene otro nombre HASH.

En la carpeta B3BZHM4JWK2DIY3KVNGSXLSM26 podemos ver que otros archivos han sido cambiados a partir de la creación del contenedor.

# ll /var/lib/docker/overlay2/l/B3BZHM4JWK2DIY3KVNGSXLSM26/
total 1000
11387137 drwxr-xr-x 5 root root    4096 oct 30 09:40 .
11387136 drwx------ 5 root root    4096 oct 30 09:18 ..
11387142 drwx------ 2 root root    4096 oct 30 09:25 root
11292268 -rw-r--r-- 1 root root 1000000 oct 30 09:42 test2.txt
11387143 drwxrwxrwt 2 root root    4096 oct 30 09:34 tmp
11387144 drwxr-xr-x 3 root root    4096 oct 19 10:15 var

La carpeta “/var/lib/docker/overlay2/” de nuestro equipo real, contendrá los cambios realizados en ese contenedor ce7aea05b590, le fué asignado un espacio llamado “B3BZHM4JWK2DIY3KVNGSXLSM26”.

Ahora actualizamos el S.O. Ubuntu de ese contenedor.

# apt update

Y vemos la carpeta /var/lib/apt/lists donde el APP apt guarda la lista de paquetes de un repositorio. Los cambios en determinadas carpetas se registran en los ficheros dentro de los “overlays”

# ll /var/lib/docker/overlay2/l/B3BZHM4JWK2DIY3KVNGSXLSM26/var/lib/apt/lists/
total 456
11387147 drwxr-xr-x 3 root root   4096 oct 30 09:15 .
11387146 drwxr-xr-x 3 root root   4096 oct 30 09:15 ..
11292274 -rw-r--r-- 1 root root  65498 abr 21  2017 archive.ubuntu.com_ubuntu_dists_artful-backports_InRelease
11292272 -rw-r--r-- 1 root root 236651 oct 19 14:56 archive.ubuntu.com_ubuntu_dists_artful_InRelease
11292273 -rw-r--r-- 1 root root  76727 oct 30 08:40 archive.ubuntu.com_ubuntu_dists_artful-updates_InRelease
11292270 -rw-r----- 1 root root      0 oct 30 09:15 lock
11387148 drwx------ 2  100 root   4096 oct 30 09:34 partial
11292271 -rw-r--r-- 1 root root  70284 oct 30 08:40 security.ubuntu.com_ubuntu_dists_artful-security_InRelease

¿ Qué pasará si ahora cambiamos el nombre del contenedor ?

Dentro del contenedor corriendo (usussh1) pisamos el fichero “hostname”.

# echo "ce7aea05b590.tst" > /etc/hostname 

El cambio quedó registrado en el fichero del contenedor y vivirá mientras no apaguemos ese contenedor.

# cat /var/lib/docker/containers/ce7aea05b590455bf6108fe464c01a0d41f247545f90db4330b960b0c3410fcc/hostname 
ce7aea05b590.tst

Sin embargo, si paro y arranco ese contenedor, el fichero vuelve a tener el contenido original.

# docker stop  ubussh1
# docker start ubussh1
# docker exec -it ubussh1 /bin/bash
root@ce7aea05b590:/# cat /etc/hostname 
ce7aea05b590

Existen varios tipos de carpetas y ficheros usados por Docker. Linux/Unix se basan en el concepto “todo es un fichero”.

“Docker” gestiona los espacios de dos maneras distintas, ficheros que construirá al arrancar el contenedor (guardados en “containers”) y ficheros que fueron agregados a un contenedor luego, que son guardados en “overlays”.

En otro post veremos los volúmenes y para que sirven.



Si te interesó el artículo escríbenos a DockerTipsHelp@gmail.com.