Una semana con Docker en Windows

Docker para Windows ha mejorado muchísimo, recuerdo que no hace tanto intenté probarlo y no pude porque utilizaba Virtual Box y yo ya tenía Hyper-V corriendo en mi máquina lo cual me hizo imposible la prueba. Ahora, por suerte, utiliza nativamente Hyper-V y además soporta los contenedores de Windows. Pero empecemos de cero.


¿Qué es un contenedor?

Hay mil definiciones online pero en resumidas cuentas un contenedor es una especie de máquina virtual con muchas limitaciones pero grandes ventajas. Los contenedores se basan en imágenes de software que parten de una imagen base y sobre la cual heredan sus características, al principio estas imágenes base solo estaban basadas en el núcleo de Linux pero con la llegada de los Server Core y Nano Core Microsoft también ha optado por crear sus imágenes base a partir de estas dos mini distribuciones de su sistema operativo.
En resumen, son un entorno operativo aislado, con controlados recursos y portátil.

¿Qué es Docker?

Docker no es más (a grandes rasgos) que la herramienta donde poder crear, ejecutar y controlar estas imágenes.

¿Por qué utilizar Docker?

Docker te ayuda a eliminar los servidores que tienes instalados localmente sustituyéndolos por contenedores que te permiten tener un entorno de desarrollo independiente para cada aplicación y además prácticamente igual a tu entorno de producción. Puedes tener alojada tu web en Linux y desarrollar en Windows sabiendo que estas ejecutando en local una versión igual al software que ejecuta tu aplicación en real.
Además, la herencia de imágenes propia de Docker, te permite reutilizar contenedores, ahorrando espacio muchas veces.

Docker en Windows ¿qué debo saber?

Lo primero que tienes que saber son las limitaciones de los contenedores, por ejemplo, de nada sirve ejecutar servicios (ej. nginx) dentro de un contenedor porque al ejecutarse en segundo plano Docker piensa que no estas haciendo nada y detiene el contenedor. Todos los procesos que corras, o por lo menos uno, debe seguir ejecutándose. De ahí que nginx o php-fpm tengan que ejecutarse como procesos y no como servicios en segundo plano.

Contenedores enlazados

Aunque bien puedes crear un contenedor que tenga nginx + php + MySQL lo ideal es crear 3 contenedores separados y enlazarlos. Ten en cuenta que para acceder a cada uno de ellos desde tu máquina es con localhost pero para ellos acceder entre sí deben hacerlo con IPs diferentes y dinámicas asignadas por el propio motor de Docker con lo cual debes utilizar el nombre del contenedor porque Docker crea internamente una entrada en sus DNS internos con los nombres de estas maquinas.
Por ejemplo, en la configuración de un vhost en nginx y suponiendo que tu contenedor PHP se llame php sería así: fastcgi_pass php:9000;
Además debes permitir a php-fpm admitir conexiones de cualquier ip modificando la directiva listen del archivo www.conf.

Compartir directorios

Cuando compartes una carpeta local en Windows dentro de un contenedor Linux esta se crea con permisos de escritura sólo para el usuario que monta la imagen: root, con lo cual o modificas los permisos de esta carpeta en el archivo Dockerfile o ejecutas los procesos como root (php-fpm suele dar problemas por ello hay que ejecutarlo con estas opciones php-fpm --allow-to-run-as-root --nodaemonize).
Como he comentado anteriormente puedes compartir carpetas locales con los contenedores de manera que tu código sigue estando en tú maquina y los datos de las bases de datos que utilices también, de manera que al parar o destruir estos contenedores puedes volver a utilizarla porque siempre ha estado en tu máquina.
Nota: en caso de que utilices un servidor web y php en maquinas separadas, como es mi caso con nginx y php-fpm, los volúmenes que compartas con el código fuente de tu aplicación deben estar en la misma ruta de ambos contenedores, da igual que no existan, Docker crea tanto las rutas locales como las internas de cada contenedor en caso de no existir.
Puedes utilizar 3 tipos de volúmenes:
  • con url relativas al contendor: ./src/conf/mysql/mysqld.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf
  • con url absolutas: c:/www/mysql:/var/lib/mysql
  • url internas de Docker que se mantienen mientras este el contenedor pero que no están en tu máquina sino que las gestiona Docker, con lo cual los datos están mientras exista el contenedor aunque lo apagues pero una vez lo destruyes esos datos se pierden: /var/lib/mysql.
Aquí dejo un ejemplo completo de un archivo yml donde construyo varios contenedores, un nginx que utiliza node y php-fpm y que estos últimos tienen acceso a bases de datos MySQL y SQL server.
web:
  image: reynier3mil/centos-nginx-openssl
  ports:
    - "80:80"
    - "443:443"
  volumes:
    - c:/www/html:/usr/share/nginx/html
    - ./src/conf/nginx/nginx.conf:/etc/nginx/nginx.conf
    - ./src/conf/nginx/vhost.conf:/etc/nginx/conf.d/vhost.conf
  links:
    - php
node:
  image: node:latest
  volumes:
    - C:/www/html/node:/usr/src/app
  working_dir: /usr/src/app
  command: node server.js
  ports:
    - "8080:8080"
  links:
    - mssql
php:
  image: reynier3mil/centos-php-fpm-msphpsql
  volumes:
    - c:/www:/usr/share/nginx
    - ./src/conf/php-fpm/php.ini:/etc/php.ini
    - ./src/conf/php-fpm/php-fpm.conf:/etc/php-fpm.conf
    - ./src/conf/php-fpm/www.conf:/etc/php-fpm.d/www.conf
  working_dir: /usr/share/nginx
  ports:
    - "9050:9050"
  links:
    - db
    - mssql
db:
  image: mysql:8
  volumes:
    - c:/www/mysql:/var/lib/mysql
    - ./src/conf/mysql/mysqld.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf
  environment:
    - MYSQL_ROOT_PASSWORD=**************
    - MYSQL_DATABASE=**************
    - MYSQL_USER=**************
    - MYSQL_PASSWORD=**************
  ports:
    - "3306:3306"
mssql:
  image: microsoft/mssql-server-linux:latest
  volumes:
    - c:/www/mssql:/var/opt/mssql
  environment:
    - ACCEPT_EULA=Y
    - SA_PASSWORD=**************
  ports:
    - "1433:1433"

Comentarios