Docker en DAW
Uso de docker en DAW
Virtualización: introducción
Virtualización tradicional
Es una abstracción de la capa de hardware
Despliegues más sencillos
Ahorro costes
Aislamiento
...

Hypervisor
Es un monitor que orquesta el acceso de varios SO a los recursos de un servidor físico.
Hypervisor type 1
Nativo o Bare Metal Hypervisor
Corre directamente en el hardware de la máquina, hacen la función de HAL (Hardware Abstraction Layer)
Ej: VMWare ESXI, Microsoft Hyper-V, Citrix/Xen Server
Hypervisor type 2
Host OS Hypervisor.
Corre sobre el sistema operativo, como una aplicación más.
Ej: VMware Workstation, VMware Player, VirtualBox, Parallel Desktop (MAC), ¿KVM?
No es adecuado cuando hay un workload elevado: Active Directory, bbdd...
Adecuados para entornos de test
Más baratos
Instalación más sencilla
Contenedores
Son una abstracción de la capa de aplicación

Ventajas contenedores
Más ligeros
Portabilidad
Contrato entre el sysadmin y el developer
Despliegues más rápidos
Mas eficientes -> menor coste
Son efímeros
Desventajas
Menor seguridad y aislamiento
Depende del host
Snapshots
Migraciones en caliente (VMWare vMotion)
Son efímeros
Google Trends

Docker
Qué es Docker
Herramienta open-source que nos permite realizar una virtualización ligera, con la que poder empaquetar entornos y aplicaciones que posteriormente podremos desplegar en cualquier sistema que disponga de esta tecnología
Objetos de Docker
Los objetos principales en Docker son las imágenes, los contenedores y los servicios
Hay otros conceptos relacionados con ellos como volúmenes, registro de imágenes que los veremos conforme los necesitemos.
Imagen
Plantilla que define todas las dependencias de mi aplicación
Es habitual que las imágenes se creen en base a otras (herencia)
Ejemplo:
FROM ubuntu
MAINTAINER username (email@domain.com)
RUN apt-get update
RUN apt-get install -y nginx
CMD ["nginx", "-g", "daemon off;"]
EXPOSE 80
Contenedor
Instancia ejecutable de una imagen
Son efímeros, la persistencia se logra mediante el uso de volúmenes
Cada contenedor se ejecuta en un entorno aislado (podemos controlar el nivel de aislamiento):
variables de entorno
Volúmenes montados
Interfaces de red
Podemos crear una imagen a partir de un estado del contenedor.
Servicios
Los servicios permiten escalar contenedores a través de múltiples demonios de Docker, los cuales trabajarán conjuntamente como un enjambre (swarm).
Desarrollo en Docker
Un contenedor -> Un proceso
Mejor escalabilidad
Mejor reutilización
Actualizaciones
Docker en Linux (I)
En Linux Docker no es virtualizado, no hay un hipervisor.
Los procesos que corren dentro de un contenedor de docker se ejecutan con el mismo kernel que la máquina anfitrión.
Docker en Linux (II)
Linux aisla los procesos, ya sean los propios de la máquina anfitrión o procesos de otros contenedores.
Controla los recursos que se le asignan a contenedores pero sin la penalización de rendimiento de los sistemas virtualizados.
Docker en Windows
Actualmente docker puede usarse en Windows
De las múltiples maneras posibles, la mejor es Docker Desktop
Windows puede crear contenedores Windows o contenedores Linux, pero no simultaneamente. Debemos decirle si vamos a usar contenedores de un tipo u otro.
El uso de contendeores linux requiere instalar LSW, Linux Subsystem for Windows. Es decir, poner un kernel linux a disposición de docker.
Instalación
Dejo estas notas aunque no explicamos nada. Nosotros ya tenemos instalado docker.
Versiones de Docker
Hasta el 2019 había dos productos:
Docker Enterprise Edition
Docker Community Edition
La versión Enterprise la compró la empresa Mirantis
Nos centraremos en la versión libre, que es la única a la que hace referencia ahora la web de Docker
Tipos de instalación
Ir a la web de Docker
Se puede instalar el Docker Desktop en Windows
Se puede instalar el Docker Engine en Linux
Se puede desplegar una imagen mediante Vagrant que tenga todo
Se puede usar una OVA.
Instalación en Linux
Lo más usual es usar imágenes basadas en Linux https://docs.docker.com/engine/install/ubuntu/
El proceso habitual de instalación es:
Añadir el repositorio de docker
Instalar Docker Engine
Configurar usuarios para uso de docker (sin privilegios root). Ver Linux PostInstall
Instalar Docker Compose
Trabajar con Docker
Utilizaremos la terminal (cliente docker)
Utilizaremos Visual Studio Code
Terminal integrada
Extensión Docker
Debug dentro de contenedores
Comandos básicos
Contenedores
Ejecutar un contenedor nuevo:
docker run
docker container run
Iniciar un contenedor existente:
docker start
docker container start
Parar un contenedor:
docker stop
docker container stop
Borrar contenedor
docker rm
docker container rm
Inspeccionar contenedor
docker inspect
docker container inspect
Ejecutar comando en un contenedor:
docker exec
docker container exec
Ver logs:
docker logs
docker container logs
Imágenes
Ver listado de imágenes
docker images
Borrar una imágen
docker rmi
Descargar imágen:
docker pull
Publicar imágen:
docker push
Descargar imágenes
Traemos la última versión de la imagen de redis:
docker pull --help
docker pull redis
Listado de imáges locales
docker images
Aparecen datos útiles:
Órigen de la imágen
Versión
Tamaño que ocupa
Fecha de creación
Ejecución imágen (I)
Recordemos que una imagen en ejecución es un contenedor
docker run redis
docker ps
CTRL + D para pararlo y podemos comprobar que ya no está
Ejecución imagen (II)
Mejor ejecutar en modo detached:
docker run -d redis
docker stop <container-id>
Si queremos arrancarlo de nuevo (no sabemos id)
docker ps -a
docker start <container-id>
Configuración de redes
Por defecto, no es necesario especificarlo. Los contenedores se comunican entre sí.
Son las más utilizadas
Déjemos que docker se encargue de todo :-)
Ejecutar comandos:
ip address docker network ls docker network inspect bridge

