miércoles, 27 de julio de 2016

CREANDO UNA APLICACIÓN MULTICONTENEDOR CON DOCKER COMPOSE

Para utilizar Docker compose, creamos un directorio y creamos un fichero con el nombre docker-compose.yml que es donde introducimos la receta de lo que debe realizar.

$ mkdir composewp
$ cd composewp/
composewp $ nano docker-compose.yml

En nuestro caso nuestro fichero quedaría de esta forma:

wp:
  image: wordpress
  links:
    - mysql:mysql
  ports:
    - "80"
mysql:
  image: mysql
  environment:
    - MYSQL_ROOT_PASSWORD=miclaverootmysql

La receta es muy sencilla, su funcionamiento sería similar al ejemplo del apartado anterior, estamos creando un contenedor en base a la imagen de wordpress donde le especificamos que esté vinculado al contenedor mysql que definimos más adelante, podemos comprobar que no exponemos ningún puerto del contenedor mysql y definimos la variable de entorno que corresponde a la contraseña del usuario root del servicio mysql. Vamos a ver si todo esto funciona. Primero simplemente vamos a ejecutar la composición mediante el parámetro up y el parámetro -d que significa que se debe ejecutar como servicio.

$ docker-compose up -d
Creating composewp_mysql_1
Creating composewp_wp_1

Vemos que ha creado dos contenedores correctamente, ahora mediante el parámetro ps vamos a ver si están en ejecución.

$ docker-compose ps
      Name                     Command               State           Ports        
----------------------------------------------------------------------------------
composewp_mysql_1   /entrypoint.sh mysqld            Up      3306/tcp             
composewp_wp_1      /entrypoint.sh apache2-for ...   Up      0.0.0.0:32768->80/tcp

Como podemos comprobar, ha iniciado correctamente los dos contenedores, no obstante vamos a ver que nos dice el demonio docker mediante el comando docker ps.

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES
77061ae8c289        wordpress           "/entrypoint.sh apach"   18 seconds ago      Up 16 seconds       0.0.0.0:32768->80/tcp   composewp_wp_1
c22cd4fa76d8        mysql               "/entrypoint.sh mysql"   18 seconds ago      Up 17 seconds       3306/tcp                composewp_mysql_1

Según esto, todo parece funcionar correctamente, aún así nos vamos a ir a nuestro navegador a comprobar si realmente se ha iniciado. Como me indica que se ha expuesto el puerto 80 de wordpress al puerto 32768 del anfitrión, ése será el puerto que debo comprobar. Y como podemos ver en la figura, todo funciona perfectamente.


Fuente: Elaboración propia

Ahora vamos a realizar otra prueba con docker compose, vamos a intentar manejar 3 servidores wordpress vinculados al mismo servidor mysql, lo cual resulta francamente sencillo con docker compose, mediante el parámetro scale, le especificamos cual de los contenedores queremos escalar y en qué cantidad.

$ docker-compose scale wp=3
Creating and starting 2 ... done
Creating and starting 3 ... done

En nuestro ejemplo le hemos dicho que queremos 3 contenedores funcionando de wordpress y como ya teníamos uno en ejecución, nos ha ejecutado 2 más, ahora vamos a comprobar que todo funciona perfectamente mediante el parámetro ps.

$ docker-compose ps
      Name                     Command               State           Ports        
----------------------------------------------------------------------------------
composewp_mysql_1   /entrypoint.sh mysqld            Up      3306/tcp             
composewp_wp_1      /entrypoint.sh apache2-for ...   Up      0.0.0.0:32768->80/tcp
composewp_wp_2      /entrypoint.sh apache2-for ...   Up      0.0.0.0:32769->80/tcp
composewp_wp_3      /entrypoint.sh apache2-for ...   Up      0.0.0.0:32770->80/tcp


Y podemos ver como tenemos funcionando los 3 contenedores en 3 puertos distintos.

martes, 26 de julio de 2016

CONECTANDO CONTENEDORES DOCKER A TRAVÉS DE ENLACES

Este enfoque para conectar contenedores se basa en una abstracción que Docker llamada link (enlaces). Éste era el método preferido para conectar los contenedores antes de Docker 1.9 y sólo se recomienda si estamos utilizando una versión anterior de Docker. La vinculación de un contenedor a otro es un proceso simple que implica nombres de contenedor. Vamos a comenzar por crear un contenedor.

