Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
nohup.out

# Python
__pycache__/
*.py[cod]
Expand All @@ -11,7 +13,6 @@ dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
Expand Down
11 changes: 11 additions & 0 deletions Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}

doodlebot.media.mit.edu {
reverse_proxy backend:80
}

http://doodlebot.media.mit.edu {
reverse_proxy backend:80
}
36 changes: 36 additions & 0 deletions DEPLOY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Deployment

The doodlebot application is currently deployed on an Ubuntu virtual machine issued to us by Necsys: [doodlebot.media.mit.edu](https://doodlebot.media.mit.edu)

It works by executing a series of [docker containers](https://www.docker.com/resources/what-container/):

- **backend:** This container executes the FastAPI application defined in [main.py](./main.py). The FastAPI is also responsible for serving the static assets of the **frontend** and **playground** containers described below.
- **frontend:** This container builds the [SvelteKit](https://svelte.dev/) web app defined in [frontend/](./frontend/) into a static website, which acts as the frontend you see when navigating to [doodlebot.media.mit.edu](https://doodlebot.media.mit.edu)
- **playground:** This container pulls down a single deployed folder of the [RAISE Playground repo](https://github.com/mitmedialab/prg-raise-playground)
- Currently, it pulls down the deploy of the [curriculum branch](https://github.com/mitmedialab/prg-raise-playground/tree/curriculum), which is configured in [docker/playground.Dockerfile](./docker/playground.Dockerfile)
- **caddy:** This container executes the [Caddy](https://caddyserver.com/) web server, which routes traffic to the **backend** container

The activity of these containers is coordinated using [docker compose](https://docs.docker.com/compose/) as configured in [docker/compose.yml](./docker/compose.yml).


## Deployment Steps

The following steps demonstrate how to re-deploy the backend after pushing up changes from your local development environment (you should **NOT** develop directly on this machine).

The steps make reference to shell scripts stored directly on the deployment machine (and not in this repo, though they make use of scripts stored inside of the [cli/](./cli/) directory). These exist just to make the deployment process easier, but they often are pretty simple and you should definitely check out their contents (e.g. `cat ./example.sh`) to get a clear picture of what's going on

1. Log onto the VM: `ssh <user_id>@doodlebot.media.mit.edu`
- Use the `user_id` @pmalacho provided to you as well as the password when prompted
2. Create a sudo session: `sudo su`
- You'll again be prompted for your password
3. Change directory to home: `cd`
3. Pull the latest changes for this repo: `./pull.sh`
4. (Re)start the docker containers: `./start.sh`
- **NOTE:** If you deem it necessary, you can explicitly stop all currently running containers first: `./stop.sh`
5. When you run the above `./start.sh` command, you should see `nohup: ignoring input and appending output to 'nohup.out'`
- This message indicates that we are running a process (specifically [cli/prod.sh](./cli/prod.sh)) through the [nohup](https://www.digitalocean.com/community/tutorials/nohup-command-in-linux) utility. It stands for "No Hang Up", which is useful for us so that the deployment process continues even when we exit the terminal (aka "hang up").
- This command won't exit until all of the docker containers are built. If you need to see the output of this build process, you can open another terminal, ssh onto the machine, start a sudo session (`sudo su`) and run `./log-build.sh` (which literally just prints the contents of the `'nohup.out'` file referenced above).
- As you can see, it's sometimes helpful to have two terminals connected to the deployment machine, especially when debugging.
6. Once the `./start.sh` command exits, the server will be starting up. During this time the site ([doodlebot.media.mit.edu](https://doodlebot.media.mit.edu)) will not be reachable -- in this sense, we do **NOT** currently support [zero downtime deployments](https://www.pingidentity.com/en/resources/blog/post/what-is-zero-downtime-deployment.html).
- To see the output of the server at runtime, run `./log-runtime.sh`.
- Once you see `doodlebot-backend | Mounted frontend at /` in the output of `./log-runtime.sh`, the full site should be responsive.
13 changes: 13 additions & 0 deletions cli/prod.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

# Exit immediately if a command exits with a non-zero status.
set -e

# Get the directory of the Docker Compose file
ROOT_DIR="$(git rev-parse --show-toplevel)"
DOCKER_DIR="$ROOT_DIR/docker"
COMPOSE_FILE="$DOCKER_DIR/compose.yml"

docker compose -f "$COMPOSE_FILE" up --build frontend playground

docker compose -f "$COMPOSE_FILE" up --build --detach backend caddy
2 changes: 2 additions & 0 deletions docker/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.frontend
.playground
16 changes: 16 additions & 0 deletions docker/backend.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM python:3.9

# Install dependencies for pyaudio
RUN apt-get update
RUN apt-get install libasound-dev libportaudio2 libportaudiocpp0 portaudio19-dev -y
RUN apt-get install gcc -y

WORKDIR /app

COPY ./requirements.txt /app/requirements.txt

RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt

COPY . /app

CMD ["uvicorn", "main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
101 changes: 101 additions & 0 deletions docker/backend.Dockerfile.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
cli
docker
frontend

# Tests
**/__tests__/
conftest.py

# Dev / database migrations
**/alembic*

# Git
.git
.gitignore
.gitattributes


# CI
.codeclimate.yml
.travis.yml
.taskcluster.yml

# Docker
docker-compose.yml
Dockerfile
*Dockerfile*
.docker
.dockerignore

# Byte-compiled / optimized / DLL files
**/__pycache__/
**/*.py[cod]

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml

# Translations
*.mo
*.pot

# Django stuff:
*.log

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Virtual environment
.env
.venv/
venv/

# PyCharm
.idea

# Python mode for VIM
.ropeproject
**/.ropeproject

# Vim swap files
**/*.swp

# VS Code
.vscode/
54 changes: 54 additions & 0 deletions docker/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
services:
frontend:
container_name: doodlebot-frontend
volumes:
- ./.frontend:/dist
build:
context: ../frontend
dockerfile: ../docker/frontend.Dockerfile # NOTE: path is relative to above context
restart: "no"

playground:
container_name: doodlebot-playground
volumes:
- ./.playground:/dist
build:
dockerfile: ./playground.Dockerfile
restart: "no"

backend:
container_name: doodlebot-backend
build:
context: ..
dockerfile: ./docker/backend.Dockerfile
ports:
- "8000:80"
volumes:
- "./.frontend:/app/frontend"
- "./.playground:/app/frontend/playground"
env_file:
- path: ../.env
required: false
networks:
- app-network

caddy:
container_name: doodlebot-caddy
image: caddy:latest
ports:
- "80:80"
- "443:443"
volumes:
- ../Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
networks:
- app-network

networks:
app-network:
driver: bridge

volumes:
caddy_data:
caddy_config:
13 changes: 13 additions & 0 deletions docker/frontend.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM node:20-slim AS dependencies
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable && npm install -g corepack@latest
COPY package.json pnpm-lock.yaml /app/
WORKDIR /app
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile

FROM dependencies AS build
COPY . /app
WORKDIR /app
RUN pnpm build
CMD cp -r build/* /dist
10 changes: 10 additions & 0 deletions docker/frontend.Dockerfile.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
18 changes: 18 additions & 0 deletions docker/playground.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM ubuntu:latest AS base
RUN apt-get update && apt-get install -y git

WORKDIR /playground

# Clone the repo shallowly, filtering out all blobs initially, and only fetching the gh-pages branch.
# "--filter=blob:none" means blobs (file contents) are only downloaded on demand.
# "--sparse" enables sparse checkout directly from clone.
RUN git clone --depth=1 --branch=gh-pages --filter=blob:none --sparse \
https://github.com/mitmedialab/prg-raise-playground.git /playground

# Enable sparse checkout and select only the "curriculum" directory.
RUN git sparse-checkout set curriculum

# After setting sparse-checkout, "git checkout" will update the working copy to include only that folder.
RUN git checkout

CMD git pull && cp -r curriculum/* /dist
23 changes: 23 additions & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
node_modules

# Output
.output
.vercel
.netlify
.wrangler
/.svelte-kit
/build

# OS
.DS_Store
Thumbs.db

# Env
.env
.env.*
!.env.example
!.env.test

# Vite
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
1 change: 1 addition & 0 deletions frontend/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
engine-strict=true
38 changes: 38 additions & 0 deletions frontend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# sv

Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).

## Creating a project

If you're seeing this, you've probably already done this step. Congrats!

```bash
# create a new project in the current directory
npx sv create

# create a new project in my-app
npx sv create my-app
```

## Developing

Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:

```bash
npm run dev

# or start the server and open the app in a new browser tab
npm run dev -- --open
```

## Building

To create a production version of your app:

```bash
npm run build
```

You can preview the production build with `npm run preview`.

> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
Loading