Debug de un contenedor
La forma más evidente es entrar a la terminal del contenedor:
Variables de entorno
Estructura ficheros
pocos comandos disponibles!
docker exec -it <name or container-id> /bin/bash
Ejercicio
Comprueba que efectivamente los contenedores se pueden comunicar entre sí.
Ejercicio - solución
Accede al fichero /etc/host de cada contenedor para ver su ip
Haz un ping entre contenedores
docker exec -it <container-name> /bin/bash apt update apt install iputils-ping # para ver la ip también podíamos haber utilizado el comando ip # apt install iproute2 # ip address ping <ip-container>
Logs de un contenedor
docker logs <name or container-id>
Los contenedores tienen un nombre aleatorio, pero se puede dar de forma explícita:
docker run -p5000:6379 --name redis-new -d redis
docker run -p5001:6379 --name redis-old -d redis:4.0
Ejercicio
Comprueba el estado de imágenes y contenedores de tu equipo
Elimina todas las imágenes
Elimina todos los contenedores (también los parados)
Solución
Estado actual:
docker ps docker ps -a docker images
Borrar imágenes:
docker rmi $(docker images -a -q)
Borrar contenedores:
docker rm $(docker ps -a -q)
Ejercicio
Descarga redis:latest y comprueba su versión
Descarga esa versión específica (redis:x.y.z)
Comprueba que tienes dos imágenes al hacer un listado pero que:
Ambas ocupan el mismo tamaño
Son idénticas:
Mismo IMAGE ID
No se ha producido ninguna descarga de layers adicionales.
Solución
Ejecutar contenedor latest y ver versión
docker run --name redis-new -d redis docker inspect redis-new|grep -i version docker exec -it redis-new env
Descargar versión actual y comprobar que ambas son idénticas
docker pull redis:6.2.5 # en mi caso docker images
Versiones imágenes
No es aconsejable utilizar imágenes con etiqueta latest
Se pueden producir breaking changes
No está claro el versionado de la imágen.
Docker Hub
Registros de imágenes
Podemos crear una imagen de cero pero lo normal es usar o partir de una ya creada.
Hay un registro oficial de imágenes proporcionado por Docker: Docker Hub
También podemos crear nuestro propio servicio.
¿Qué es Docker hub?
Un repositorio de imágenes: descarga y publicación.
Repositorio de imágenes oficiales de Docker, de alta calidad.
Repositorio de imágenes verificadas publicadas por terceros.
¿Que más ofrece?
Gestor de equipos y organizaciones: acceso a repositorios privados.
Autobuilds: crea nuevas versiones de imágenes en base a cambios en repos de Github/Bitbucket
Webhooks: Ejecuta acciones después para integrar DockerHub con otros servicios
Limitaciones descargas
Desde final del 2020 Docker impuso limitaciones en el uso de su registro.
100 descargas de imágenes cada 6 horas para usuarios anónimos (por IP)
200 descargas de imágenes cada 6 horas para usuarios autenticados
Cuentas pro y team para aumentar los límites.
Conclusión: ¡¡¡Debemos hacer docker login!!!
Autenticación
Crear cuenta en Docker Hub
Hacer login desde consola
docker login
Se crea un fichero de configuración en $HOME/.docker/config.json
Las siguientes veces que nos autentiquemos, al hacer docker login leerá directamente el fichero
Observa que si cerramos la sesión la entrada auths del fichero config.json queda vacía
Workflows
Si queremos un repositorio compartido entre varios usuarios necesitamos crear una organización
Desde Junio 2021 los autobuilds son de pago
Si usamos GitHub podemos usar GitHub Actions
Nuestro propio registro
Docker viene configurado por defecto para buscar las imágenes de Docker Hub
Es posible usar nuestro propio registro:
Podemos usar la misma implementación vanilla del Docker registry que usa Docker Hub
Otros más avanzados como Harbor (Open Source, era VMWare), Artifactory (JFrog), Nexus (Sonatype), etc.
Otros registros
Docker también ofrece una versión enterprise de su registro llamada Docker Trusted Registry (DTR)
Google Container Registry (GCR), Amazon Elastic Container Registry (ECR), Azure Container Registry (ACR), Quay (Redhat, versión On-Prem y versión cloud), Gitlab Container Registry, Github Packages, etc.
Repositorios
Pueden ser públicos o privados (1 gratis)
Se crean desde Docker Hub
Cada repo puede tener una o varias imágenes, en función de la tag
Las imágenes se publican mediante el comando
docker push <hub-user>/<repo-name>:<tag>
Se pueden consultar mediante
docker search <keyword>
Lo más habitual es hacerlo vía web, no con consola
Prácticas DockerHub
Práctica 1
redis y redis-commander dockerizados
Evitamos problemas de dependencias
las máquinas host se quedan "limpias"
redis-comander
Paquete de npm para acceder a Redis desde el navegador
Instalación:
Debemos instalar nodejs, la versión de la distribución de Ubuntu es antigua (v10)
Instalamos usando el PPA oficial
sudo curl -sL https://deb.nodesource.com/setup_14.x -o nodesource_setup.sh
sudo bash nodesource_setup.sh
sudo apt-get install -y nodejs
node --version
sudo npm i -g redis-commander
redis-commander
Comunicación entre contenedores
Queremos que se comuniquen entre sí utilizando redes bridge:
default: las que utilizabamos hasta ahora
user defined:
Interacionan solo los contenedores definidos en esta red
Hay resolución de nombres
User defined vs default bridge


