Ciclo de vida de nuestras aplicaciones en docker

"Build, Ship and Run. Any application, Anywhere"

Alberto Molina Coballes, José Luis Rodríguez Rodríguez and José Domingo Muñoz Rodríguez

Cloud Computing in European schools. Project: 2017-1-ES01-KA202-038471

Theme by: reveal.js

Docker

  • Virtualización ligera: aprovechamos mejor el hardware y únicamente necesitamos el sistema de archivos mínimo para que funcionen los servicios.
  • Los contenedores son autosuficientes, sólo necesitamos una imagen para crear contenedores.
  • Una imagen Docker podríamos entenderla como "un Sistema Operativo con aplicaciones instaladas".
  • El proyecto nos ofrece es un repositorio de imágenes: Registry Docker Hub que nos permite gestionar imágenes.
  • Un contenedor suele ejecutar un sólo servicio. Una aplicación suele necesitar la ejecución de varios contenedores que trabajan juntos.

Componentes de Docker

  • Docker Engine: Es un demonio que corre sobre cualquier distribución de Linux y que expone una API externa para la gestión de imágenes y contenedores.
  • Docker Client: Es el cliente de línea de comandos (CLI) que nos permite gestionar el Docker Engine. El cliente docker se puede configurar para trabajar con con un Docker Engine local o remoto.
  • Docker Registry: La finalidad de este componente es almacenar las imágenes generadas por el Docker Engine. Nos permite distribuir nuestras imágenes. Podemos instalar un registro privado, o hacer uso de uno público como Docker Hub.

Ciclo de vida de nuestras aplicaciones en docker

Paso 1:Desarrollo de nuestra aplicación

En este ejemplo vamos a desarrollar una página web que va a ser servida por un servidor web que se ejecutará en un contenedor Docker.

Por lo tanto lo primero que debemos hacer es crear nuestra página web:


  $ cd public_html
  echo "<h1>Prueba</h1>" > index.html
  

Paso 2: Creación de la imagen Docker

Utilizando un fichero Dockerfile definimos como vamos a crear nuestra imagen:

  • Qué imagen base vamos a utilizar.
  • Qué paquetes vamos a instalar
  • Donde copiamos nuestro código fuente (página web)
  • Indicamos el servicio que va a ejecutar el contenedor (servidor apache)

Paso 2: Creación de la imagen Docker