$ docker run -d --name mysql2 -e MYSQL_ROOT_PASSWORD=miclave123 mysql

Podíamos haber utilizado el contenedor creado anteriormente o si usamos el mismo nombre, debemos recordar que el nombre de contenedor debe ser único y si queremos crearlo con el mismo nombre, debemos borrarlo primero con el comando “docker rm”.

Hemos ejecutado una instancia de un nuevo contenedor mysql. Lo hemos nombrado mysql2 utilizando el parámetro –name. También podemos observar que no hemos publicado ningún puerto en el contenedor, vamos a ver enseguida el por qué.

 Vamos a ejecutar un contenedor con wordpress en él y enlazamos nuestro nuevo contenedor mysql2.

$ docker run --name wordpress1 -p 8081:80 --link mysql2:mysql -ti wordpress /bin/bash
root@ba2cf804e098:/var/www/html#

Este comando hace muchas cosas, estamos publicando el puerto 8081 utilizando el parámetro –p para que podemos acceder a nuestra aplicación web. Hemos utilizado un nuevo parámetro denominado –link. El parámetro –link crea un vínculo cliente-servicio entre dos contenedores. El parámetro tiene dos argumentos: el nombre del contenedor de enlace y un alias para el enlace. En este caso, estamos creando una relación con el cliente, nuestro contenedor wordpress1 es el cliente, con el contenedor mysql2, que es el “servicio”. También hemos añadido un alias para ese “servicio” de mysql. El alias nos permite acceder a la información expuesta constantemente sin necesidad de preocuparse por el nombre del contenedor subyacente. El enlace le da al contenedor de servicios la capacidad de comunicarse con el contenedor cliente y comparte algunos detalles de la conexión con ella, para ayudarle a configurar las aplicaciones para hacer uso de la conexión. También recibimos un beneficio relacionado con la seguridad de esta vinculación. Cuando lanzamos nuestro contenedor mysql2 no publicamos el puerto de mysql con el parámetro –p. No lo necesitamos, al vincular los contenedores juntos, estamos permitiendo que el contenedor de cliente pueda comunicarse con cualquier puerto publicado sobre el contenedor de servicios. Pero aún mejor, sólo los contenedores vinculados explícitamente a este contenedor que utilicen el parámetro –link pueden conectarse a este puerto. Teniendo en cuenta que el puerto no se publica en el host local, ahora tenemos un modelo de seguridad muy fuerte para limitar la superficie de ataque y la exposición a la red de una aplicación en contenedores.

Si nosotros lo deseamos por razones de seguridad, por ejemplo, podemos forzar a Docker para permitir sólo la comunicación entre los contenedores si existe un enlace. Para ello, se puede iniciar el demonio Docker con el parámetro --icc=false. Esto desactiva las comunicaciones entre todos los contenedores, a menos que exista una relación. Podríamos enlazar varios contenedores juntos. Por ejemplo, si se quiere utilizar nuestra instancia mysql2 para múltiples aplicaciones web, podríamos vincular cada contenedor de aplicaciones web para el mismo contenedor mysql.

También podemos especificar el parámetro --link varias veces para enlazar a varios contenedores. Docker no puede vincular entre contenedores en hosts Docker separados. Para la creación de redes multi-host, debemos utilizar las redes Docker o Docker Networking.

Por último, en lugar de ejecutar el contenedor como un demonio, hemos lanzado una sesión interactiva. Hemos hecho esto para poder ver como nuestros contenedores están vinculados. Los vínculos de Docker pueblan información sobre el contenedor de servicios en dos lugares:
·         En el archivo /etc/hosts
·         En las variables de entorno que contienen información de conexión.

Vamos a ver el archivo host:

root@ba2cf804e098:/var/www/html# cat /etc/hosts
172.17.0.4  ba2cf804e098
127.0.0.1   localhost
.  .  .
172.17.0.2  mysql 7b8bff74363c mysql2

Podemos ver que tenemos algunas entradas útiles aquí. La primera de ellas, es la dirección de nuestra propia IP de contenedor y el nombre de host (en este caso el ID corto de contenedor). La segunda entrada que ha sido generada por el parámetro --link, es la dirección IP, el nombre y la identificación del contenedor mysql, con el nombre de host adicional especificado como alias en el enlace. Vamos a tratar de hacer ping a ese contenedor ahora.

