Docker Compose Dev Workspace Setup
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
Section titled “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=noninteractiveENV PYTHONDONTWRITEBYTECODE=1ENV 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/venvRUN /opt/venv/bin/pip install --upgrade pipRUN /opt/venv/bin/pip install --no-cache-dir -r /tmp/requirements.txt
ENV PATH="/opt/venv/bin:$PATH"Frontend Dockerfile
Section titled “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
Section titled “compose.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
Section titled “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
Section titled “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
Section titled “Manual 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 bashpip install package-namepip 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_beatdocker compose up -d backend celery_worker celery_beatDaily usage
Section titled “Daily 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 bashdocker 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
Section titled “Celery 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
Section titled “Compose checks”Use these commands to inspect the local stack and verify that all services are running.
docker compose psdocker compose logs --tail=50 backenddocker compose logs --tail=50 celery_workerdocker 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
Section titled “Cleanup 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 bashcd /workspacerm -rf .venvKeep .venv ignored so it is not committed if it is recreated later by editor tooling or local experiments.
.venv/celerybeat-schedule