Skip to content

Commit 4a7eec4

Browse files
committed
Migrate to docker containers
1 parent 4f4e281 commit 4a7eec4

16 files changed

+736
-637
lines changed

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules/

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ repos:
99
- id: trailing-whitespace
1010
# python
1111
- repo: https://github.com/psf/black
12-
rev: 22.12.0
12+
rev: 23.3.0
1313
hooks:
1414
- id: black
1515
- repo: https://github.com/PyCQA/isort
16-
rev: 5.11.4
16+
rev: 5.12.0
1717
hooks:
1818
- id: isort
1919
- repo: local

Dockerfile.django

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# set up environment variables
2+
FROM python:3.9.16
3+
4+
ENV POETRY_VIRTUALENVS_CREATE false
5+
ENV POETRY_VERSION 1.3.1
6+
ENV POETRY_HOME /opt/poetry
7+
ENV POETRY_NO_INTERACTION 1
8+
ENV VIRTUAL_ENV /venv
9+
ENV PYTHONUNBUFFERED 1
10+
11+
ENV PATH $POETRY_HOME/bin:$PATH
12+
13+
# set up dependencies, create virtual environment
14+
RUN mkdir -p /opt/csm_web
15+
WORKDIR /opt/csm_web
16+
17+
# install poetry
18+
RUN curl -sSL https://install.python-poetry.org | python3 -
19+
# create and activate virtual environment for poetry
20+
RUN python3 -m venv $VIRTUAL_ENV
21+
ENV PATH $VIRTUAL_ENV/bin:$PATH
22+
23+
# install python dependencies
24+
COPY poetry.lock pyproject.toml ./
25+
RUN poetry install --no-root --with=dev
26+
27+
# start database
28+
COPY ./docker-django-entrypoint.sh ./
29+
ENTRYPOINT ["./docker-django-entrypoint.sh"]

Dockerfile.node

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
FROM node:18
2+
3+
# install inotify-tools for webpack reloading
4+
# RUN apt install inotify-tools
5+
6+
RUN mkdir -p /opt/csm_web \
7+
# change ownership of /opt/csm_web to install dependencies
8+
&& chown node:node /opt/csm_web
9+
10+
WORKDIR /opt/csm_web
11+
12+
USER node
13+
14+
# install npm dependencies
15+
COPY --chown=node:node package.json package-lock.json ./
16+
RUN npm install && npm cache clean --force
17+
ENV PATH /opt/csm_web/node_modules/.bin:$PATH
18+
19+
WORKDIR /opt/csm_web/app
20+
21+
# change to root to allow permission changes in entrypoint
22+
USER root
23+
24+
# specify entrypoint to execute pre-command tasks
25+
COPY ./docker-node-entrypoint.sh ./
26+
ENTRYPOINT ["./docker-node-entrypoint.sh"]
27+
28+
# start continuous compilation
29+
CMD ["npm", "run", "watch"]

README.md

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,28 @@ If you're unfamiliar with CSM and/or its web applications, check out [this repos
1111
We don't know what specific minimum version you would need for any of the following software, but the most recent version of any of the below should work.
1212