root@ba2cf804e098:/var/www/html# ping mysql
PING mysql (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: icmp_seq=0 ttl=64 time=0.119 ms
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.147 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.147 ms
.  .  .

El nombre de host de contenedor no tiene por que ser el ID corto, podríamos utilizar el parámetro –h o --hostname con el comando docker run para especificar un nombre de host especifico para el contenedor.

También podemos agregar entradas adicionales al fichero /etc/hosts cuando ejecutamos un contenedor utilizando el parámetro --add-host. Por ejemplo, podríamos querer añadir el nombre de host y la dirección IP del host que ejecuta Docker en nuestro contenedor.

$ docker run -p 80 --add-host=docker:10.0.0.1 --name web2 --link mysql:mysql2 …

Esto añadiría una entrada para un host llamado docker con una dirección IP 10.0.0.1 dentro del fichero /etc/hosts de nuestro contenedor.

Las direcciones IP de los contenedores cambian cuando se reinicia un contenedor, pero docker actualizará el fichero /etc/hosts del contenedor vinculado con la nueva IP.

Ahora ya tenemos conectividad con nuestro servidor mysql2, pero antes de usarlos vamos a ver más información de conexión contenida en nuestras variables de entorno. Vamos a ejecutar el comando env para ver las variables de entorno.

root@ba2cf804e098:/var/www/html# env
HOSTNAME=ba2cf804e098
MYSQL_ENV_MYSQL_ROOT_PASSWORD=miclave123
TERM=xterm
PHP_INI_DIR=/usr/local/etc/php
PHP_FILENAME=php-5.6.16.tar.xz
MYSQL_PORT_3306_TCP_PORT=3306
MYSQL_PORT_3306_TCP=tcp://172.17.0.2:3306
WORDPRESS_VERSION=4.4
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
GPG_KEYS=0BD78B5F97500D450838F95DFE857D9A90D90EC1 6E4F6AB321FDC07F2C332E3AC2BF0BC433CFC8B3
PWD=/var/www/html
MYSQL_ENV_MYSQL_VERSION=5.7.10-1debian8
HOME=/root
SHLVL=1
PHP_SHA256=8ef43271d9bd8cc8f8d407d3ba569de9fa14a28985ae97c76085bb50d597de98
WORDPRESS_SHA1=d647a77c63f2ba06578f7747bd4ac295e032f57a
MYSQL_PORT_3306_TCP_PROTO=tcp
MYSQL_NAME=/wordpress1/mysql
MYSQL_PORT_3306_TCP_ADDR=172.17.0.2
PHP_EXTRA_BUILD_DEPS=apache2-dev
MYSQL_ENV_MYSQL_MAJOR=5.7
MYSQL_PORT=tcp://172.17.0.2:3306
PHP_VERSION=5.6.16
PHP_EXTRA_CONFIGURE_ARGS=--with-apxs2
_=/usr/bin/env

Podemos ver un montón de variables de entorno aquí, entre ellas algunas con el prefijo MYSQL. Docker crea automáticamente estas variables cuando vinculamos los contenedores wordpress y mysql. Comienzan con MYSQL, ya que es el alias que usamos cuando creamos nuestro enlace.

Las variables de entorno creadas automáticamente incluyen una variedad de información:
• El nombre de host del contenedor.
• El protocolo, IP y puerto del servicio que se ejecuta en el contenedor.
• Los protocolos específicos, IP, y los puertos de varios servicios que se ejecutan en el contenedor.
• Los valores de las variables de entorno especificadas al iniciar el contenedor.

Las variables precisas variarán de un contenedor a otro, dependiendo de lo que esté configurado en ese contenedor (por ejemplo, lo que se ha definido por la instrucción ENV y EXPOSE en el fichero Dockerfile del contenedor). Incluyen información que podemos usar dentro de nuestras aplicaciones para vincular consistentemente entre los contenedores.

Nuestra aplicación entonces tiene dos formas de conectar wordpress a mysql:
·         El uso de parte de la información de conexión en nuestras variables de entorno.
·         El uso de DNS y la información del fichero /etc/hosts

Veamos el primer método, nuestra aplicación podría leer de las variables de entorno MYSQL_PORT y podría usar la salida de host y puerto resultante para configurar la conexión mysql. Nuestra aplicación puede ahora utilizar esta información de conexión para encontrar mysql en un contenedor vinculado. Éste abstrae la necesidad de codificar una dirección IP y el puerto para proporcionar conectividad.

Alternativamente, existe el DNS local que es más flexible, que es la solución más habitual.


También podríamos configurar los servidores DNS para nuestros contenedores, utilizando el parámetro -dns y --dns-search en el comando docker run. Esto nos permite establecer la ruta de resolución de DNS y dominios de búsqueda locales. Si no se especifica, Docker utilizará la resolución de DNS que tenga configurada el anfitrión Docker.

jueves, 21 de julio de 2016

REDES EN DOCKER

Las conexiones de los contenedores son creadas utilizando redes. Estas son llamadas “Docker Networking” y fueron introducidas en Docker 1.9. Docker Redes permite que podamos configurar nuestras propias redes a través de las cuales los contenedores pueden comunicarse. Básicamente, esto complementa la red docker0 existente por defecto con nuevas redes gestionadas por el usuario. Es importante destacar que los contenedores pueden comunicarse entre ellos a través del host y la configuración de las redes puede ser totalmente personalizada. Docker Redes también se integra con Docker compose y Swarm.

El soporte de red también es pluggable o enchufable, lo que significa que puede agregar controladores de red para soportar topologías específicas y marcos de redes de proveedores como Cisco y VMware.

Vamos a ver un sencillo ejemplo de cómo utilizar una aplicación web y contenedores. Para utilizar las redes Docker, primero tenemos que crear una red y luego ejecutar el contenedor dentro de esa red.

$ docker network create app
3395f15bf73e310b7ef4330187398a56c87c4b5b278494ec3adb7423578df839

Hemos utilizado el comando docker network para crear una red puente llamada app. Nos devuelve un ID para nuestra red. Entonces podemos inspeccionar esta red utilizando el comando “docker network inspect”.

$ docker network inspect app
[
    {
        "Name": "app",
        "Id": "3395f15bf73e310b7ef4330187398a56c87c4b5b278494ec3adb7423578df839",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {}
            ]
        },
        "Containers": {},
        "Options": {}
    }
]

