Enmilocalfunciona

Thoughts, stories and ideas.

Creación de un entorno virtual en Windows 10 mediante Docker Compose

Publicado por Cristina Lopez-Goicochea Juarez el

En este artículo vamos ver cómo instalar, configurar y ejecutar ficheros Compose dentro de Docker para Windows 10. Para ello, veremos el ejemplo de un fichero Compose para levantar un entorno con diferentes productos de la suite Atlassian.

Instalación y configuración de Docker Desktop

Antes de nada, deberemos instalarnos en nuestro equipo la aplicación Docker Desktop y realizar las configuraciones necesarias en función del número de contenedores (aplicaciones) que queramos crear. Importante destacar que, en función de la aplicación, cada contenedor consume una memoria que puede oscilar entre 1Gb y 2Gb con lo que deberemos tener en cuenta estas premisas a la hora de configurar Docker. No obstante, dentro de la página de información de cada imagen en DockerHub nos especifica normalmente qué memoria deberemos indicar.

Para instalar Docker Desktop ir a la página siguiente:
https://www.docker.com/products/docker-desktop

Y descargaremos, para nuestro caso, Docker Desktop en entorno Windows. La instalación no supone problemas destacados. Una vez instalado, reiniciamos equipo.

En el caso de que la aplicación no se haya ejecutado de forma automática al iniciar Windows, buscaremos "Docker Desktop" en el menú Inicio. En caso que sí se haya ejecutado al inicio, encontraremos el icono en las aplicaciones cargadas. Con el botón derecho accedemos a Settings:

Una vez entramos en Settings nos aparece la pantalla siguiente:

En el menú General, desmarcaremos todos los checks de carga de Docker al iniciar Windows, actualizaciones automáticas, estadísticas y TLS. Desmarcamos el check de cargar Docker al inicio ya que de esta manera evitamos tener Docker ejecutándose en background, con los contenedores en marcha, consumiendo memoria sin estar utilizándose.

Dentro de Shared Drives, marcaremos la unidad C. Nos pedirá las credenciales de acceso al Sistema Operativo e introducimos el password.

Dentro de Advanced, estableceremos las opciones de memoria de ejecución. Destacar que es importante establecer correctamente estos parámetros para el correcto funcionamiento de los contenedores. Aun así, se trata de parámetros que se pueden modificar a posteriori. En el caso de la confección del entorno Atlassian se ha establecido, según documentación oficial de la imagen, una memoria mínima y máxima que oscila entre 1Gb y 2Gb por aplicación. Por ello aplicaremos unos 8Gb de memoria para ir holgados, aún así lo recomendable es solamente tener activos aquellos contenedores que queramos utilizar. Más adelante veremos los comandos básicos.

Importante establecer la memoria de intercambio (Swap) al mínimo, 512Mb para evitar que se realicen intercambios que provoquen lentitud en la ejecución de las aplicaciones, por ende, intentaremos utilizar el máximo posible de memoria, sin intercambio.

Cada vez que realicemos cambios en esta pantalla, Docker realizará un reinicio completo para la aplicación de los cambios.

Comentar que en el caso de reestablecer Docker con la configuración por defecto, ésto afectará a los contenedores que tengamos actualmente ya que realizará un reset completo borrando todos aquellos elementos que tengamos configurados y teniendo de nuevo que configurar la pestaña General, Shared Drives y Advanced.

Con estos pasos tenemos Docker inicialmente configurado.

¿CÓMO FUNCIONA DOCKER?

Para poder gestionar los elementos de Docker es necesario saber cómo funciona Docker y su infraestructura.

Fuente imagen: https://docs.docker.com/engine/docker-overview/

Docker se forma de los siguientes elementos:

  • Redes
  • Contenedores
  • Volúmenes
  • Imágenes

Una red en Docker contendrá de 1 a N contenedores. A su vez, cada contenedor contendrá asociado su propio volumen, relación 1..1. Y cada volumen estará creado con la imagen dockerizada de la aplicación que queramos instalar.

Esto significa que podemos crearnos una red con nombre "devNetwork" el cual tendrá asociados N contenedores (con su correspondiente volumen) que constituya cada aplicación Atlassian:

JIRA
Confluence
Bamboo
Bitbucket

Cada vez que levantemos un contenedor, nos cargará la aplicación almacenada en su volumen correspondiente, y podremos acceder a ella a través del puerto que le hayamos configurado al crear dicho contenedor.

Comandos básicos de Docker

Aquí veremos cómo utilizar los comandos básicos de Docker para la gestión de las redes, contenedores, volúmenes e imágenes.

La sintaxis sería la siguiente:

docker {network/container/volume/image} {list/create/start/stop/rm/rmi/restart/inspect/...} {name_of_the_element}  

Si queremos ver la lista de contenedores activos ejecutaríamos el comando:

docker container list  

Para ver los contenedores activos e inactivos ejecutaríamos:

