Docker: Imágenes y vida de los contenedores
30/03/2017 -
Al iniciarse en Docker suelen surgir dudas sobre la volatilidad del contenedor, es decir, su tiempo de vida.
Dicha volatilidad depende en gran medida de la utilidad que le queramos asignar al contenedor. Por ejemplo, si lo utilizamos para hacer una prueba de una configuración tendremos que levantar el Docker desde cero hasta que demos con la configuración buena, o podamos grabarla y seguir trabajando sobre él. Además, una de las utilidades de Docker es que todo está en un script y no tenemos que ir recordando los pasos previos, por lo tanto, se recomienda ir pasando los cambios a script.
Para este ejemplo vamos a crear un servicio en el Service bus de Oracle. Para hacer la prueba nos descargaremos una imagen del Service Bus 11.1.1.7 como ya indicamos en la entrada anterior del blog.
docker pull avanttic/osb1117
Si visualizamos las imágenes que tenemos, aparecerá la recién descargada.
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
avanttic/osb1117 latest e558b012f4a5 3 minutes ago 10.1 GB
Aquí es donde tenemos que diferenciar entre imagen y contenedor. Una imagen es la base a partir de la cual se ejecutan los contenedores. Es decir, cada vez que hacemos un run sobre la imagen nos levanta un contenedor con esa configuración. Si modificamos el contenedor, lo paramos y arrancamos otra vez la imagen, los datos no estarán, porque arrancará un nuevo contenedor.
Por ejemplo, arrancamos nuestra imagen de Service Bus:
# docker run -ti avanttic/osb1117
Para mirar los contenedores que tenemos se usa el comando:
# docker ps -a
CONTAINER ID IMAGE CREATED STATUS
ac43456e2203 avanttic/osb1117 4 minutes ago Up 4 minutes
Sobre ella, creamos un proyecto que moverá mensajes entre dos colas:
Ahora paramos el contenedor. Disponemos de una imagen y un contenedor, y si volvemos a ejecutar la imagen, iniciará un nuevo contenedor desde cero y no tendremos el servicio creado.
Ejecutamos un nuevo contenedor a partir de la imagen:
# docker run -ti avanttic/osb1117
Ahora tenemos dos contenedores:
# docker ps -a
CONTAINER ID IMAGE CREATED STATUS
672cd54d06f0 avanttic/osb1117 4 seconds ago Up 3 seconds
ac43456e2203 avanttic/osb1117 13 minutes ago Exited (130) 6 seconds ago
Vemos que hay un contenedor parado (Exited) y otro arrancado (Up). Si entramos en el Service Bus veremos que el servicio no está, pero podemos arrancar el contenedor antiguo par exportarlo o comparar con el contenedor nuevo. Para arrancarlo hacemos:
# docker start -i ac43456e2203
La diferencia entre run y start, es que run nos arranca un nuevo contenedor a partir de una imagen con su configuración base y start nos arranca un contenedor que ya existía con cambios.
Si vamos a usar mucho un contenedor, podríamos asignarle un nombre para que no sea tan engorroso como con los ids. Docker de por sí, pone nombres aleatorios bastante frikies compuestos de un adjetivo y científicos famosos, como heuristic_archimedes o hungry_montalcini. Ahora vemos que los dos contenedores están levantados:
# docker ps -a
CONTAINER ID IMAGE CREATED STATUS
672cd54d06f0 avanttic/osb1117 4 seconds ago Up 3 seconds
ac43456e2203 avanttic/osb1117 20 minutes ago Up About a minute
Siempre digo que no hay una forma correcta de trabajar con Docker, sino que lo mejor es conocer todas las posibilidades que Docker ofrece y utilizar aquella que más se adapte a nuestras necesidades.
Si queremos guardar de forma permanente el servicio que hemos hecho en la imagen, para que cuando la levantemos tenga el servicio configurado, podemos hacer un commit del contenedor sobre la imagen. Podemos añadir varias etiquetas, como comentarios y un tag. Ponemos el id del container ac43456e2203 y el nombre de la imagen avanttic/osb1117:
# docker commit -m “Servicio mover colas” ac43456e2203 avanttic/osb1117:v2
Si miramos las imágenes que tenemos, vemos que se ha añadido la nueva:
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
avanttic/osb1117 v2 e35eeec8f8b6 About a minute ago 10.1 GB
avanttic/osb1117 latest e558b012f4a5 35 minutes ago 10.1 GB
Ahora cada vez que arranquemos la v2 vendrá con el servicio que hemos creado incluido. Si no hubiéramos puesto tag hubiera sobrescrito el latest. Antes he comentado que no hay una forma correcta de trabajar con Docker, pero si existen buenas prácticas, como no usar siempre el tag latest o no realizar este tipo de commits. Ya dijimos en el post anterior que Docker no aportaba tecnología nueva, pero sí una manera más estructurada de trabajar. Lo ideal sería escriptar este cambio, meterlo en el Dockerfile y que la imagen se generase con el cambio. Si hacemos un commit, Docker guarda el binario ya compilado y no permite modificarlo.
Para ello exportamos el proyecto desde la consola del service BUS y con unos simples comandos de WLST importamos el servicio:
OSBConfigurationMBean.uploadJarFile
OSBConfigurationMBean.importUploaded
Volvemos a hacer el build con la nueva etiqueta:
# docker built -t avanttic:osb1117:v2 Dockerfile
Ahora tendríamos las dos imágenes anteriores, pero con la diferencia que disponemos del código fuente del cambio; y si en vez de ése servicio, deseamos importar otro, solo tendríamos que cambiar el fichero. Por supuesto, lo ideal es que todos estos cambios los pongamos en github para que genere las imágenes automáticamente a partir del código.
En resumen, la vida de un contenedor es la que le queramos dar, pero si va a ser muy larga, mejor pasarla al Dockerfile y crear la imagen con los cambios.