Podemos ver que nuestra nueva red es una red local, un puente muy similar a nuestra red docker0 y que en la actualidad no hay contenedores ejecutándose dentro de la red.
Además de crear una red de puente que sólo existe en un único host, también podemos crear redes superpuestas (overlay), lo que nos permite abarcar varios host.
Podemos enumerar todas las redes actuales utilizando el comando “docker network ls”.

$ docker network ls
NETWORK ID          NAME                DRIVER
cb1379376867        host                host               
3395f15bf73e        app                 bridge             
bb419a78dd86        bridge              bridge             
b6fa624cb73c        none                null

y también podemos eliminar una red con el comando “docker network rm”.
Vamos a añadir algunos contenedores a nuestra red comenzando por un contenedor mysql

$ docker run --net=app --name mimysql -e MYSQL_ROOT_PASSWORD=clave123 -d mysql

Hemos creado un nuevo contenedor llamado mimysql, usando la imagen por defecto de la última versión de mysql, también hemos especificado un nuevo parámetro –net. El parámetro –net especifica una red para que utilice nuestro contenedor.
Ahora, si volvemos a ejecutar el comando “docker network inspect”, veremos mucha más información:

$ docker network inspect app
[
    {
        "Name": "app",
        "Id": "3395f15bf73e310b7ef4330187398a56c87c4b5b278494ec3adb7423578df839",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {}
            ]
        },
        "Containers": {
            "e995e69fc19cb92d64dd802e59744256bf450685e4738866c77d2283877e1b12": {
                "EndpointID": "3a6c17ad1c30aa00b074d11183f7cfbc7c74c0e45846863391ebb69af78f5f49",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {}
    }
]

Ya, dentro de nuestra red, podemos ver un contenedor con una dirección MAC y una dirección IP, 172.18.0.2.
Ahora vamos a ejecutar un contenedor con una aplicación en la red que acabamos de crear, en este caso, vamos a utilizar la imagen por defecto de wordpress, que está alojada en docker hub.

$ docker run --net=app --name miwordpress -t -i -p 8080:80 wordpress /bin/bash

Hemos ejecutado un contenedor llamado miwordpress dentro de la red app. Hemos ejecutado de forma interactiva para poder mirar dentro lo que está sucediendo. A medida que el contenedor se inicia dentro de la red de aplicaciones, Docker habrá tomado nota de todos los demás contenedores que se ejecutan dentro de esa red y poblará sus direcciones en el DNS local mediante el fichero /etc/hosts. Vamos a verlo dentro del contenedor que acabamos de ejecutar:

root@4f3cdb6d7626:/var/www/html# cat /etc/hosts
172.18.0.3  4f3cdb6d7626
127.0.0.1   localhost
::1   localhost ip6-localhost ip6-loopback
fe00::0     ip6-localnet
ff00::0     ip6-mcastprefix
ff02::1     ip6-allnodes
ff02::2     ip6-allrouters
172.18.0.2  mimysql
172.18.0.2  mimysql.app

Podemos ver que el archivo /etc/hosts contiene la dirección IP del contenedor wordpress y una entrada para localhost. También contiene dos entradas para el contenedor mimysql. La primera entrada, es el nombre de host y la dirección IP del contenedor mimysql, 172.18.0.2. El segundo, añade la red app como un sufijo de dominio para la red. Cualquier host en la red app puede ser resuelto por nombrehost.app, en este caso mimysql.app. Vamos a probarlo:

root@4f3cdb6d7626:/var/www/html# ping mimysql.app
PING mimysql.app (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: icmp_seq=0 ttl=64 time=0.113 ms
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.224 ms
64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.179 ms

Es importante destacar que si se reinician los contenedores, entonces su información de la dirección IP se actualizará en el archivo /etc/hosts. Esto significa que el cambio de los contenedores subyacentes no tendrá un impacto en el funcionamiento de nuestra aplicación.
Ahora vamos a eliminar nuestro contenedor y ejecutarlo de nuevo como servicio para utilizar nuestro wordpress

$ docker run --net=app --name miwordpress -p 8080:80 -e WORDPRESS_DB_HOST=mimysql:3306 -e WORDPRESS_DB_PASSWORD=clave123 -d wordpress
6042dc762061131c376626c23d5f9c4b0d02cba2e6e3912339c6507415159e4c

y vamos a nuestro navegador para ver si funciona:

Figura 14. Pantalla de instalación de wordpress.
Fuente: Elaboración propia

Y aquí tenemos nuestro sitio wordpress funcionando en menos de un minuto:

Figura 15. Pantalla de wordpress instalado.

Fuente: Elaboración propia

También podemos añadir contenedores que están ya en ejecución a contenedores existentes usando el comando “docker network connect”. Vamos a añadir un contenedor existente a nuestra red app.  Como tenemos un contenedor que se llama web, vamos a conectarlo.

$ docker network connect app web

Ahora vamos a comprobar la red app.

$ docker network inspect app
[
    {
        "Name": "app",
        "Id": "3395f15bf73e310b7ef4330187398a56c87c4b5b278494ec3adb7423578df839",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {}
            ]
        },
        "Containers": {
            "6042dc762061131c376626c23d5f9c4b0d02cba2e6e3912339c6507415159e4c": {
                "EndpointID": "e9e6b25da5ec45926654246398ed69b2dfa1055a4120631deaeba5a0eaf847c5",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            },
            "783b2527f17f191b824098b72966534bde9fa06ef907410ef830d54d0623051f": {
                "EndpointID": "fffc03dcb3ccdc82196d2c64c6a59f0993484e3c2e3c68cd3f0d61f7cdc3b065",
                "MacAddress": "02:42:ac:12:00:04",
                "IPv4Address": "172.18.0.4/16",
                "IPv6Address": ""
            },
            "e995e69fc19cb92d64dd802e59744256bf450685e4738866c77d2283877e1b12": {
                "EndpointID": "3a6c17ad1c30aa00b074d11183f7cfbc7c74c0e45846863391ebb69af78f5f49",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {}
    }
]

El fichero /etc/hosts en todos nuestros contenedores contiene información de DNS local para los contenedores miwordpress, mimysql y web.
También podemos desconectar un contenedor de una red utilizando el comando “docker network disconnect”.

$ docker network disconnect app web

Esto elimina el contenedor web de la red app.

Los contenedores pueden estar en múltiples redes a la vez para poder crear modelos de redes muy complejas.

miércoles, 20 de julio de 2016

Creando un sitio web estático con Docker


Uno de los casos de uso más simples para poder utilizar Docker, es creando una web local en un entorno de desarrollo. Como el entorno nos permite replicarlo al entorno de producción, nos aseguramos que nuestros desarrollos siempre se ejecutarán en producción. Vamos a realizar una prueba instalando un servidor web Nginx en un contenedor para ejecutar una página web sencilla. Nuestro sitio web se va a llamar ejemplo.

Para conseguirlo, vamos a comenzar con un simple Dockerfile. Comenzamos creando un directorio donde crear nuestro fichero Dockerfile.

mkdir ejemplo
cd ejemplo
touch Dockerfile

Ahora necesitamos algunos ficheros de configuración de Nginx para nuestro sitio web. Vamos a crear un directorio llamado nginx dentro de nuestro directorio ejemplo.

mkdir nginx && cd nginx

y dentro del mismo creamos un fichero de configuración global.conf con el siguiente contenido:

server {
        listen          0.0.0.0:80;
        server_name     _;

        root            /var/www/html/website;
        index           index.html index.htm;

        access_log      /var/log/nginx/default_access.log;
        error_log       /var/log/nginx/default_error.log;
}

y otro fichero denominado nginx.conf

user www-data;
worker_processes 4;
pid /run/nginx.pid;
daemon off;

events {  }

http {
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  keepalive_timeout 65;
  types_hash_max_size 2048;
  include /etc/nginx/mime.types;
  default_type application/octet-stream;
  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;
  gzip on;
  gzip_disable "msie6";
  include /etc/nginx/conf.d/*.conf;
}

y ahora vamos a crear nuestro fichero Dockerfile

FROM ubuntu:14.04
MAINTAINER Javier Hernandez
ENV ACTUALIZADO_FECHA 29-12-2015
RUN apt-get –yqq update && apt-get –yqq install nginx
RUN mkdir –p /var/www/html/web
ADD nginx/global.conf /etc/nginx/conf.d/
ADD nginx/nginx.con /etc/nginx/nginx.conf
EXPOSE 80

Nuestro fichero Dockerfile realiza lo siguiente:
·         Instala Nginx
·         Crea un directorio /var/www/html/web/ dentro de la imagen.
·         Añade la configuración de nginx desde nuestro sistema de ficheros local a nuestra imagen
·         Publica el puerto 80 en la imagen

Nuestros dos ficheros de configuración de Nginx son copiados. Global.conf es copiado a la carpeta /etc/nginx/conf.d mediante la instrucción ADD y el fichero nginx.conf es copiado al directorio /etc/nginx

En este fichero de configuración, la opción “daemon off” fuerza que nginx no se ejecute como demonio o servicio, esto es, porque nuestro contenedor Docker se encargará de que el proceso se mantenga activo por defecto, esto hará que se ejecute como demonio cuando el contenedor comience y se parará cuando el mismo se pare.
Podemos ver también algunas diferencias entre las rutas destino de las dos instrucciones ADD, la primera termina en un directorio, pues acaba con “/” y la segunda especifica un fichero, los dos estilos están permitidos para copiar ficheros en una imagen Docker.
Ahora vamos a crear nuestra nueva imagen con el comando Docker build, la vamos a llamar “jalapuente/nginx”.

docker build –t jalapuente/nginx .

Esto construirá y nombrará nuestra nueva imagen y veremos como se van ejecutando los distintos pasos. Podemos ver las capas y pasos utilizados utilizando el comando “docker history”.

$ docker history jalapuente/nginx
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
22aa8432c73e        22 hours ago        /bin/sh -c #(nop) EXPOSE 80/tcp                 0 B                
da09a1e3cde1        22 hours ago        /bin/sh -c #(nop) ADD file:6b400357b23615a407   415 B              
9f9c6ca0ee34        22 hours ago        /bin/sh -c #(nop) ADD file:527ff78465dc48bf6c   286 B              
3082b1b65403        22 hours ago        /bin/sh -c mkdir  /var/web                      0 B                
d93ddca5468f        23 hours ago        /bin/sh -c apt-get update && apt-get install    39.58 MB           
61da7c1ebfde        23 hours ago        /bin/sh -c #(nop) ENV ACTUALIZADO_FECHA=29-12   0 B                
a7518518555c        23 hours ago        /bin/sh -c #(nop) MAINTAINER Javier Hernandez   0 B                
89d5d8e8bafb        3 weeks ago         /bin/sh -c #(nop) CMD ["/bin/bash"]             0 B                
e24428725dd6        3 weeks ago         /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/   1.895 kB           
1796d1c62d0c        3 weeks ago         /bin/sh -c echo '#!/bin/sh' > /usr/sbin/polic   194.5 kB           
0bf056161913        3 weeks ago         /bin/sh -c #(nop) ADD file:9b5ba3935021955492   187.7 MB 

El comando nos muestra al principio la capa final, nuestra nueva imagen tiene como padre original a ubuntu:14.04. Cada paso nos muestra una nueva capa y la instrucción del fichero Dockerfile que la ha generado.

Creando contenedores de nuestra imagen nginx en nuestro sitio web de ejemplo
Ahora tenemos nuestra imagen jalapuente/nginx y podemos empezar a crear contenedores de ella, lo que permitirá poner a prueba nuestra página web de ejemplo. Para ello, tenemos que añadir el código de la página web de ejemplo.

$ mkdir web && cd web
$ nano index.html
<head>
<title>Sitio web de ejemplo </title>
</head>
<body>
<h1>Esto es una prueba de sitio web</h1>
</body>

Esto creará un directorio llamado web. Luego creamos archivo index.html para nuestro sitio web de ejemplo.
Ahora vamos a ver cómo podemos ejecutar un contenedor utilizando el comando docker run.

$ docker run -d -p 80 --name web -v $PWD/web:/var/web jalapuente/nginx nginx

Podemos ver que hemos pasado el comando nginx como parámetro al comando docker run. Normalmente esto no tendría que ser necesario para ejecutar Nginx. En la configuración suministrada a Docker, hemos añadido la directiva daemon off. Esta directiva hace que Nginx se ejecute de forma interactiva cuando es ejecutado.
Se puede ver que hemos utilizado el comando docker run para crear un contenedor desde nuestra imagen jalapuente/nginx llamada web. Aquí podemos ver que hemos utilizado la opción -v. Esta nueva opción nos permite crear un volumen en nuestro contenedor de un directorio en el host.
Vamos a ver los volúmenes, ya que son importantes y útiles en Docker. Los volúmenes están especialmente designando directorios dentro de uno o más contenedores que no utilizan el sistema de archivos en capas para proporcionar datos persistentes o compartidos por Docker. Esto significa que los cambios en un volumen se hacen directamente y no tienen nada que ver con la imagen. Los volúmenes no se incluirán cuando construimos una imagen.
Los volúmenes también pueden ser compartidos ente contenedores y pueden persistir incluso cuando se detienen los contenedores.
Aquí podemos ver algunos casos que pueden resultar útiles, podemos ver el valor de volúmenes cuando no queremos para construir nuestra aplicación o código en una imagen. Por ejemplo:
• Queremos trabajar y probarlo de forma simultánea.
• La información cambia con frecuencia, y no queremos reconstruir la imagen durante nuestro proceso de desarrollo.
• Queremos compartir el código fuente entre varios contenedores.
La opción -v funciona mediante la especificación de un directorio del host local separado por dos puntos del directorio a montar dentro del contenedor. Si el directorio contenedor no existe, Docker lo creará.
También podemos especificar el modo en que se monta el volumen, bien de lectura/escritura del directorio contenedor añadiendo rw o bien de sólo lectura añadiendo ro después del directorio, por ejemplo:

$ docker run -d -p 80 --name web -v $PWD/website:/var/www/html/website: ro jalapuente/nginx nginx

Esto haría que el contenedor montara el directorio /var/www/html/website de sólo lectura.
En nuestro sitio web que utiliza el contenedor Nginx, para ello, hemos montado un sitio Web local que estamos desarrollando. Para ello hemos montado como volumen el directorio $PWD/website como directorio /var/www/html/website en nuestro contenedor. En nuestra configuración de Nginx (en el archivo de configuración /etc/nginx/conf.d/global.conf), hemos especificado este directorio como la ubicación para ser servido por el servidor Nginx.
Ahora bien, si nos fijamos en nuestro contenedor en ejecución con el comando docker ps, podemos ver que está activo, se nombra web, y el puerto 80 en el contenedor se asigna al puerto 32768 en el host.

$ docker ps -l
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                   NAMES
783b2527f17f        jalapuente/nginx    "nginx"             6 seconds ago       Up 6 seconds        0.0.0.0:32768->80/tcp   web

Si navegamos al puerto 32768 en nuestro anfitrión Docker, vamos a ser capaces de ver nuestra página web de muestra, en este caso he creado un fichero index.html con el texto “prueba”.

 Fuente: Elaboración propia

En nuestro caso, hemos realizado el ejemplo utilizando “Docker Toolbox” el cual utiliza docker-machine, hemos tenido que ver que dirección IP tenía nuestro demonio docker para poder mostrar nuestro sitio web, en mi caso, la máquina docker dentro de docker-machine se llama docker2, así que ejecutamos lo siguiente para averiguar su IP:

$ docker-machine ip docker2
192.168.99.100

Ahora vamos a editar nuestro sitio web:

$ nano $PWD/website/index.html

y ponemos:

Esto es una prueba de sitio web con Docker

Entonces pulsamos la tecla refrescar de nuestro navegador y vemos el resultado:

Fuente: Elaboración propia


Podemos ver que nuestro sitio web de ejemplo ha sido actualizado. Esto es un ejemplo increíble y bastante simple de editar un sitio web, pero podríamos hacer muchísimo más, cosas más importantes, incluso sitios que reflejen la información de producción realmente. Podemos tener contenedores para cada tipo de entorno de producción como Apache, nginx, etc…, para poder ejecutar variedad de versiones de framework como PHP o conectar a unas u otras bases de datos.

viernes, 10 de junio de 2016

RESUMEN DE COMANDOS DOCKER


Resumen de comandos Docker.


Actividad
Comando
Ejemplo
Contenedores


Arrancar o comenzar contenedor
docker start <id o nombre>
docker start micontenedor
Reiniciar contenedor
docker restart <id o nombre>
docker restart micontenedor
Parar contenedor
docker stop <id o nombre>
docker stop micontenedor
Eliminar contenedor
docker rm <id o nombre>
docker rm micontenedor
Crear y ejecutar contenedor interactivo
docker run –i –t <image> /bin/bash
docker run –i –t Ubuntu /bin/bash
Crear y ejecutar contenedor como servicio o demonio
docker run –d <image> <cmd>
docker run –d Ubuntu ping docker.com
Listar todos los contenedores en ejecución
docker ps

Listar todos los contenedores
docker ps –a

Abrir una ventana de comandos o Shell en un contenedor en ejecución
docker exec –i –t <id o nombre> bash
docker exec –i –t micontenedor bash
Mostrar detalles de un contenedor
docker inspect <id o nombre>
docker inspect micontenedor
Mostrar eventos de un contenedor
docker events <id o nombre>
docker events postgres
Mostrar los puertos a exponer de un contenedor
docker port <id o nombre>
docker port postgres
Mostrar ficheros modificados
docker diff <id o nombre>
docker diff micontenedor
Mostrar los procesos de un contenedor
docker top <id o nombre>
docker top micontenedor
Mostrar registro de eventos o log de un contenedor
docker logs <id o nombre>
docker logs micontenedor
Ver el registro de eventos interactivo (tipo tail –f)
docker logs –f <id o nombre>
docker logs –f micontenedor
Copiar ficheros de un contenedor
docker cp ‘<id>’:<origen> <destino>
docker cp micontenedor:/etc/hosts /tmp/hosts
Exportar contenedor
docker export <id o nombre>
docker export micontenedor >micontenedor.tar
Guardar cambios de contenedor como imagen nueva
docker commit <id o nombre> <nombre de imagen>
docker commit micontenedor jalapuente/imagen2
Imágenes


Listar todas las imágenes locales
docker images

Obtener una imagen del repositorio oficial
docker pull <nombre>
docker pull ubuntu
Obtener una imagen no oficial
docker pull <espacio de nombres>/<nombre>
docker pull jalapuente/mysql
Subir una imagen a un repositorio oficial (Docker Hub)
docker push <espacio de nombres>/<nombre>
docker pull jalapuente/mysql
Crear una imagen de un fichero Dockerfile
docker build <path>
docker build .
Borrar una imagen
docker rmi <nombre>
docker rmi Ubuntu
Mostrar historial de una imagen
docker history <nombre>
docker history Ubuntu
Mostrar detalles de una imagen
docker inspect <nombre>
docker inspect postgres
Nombrar una imagen y establecer versión de una imagen
docker tag <id> <espacio de nombres>/<nombre>:<version>
docker tag 65f515144e5f jalapuente/mysql:version1
Buscar una imagen
docker search <consulta>
docker search django
Fuente: Elaboración propia.