Docker: Gestión y Administración

11 septiembre 2016 at 16:12 by Adrián Pérez

docker

Tenía pendiente ver el tercer vídeo de self-training que tiene Docker en su web. Como soy mucho de hacer resúmenes de aquello que me parece interesante (para interiorizar y poder volver a consultarlo más adelante), y ya que hice lo propio con la entrada "Introducción a Docker", con este tercer vídeo no podía hacer menos.

Container troubleshooting

Podemos ver la salida del proceso con PID 1 (correspondiente al "comando" pasado en el "docker run") con "docker logs".

docker logs [-f] <container_name>
</container_name>

Otra opción, es directamente mapear un directorio del host al directorio de logs de la aplicación que se corre en el container:

docker run -d -P -v /nginxlogs:/var/log/nginx nginx

Con "docker inspect" devolveremos todos los detalles del contendor en un json.

docker inspect <container_name>
</container_name>

En /etc/default/docker se define la variable DOCKER_OPTS, la cual controla las opciones de arranque cuando iniciamos docker como servicio. Por ejemplo, podremos cambiar el nivel de log por defecto especificándolo en DOCKER_OPTS mediante la opción "--log-level", la cual dejará los logs en /var/log/upstart/docker.log. Esta variable nos dará mucha flexibilidad.

Seguridad

Docker está basado en los Namespaces de Linux, usando Cgroups para aislar no sólo los recursos de cada container, sino también su propio stack de red, sistema de ficheros raíz, etc. lo cual hace que las aplicaciones que corran en el container sean de por sí, algo más seguras (al correr en entornos aislados).

Algunas consideraciones:
- Cuidado a quién metemos en el group "docker", pues el demonio de docker corre como root.
- No olvidemos seguir las best practices habituales (usar TLS en nuestras comunicaciones, habilitar selinux o similares, etc.)

Registro privado

Podemos montar nuestro propio registro privado en el que almacenar nuestras imagenes, fuera de Docker Hub. La forma más sencilla, es directamente correr un container con la imagen del Docker Registry 2.0.

docker run -d -p 5000:5000 registry:2.0

Para poder guardar una imagen en nuestro registro privado, deberemos tagearla. Tras ello, ya podremos guardarla con un "push" y descargarla posteriormente con un pull.

docker tag <image id> <myregistry_ip>:5000/my-repository-name:1.0
docker push <myregistry_ip>:5000/my-repository-name:1.0
docker pull <myregistry_ip>:5000/my-repository-name:1.0

Para poder acceder a nuestro registro desde otra máquina, deberemos usar TLS para securizar nuestro registro. Desde la propia documentación de Docker nos proponen el uso de LetsEncrypt.org para obtener nuestro certificado, gratuitamente. Los pasos para generar y usar nuestro certificado de ejemplo con LetsEncrypt están descritos aquí, y resumidos a continuación, aunque para poder seguirlos deberemos contar con un dominio o subdominio con un registro tipo A que apunte al host con nuestro registro (en el ejemplo, registry.helloit.es).

$ sudo apt-get install letsencrypt
$ sudo letsencrypt certonly --standalone -d registry.helloit.es

El último comando generará una serie de ficheros .pem en /etc/letsencrypt/live/registry.helloit.es/ que usaremos para obtener los ficheros .crt y .key que necesitaremos para configurar TLS en nuestro registro.

$ sudo cat /etc/letsencrypt/live/registry.helloit.es/cert.pem /etc/letsencrypt/live/registry.helloit.es/chain.pem > /path/to/certs/registry_helloit_es.crt
$ sudo cp /etc/letsencrypt/live/registry.helloit.es/privkey.pem /path/to/certs/registry_helloit_es.key

El siguiente paso será crear un htpasswd con nuestro primer usuario con acceso al registro, y tras ello, ya podremos crear e iniciar el container con TLS y autenticación.

$ docker run --entrypoint htpasswd registry:2 -Bbn usuario password > /path/to/auth/htpasswd

Iniciaremos el container para nuestro registro privado, tal que así:

docker run -d -p 5000:5000 --restart=always \
     -v `pwd`/certs:/certs \
     -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/registry_helloit_es.crt \
     -e REGISTRY_HTTP_TLS_KEY=/certs/registry_helloit_es.key \
     -v `pwd`/auth:/auth \
     -e "REGISTRY_AUTH=htpasswd" \
     -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
     -e REGISTRY_AUTH_HTPASSWD_PATH=/path/to/auth/htpasswd \
     --name=registry \
     registry:2

Ya estaremos listos para hacer un "docker login" contra nuestro registro.