Dockerfile


    FROM debian
    RUN apt-get update -y && apt-get install -y \
        apache2 \
        && apt-get clean && rm -rf /var/lib/apt/lists/*
    COPY ./public_html /var/www/html/
    ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
  

Podríamos usar una imagen base con apache2 ya instalado:


    FROM httpd:2.4
    COPY ./public_html /usr/local/apache2/htdocs/
  

Paso 2: Creación de la imagen Docker

Creamos nuestra imagen, desde el directorio donde tenemos el Dockerfile, ejecutamos:


    $ docker build -t josedom24/aplicacionweb:v1 .
    Sending build context to Docker daemon  3.584kB
    Step 1/4 : FROM debian
     ---> be2868bebaba
    Step 2/4 : RUN apt-get update -y && apt-get install -y apache2 & apt-get clean && rm -rf /var/lib/apt/lists/*
     ...
    Successfully built 518871c9fc0c
    Successfully tagged josedom24/aplicacionweb:v1
  

Paso 2: Creación de la imagen Docker

Podemos comprobar que en nuestro entorno local tenemos la imagen que acabamos de crear:


    $ docker image ls
    REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
    josedom24/aplicacionweb   v1                  b2e0df215145        7 seconds ago       204MB
    debian                    latest              be2868bebaba        10 days ago         101MB
  

Paso 3: Probamos nuestra aplicación en el entorno de desarrollo

Creamos un contenedor en nuestro entorno de desarrollo:


  $ docker run --name aplweb -d -p 80:80 josedom24/aplicacionweb:v1
  fbdd73529e2bb2d9ee9c6415031513741688e6d38509572251f5b624ed7dc23f
  
  $ docker container ls
  CONTAINER ID        IMAGE                        COMMAND                    CREATED             STATUS              PORTS                NAMES
  fbdd73529e2b        josedom24/aplicacionweb:v1   "/usr/sbin/apache2ct…"   6 seconds ago       Up 5 seconds        0.0.0.0:80->80/tcp   aplweb
  

Paso 3: Probamos nuestra aplicación en el entorno de desarrollo

Probamos nuestra aplicación:

Paso 4: Distribuimos nuestra imagen

Vamos a subir nuestra imagen al registro Docker Hub:


    $ docker login
    ...
    $ docker push josedom24/aplicacionweb:v1
    The push refers to repository [docker.io/josedom24/aplicacionweb]
    ac126159496f: Pushed 
    cc15ec5f0c43: Pushed 
    ...
  

Comprobamos que está subida al repositorio:


    $ docker search josedom24/aplicacionweb
    NAME                     DESCRIPTION...
    josedom24/aplicacionweb:v1   
  
Paso 5:Implantación de la aplicación

En el el entorno de producción, bajamos la imagen de Docker Hub y creamos el contenedor:


    $ docker pull josedom24/aplicacionweb:v1
    v1: Pulling from josedom24/aplicacionweb
    9a029d5ca5bb: Pull complete 
    ...
    $ docker run --name aplweb_prod -d -p 80:80 josedom24/aplicacionweb:v1
  

Paso 6: Modificación de la aplicación

Al modificar el código de la aplicación tenemos que generar una nueva imagen.


    $ cd public_html
    echo "<h1>Prueba 2</h1>" > index.html
    $ docker build -t josedom24/aplicacionweb:v2 .
    

Podemos probarla en el entorno de desarrollo, eliminando el contenedor anterior:


    $ doker container rm -f aplweb
    $ docker run --name aplweb2 -d -p 80:80 josedom24/aplicacionweb:v2
  

Paso 6: Modificación de la aplicación

Subimos la nueva versión de la aplicación. En el entorno de producción: bajamos la nueva versión, eliminamos el contenedor de la versión antigua y creamos un nuevo contenedor con la nueva imagen:


    $ docker push josedom24/aplicacionweb:v1
    ...
  

En producción:


    $ docker pull josedom24/aplicacionweb:v2
    ...
    $ doker container rm -f aplweb_prod
    $ docker run --name aplweb2_prod -d -p 80:80 josedom24/aplicacionweb:v2
  

Construir aplicaciones sin estado(Stateless)

  • Una aplicación sin estado(Stateless) es aquella que no guarda ninguna información. Se ejecuta, hace su trabajo y se elimina.
  • Una aplicación con estado (Stateful) es aquella que necesita guardar información para su funcionamiento.
  • Si creo una aplicación desde 0 debería construirla sin estado
  • La mayoría de las aplicaciones actuales son Stateful.

Uso de volúmenes persistentes

  • La información que se guarda en un contenedor no es persistente.
  • Los contenedores que implementan aplicaciones Stateful deben guardar los datos en un medio de almacenamiento persistente. Desacoplamos la aplicación de los datos.
  • Con docker podemos gestionar volúmenes de datos, que nos permiten guardar la información en el host (almacenamiento persistente).

Ventajas de guardar los datos en almacenamiento persistente

  • Los contenedores son más livianos.
  • Puedo tener datos distintos en los distintos entornos de desarrollo.
  • Si un contenedor falla, no se pierde información sólo tengo que crear un nuevo contenedor.
  • La modificación de los datos de la aplicación no conlleva la construcción de una nueva imagen.

Ejemplo de almacenamiento persistente

Contenedor con mysql. guardamos la información de la base de datos en un volumen persistente:


    $ docker run --name some-mysql \ 
                 -v /opt/mysql:/var/lib/mysql \
                 -e MYSQL_ROOT_PASSWORD=asdasd \
                 -d mysql
  
Comprobamos que se ha guardado la BD en el host:

    /opt/mysql$ ls
    ibdata1  ib_logfile0  ib_logfile1  ibtmp1  #innodb_temp  mysql  mysql.ibd  undo_001  undo_002
  

Ejemplo de almacenamiento persistente

Creamos una base de datos:

  $ docker exec -it some-mysql bash
  root@75544a024f9b:/# mysql -u root -p -h localhost
  ...
  create database dbtest;
  Query OK, 1 row affected (0.07 sec)
  
Nuestro contenedor falla!!!

  $ docker container rm -f some-mysql 

Ejemplo de almacenamiento persistente

Podemos crear otro contenedor y comprobar como sigue existiendo la BD:

    $ docker run --name some-mysql2 \
                -v /opt/mysql:/var/lib/mysql \
                -e MYSQL_ROOT_PASSWORD=asdasd \
                -d mysql
    
    $ docker exec -it some-mysql2 bash
    root@878f77d80fcf:/# mysql -u root -p -h localhost
    ...
    show databases;
    ...
    | dbtest             |
    ...