Buscar imagen en Docker Hub
Opciones
Construir nuestra propia imagen (todavía no sabemos)
Utilizar una imagen ya preparada en Docker Hub:
Menos propenso a errores
Más rápido
Modificar una imagen ya preparada:
¿Dockerfile? ¿FROM?
User defined network
Creación de red:
# docker network rm my-net
docker network create my-net
Uso de red:
docker create --name my-nginx \
--network my-net \
--publish 8080:80 \
nginx:latest
Solución
docker network create redis-net
docker run --rm --name redis --network redis-net -d redis
docker run --rm --name redis-commander --network redis-net -d \
--env REDIS_HOSTS=redis \
-p 8081:8081 \
rediscommander/redis-commander:latest
Comprueba que efectivamente funciona (docker log)
Entra a uno de los dos contenedores y comprueba el ping por name
Práctica 2
Monta un escenario como el anterior con MySQL o MariaDB y phpMyAdmin
Práctica 3
Comprueba las versiones de imágenes de httpd
¿Vía web?
¿Vía docker search?
Práctica 3 - opciones
docker search no nos sirve
Vía web aunque es algo "laborioso"
Prueba y error con la versión que queremos
Usando hub tool
hub-tool tag ls <repo-name>
Práctica 4
Ejecuta una imagen 2.2 de Apache en DockerHub y modifica el index.html para que aparezca HolaMundo
¿Cómo has modificado el index.html?
Práctica 4 - opciones
Instalando en el contenedor un editor y entrando mediante:
docker exec -it <container> bash
Mediante el comando cp de Docker
Mediante el plugin Docker de Visual Studio Code (lo más sencillo)
Práctica 5
Imagina que hay un bug importante en Apache que está arreglado en la versión 2.4
Actualiza la versión de nuestra aplicación HolaMundo anterior a Apache2.4
Práctica 5 - opciones
Las dos opciones más adecuadas serían:
Generar una nueva imagen de nuestra aplicación
No sabemos hacerlo todavía
Realmente tampoco lo habíamos hecho, utilizabamos directamente la imagen de Apache
Buscar persistencia de algún modo en nuestro contenedor efímero.
Usámos volúmenes o bind-mounts
Volúmenes
Docker gestiona el volumen de forma transparente
docker-volume ls
docker volume rm <volume-id>
docker volume inspect <volume-id>
Ejemplo con nginx:
docker run -d --name=nginx -v nginx-vol:/usr/share/nginx/html nginx:latest
Bind mounts
El volumen se mapea a un directorio físico acccesible no solo por Docker.
Si el directorio no existe, se crea.
docker run -d --name=nginx -v ./nginx-web:/usr/share/nginx/html nginx:latest
Construcción imágenes en Docker (1)
Objetivos
Aprender a crear ficheros Dockerfile
Aprender a crear y publicar imágenes
Entender el concepto de layers en imágenes.
¿Qué es un dockerfile?
Plantilla en texto plano que define las dependencias de mi aplicación y la imagen.
Cada línea del fichero Dockerfile contiene una serie de comandos que generan una capa en la imágen
Se ejecutan de manera secuencial
Existe una caché que funciona por cada línea o capa.
Es habitual que las imágenes se creen en base a otras (herencia)
Concepto de capas
Una imágen es un conjunto de capas de solo lectura, generadas por el Dockerfile
¿Qué es un contenedor?
Una imagen en ejecución
Una imágen con una capa de lectura/escritura encima del resto de capas llamada container layer
Cualquier cambio que hagamos en un contenedor, se lleva a cabo en la container layer
Ejemplo
Vamos a crear una imagen que visualice el contenido de un fichero al ejecutar el contenedor
Crea un directorio y coloca un fichero holaMundo.txt con el texto ¡Hola Mundo!
Crea un fichero Dockerfile en el mismo directorio con el siguiente contenido:
FROM ubuntu:latest
RUN mkdir -p /app
COPY holaMundo.txt /app/holaMundo.txt
RUN chmod 600 /app/holaMundo.txt
CMD cat /app/holaMundo.txt
Creamos la imagen y etiquetamos:
docker build -t <dockerHubUserName>/holaMundo .
docker tag <dockerHubUserName>/holaMundo:1
docker tag <dockerHubUserName>/holaMundo:1.0
docker tag <dockerHubUserName>/holaMundo:1.0.0
docker image ls
Ejecutamos la imagen:
docker run <dockerHubUserName>/holaMundo
Subimos la imagen con todas sus tags
docker push -a <dockerHubUserName>/holaMundo
Análisis Dockerfile
FROM nos sirve para partir de una imagen previa
RUN: ejecuta comandos
COPY: copia ficheros de nuestro contexto a la imagen
CMD: Ejecuta un comando al iniciar el contenedor
Más info en las referencias de Dockerfile
Explorar capas
Podemos ver las capas también mediante docker inspect y docker history
No todos los pasos generan una nueva capa, algunos comandos solo alteran configuración (CMD, ENV, ENTRYPOINT, EXPOSE, etc.).
La herramienta Dive nos sirve para explorar con más detalle las capas de las imágenes de Docker https://github.com/wagoodman/dive
Cache
Las líneas del Dockerfile en principio se cachean
Si se produce un MISS ya no se usa más caché en esa compilación
Escribir las líneas más "frecuentes primero"
Si hay líneas "con dependencias", ej apt-get update y apt-install juntas.
Si no queremos caché (ni para FROM image):
docker build --no-cache --pull -t myApp .
PRACTICAS IMÁGENES
PRACTICA 1
Crea una imagen que se base en Ubuntu y que permita:
Editar ficheros con vim
Ejecutar el comando ping
Solución
Observa el -y para evitar la parte interactiva del comando apt-get install
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -y vim iputils-ping
Comprueba con dive los recursos utilizados
docker build -t test .
dive test
Mejor solución
FROM ubuntu:latest
RUN apt-get update && apt-get install -y --no-install-recommends \
vim \
iputils-ping \
&& rm -r /var/lib/apt/lists/*;
¿Qué falla aquí?
FROM ubuntu:latest
RUN apt-get update && apt-get install -y --no-install-recommends \
vim \
iputils-ping
RUN rm -r /var/lib/apt/lists/*; \
PRÁCTICA 2
Crea una imagen a partir de las instrucciones del ejercicio anterior (vim + ping) pero con el comando docker commit
Verifica la imagen (capas y tamaño)
PRÁCTICA 3
Vamos a crear una versión v2.0 de nuestro holaMundo, que en vez de coger el fichero de local lo coja de una URL mediante el comando ADD
Compila la imagen y ejecútala
Cambiaremos los datos del fichero apuntado por la URL
Compila de nuevo la imagen y ejecuta otra vez
¿Qué pasa? ¿Comó lo solucionas?
Construcción imágenes en Docker (2)
Almacenamiento
En docker, las imágenes se construyen a base de capas
Cada capa contiene únicamente las diferencias respecto a la capa padre.
Docker utiliza mecanismos de union filesystems para montar en una carpeta la combinación de las distintas capas.
Almacenamiento
Al crear un contenedor, Docker añade una capa adicional (la capa de contenedor), que es la única sobre la que es posible escribir.
El contenedor modifica aparentemente la imagen base, como si tuviera una copia real, pero únicamente está modificando esta última capa.
Podemos crear múltiples contenedores sobre una misma imagen, reutilizando todas las capas excepto la capa de contenedor.
Al destruir un contenedor, esta capa con las modificaciones se destruye.
Tamaño de las imágenes
Borrar un archivo en un paso del Dockerfile no elimina ese archivo de las capas anteriores de la imagen.
El archivo sigue presente, pero no es accesible desde el contenedor.
Es la forma de comportarse de los union filesystems
FROM ubuntu RUN apt-get install alguna-herramienta RUN algo-que-utiliza-la-herramienta para compilar o hacer algo RUN apt-get remove alguna-herramienta
Build Context
Al hacer un build se envían al daemon docker los ficheros de la ruta especificada como contexto:
# En este caso el contexto es ".", el directorio actual:
$ docker build -t myimage -f Dockerfile .
Es recomendable usar una carpeta separada para almacenar el contexto.
Podemos crear un fichero .dockerignore
# contexto vacío, si no necesitamos añadir ficheros al contenedor, mediante "-"
docker build -t myimage -f Dockerfile -
Tipos de imágenes
Used: Las que aparecen al hacer un docker ps -a
Unused: Las que no aparecen (se usaron en su momento pero se ha borrado el contenedor)
Dangling images: Imágenes que se crean sin nombre, y se muestran como <none>.
Útil cuando estamos haciendo pruebas de compilación
Gestión de espacio
Conforme vamos usando docker, descargando imágenes... empezamos a ocupar espacio
Comprobar el espacio usado:
docker system df
Eliminación de imágenes:
docker system prune -a # unused y dangling images
docker system prune # dangling images
Multistage builds
Se crea la primera imagen que sirve para obtener lo que se usa en el segundo stage (ver --from=n)
Todo lo que no se usa queda fuera del último stage que es el definitivo
Útil para entorno de compilación
Se reduce el tamaño final de la imagen al quedarnos solo con el ejecutable
Ejemplo multistage
# syntax=docker/dockerfile:1
FROM golang:1.16
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go ./
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app ./
CMD ["./app"]
Docker Compose
Qué es Docker Compose
Herramienta para definir y ejecutar aplicaciones con varios contenedores Docker.
Se definen los contenedores (servicios) de la aplicación mediante un fichero YAML.
Se levantan mediante el comando
docker-compose up
Prueba de uso
Vamos a analizar un caso sencillo con 3 contenedores:
web server con php
db con MySQL
phpMyAdmin
Clona este repositorio
Docker-compose con Image
Óptimo para producción, más rápido que un build y todo empaquetado
Crea una imagen de Apache con un HolaMundo
Ejecútala mediante docker-compose.yml
Proxy inverso
Para dar un servicio externo, en web el puerto es el 80
¿Cómo hacemos para que los servicios anteriores funcionen todos en el 80?
Proxy inverso en función de la url
Similar a un virtual host de apache pero que se configura solo en función de las peticiones que le llegan al docker daemon
Usaremos nginx-proxy o traefik
Práctica ODOO
Seleccionar en DockerHub una imagen de Odoo
Desplegar la imagen con la bbdd adecuada como servicios (usando docker-compose.yml)
Práctica Dolibarr
Seleccionar en DockerHub una imagen de Dolilbarr
Desplegar la imagen con la bbdd adecuada como servicios (usando docker-compose.yml)
Práctica Wordpress
En la web de Docker hay ejemplos de Wordpress, Django o Rails
Mooodle
Problema de espera entre contenedores
Una buena forma es usar dockerize
Instalación:
RUN curl -o dockerize.tar.gz -fSL "https://github.com/jwilder/dockerize/releases/download/${DOCKERIZE_VERSION}/dockerize-linux-amd64-${DOCKERIZE_VERSION}.tar.gz"; \
tar -xf dockerize.tar.gz -C /usr/local/bin; \
rm dockerize.tar.gz
crontab
¿Añadir un servicio de crontab a nuestro contenedor?
¡¡¡no!!! Filosofía docker: 1 contenedor = 1 servicio
Podemos crear un crontab en el host con comandos como:
docker exec -it <containerId> <command> docker run --rm <containerId> <command>
Usar soluciones ya preparadas: Ofelia
Práctica copias de seguridad
Propongo uso de rsnapshot
rsync para hacer instantáneas con hard links
Interfaz gráfico para su gestión
Y para hacer deploy en Docker
¿Existe esto?
Monitorización
Visión general


Datos en docker
Ver uso contenedores
docker stats --no-stream
Procesos en ejecución
docker top <container_id>
Consultas al demonio de docker
Consultas específicas por contenedor
docker exec -it <container-id> top
Configuraciones intrínsecas a los servicios (por ej. mod_status en Apache)
Gestión de la memoria
El kernel si no tiene suficiente memoria arroja un OOME (Out of memory exception).
Empieza a matar procesos para liberar memoria
Puede tirar todo el sistema si mata el proceso equivocado (por ej. el demonio de Docker)
Docker ajusta la prioridad de OOM del demonio para reducir la probabilidad de recibir un kill.
Gestion de memoria de los contenedores
La prioridad de los contenedores no se debe ajustar.
El host debe tener suficiente memoria
Para evitar errores se debe limitar el uso de memoria de los contenedores
Ejemplo configuración
La configuración cambia bastante entre versiones de docker-compose
services:
service:
image: nginx
deploy:
resources:
limits:
cpus: 0.50
memory: 512M
reservations:
cpus: 0.25
memory: 128M
Workflow con docker
Desarrollo con Vagrant
Buena opción si trabajamos en equipos Windows y no queremos preocuparnos de despliegues
Descargamos Vagrant
Configuramos Vagrant (ver después) o hacemos un git clone de https://github.com/juanda99/vagrant-deploy-virtualbox-docker
Configuración Vagrant-Virtual Box
Nos situamos en un directorio e inicializamos mediante
vagrant init
Modificamos el fichero Vagrantfile creado con algo como:
# Every Vagrant development environment requires a box. You can search for # boxes at https://vagrantcloud.com/search. #config.vm.box = "base" config.vm.box = "bento/ubuntu-20.04" config.vm.network :forwarded_port, host: 8000, guest: 8000 # require plugin https://github.com/leighmcculloch/vagrant-docker-compose config.vagrant.plugins = "vagrant-docker-compose" # install docker and docker-compose config.vm.provision :docker config.vm.provision :docker_compose, yml: "/vagrant/docker-compose.yml", rebuild: true, run: "always"
Añadimos servicios mediante docker-compose cuyo punto de entrada se mapee al host en el 8000
Workflow en local

Workflow global

Development
CI/CD
Deployment
Last updated
Was this helpful?