Para aprender a utilizar Docker Compose, la documentación oficial es el mejor recurso debido a la gran cantidad de casos de uso y ejemplos sobre directivas disponibles. Sin embargo, esta guía te enseñará a crear aplicaciones multicontenedor con Docker Compose para recordar los conceptos que detallamos en el artículo anterior y agregar otros. Aunque emplearemos Django y PostgreSQL para ilustrar, los mismos conceptos te serán de utilidad si decides usar otro stack.
Antes de comenzar
- Asegúrate de instalar Docker y crear un contenedor en Ubuntu 20.04 y de hacer lo mismo con Docker Compose.
- Agregar una regla en el cortafuegos de Donweb que permita el tráfico entrante a los puertos 8000 y 5432 de TCP. Este último solamente es necesario para hacer consultas a la base de datos PostgreSQL desde un cliente externo, luego de lo cual te aconsejamos cerrarlo. En el artículo Firewall de la sección de ayuda encontrarás las instrucciones para completar este punto.
Crear un Dockerfile y el archivo docker-compose.yml
Como primer paso, crea un nuevo Dockerfile con el siguiente contenido:
nano Dockerfile
FROM python:3
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/
El archivo requirements.txt al que hacemos referencia arriba también debe estar en el mismo directorio que el Dockerfile, de acuerdo a la ruta que especificamos. Créalo y agrega el contenido que aparece a continuación:
nano requirements.txt
Django>=3.0,<4.0
psycopg2>=2.8
django-environ==0.8.0
Finalmente, agrega el archivo para Docker Compose:
nano docker-compose.yml
con estas directivas:
version: "3"
services:
db:
image: postgres
ports:
- "5432:5432"
volumes:
- ./data/db:/var/lib/postgresql/data
environment:
- POSTGRES_NAME=${DB_NAME}
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
web:
build: .
command: bash -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
networks:
default:
name: webinar-compose
En el apartado siguiente veremos el contenido del archivo YAML con más detenimiento.
Directivas y variables de entorno
Además de version
, services
, image
, ports
y volumes
(que ya conoces), en docker-compose.yml encontrarás algunas nuevas:
command
es el comando que se correrá durante la construcción de la imagen. En este ejemplo, estamos ejecutando las migraciones del proyecto de Django para crear la base de datos y llenarla.build
indica el contexto para la construcción de la imagen. El punto que aparece aquí indica que este archivo se encuentra en el mismo directorio y que tiene ese nombre. De cualquier forma, también puedes colocarlo en otra ubicación. Para eso, deberías emplear las directivascontext
para indicar la ruta ydockerfile
para especificar el nombre. La documentación muestra varios ejemplos de este punto.depends_on
indica la dependencia que un servicio o contenedor tiene de otro. En este caso, web depende de db, lo que hace que Docker Compose inicie primero este último (o lo detenga si es lo que deseas luego).environment
se require para poder usar variables de entorno en Docker Compose. Si bien es posible agregarlas en texto plano en docker-compose.yml, es más prudente emplear variables de entorno del sistema operativo o emplear un archivo .env. La sintaxis${VARIABLE}
hace que Docker Compose incluya la variable correspondiente antes de levantar el servicio en cuestión.
Teniendo en cuenta que ya mencionamos las variables de entorno, agrega las siguientes en el archivo .env dentro del directorio actual:
nano .env
DB_NAME=postgres
DB_USER=postgres
DB_PASSWORD=postgres
Recuerda guardar los cambios antes de continuar.
Crear un proyecto inicial de Django
El comando docker-compose run
seguido del nombre de uno de los servicios definidos en docker-compose.yml levanta ese contenedor. A continuación, ejecuta django-admin startproject guiadonweb .
en este. También creará el directorio guiadonweb ya que estamos utilizando bind mounts, el cual incluirá el esqueleto del proyecto de Django.
sudo docker-compose run web django-admin startproject guiadonweb .
Los archivos que generó el comando anterior son propiedad de root, por lo que modificaremos el dueño y el grupo:
sudo chown -R $USER:$USER .
La razón por la que django-admin
generó recursos propiedad de root es que el contenedor corre como esa cuenta por defecto. Esto es un punto a mejorar en lo que a seguridad se refiere, por lo que lo abordaremos de forma integral en un próximo artículo.
Conectar la base de datos
Para cumplir con este objetivo, localiza las secciones ALLOWED_HOSTS y DATABASES dentro del archivo guiadonweb/settings.py y haz los cambios que detallamos abajo. Estos te permitirán acceder a la aplicación desde afuera del contenedor y cambiarán la base de datos por defecto (SQLite) por PostgreSQL. Para efectuar la conexión, emplearán las variables de entorno que definiste en el archivo .env. Asegúrante de cambiar IP DEL VPS AQUÍ por la dirección de tu host tal como aparece en la lista de servicios dentro de tu cuenta Donweb.
nano guiadonweb/settings.py
ALLOWED_HOSTS = ['IP DEL VPS AQUÍ']
import os
import environ
env = environ.Env(
# set casting, default value
DEBUG=(bool, False)
)
# Take environment variables from .env file
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': env('DB_NAME'),
'USER': env('DB_USER'),
'PASSWORD': env('DB_PASSWORD'),
'HOST': 'db',
'PORT': 5432,
}
}
En el bloque de arriba, 'HOST': 'db'
representa el servicio que definiste en el archivo .yml.
Ejecutar el stack
Luego de guardar el archivo settings.py, levanta el stack completo:
sudo docker-compose up
Como resultado, podrás acceder a la pantalla inicial del proyecto a través de un navegador web:
Para finalizar, con sudo docker container ls
puedes verificar el listado de los contenedores actuales:
Cuando desees detener la aplicación utiliza sudo docker-compose down
desde otra terminal.
Para terminar
En esta guía aprendiste los conceptos necesarios para desarrollar aplicaciones multicontenedor con Docker Compose. La gran ventaja de partir desde una imagen propia puedes adaptar cada servicio según tu gusto y necesidades. Si bien en este artículo utilizamos Django y PostgreSQL, los principios que hemos detallado se aplican a cualquier conjunto de componentes que puedas imaginar.