Cristian Gutierrez/Guia Docker-compose que es y como usarlo

Created Tue, 15 Feb 2022 00:19:14 +0200 Modified Fri, 05 Aug 2022 18:10:10 +0000
2346 Words Reading time 8 min

En esta guía, aprenderás todo lo que necesitas saber sobre Docker Compose y cómo puedes utilizarlo.

Con aplicaciones cada vez más grandes a medida que pasa el tiempo, se hace más difícil gestionarlas de forma sencilla y fiable. Ahí es donde entra en juego Docker Compose. Docker Compose nos permite a los developers escribir un manifiesto declarativo de configuración YAML para nuestro servicio que luego puede iniciarse utilizando un único comando.

Esta guía vamos a ver todos los comandos importantes de Docker Compose y la estructura del archivo de configuración. También se puede utilizar para buscar los comandos y opciones disponibles más adelante.

Por qué tener en cuenta Docker-compose

Antes de entrar en los detalles técnicos, vamos a discutir por qué un programador debería usar Docker-compose en primer lugar. Aquí hay algunas razones por las que los developers deberían considerar la implementación de Docker en su trabajo.

Portabilidad:

Docker Compose permite crear un entorno de desarrollo completo con un solo comando: docker-compose up, y desmontarlo con la misma facilidad usando docker-compose down. Esto nos permite a los desarrolladores mantener nuestro entorno de desarrollo en un lugar central y nos ayuda a desplegar fácilmente nuestras aplicaciones.

Pruebas:

Otra gran característica de Compose es su soporte para ejecutar pruebas unitarias y E2E de una manera rápida y repetible poniéndolas en sus propios entornos. Esto significa que en lugar de probar la aplicación en tu sistema operativo local/host, puede ejecutar un entorno que se asemeja mucho a las circunstancias de producción.

Múltiples entornos aislados en un solo host:

Compose utiliza los nombres de los proyectos para aislar los entornos entre sí, lo que aporta las siguientes ventajas:

  • Puede ejecutar varias copias del mismo entorno en una sola máquina
  • Evita que diferentes proyectos y servicios interfieran entre sí

Casos de uso comunes

Ahora que sabes por qué Compose es útil y dónde puede mejorar nuestro flujo de trabajo , echemos un vistazo a algunos casos de uso comunes.

Despliegues de un solo host:

Compose se centraba tradicionalmente en el desarrollo y las pruebas, pero ahora puede utilizarse para desplegar y gestionar todo un despliegue de contenedores en un único host.

Entornos de desarrollo:

Compose proporciona la capacidad de ejecutar nuestras aplicaciones en un entorno aislado que puede ejecutarse en cualquier máquina con Docker instalado. Esto hace que sea muy fácil de probar nuestra aplicación y proporciona una manera de trabajar lo más parecida posible al entorno de producción.

El archivo Compose gestiona todas las dependencias (bases de datos, colas, cachés, etc.) de la aplicación y puede crear cada contenedor utilizando un único comando.

Entornos de pruebas automatizadas:

Una parte importante de la integración de Continua y de todo el proceso de desarrollo es el conjunto de pruebas automatizadas, que requiere un entorno en el que se puedan ejecutar las pruebas. Compose ofrece una forma cómoda de crear y destruir entornos de prueba aislados y muy parecidos al entorno de producción.

Estructura del archivo Compose

Compose nos permite manejar fácilmente varios contenedores docker a la vez aplicando muchas reglas que se declaran en nuestro archivo docker-compose.yml.

Consta de múltiples capas que se dividen utilizando tabuladores o espacios en lugar de las llaves que conocemos en la mayoría de los lenguajes de programación. Hay cuatro cosas principales que casi todos los archivos de composición deben tener, que incluyen

  • La versión del Compose
  • Los servicios que se construirán
  • Todos los volúmenes utilizados
  • Las redes que conectan los diferentes servicios