docker container list -a  

Para inspeccionar un contenedor ejecutaríamos:

docker container inspect <nombre_del_contenedor>  

Para borrar un contenedor ejecutaríamos:

docker container rm <nombre_del_contenedor>  

Para arrancar un contenedor ejecutaríamos:

docker container start <nombre_del_contenedor>  

Para parar un contenedor ejecutaríamos:

docker container stop <nombre_del_contenedor>  

Si queremos obtener ayuda sobre los comandos en general podemos ejecutar:

docker --help  

O bien si queremos obtener ayuda sobre los comandos de un tipo de elementos en particular (contenedores, por ejemplo) :

docker container --help  
Estructura básica de un fichero Compose

Estos ficheros tienen la extensión ".yml" y contienen la configuración del servicio que queremos dar de alta. Aquí un ejemplo de configuración para JIRA Software:

version: '3'

services:  
  # JIRA SERVER
  jira:
    container_name: jira_container
    depends_on:
      - database
    image: atlassian/jira-software   
    restart: always   
    networks:
      - devnetwork
    volumes:
      - jiradata:/var/atlassian/application-data/jira
    ports:
      - '8070:8080' 
    environment:
      - 'DATABASE_URL=postgresql://databaseuser@postgresql/database'
      - 'DB_PASSWORD=databasepwd'
      - 'SETENV_JVM_MINIMUM_MEMORY=1024m'
      - 'SETENV_JVM_MAXIMUM_MEMORY=2048m'
      - 'JIRA_PROXY_NAME='
      - 'JIRA_PROXY_PORT='
      - 'JIRA_PROXY_SCHEME='
    logging:
      # limit logs retained on host to 25MB
      driver: "json-file"
      options:
        max-size: "500k"
        max-file: "50" 

  # DATABASE POSTGRESQL
  database:
    container_name: database_container
    image: postgres:9.5-alpine
    restart: always
    networks:
      - devnetwork
    volumes:
      - databasedata:/var/lib/postgresql/data
    environment:
      - 'POSTGRES_DB=database'
      - 'POSTGRES_USER=databaseuser'
      - 'POSTGRES_PASSWORD=databasepwd'
      - 'POSTGRES_ENCODING=UTF8'
      - 'POSTGRES_COLLATE=C'
      - 'POSTGRES_COLLATE_TYPE=C'  
    logging:
      # limit logs retained on host to 25MB
      driver: "json-file"
      options:
        max-size: "500k"
        max-file: "50"

volumes:  
  jiradata:
    external: false    
  databasedata:
    external: false 

networks:  
  devnetwork:
    driver: bridge

Si analizamos detenidamente el contenido de este fichero, vemos que consta de varias partes:

version: '3'  

Aquí determinamos la versión que vamos a utilizar en la confección del fichero.

services:  

En este apartado incluiremos todos aquellos servicios (aplicaciones) que queramos ejecutar dentro del mismo fichero de configuración. Podemos incluir de 1 a N servicios.

jira:  
    container_name: jira_container
    depends_on:
      - database
    image: atlassian/jira-software   
    restart: always   
    networks:
      - devnetwork
    volumes:
      - jiradata:/var/atlassian/application-data/jira
    ports:
      - '8070:8080' 
    environment:
      - 'DATABASE_URL=postgresql://databaseuser@postgresql/database'
      - 'DB_PASSWORD=databasepwd'
      - 'SETENV_JVM_MINIMUM_MEMORY=1024m'
      - 'SETENV_JVM_MAXIMUM_MEMORY=2048m'
      - 'JIRA_PROXY_NAME='
      - 'JIRA_PROXY_PORT='
      - 'JIRA_PROXY_SCHEME='
    logging:
      # limit logs retained on host to 25MB
      driver: "json-file"
      options:
        max-size: "500k"
        max-file: "50"