A modo de prueba, si no contamos con certificado, podremos, desde la máquina externa que está intentando acceder al registro, para el servicio de docker y configurar en el DOCKER_OPTS (del que hemos hablado antes) la opción "--insecure-registry :", con lo que este cliente ignorará el hecho de que el registro no tenga configurado el TLS.

Más info, incluyendo el uso de Compose para orquestar el inicio del container con el registro: https://docs.docker.com/registry/deploying/

Docker Machine

Docker Machine es una herramienta que automáticamente crea el servidor en un proveedor cloud (AWS, DigitalOcean, Azure, etc.) o en local (hosts "Virual Box"), instala Docker y configura el Docker client (provisiona hosts Docker). Más info. Además, configura el acceso SSH como root en los hosts que creamos con "docker-machine create" a las cuales podremos acceder desde nuestra máquina con "docker-machine ssh ".

Docker Swarm

Docker Swarm es una herramienta que "clusteriza" hosts Docker (convierte un grupo de hosts en un único "host virtual") y programa containers. Soporta varias soluciones de descubrimiento de servicios como etcd, consul, zookeeper o con el propio agente de swarm instalado en los hosts (método llamado "hosted discovery"). Más info.

swarm

Se recomienda usar la imagen de Docker Swarm en Docker Hub para correr Docker Swarm, en lugar de descargar el binario. Cuando usamos el protocolo "hosted discovery", ejecutaremos el comando "swarm create" el cual devolverá el token que deberemos usar para identificar nuestro cluster.

docker run --rm swarm create //-rm elimina el container una vez acaba la ejecución

Lo anotamos e iniciamos el Swarm Manager mapeando el puerto de Swarm y pasándole el token.

docker run -d -P swarm manage token://<cluster_token>

Para conectar un nodo al cluster, iniciaremos un container que ejecutará el comando "swarm join", lo cual iniciará el agente swarm, el cual se registrará en el cluster, y updateará y monitorizará los containers del host.

docker run -d swarm join --addr=<node_ip>:<daemon_port> token://<cluster_token>

NOTAS: La IP a la que hacemos referencia, es la IP del nodo, la que usará el Swarm Manager para conectar con ese nodo. Por otro lado, ésto implica que el demonio de docker ha de escuchar por un puerto TCP, lo cual se puede especificar en el DOCKER_OPTS de la máquina.

DOCKER_OPTS="-H 0.0.0.0:2375"

Sin embargo, ésto hará que no podamos conectar como habitualmente (vía socket) con el docker de la máquina, al estar ahora escuchando en un puerto TCP. Desde la terminal podemos exportar la variable de entorno DOCKER_HOST para solucionarlo.

export DOCKER_HOST=localhost:2375

Finalmente, deberemos apuntar el cliente de docker del host que corre el Swarm Manager, al prorio Swarm Manager. De esta manera, desde el manager, cuando ejecutemos el comando "docker" en realidad estaremos ejecutando el Swarm Manager. Ésto podemos hacerlo exportando la variable de entorno DOCKER_HOST con el valor IP:Puerto del container que corre el Swarm Manager.

export DOCKER_HOST=localhost:34512  //OJO, ¡el puerto de escucha del container, no el mapeado!

Ejecutando "docker version" podremos verificar en la sección "Server version" como en efecto el cliente estará conectado a Swarm.

Desde entonces, podremos ejecutar un seguido de comandos útiles:
- docker info: lista los nodos conectados a Swarm, sus containers y la CPU/RAM disponible
- docker run: el comando habitual para lanzar un container, en el que el Swarm Master decidirá en qué nodo se correrá el container.
- docker ps: ahora muestra en qué nodo se está corriendo el container.

Docker Compose

Docker compose es una herramienta para crear y gestionar aplicaciones multi-container. Los containers se definen en un único fichero, llamado "docker-compose.yml" que permitirá eso, crear y desplegar varios containers en varios hosts de forma sincronizada.

Nuestro yml tendrá una sección para cada uno de nuestros servicios, las cuales a su vez contendrán las instrucciones para crear y ejecutar su container. Todos los servicios deben tener una de las dos siguientes instrucciones:
- build: define el path al build context (el directorio donde estará la Dockerfile así como los posibles ficheros a inyectar) para generar la imagen que se usará para correr el container.
- image: si no necesitas crear tu propia imagen via la Dockerfile, puedes directamente indicar la imagen a usar.

Además, podremos definir otras instrucciones para cada servicio:
- links: linka el container a otro (que será el "origen") especificando el nombre del servicio definido en el yml.

compose

Para iniciar nuestra aplicación (construir las imagenes de cada servicio definido en el yml, crear los containers e iniciarlos) ejecutaremos:

docker-compose up