This setup uses Docker Compose to create separate backend and frontend development environments, plus Redis, MySQL, Celery worker, and Celery beat services. Project files stay in the local backend and frontend folders on the host, and each development container mounts that folder to /workspace. The backend image installs Python dependencies into /opt/venv during build, while /workspace stays focused on source code.
Backend Dockerfile
This prepares an Ubuntu 24.04 based Python development image. The image installs system packages, creates a Docker-managed virtual environment at /opt/venv, installs requirements.txt into that environment, and exposes it through PATH.
The backend source code is still mounted later into /workspace by Docker Compose. This keeps source files on the host while dependencies are managed by the Docker image.
FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
RUN apt update && apt install -y \
python3 \
python3-venv \
python3-pip \
git \
curl \
ca-certificates \
build-essential \
default-libmysqlclient-dev \
pkg-config \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /workspace
COPY requirements.txt /tmp/requirements.txt
RUN python3 -m venv /opt/venv
RUN /opt/venv/bin/pip install --upgrade pip
RUN /opt/venv/bin/pip install --no-cache-dir -r /tmp/requirements.txt
ENV PATH="/opt/venv/bin:$PATH"Frontend Dockerfile
This prepares a Node.js development environment on Ubuntu 24.04. The frontend source code is mounted later into /workspace by Docker Compose.
This image installs the Node.js runtime and basic tools only. Project dependencies are normally installed and managed from inside the mounted frontend workspace.
FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && apt install -y \
curl \
ca-certificates \
git \
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt install -y nodejs \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /workspacecompose.yaml
This Compose file defines the local development stack. The backend and frontend services mount local source folders into /workspace. Redis is used by Celery as broker and result backend. MySQL stores application data. Celery worker and Celery beat use the same backend image and the same mounted backend source folder.
The backend, worker, and beat services all use the backend image dependencies from /opt/venv. No manual /workspace/.venv activation is needed.
services:
backend:
build:
context: ./backend
env_file:
- .env.dev
container_name: project-backend
working_dir: /workspace
volumes:
- ./backend:/workspace
ports:
- "8000:8000"
stdin_open: true
tty: true
depends_on:
- redis
- mysql
environment:
- CELERY_BROKER_URL=redis://redis:6379/0
- CELERY_RESULT_BACKEND=redis://redis:6379/0
celery_worker:
build:
context: ./backend
env_file:
- .env.dev
container_name: project-celery-worker
working_dir: /workspace
volumes:
- ./backend:/workspace
depends_on:
- redis
- mysql
- backend
environment:
- CELERY_BROKER_URL=redis://redis:6379/0
- CELERY_RESULT_BACKEND=redis://redis:6379/0
command: celery -A celery_app:app worker -l info --concurrency=1 -P solo
stdin_open: true
tty: true
celery_beat:
build:
context: ./backend
env_file:
- .env.dev
container_name: project-celery-beat
working_dir: /workspace
volumes:
- ./backend:/workspace
depends_on:
- redis
- mysql
- backend
environment:
- CELERY_BROKER_URL=redis://redis:6379/0
- CELERY_RESULT_BACKEND=redis://redis:6379/0
command: celery -A celery_app:app beat -l info --pidfile=
stdin_open: true
tty: true
frontend:
build:
context: ./frontend
env_file:
- .env.dev
container_name: project-frontend
working_dir: /workspace
volumes:
- ./frontend:/workspace
ports:
- "3000:3000"
stdin_open: true
tty: true
redis:
image: redis:7-alpine
container_name: project-redis
ports:
- "6379:6379"
mysql:
image: mysql:8
container_name: project-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: "change-this-root-password"
MYSQL_DATABASE: "project_db"
TZ: "UTC"
ports:
- "3306:3306"
volumes:
- project_mysql_data:/var/lib/mysql
command:
- "--character-set-server=utf8mb4"
- "--collation-server=utf8mb4_0900_ai_ci"
volumes:
project_mysql_data:Workspace mapping
- In the backend container, /workspace is the local backend folder.
- In the frontend container, /workspace is the local frontend folder.
- The Celery worker and Celery beat containers also mount the local backend folder to /workspace.
- Backend Python packages are installed into /opt/venv inside the backend image.
- Port 8000 connects the host machine to port 8000 in the backend container.
- Port 3000 connects the host machine to port 3000 in the frontend container.
- Port 6379 exposes Redis locally for development and debugging.
- Port 3306 exposes MySQL locally for development and debugging.
Backend dependencies
Backend dependencies should be added to requirements.txt. The backend Docker image creates a virtual environment at /opt/venv and installs requirements.txt into that environment during image build.
This keeps Python packages inside the Docker image while /workspace remains the mounted source-code folder from the host. Backend, Celery worker, and Celery beat all use the same image dependency environment.
docker compose build backend celery_worker celery_beatConfirm that the backend container is using the Docker-managed Python environment.
docker compose exec backend bash -lc "which python && which pip && which uvicorn && which celery"Expected paths should point to /opt/venv.
/opt/venv/bin/python
/opt/venv/bin/pip
/opt/venv/bin/uvicorn
/opt/venv/bin/celeryManual dependency installs during development
During active development, it is fine to install a package manually inside the running backend container to test it quickly. This changes the current container environment only.
After confirming the package works, add it to requirements.txt so future Docker builds can reproduce the same environment.
docker compose exec backend bash
pip install package-name
pip show package-nameA rebuild is not required after every manual install during development. Rebuild when requirements.txt changes need to be verified, before committing, before deployment, or when Celery worker and beat must use the same new dependency set.
docker compose build backend celery_worker celery_beat
docker compose up -d backend celery_worker celery_beatDaily usage
Start the full development stack from the folder where compose.yaml is located:
docker compose up -dOpen a shell in the backend or frontend container:
docker compose exec backend bash
docker compose exec frontend bashRun the FastAPI development server inside the backend container:
docker compose exec backend bash -lc "uvicorn main:app --host 0.0.0.0 --port 8000 --reload"Run the frontend development server inside the frontend container:
docker compose exec frontend bash -lc "npm run dev"Rebuild the images after changing a Dockerfile, requirements.txt, or system-level dependencies:
docker compose up -d --buildCelery usage
Celery worker and Celery beat run as separate Compose services. They use the same backend image and source mount as the backend container.
docker compose up -d celery_worker celery_beatFollow live Celery logs. The --tail=0 option skips old logs and shows only new events.
docker compose logs --tail=0 -f celery_worker celery_beatFollow backend, worker, and beat logs together.
docker compose logs --tail=0 -f backend celery_worker celery_beatCall a test task manually when a smoke test task exists in the Celery app.
docker compose exec backend celery -A celery_app:app call test.echo --args='["manual trigger works"]'Compose checks
Use these commands to inspect the local stack and verify that all services are running.
docker compose ps
docker compose logs --tail=50 backend
docker compose logs --tail=50 celery_worker
docker compose logs --tail=50 celery_beatUse live logs when debugging startup or scheduled task execution.
docker compose logs --tail=0 -f backend frontend celery_worker celery_beatCleanup old workspace venv
After the Docker image installs backend dependencies into /opt/venv and the services run correctly, the old /workspace/.venv folder is no longer needed for Docker usage.
docker compose exec backend bash
cd /workspace
rm -rf .venvKeep .venv ignored so it is not committed if it is recreated later by editor tooling or local experiments.
.venv/
celerybeat-schedule