Aquí definimos la configuración para el servicio Jira, que consta de las siguientes partes:

  • container_name: Indicaremos el nombre que queremos darle al contenedor.
  • depends_on: Este parámetro es opcional y, en este caso, estamos indicando que para que el servicio de JIRA funcione correctamente, es preciso que se configure primero la base de datos. Por ende, se le indica que "depende" del servicio de database. Cuando se construyan los contenedores, primero se generará el contenedor de la dependencia "database" para luego generarse el contenedor de JIRA.
  • image: Aquí indicaremos el path donde se ubica la imagen a descargar dentro del repositorio de Docker. Para saber cuál es la ruta que hay que indicar, es preciso consultar previamente la documentación de la imagen que queremos descargar. Ver : https://hub.docker.com/r/atlassian/jira-software
  • restart: Con este comando indicaremos a Docker que en caso de que éste se reinicie, que también reinicie los contenedores que tenga asociados. Solamente reiniciará aquellos contenedores cuyo valor en este parámetro sea "always".
  • networks: Aquí indicaremos el nombre de la red sobre la cual vamos a aplicar el nuevo contenedor.
  • volumes: La sintaxis es la siguiente <nombre_volumen>:<path_volumen> donde <nombre_volumen> será el nombre que le daremos al volumen y <path_volumen> será el path físico en el disco virtual donde se ubicará la aplicación. Este path se puede consultar en la documentación de la imagen. Ver: https://hub.docker.com/r/atlassian/jira-software
  • ports: Se especifica el/los puerto/s donde ejecutaremos la aplicación. Si bien en la documentación figuran unos puertos específicos, éstos se pueden modificar. Importante sobre todo destacar que en el caso de generar más de una aplicación verifiquemos que no existe conflicto de puertos. De ser así deberemos volver a generar los contenedores afectados.
  • environment: Especificaremos el entorno de configuración de la aplicación a instalar. Este parámetro es opcional ya que pueden existir aplicaciones cuya configuración no es precisa, sin embargo, para este caso sí es necesaria e indicaremos la base de datos sobre la cual vamos a operar y estableceremos la memoria mínima y máxima sobre la cual se ejecutará el contenedor.
  • logging: También es opcional y estableceremos la configuración de logs.
volumes:  
  jiradata:
    external: false    
  databasedata:
    external: false

Bajo el elemento volumes incluiremos todos los nombres de los volúmenes que hemos indicado en todo el fichero YAML. Con el parámetro "external" estamos indicando que el volumen NO se ha creado en otro fichero Compose, sino que se ha creado dentro de éste mismo. En caso de indicar "external" true, Docker no creará el volumen y en caso de no existir, dará un error por elemento no existente.

networks:  
  devnetwork:
    driver: bridge

En este apartado incluiremos la definición de la red sobre la cuál crearemos el o los contenedores.

Ejecución de un fichero Compose. Gestión del contenedor

Una vez tenemos generado el fichero Compose, lo ejecutaremos de la siguiente manera:

1) Abrir ventana CMD e ir al directorio donde tenemos guardado el fichero. Ejecutar la siguiente sentencia:

docker-compose -f <nombre_del_fichero.yml> up  

Con el comando "up" estamos indicando a Docker que queremos construir y generar todos los elementos que tenemos definidos dentro del fichero de configuración. Si no existe ningún error dentro del fichero, empezará a descargar la imagen del repositorio de Docker, si ésta no existe, creará el contenedor, el volumen y comenzará a instalar a la aplicación.

En pantalla podremos ir viendo todos los logs generados:

Una vez arrancado, podremos acceder a través del puerto configurado a la aplicación. La primera vez aparecerá la pantalla de configuración inicial de JIRA. Una vez configurado se nos presentará directamente la pantalla de Login.

Si queremos consultar la memoria que está utilizando cada contenedor que tenemos arrancado en ese preciso momento, ejecutaremos el comando:

docker stats  

Y nos aparecerá una pantalla como la siguiente:

Este comando nos será muy útil para determinar con exactitud cuánta memoria está consumiendo cada contenedor (aplicación) y así poder configurar el Docker Desktop en Settings con la memoria correcta. Como podemos ver en la imagen, JIRA está consumiendo alrededor de 1,5Gb con lo que está dentro de los límites 1Gb - 2Gb que hemos determinado dentro del apartado "environment" en el fichero compose.

Ejecutando el comando :

docker ps -a  

Veremos la totalidad de contenedores que tenemos y si éstos están arrancados "Up" o parados "Exited".

Si quisiéramos arrancar el contenedor de Jira, ejecutaríamos el comando :

docker container start jira_container  

Y si quisiéramos pararlo, ejecutaríamos:

docker container stop jira_container  

Para inspeccionarlo, ejecutaríamos:

docker container inspect jira_container  

Y nos aparecería la configuración del contenedor en formato JSON:

Para borrar el contenedor, ejecutaríamos:

docker container rmi jira_container  

Esto solamente borra el contenedor, por lo que si quisiéramos eliminar todo lo relacionado con JIRA deberíamos ejecutar los siguientes pasos:

1) Parar el contenedor
2) Eliminar el contenedor
3) Eliminar el volumen
4) Eliminar la imagen
5) Eliminar la red (si procede, es decir, solamente si no es compartida con más contenedores).

Conclusión

A modo de resumen, las ventajas de utilizar Docker son diversas. La más importante si cabe es la posibilidad de poder crearnos entornos virtualizados, que podremos tener arrancados a petición, sin tener que tener instalada la aplicación en disco físico con su servicio Windows correspondiente. Si, por ejemplo, tenemos una aplicación dockerizada y no la vamos a utilizar más, bastará con borrar su contenedor, volumen e imagen asociada, evitando así que la desinstalación pueda dejar residuos de ficheros temporales y no utilizados en nuestro dispositivo.

Si te ha gustado, ¡síguenos en Twitter para estar al día de nuevas entregas!