1313
- Python 3.9.13
14-
- It is recommended that you use [`pyenv`](https://github.com/pyenv/pyenv) to manage python versions, so that you can use a consistent python version for `csm_web`, and another python version for your other projects.
14+
- It is recommended that you use a python version manager like [`pyenv`](https://github.com/pyenv/pyenv) or [`asdf`](https://asdf-vm.com) (with [`asdf-python`](https://github.com/asdf-community/asdf-python)), so that you can use a consistent python version for `csm_web`, and another python version for your other projects.
1515
- [`poetry`](https://python-poetry.org/docs/#installation)
16+
- We use poetry to manage python dependencies; this should be installed _outside_ of a virtual environment.
17+
- Although everything will be run through Docker containers, you should use Poetry to get the dependencies locally for editing.
1618
- `npm`
17-
- It is recommended that you use [`nvm`](https://github.com/nvm-sh/nvm) to manage node/npm versions, so that you can use a consistent node/npm version for `csm_web`, and another verison for your other projects.
18-
- [PostgreSQL](https://www.postgresql.org/download/)
19-
- [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli#download-and-install)
19+
- It is recommended that you use a node version manager like [`nvm`](https://github.com/nvm-sh/nvm), [`n`](https://github.com/tj/n), or [`asdf`](https://asdf-vm.com) (with [`asdf-nodejs`](https://github.com/asdf-vm/asdf-nodejs)), so that you can use a consistent node/npm version for `csm_web`, and another verison for your other projects.
20+
- Although everything will be run through Docker containers, you should get the dependencies locally for editing.
21+
- [Docker](https://www.docker.com)
22+
- Your development environment will be hosted through docker containers, so that you do not need to do much local setup.
23+
- [PostgreSQL](https://www.postgresql.org/download/) (optional)
24+
- This should not be necessary now that we have migrated to Docker, but install it if any issues arise when editing.
25+
- [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli#download-and-install) (optional)
2026
- Create an account on [Heroku](https://id.heroku.com/login) and [login](https://devcenter.heroku.com/articles/heroku-cli#getting-started)
21-
- [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html)
27+
- This is not completely necessary for the application to work locally; it is only used for interactions with the production/staging environment.
28+
- [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html) (optional)
2229
- We use an S3 bucket to store course resources. See [here](https://aws.amazon.com/s3/) to get started.
23-
- Log in to AWS CLI (`aws configure`) This will prompt an interactive session to enter login credentials.
24-
- AWS Access Key ID: (ask tech chair)
25-
- AWS Secret Access Key: (ask tech chair)
26-
- Default region name: `us-east-1`
27-
- Default output format: `json`
30+
- Log in to AWS CLI (`aws configure`) This will prompt an interactive session to enter login credentials.
31+
- AWS Access Key ID: (ask tech chair)
32+
- AWS Secret Access Key: (ask tech chair)
33+
- Default region name: `us-east-1`
34+
- Default output format: `json`
35+
- This is not completely necessary for the application to work locally; it is only used for interactions with the resources page in production/staging.
2836

2937
Other miscellaneous requirements will be installed by the commands below.
3038

@@ -34,23 +42,23 @@ To ensure package version consistency and avoid polluting your global package in
3442

3543
Firstly, make sure you have the right python version (see `runtime.txt` for the expected python version to install). If you're using `pyenv` to manage python versions (this is recommended), you can install the specified python version with `pyenv install <version>`.
3644

37-
From a terminal in the top level of the project directory, run `python3 -m venv venv`; if your system python version is different from the version required here, and you're using `pyenv`, run `PYENV_VERSION=<version> python3 -m venv venv` instead (for example, `PYENV_VERSION=3.9.13 python3 -m venv venv`). This will initialize a new virtual environment in the `venv/` folder, with the correct base python version.
45+
Next, make sure that your current python version is correct (i.e. as specified in the previous section); if it is different, then change to the correct python version. That is, with `pyenv`, run `pyenv local <version>`; with `asdf`, run `asdf local python <version>`.
3846

39-
To activate the environment, run `source venv/bin/activate`. You will need to run this command every time you open a new terminal.
47+
Finally, run `./setup.sh`. This will install additional requirements needed by the server, and set up some necessary environment variables. In particular, the setup script installs all dependencies locally and builds the Docker images.
4048

41-
Finally, run `./setup.sh`. This will install additional requirements needed by the server, and set up some necessary environment variables. You should _not_ be running this script after it has succeeded and set up the environment for the first time.
49+
Note that generally, you should not need to run `setup.sh` after first setting up the repository.
4250

4351
## Running
4452

45-
To start the Django server, run `python3 csm_web/manage.py runserver` and visit `localhost:8000` in your browser.
53+
To start the Django server and other services, make sure Docker is up and run `docker compose up -d`. This will start Django, automatically compile and watch frontend files, and start a development database. (The `-d` puts the process in the background.)
4654

47-
Run `python3 csm_web/manage.py createtestdata` to generate some test data. If you ran `./setup.sh`,
48-
this was done for you.
55+
To generate test data, run `docker compose exec django python3 csm_web/manage.py createtestdata`. In general, if you'd like to run any commands in the Django docker container, run `docker compose exec django <command>`. (You can make an alias in your shell if you'd like to avoid typing all of this each time.)
4956

50-
_If you are working on the frontend_:
57+
If all of the above has worked, visit [http://localhost:8000](http://localhost:8000) in your browser and you should see a log in screen; don't actually use this to actually log in locally. Visit [http://localhost:8000/admin/](http://localhost:8000/admin/) to log in instead.
5158

52-
Run `npm run watch`, which will automatically rebuild the JS bundle if any changes to the frontend JS are detected.
53-
Alternatively you can run `npm run dev` manually each time you make changes to the frontend.
59+
Any changes will automatically reload the server in the docker containers, but you will usually need to force refresh (`ctrl + shift + R` or `cmd + shift + R` on most browsers) for frontend changes to be reflected (this clears the browser cache for the page).
60+
61+
During development, you should use the virtual environment as much as possible---while Docker makes this less necessary, your choice of editor may require the dependencies in the virtual environment. To activate the virtual environment, you can use `poetry shell` (this will start a new nested shell instance), or you can use `source .venv/bin/activate` (more generally, `source $(poetry env info --path)/bin/activate`).
5462

5563
## Troubleshooting
5664

@@ -122,5 +130,4 @@ could not connect to server: Connection refused
122130
TCP/IP connections on port 5432?
123131
```
124132

125-
Your postgres server is likely not running. On a mac (which is the only platform we've done local
126-
testing on), run `brew services start postgres` before invoking `runserver` again.
133+
Your PostgreSQL server is likely not running. On MacOS, run `brew services start postgres` before invoking `runserver` again; on Unix, run `sudo service postgresql restart` before invoking `runserver` again.

csm_web/csm_web/settings.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,10 @@
115115
DATABASES = {
116116
"default": {
117117
"ENGINE": "psqlextra.backend",
118-
"NAME": "csm_web_dev",
119-
"USER": "postgres",
118+
"NAME": os.environ.get("POSTGRES_DB", "csm_web_dev"),
119+
"USER": os.environ.get("POSTGRES_USER", "postgres"),
120120
"PASSWORD": os.environ.get("POSTGRES_PASSWORD", ""),
121-
"HOST": "localhost",
121+
"HOST": os.environ.get("POSTGRES_HOST", "localhost"),
122122
"PORT": "5432",
123123
}
124124
}

cypress/support/commands.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,14 @@ Cypress.Commands.add(
3838
"setupDB",
3939
(script_path: string, func_name: string, options: SetupDBOptions = { force: false, mutate: false }) => {
4040
// validate arguments
41-
expect(script_path.match(/[a-zA-Z0-9_\/\.\-]/)).to.not.be.null;
41+
expect(script_path.match(/[a-zA-Z0-9_/.-]/)).to.not.be.null;
4242
expect(func_name.match(/[a-zA-Z0-9_]/)).to.not.be.null;
4343

44+
// insert prefix in case of docker container; default to empty
45+
const prefix = Cypress.env("DOCKER_PREFIX") ?? "";
46+
4447
// run setup script
45-
let command = `python3 cypress/db/_setup.py "${script_path}" "${func_name}"`;
48+
let command = `${prefix} python3 cypress/db/_setup.py "${script_path}" "${func_name}"`;
4649
if (options.force) {
4750
command += " --force";
4851
}
@@ -57,7 +60,9 @@ Cypress.Commands.add(
5760
* Initialize the Django database and cache
5861
*/
5962
Cypress.Commands.add("initDB", () => {
60-
cy._exec("python3 cypress/db/_setup.py --init");
63+
// insert prefix in case of docker container; default to empty
64+
const prefix = Cypress.env("DOCKER_PREFIX") ?? "";
65+
cy._exec(`${prefix} python3 cypress/db/_setup.py --init`);
6166
});
6267

6368
/**

docker-compose.yml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
services:
2+
postgres:
3+
image: postgres:14
4+
healthcheck:
5+
test: /usr/bin/pg_isready
6+
interval: 5s
7+
timeout: 10s
8+
retries: 120
9+
environment:
10+
POSTGRES_DB: csm_web_dev
11+
PGUSER: postgres
12+
POSTGRES_HOST_AUTH_METHOD: trust
13+
node:
14+
build:
15+
context: .
16+
dockerfile: Dockerfile.node
17+
volumes:
18+
# mount source files
19+
- type: bind
20+
source: ./
21+
target: /opt/csm_web/app
22+
read_only: true
23+
# output from webpack
24+
- type: bind
25+
source: ./csm_web/frontend/static/frontend/
26+
target: /opt/csm_web/app/csm_web/frontend/static/frontend/
27+
# mount package files
28+
- type: bind
29+
source: ./package.json
30+
target: /opt/csm_web/package.json
31+
read_only: true
32+
- type: bind
33+
source: ./package-lock.json
34+
target: /opt/csm_web/package-lock.json
35+
read_only: true
36+
# prevent node modules from being overwritten on host
37+
- notused:/opt/csm_web/app/node_modules
38+
django:
39+
tty: true
40+
build:
41+
context: .
42+
dockerfile: Dockerfile.django
43+
env_file: .env
44+
environment:
45+
POSTGRES_DB: csm_web_dev
46+
POSTGRES_USER: postgres
47+
POSTGRES_HOST: postgres
48+
ports:
49+
- 8000:8000
50+
volumes:
51+
- type: bind
52+
source: ./
53+
target: /opt/csm_web
54+
read_only: true
55+
depends_on:
56+
postgres:
57+
condition: service_healthy
58+
59+
networks:
60+
default:
61+
name: csm_web_default
62+
63+
# volume to exclude files from being mounted
64+
volumes:
65+
notused:

docker-django-entrypoint.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env bash
2+
3+
python3 csm_web/manage.py migrate
4+
exec python3 csm_web/manage.py runserver 0.0.0.0:8000

docker-node-entrypoint.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env bash
2+
3+
chmod -R a+w /opt/csm_web/app/csm_web/frontend/static/frontend/
4+
exec runuser -u node "$@"

0 commit comments

Comments
 (0)