Un archivo de ejemplo podría ser como este de caddy:

version: '3.7'
services:
  caddy:
    image: caddy
    volumes:
      - '/nuestro/directorio/local:/srv'
      - '/nuestro/directorio/local:/etc/caddy/Caddyfile'
    ports:
    - '2019:2019'
    entrypoint: caddy file-server --root /srv --browse
    restart: unless-stopped

Ahora que conocemos la estructura básica de un archivo Compose, vamos a ver los conceptos importantes.

Conceptos / Palabras clave

Los aspectos centrales del archivo Compose son sus conceptos, que le permiten gestionar y crear una red de contenedores. En esta sección, exploraremos estos conceptos en detalle y echaremos un vistazo a cómo podemos utilizarlos para personalizar nuestra configuración del Compose.

Servicios:

La etiqueta services contiene todos los contenedores que se incluyen en el archivo Compose y actúa como su etiqueta padre. Básicamente dentro de services metemos cada app que queramos levantar.

services:
  proxy:
    build: ./proxy
  app:
    build: ./app
  db:
    image: postgres

Imagen base (Build):

La imagen base de un contenedor la definimos utilizando una imagen que esté disponible en DockerHub o construyendo imágenes utilizando un Dockerfile.

Estos son algunos ejemplos básicos:

version: '3.7'

services:
    alpine:
        image: alpine:latest

version: '3.7'
services:
  caddy:
    image: caddy
    volumes:
      - '/storage:/srv'
      - '/Caddyfile:/etc/caddy/Caddyfile'
    ports:
    - '2019:2019'
    entrypoint: caddy file-server --root /srv --browse

Aquí podemos ver ejemplos de composes con imágenes de Dockerhub.

version: '3.7'

services:
  app:
     container_name: homeserver-web
     build: .
     ports:
         - '3000:3000'
    restart: unless-stopped

Para el build de esta imagen podemos definirlo en el Dockerfile, aunque lo suyo sería más bien que lo hicise nuestro CI, que genere una imagen en nuestro registry y de ahí la cogería nuestro compose.

build:
    context: ./dir
    dockerfile: Dockerfile

Puertos:

Para exponer los puertos en nuestro Compose funciona de forma similar a la del Dockerfile. Diferenciamos entre dos métodos diferentes para exponer el puerto:

Exponer los puertos que queremos para el servicio:

expose:
 - "3000"
 - "8000"

Exponiendo el puerto al host:

ports:
  - "8000:80"  # host:container

En este ejemplo, definimos el puerto que queremos exponer y el puerto del host al que debe ser expuesto.

También se puede definir el protocolo del puerto UDP o TCP:

ports:
  - "8000:80/udp"

Volumes:

Los volúmenes ses la forma que tenemos en Docker para que los datos sean persistentes. Son completamente gestionados por Docker y pueden ser utilizados para compartir datos entre contenedores y el Host:

Básicamente lo que hacemos es montar las carpetas que queramos del container en el host como si fuese un puente.

Hay varios tipos de volúmenes que se pueden utilizar en Docker. Todos ellos pueden ser definidos usando la palabra clave volumes pero tienen algunas diferencias:

Volumen “normal”:

La forma normal de utilizar los volúmenes es simplemente definiendo una ruta específica y dejando que el Engine cree un volumen para esa ruta:

volumes:
  - /var/www/html 

Mapeo de rutas:

También puedes definir el mapeo de la ruta absoluta de tus volúmenes definiendo la ruta en el host y mapeándola a una carpeta del contenedor:

volumes:
  - home/myweb:/var/www/html  # host:container

Volumen por nombre:

Otro tipo de volumen es el volumen por nombre (así al menos le he llamado yo) que es similar a los otros volúmenes pero tiene su propio nombre específico que hace más fácil su uso en múltiples contenedores. Por eso se suele utilizar para compartir datos entre varios contenedores y servicios.

volumes:
  - web:/var/www/html

