Docker for Windows, una vista rápida del panorama actual

El pásado día 5 de mayo tuvo lugar en nuestras oficinas una nueva edición del Meetup de Docker Madrid. Gracias al equipo de DX de Microsoft España ya tenemos las sesiones disponibles en Channel 9.

En primer lugar, contamos con la participación de Ignacio Sánchez y Ramón Román de atSistemas donde me quedo sin duda con su clúster de Raspberry Pi integrado con los nuevos pipelines de Jenkins 2.0. Media hora de sesión donde ver cómo emplear Docker Swarm para la gestión de clústeres basados en Docker y la instanciación de aplicaciones basadas en microservicios. Muy útil las nuevas capacidades incorporadas en Swarm para reinstanciar los contenedores en otro nodo si el host se cae.

Tras ellos, por mi parte hice una breve introducción a cómo se encuentra el ecosistema de Docker en entornos basados en Windows. Desde los avances en Docker for Windows con Kitematic para permitirte trabajar con Docker directamente en Windows 10 con Hyper-V de forma sencilla, hasta los cambios que están llegando en la parte de Windows Server con la implementación a nivel del núcleo del soporte a contenedores.

Tenéis disponible el vídeo y la presentación

Configurando Docker para acceso a través de HTTPs

Comentaba en el artículo anterior que activar el extremo de escucha HTTP en Docker para que otras máquinas de la red pudieran acceder al motor no era una buena práctica. Esto se debe a que al habilitarlo estamos dando acceso a cualquier persona que conozca la combinación de IP y puerto donde tenemos nuestra instancia de Docker en ejecución. Para protegerlo será necesario configurar Docker para que haga uso de la conexión a través de HTTPs.

El proceso de configuración no es trivial ya que lleva involucrado la creación de certificados para el servidor y los diferentes clientes que se conecten. Gracias a ellos, es posible establecer una relación de confianza entre ambos extremos de la conexión y así, en el caso de que otra persona se intente conectar sin disponer de los certificados correctos, el motor de Docker rechazará la conexión. Para crearlos necesitaremos trabajar con OpenSSL dentro de nuestra máquina con Linux.

A la hora de trabajar con sistemas de clave pública es necesario tener mucho cuidado en la configuración y gestión de su información como las claves privadas. Este artículo no entra en detalles de cómo montar una buena solución basada en OpenSSL, únicamente emplea los elementos necesarios para mostrar la configuración del acceso por HTTPs en Docker

Tras esta pequeña advertencia comenzamos.

Creando nuestra entidad certificadora

Para tener un poco ordenada la información relacionado con este proceso de generar los certificados trabajaremos con un directorio a nivel local de nuestro usuario. Dentro del mismo, crearemos varias subcarpetas para guardar los diferentes ficheros involucrados ref. En la primera guardaremos los certificados emitidos, en la segunda las peticiones para generar nuevos certificados, en la tercera la lista de revocación de certificados y por último, la que contendrá la información privada de nuestra CA. Necesitaremos protegerla para evitar el acceso por otros usuarios.

mkdir -p $HOME/CA/{certsdb,certreqs,crl,private}
chmod 700 CA/private

En el siguiente paso, crearemos los dos ficheros necesarios por nuestra entidad certificadora. El fichero index.txt es empleado por OpenSSL para llevar un listado de los certificados firmados y el fichero ca.srl los números de serie. Ambos forman la base de datos de nuestra entidad.

cd CA
echo "01" > ca.srl
touch index.txt

Tras ello, generaremos nuestra clave RSA privada de tamaño 2048 bits. Durante el proceso nos pedirá la clave de paso que queremos usar para protegerla.

openssl genrsa -des3 -out "CA/private/ca-private-key.pem" 2048
Configurando la entidad certificadora para Docker
Configurando la entidad certificadora para Docker

El siguiente paso será obtener la clave pública de nuestra entidad certificadora. Los campos que nos piden los podemos completar con nuestra información correcta o no, según deseamos. El que será importante será el definir el FQDN de nuestro servidor.

openssl req -new -x509 -days 365 -key "CA/private/ca-private-key.pem" -out "CA/private/ca-public-key.pem"
Configurando la entidad certificadora para Docker
Configurando la entidad certificadora para Docker

Generando el certificado para el servidor

