Guía paso a paso para aprender Docker Compose

Si trabajas con Docker, escribir comandos para cada acción no es nada práctico, y a veces puede convertirse en una pesadilla cuando un error tipográfico rompe el proceso y te obliga a ejecutar todo de nuevo.
Hoy aprenderemos cómo Docker Compose hace que nuestra experiencia con Docker sea fácil y entretenida.
El contenido de este artículo incluye:
-
¿Por qué usar Docker Compose?
-
Cómo crear un archivo docker-compose.yml.
-
Automatizar la construcción de imágenes y variables de entorno.
-
Orquestar y comunicar contenedores con Docker Compose (agregando puertos, volúmenes y redes).
-
Solución de problemas con logs de contenedores y acceso a la shell.
La idea es mover todos nuestros comandos y tareas cotidianas desde la terminal de Docker hacia Docker Compose usando un archivo docker-compose.yml, acelerando nuestra productividad.
Si todavía no estás familiarizado con Docker, te invito a leer mi artículo anterior sobre Docker desde cero para sobrevivir.
¿Por qué usar Docker Compose?
Hoy en día, la mayoría de nuestras aplicaciones no funcionan solas. Necesitan una base de datos, un servicio de almacenamiento, una API de autenticación y otros servicios a su alrededor, donde cada uno debe convertirse en un contenedor.
Docker Compose nos simplifica la vida: realiza todo con un solo comando, ayuda a compilar imágenes y orquesta nuestros contenedores.
En resumen, Docker Compose se encarga del ciclo de vida de la aplicación y nos permite gestionar acciones de los contenedores como iniciar, detener, consultar su estado, publicar puertos y comunicarlos entre redes.
El comando docker-compose cuenta con tres opciones esenciales:
-
docker-compose build: Compila los contenedores definidos en el archivo docker-compose.yml. -
docker-compose up: Inicia los contenedores y las redes. -
docker-compose down: Detiene los contenedores y las redes.
Toda la configuración funciona gracias al archivo docker-compose.yml que está detrás, así que vamos a hablar de él.
El archivo docker-compose.yml
Al igual que con el Dockerfile, usamos el archivo docker-compose.yml, el cual tiene dos áreas principales: la versión, que define el esquema soportado, y los servicios (services), que representan las definiciones de nuestros contenedores.
La sección de servicios es el lugar donde definimos nuestros contenedores. Soporta propiedades adicionales como image, build, environment, volumes, ports, networks y más.
En los archivos YML, la indentación es fundamental y siempre debes usar espacios.
Tenemos la forma tradicional con Docker y la forma con Docker Compose: la primera requiere escribir comandos largos en la terminal, mientras que la segunda consiste en declarar la configuración dentro del archivo docker-compose.yml.
Crea un archivo docker-compose.yml con dos propiedades: version y services.
-
version: le indicamos a Docker qué versión del esquema vamos a usar. -
services: declara el contenedorweb. Además, agregamos la propiedadimagecon el valornginx.
version: '3.0'
services:
web:
image: nginxGuarda el archivo y ejecuta el comando docker-compose up para compilar, crear e iniciar el contenedor.
dany@dany:~/Documents/docker-learn$ docker-compose up
Building with the native build. Learn about the native build in Compose here: https://docs.docker.com/go/compose-native-build/
Creating docker-learn_web_1 ... done
Attaching to docker-learn_web_1
web_1 | Starting up HTTP-server, serving ./Docker Compose termina el proceso y muestra la salida directamente en la terminal.
Comandos de Docker Compose
Tenemos más opciones para iniciar, detener y monitorear nuestros contenedores.
Docker Compose acepta los siguientes parámetros:
start: Inicia contenedores sin vincularse a la terminal.
docker-compose startstart -d: Inicia un contenedor específico y se desconecta de la terminal usando la bandera -d.
docker-compose up -d web--no-deps nombre_del_contenedor: Inicia un contenedor específico sin levantar sus dependencias.
docker-compose up --no-deps webps: Muestra los contenedores activos.
docker-compose psstop: Detiene los contenedores.
docker-compose stopPuertos
Con nuestras imágenes listas, el siguiente paso es declarar puertos para acceder a los contenedores. De la forma tradicional con Docker, escribimos:
docker run -p 80:80 imagenameEn Docker Compose, agregamos la propiedad ports, por ejemplo:
ports:
- "3000:3000"Volúmenes
Para guardar datos de nuestro contenedor en nuestra máquina local, usamos volúmenes. Con Docker tradicional escribimos:
docker run -v $(PWD):/var/www imagenameEn Docker Compose, agregamos una nueva propiedad volumes indicando el directorio del host y la ruta del contenedor:
volumes:
-./logs: var/www/logsVariables de entorno
Para declarar una variable de entorno de la forma tradicional con Docker, escribimos:
docker run --env NODE_ENV=production imagenameEn Docker Compose, agregamos la propiedad environment con la lista de todas las variables:
environment:
- NODE_ENV=production
- APP_VERSION: 1.0O también podemos cargarlas desde un archivo externo:
env_file
- ./settings.env
- ./app.envRedes bridge
Necesitamos una red para comunicar aplicaciones, APIs o bases de datos. Una red de tipo bridge permite la comunicación entre contenedores.
De la forma tradicional con Docker escribimos:
docker network create --driver bridge network nameEn Docker Compose, agregamos la clave networks con el nombre y el tipo de driver:
networks:
danynetwork:
driver: bridgeUsar variables de entorno
En la mayoría de los escenarios, queremos tener contenedores para producción y para desarrollo. Podemos indicarle a Docker Compose qué compilación usar para cada entorno mediante variables de entorno.
Primero, definimos nuestra variable de entorno en la máquina en Linux o Mac usando export:
export WEB_ENV=dev
export WEB_ENV= prodEn una máquina Windows con PowerShell: bash $env:WEB_ENV = "dev". El siguiente paso es crear dos archivos Dockerfile con los nombres web.dev.dockerfile y web.prod.dockerfile.
El archivo web.dev.dockerfile usa un servidor HTTP en modo desarrollo:
FROM node:alpine
LABEL author=" Dany Paredes"
WORKDIR /var/www
COPY src/index.html .
RUN npm install http-server -g
EXPOSE 8080
ENTRYPOINT ["http-server"]El archivo web.prod.dockerfile usa nginx: yml FROM nginx LABEL author="Production" WORKDIR /usr/share/nginx/HTML COPY src/index.html . EXPOSE 80. Luego editamos el archivo docker-compose.yml en el servicio: eliminamos la clave image y agregamos la opción build para indicar el contexto y el nombre del Dockerfile.
El nombre del Dockerfile utiliza interpolación con nuestra variable de entorno, como web.${WEB_ENV}.dockerfile, y toma el valor correspondiente, por ejemplo, dev.
version: '3.0'
services:
web:
build:
context: .
dockerfile: web.${WEB_ENV}.dockerfile
networks:
danynetwork:
driver: bridgeDocker Compose toma la variable de entorno WEB_ENV durante el proceso de compilación y reemplaza el valor con el entorno configurado.
En la terminal, ejecutamos docker-compose build. Esto creará nuestros contenedores utilizando el entorno de desarrollo:
docker-compose build
Sending build context to Docker daemon 47.62kB
Successfully built f68d5cded665
Successfully tagged docker-learn_web:latestTambién podemos usar las variables de entorno en el proceso de publicación hacia Docker Hub.
Publicar en Docker Hub
Si recuerdas el proceso para publicar nuestras imágenes en Docker Hub, necesitamos indicar el usuario de Docker Hub y el nombre de la imagen.
De la forma tradicional con Docker: bash docker push dockerhubusername/imagename. Con Docker Compose, declaramos otra variable de entorno para el usuario de Docker Hub, como DOCKERHUBUSER:
export DOCKERHUBUSER=danywallsEditamos el archivo docker-compose.yml y agregamos la propiedad image con ${DOCKERHUBUSER} como parte del nombre de la imagen:
version: '3.0'
services:
web:
image: ${DOCKERHUBUSER}/web
build:
context: .
dockerfile: web.${WEB_ENV}.dockerfile
networks:
- danynetwork
networks:
danynetwork:
driver: bridgeA continuación, ejecutamos docker-compose push. Esto publica automáticamente nuestra imagen en Docker Hub:
dany@dany:~/Documents/docker-learn$ docker-compose push
Pushing web (danywalls/web:latest)...
The push refers to repository [docker.io/danywalls/web]
latest: digest: sha256:c4ac44d2e318200eeafb03cdb7e64bc60d0da52092de5bacd69e2e9de10402c0 size: 1783Solución de problemas en contenedores
A veces los contenedores fallan o necesitamos consultar los logs.
De la forma tradicional con Docker, necesitamos escribir el ID del contenedor: bash docker logs myid. En Docker Compose, aprovechamos el contexto de ejecución para mostrar los logs de todos los servicios declarados en el archivo docker-compose.yml:
docker-compose logsO también podemos elegir un contenedor específico usando su nombre: bash docker-compose logs web. Y si queremos leer las últimas cinco líneas del log: docker-compose logs --tail=5.
Acceder a la shell de un contenedor
A veces necesitamos acceder al contenedor para listar archivos o navegar dentro de él.
De la forma tradicional con Docker:
bash docker exec it container id sh. Con Docker Compose es muy similar, usando el nombre del servicio:
docker-compose exec web shResumen
Aprendimos cómo usar Docker Compose para orquestar contenedores y declarar puertos, volúmenes, variables de entorno y redes directamente en nuestros archivos de configuración.
También vimos cómo consultar logs y usar comandos de Docker Compose para iniciar, detener o listar contenedores.
Trabajar con Docker Compose simplifica nuestras tareas diarias con Docker porque tenemos todo el contexto de ejecución y de los contenedores en un solo lugar.
Foto de frank mckenna en Unsplash
Foto de David Clode en Unsplash
Explora más guías prácticas y arquitecturas reales en la serie Cloud.
Artículos Relacionados
Compartir este artículo
Si esta guía te resultó útil, compártela con tu equipo o con otros desarrolladores.
Software real. Lecciones reales.
Comparto las lecciones que aprendí por las malas, para que puedas evitarlas o estar preparado cuando ocurran.
Únete a 13,800+ desarrolladores y lectores.
Cero spam. Cancela tu suscripción en cualquier momento.