Este tipo de volumes lo debemos definir posteriormente en el compose.

Dependencias:

Las dependencias en Docker se utilizan para asegurarse de que un servicio específico está disponible antes de que el contenedor dependiente se inicie. Esto se utiliza a menudo si tienes un servicio que no puede ser utilizado sin otro:

version: '2.1'
services:
  nginx:
    image: nginx
    volumes:
      - /storage/config:/config
    ports:
      - 8085:8085
    depends_on:
      - db
restart: unless-stopped
  db:
    image: mariadb
    restart: unless-stopped
    ports:
     - 3306
    environment:
      - MYSQL_ROOT_PASSWORD=yourpassword
    volumes:
     - /home/db:/var/lib/mysq

Variables de entorno:

Las variables de entorno se utilizan para introducir datos de configuración en tus aplicaciones.

Hay muchas opciones diferentes de pasar variables de entorno en nuestro Compose:

Estableciendo una variable de entorno:

Puedes asignar variables de entorno en un container utilizando la palabra “environment”, al igual que con el comando normal docker container run –environment.

db:
  environment:
    - MYSQL_ROOT_PASSWORD=yourpassword

Pasar una variable de entorno:

Puedes asignar variables de entorno desde tu shell directamente a un container simplemente definiendo una key en tu Compose y no dándole un valor:

db:
  environment:
    - MYSQL_ROOT_PASSWORD

Utilizar un archivo .env:

A veces necesitamos muchas variables de entorno y gestionarlas en el Compose es muy tedioso. Para eso están los archivos .env, donde simplemente el compose coge las variables de ese archivo.

web:
  env_file:
    - variables.env

Networks

El networking en Docker es muy importante ya que lo usamos para definir la comunicación entre los containers y con el host. Gracias a esto podemos aislar los containers y tener dos aplicaciones que funcionan de forma conjunta de forma segura.

Por defecto, nuestro Compose nos crea una red para cada contenedor; gracias a esto nos hace accesible este contenedor para que otros contenedores en la red tengan acceso a él mediante su nombre de host.

Redes personalizadas:

En lugar de utilizar únicamente la red predeterminada, también puedes especificar tus propias redes, lo que permite crear topologías más complejas y conectar diferentes containers entre sí.

Cada container puede especificar a qué redes conectarse con la variable “networks”.

services:
  app:
    build: ./app
    networks:
      - frontend
      - backend
  db:
    image: postgres
    networks:
      - backend

Para una configuración más específica podemos consultar la documentación oficial de Docker:

Configurar las redes por defecto:

En lugar de definir tus propias redes, puedes cambiar la configuración de la red por defecto definiendo una entrada con el nombre de por defecto mediante la variable “Networks” en nuestro compose:

version: "3"
services:
  web:
    iamge: nginx
    ports:
      - "8085:8085"
  db:
    image: postgres

networks:
  default:
    driver: custom-driver

CLI

Para usar docker-compose a través de la línea de comandos es muy parecido a usar docker, de hecho ya está incluido en el propio docker por lo que desde la línea de comandos podemos hacer todo:

build    Build or rebuild services 
help     Get help on a command 
kill     Kill containers 
logs     View output from containers 
port     Print the public port for a port binding 
ps       List containers 
pull     Pulls service images 
rm       Remove stopped containers 
run      Run a one-off command 
scale    Set number of containers for a service 
start    Start services 
stop     Stop services 
restart  Restart services 
up       Create and start containers
down     Stops and removes containers

Finalmente voy a poner un ejemplo de un compose de un server web de Caddy muy sencillo y de como deployearlo:

version: '3.7'
services:
  caddy:
    image: caddy
    volumes:
      - 'home/myweb:/srv'
      - '/home/myweb/Caddyfile:/etc/caddy/Caddyfile'
    ports:
    - '2019:2019'
    entrypoint: caddy file-server --root /srv --browse