Una vez que hemos terminado con nuestra entidad certificadora nos toca configurar ahora el certificado para nuestro motor de Docker. Para ello, tendremos que generar una nueva clave privada de forma similar a lo que hemos hecho anteriormente. Necesitaremos introducir una nueva clave de paso para protegerla.

openssl genrsa -des3 -out "CA/private/server-private-key.pem" 2048

Una vez que la tenemos el siguiente paso es solicitar una petición de firma de nuestro certificado, también conocido como Certificate Signing Request . Es muy importante sustituir el parámetro CN, Common Name, por el nombre del servidor al que nos conectaremos. En mi caso será jangelfdez.cloudapp.net. Será necesario introducir la clave que hemos definido en el paso anterior.

openssl req -subj '/CN=jangelfdez.cloudapp.net' -new -key "CA/private/server-private-key.pem" -out "CA/certreqs/server.csr"

Tras haber hecho la solicitud el siguiente paso es firmar nuestra clave por nuestra entidad certificadora. Para ello, ejecutamos lo siguiente.

openssl x509 -req -days 365 -in "CA/certreqs/server.csr" -CA "CA/private/ca-public-key.pem" -CAkey "CA/private/ca-private-key.pem" -CAserial "CA/ca.srl" -out "CA/certsdb/server-cert.pem"
Configurando la entidad certificadora para Docker
Configurando la entidad certificadora para Docker

Generando el certificado para el cliente

Este proceso será muy parecido al del apartado anterior, la única diferencia será que necesitaremos configurar una de las extensiones del certificado para que permita ser utilizado para autenticación. Por lo tanto, comenzamos creando la clave privada y generando la petición de firma de nuestro certificado.

openssl genrsa -des3 -out "CA/private/client-private-key.pem" 2048
openssl req -subj '/CN=client' -new -key "CA/private/client-private-key.pem" -out "CA/certreqs/client.csr"

Una vez que lo tenemos, configuramos la extensión para autenticación. Únicamente será necesario definir una pareja clave-valor y pasarle el fichero a la hora de firmar la petición.

echo extendedKeyUsage = clientAuth > extfile.cnf
openssl x509 -req -days 365 -in "CA/certreqs/client.csr "CA/private/ca-public-key.pem" -CAkey "CA/private/ca-private-key.pem" -CAserial "CA/ca.srl" -out "CA/certsdb/client-cert.pem" -extfile extfile.cnf

Configurando Docker para hacer uso de HTTPs

La parte complicada ya la hemos terminado, ahora necesitaremos dos cosas más antes de tener listo el acceso por HTTPs. En primer lugar, eliminar la frase de paso de las claves de nuestro cliente y servidor.

openssl rsa -in "CA/private/server-private-key.pem" -out "CA/private/server-private-key.pem"
openssl rsa -in "CA/private/client-private-key.pem" -out "CA/private/client-private-key.pem"

Tras ello, arrancamos nuestro motor de Docker pasándole los parámetros que especifican su certificado y clave correspondiente.

docker -d --tlsverify --tlscacert="CA/private/ca-public-key.pem" --tlscert="CA/certsdb/server-cert.pem" --tlskey="CA/private/server-private-key.pem" -H=0.0.0.0:2376
Ejecutando Docker con HTTPs
Ejecutando Docker con HTTPs

El servidor ya está configurado correctamente para aceptar únicamente peticiones a través de HTTPs y que se autentiquen con un certificado firmado por nuestra autoridad certificadora en el puerto 2376. Por lo tanto, faltará a nuestro cliente indicarle que queremos utilizar este tipo de autenticación lanzándolo con los siguientes parámetros.

docker.exe --tlsverify --tlscacert="C:\Users\jangelfdez\Desktop\ca-public-key.pem" --tlscert="C:\Users\jangelfdez\Desktop\client-cert.pem" --tlskey="C:\Users\jangelfdez\Desktop\client-private-key.pem" -H=jangelfdez.cloudapp.net:2376 info

Y con ello tendremos nuestro cliente desde Windows 10 conectado a nuestro motor de Docker a través de HTTPs.

Cliente de Windows de Docker conectado por HTTPs
Cliente de Windows de Docker conectado por HTTPs

Conexión entre el cliente y servidor de Docker desplegados de forma manual en Azure

En los dos artículos anteriores hemos visto en primer lugar cómo desplegar el motor de Docker en una máquina virtual desplegada en Azure de forma manual; en segundo lugar, cómo configurar el cliente de Docker en Windows con la primera versión de prueba del mismo en un Windows 10 que también está desplegado en Azure. Ambas máquinas se encuentra dentro de la misma red virtual de Azure, un entorno similar al que tendríamos en local si estuviéramos utilizando Hyper-V; por ejemplo, para montar este entorno de pruebas.

El siguiente paso consiste en probar la comunicación entre ambos extremos. Por defecto, Docker escucha las conexiones entrantes a través del siguiente socket unix:///var/run/docker.sock. La única conexión permitida será a nivel local accediendo con el usuario root. Sin embargo, para hacer esta prueba rápida vamos a ver cómo modificarlo para que escuche en un puerto TCP y nos podamos conectar desde otras IPs.

Es muy importante tener en cuenta que esto habilita el acceso a nuestro motor de Docker a cualquier persona que conozca la combinación de IP y puerto, por ello no lo debemos realizar nunca fuera de entornos de prueba.

Para ello, lanzaremos el demonio de Docker pasánadole el parámetro -H donde especificaremos que escuche a través de TCP en el puerto que le indiquemos.

$ sudo docker -H 0.0.0.0:2375 -d &
Arrancando el motor de Docker
Arrancando el motor de Docker

Ahora, podremos conectarnos desde nuestro cliente Windows y mostrar la información de nuestro servidor:

Cliente de Docker en Windows
Cliente de Docker en Windows

Lo siguiente será configurarlo utilizando HTTPs para permitir la conexión segura desde otros equipos fuera de la red local como el ordenador en mi oficina y el servidor desplegado en Azure.

Instalando el cliente de Docker en Windows

La firma del acuerdo colaboración entre Docker y Microsoft anunciada a mediados de octubre de este año va a traer dos piezas importantes de Docker a los entornos Windows. En primer lugar, la disponibilidad del engine de Docker en Windows Server para poder desplegar contenedores de una forma similar a la que se realizar a día de hoy en Linux/Unix. Y en segundo, la disponibilidad del cliente de Docker para Windows con lo que no necesitaremos ya soluciones como Boot2Docker para trabajar con él.

El trabajo de implementación ha empezado y ya podemos ver los primeros resultados: la disponibilidad de las herramientas de línea de comandos para Docker en nuestro sistema operativo Windows. Vamos a ver cómo podemos instalar el cliente sobre una máquina con Windows 10 en este caso.

En primer lugar necesitaremos tener instalado en nuestra máquina Go, el lenguaje de programación. Si no lo tenemos, desde la página del proyecto podemos descargarnos el instalador para Windows y completar este primer paso.

Descargar instalador Go
Descargar instalador Go

Una vez que lo tengamos, necesitamos comprobar que funciona de forma correcta ejecutando el comando go en nuestra consola.

Go ejecutado desde PowerShell
Go ejecutado desde PowerShell

Tras ello, necesitaremos Git para podernos descargar el código fuente del cliente y proceder a compilarlo en nuestra máquina. Si no lo tienes disponible, también podemos bajarlo desde la página oficial de Git.

Instalación de Git para Windows
Instalación de Git para Windows

Una vez que lo tengamos, comprobaremos también que funciona correctamente.

Git ejecutándose en Windows
Git ejecutándose en Windows

Tras cumplir con los dos requisitos previos ya estamos preparados para obtener el código y compilarlo. Para ello, clonaremos el repositorio de Docker disponible de forma pública en GitHub.

git clone https://github.com/docker/docker.git c:\go\src\github.com\docker\docker
Clonando repositorio de Docker
Clonando repositorio de Docker

Una vez clonado, configuramos las siguientes variables de entorno para definir dónde se puede encontrar el compilador de Go y activar la flag del proceso de compilación que sólo habilitará el proceso que genera la parte cliente de Docker. A día de hoy no existe aún la parte de servidor.

set GOPATH=c:\go;c:\go\src\github.com\docker\docker\vendor
set DOCKER_CLIENTONLY=1
cd c:\go\src\github.com\docker\docker\docker
go build -v
Compilando el cliente de Docker en Windows
Compilando el cliente de Docker en Windows

Si has seguido todos los pasos de forma correcta ya tendrás disponible tu cliente de Docker en Windows para empezar a trabajar con él de forma similar a como lo realizas ya en Linux/Unix.

Cliente de Docker ejecutándose en Windows
Cliente de Docker ejecutándose en Windows