Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor docker setup #134

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
157 changes: 94 additions & 63 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,99 +1,130 @@
FROM python:3.7
# This is oioioi user linux uid. Setting it is useful in development.
# By default we use an unused uid of 1234.
# This is placed here to avoid redownloading package on uid change
ARG OIOIOI_UID=1234

FROM python:3.7 AS build

ENV PYTHONUNBUFFERED 1

RUN dpkg --add-architecture i386 && \
apt-get update && \
apt-get install -y \
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
build-essential \
git \
libpq-dev \
libdb5.3-dev

ARG OIOIOI_UID

RUN useradd -u ${OIOIOI_UID} -m oioioi \
&& mkdir -p /sio2/oioioi \
&& chown -R oioioi:oioioi /sio2

USER oioioi
WORKDIR /sio2

RUN pip install --user virtualenv \
&& /home/oioioi/.local/bin/virtualenv -p python3.7 venv

RUN . /sio2/venv/bin/activate \
&& pip install psycopg2-binary==2.8.6 twisted librabbitmq uwsgi

COPY --chown=oioioi:oioioi setup.py requirements.txt /sio2/oioioi/

WORKDIR /sio2/oioioi

RUN . /sio2/venv/bin/activate \
&& pip install -r requirements.txt

COPY --chown=oioioi:oioioi . /sio2/oioioi

FROM python:3.7 AS base

ENV PYTHONUNBUFFERED 1

RUN dpkg --add-architecture i386 \
&& apt-get update \
&& apt-get install -y \
sudo \
wget \
locales \
libdb5.3 \
postgresql-client \
libdb-dev \
fp-compiler fp-units-base fp-units-math \
texlive-latex-base \
texlive-lang-polish \
texlive-latex-extra \
texlive-lang-german \
texlive-lang-european \
texlive-lang-czechslovak \
texlive-pstricks \
ghostscript \
texlive-fonts-recommended \
gcc-multilib \
sudo \
ghostscript \
flite \
sox \
libstdc++6:i386 \
zlib1g:i386 \
locales \
python3-pip && \
apt-get clean
&& rm -rf /var/lib/apt/lists/*

# This is oioioi user linux uid. Setting it is useful in development.
# By default we use an unused uid of 1234.
# This is placed here to avoid redownloading package on uid change
ARG oioioi_uid=1234
ARG OIOIOI_UID

#Bash as shell, setup folders, create oioioi user
RUN rm /bin/sh && ln -s /bin/bash /bin/sh && \
mkdir -pv /sio2/oioioi && \
mkdir -pv /sio2/sandboxes && \
useradd -U oioioi -m -d /home/oioioi/ -u $oioioi_uid && \
echo "oioioi ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \
chown -R oioioi:oioioi /sio2
RUN useradd -u ${OIOIOI_UID} -m oioioi \
&& mkdir -p /sio2/oioioi \
&& chown -R oioioi:oioioi /sio2 \
&& echo "oioioi ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

# Modify locale
RUN sed -i -e "s/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/" /etc/locale.gen && \
locale-gen
RUN sed -i -e "s/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/" /etc/locale.gen \
&& locale-gen

COPY ./entrypoint_checks.sh /entrypoint_checks.sh
RUN chmod +x /entrypoint_checks.sh && chown oioioi /entrypoint_checks.sh

# Installing python dependencies
USER oioioi

ENV PATH $PATH:/home/oioioi/.local/bin/

RUN pip3 install --user psycopg2-binary==2.8.6 twisted uwsgi
COPY --from=build --chown=oioioi:oioioi /sio2 /sio2

WORKDIR /sio2/oioioi
WORKDIR /sio2

COPY --chown=oioioi:oioioi setup.py requirements.txt ./
RUN pip3 install -r requirements.txt --user
COPY --chown=oioioi:oioioi requirements_static.txt ./
RUN pip3 install -r requirements_static.txt --user

COPY --chown=oioioi:oioioi . /sio2/oioioi

RUN oioioi-create-config /sio2/deployment
RUN . /sio2/venv/bin/activate \
&& oioioi-create-config --docker deployment

WORKDIR /sio2/deployment

RUN sed -i -e \
"s/SERVER = 'django'/SERVER = 'uwsgi-http'/g;\
s/DEBUG = True/DEBUG = False/g;\
s/django.db.backends./django.db.backends.postgresql/g;\
s/'NAME': ''/'NAME': 'oioioi'/g;\
s/'USER': ''/'USER': 'oioioi'/g;\
s/'HOST': '',/'HOST': 'db',/g;\
s/'PASSWORD': ''/'PASSWORD': 'password'/g;\
s/#BROKER_URL/BROKER_URL/g;\
s/#FILETRACKER_LISTEN_ADDR/FILETRACKER_LISTEN_ADDR/g;\
"s/#FILETRACKER_LISTEN_ADDR/FILETRACKER_LISTEN_ADDR/g;\
s/#FILETRACKER_LISTEN_PORT/FILETRACKER_LISTEN_PORT/g;\
s|#FILETRACKER_URL = '.*'|FILETRACKER_URL = 'http://web:9999'|g;\
s/#RUN_SIOWORKERSD$/RUN_SIOWORKERSD/g;\
s/#SIOWORKERS_LISTEN_ADDR/SIOWORKERS_LISTEN_ADDR/g;\
s/#SIOWORKERS_LISTEN_PORT/SIOWORKERS_LISTEN_PORT/g;\
s/RUN_LOCAL_WORKERS = True/RUN_LOCAL_WORKERS = False/g;\
s/AVAILABLE_COMPILERS = SYSTEM_COMPILERS/#AVAILABLE_COMPILERS = SYSTEM_COMPILERS/g;\
s/DEFAULT_COMPILERS = SYSTEM_DEFAULT_COMPILERS/#DEFAULT_COMPILERS = SYSTEM_DEFAULT_COMPILERS/g;\
s/USE_UNSAFE_EXEC = True/USE_UNSAFE_EXEC = True/g;\
s/#DEFAULT_SAFE_EXECUTION_MODE/#DEFAULT_SAFE_EXECUTION_MODE/g;\
s/#USE_UNSAFE_CHECKER = True/#USE_UNSAFE_CHECKER = False/g;\
\$afrom basic_settings import *\nALLOWED_HOSTS = ALLOWED_HOSTS + \\['oioioi', '127.0.0.1', 'localhost', 'web'\\]" \
\$afrom basic_settings import *" \
settings.py && \
cp /sio2/oioioi/oioioi/selenium_settings.py selenium_settings.py && \
mkdir -p /sio2/deployment/logs/{supervisor,runserver}

# Download sandboxes
RUN ./manage.py supervisor > /dev/null --daemonize --nolaunch=uwsgi && \
./manage.py download_sandboxes -q -y -c /sio2/sandboxes && \
./manage.py supervisor stop all
FROM base AS development

USER root

RUN apt-get update \
&& apt-get install -y \
fp-compiler \
fp-units-base \
fp-units-math \
gcc-multilib \
&& rm -rf /var/lib/apt/lists/*

USER oioioi

WORKDIR /sio2/oioioi

COPY --chown=oioioi:oioioi requirements_static.txt /sio2/oioioi
RUN . /sio2/venv/bin/activate \
&& pip install -r requirements_static.txt

RUN cp /sio2/oioioi/oioioi/selenium_settings.py /sio2/deployment/selenium_settings.py

WORKDIR /sio2/deployment

ENTRYPOINT [ "/sio2/oioioi/scripts/docker-entrypoint.sh" ]

FROM base as production

WORKDIR /sio2/deployment

ENTRYPOINT [ "/sio2/oioioi/scripts/docker-entrypoint.sh" ]
64 changes: 41 additions & 23 deletions GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ newgrp docker
```

All the commands below are being run in `oioioi` directory (main directory of the repository).
In order to use `easy_toolbox.py` alternative method, check python package requirements in `easy_toolbox.py`.
In order to use `easy_toolbox.py` alternative method, check python package requirements in `easy_toolbox.py`.

To build OIOIOI image run
To build OIOIOI image run
```bash
OIOIOI_UID=$(id -u) docker-compose -f docker-compose-dev.yml -f extra/docker/docker-compose-dev-noserver.yml build
```
or
```bash
./easy_toolbox.py build
./easy_toolbox.py build
```

Set your containers up and running
Expand All @@ -50,7 +50,7 @@ Wait some time for the migration to finish (no more than a few minutes).

Run your web service
```bash
OIOIOI_UID=$(id -u) docker-compose -f docker-compose-dev.yml -f extra/docker/docker-compose-dev-noserver.yml exec web python3 manage.py runserver 0.0.0.0:8000
OIOIOI_UID=$(id -u) docker-compose -f docker-compose-dev.yml -f extra/docker/docker-compose-dev-noserver.yml exec web ./manage.py runserver 0.0.0.0:8000
```
or
```bash
Expand All @@ -59,6 +59,23 @@ or

Now visit `localhost:8000` and start exploring OIOIOI.

### Download sandboxes

To properly judge submissions in an isolated environment, you need to download the execution sandboxes.
This is necessary if you're going to work on any part of the judging process.
To download them, run:

```bash
./easy_toolbox.py download-sandboxes
```
or
```bash
OIOIOI_UID=$(id -u) docker-compose -f docker-compose-dev.yml -f extra/docker/docker-compose-dev-noserver.yml exec web ./manage.py download_sandboxes
```
and follow the prompts.

This needs to be done only one time, unless you remove the filetracker database that stores them.

## Run unit tests
In order to run unit tests Docker installation is required.
To do it just run
Expand All @@ -75,9 +92,10 @@ In order to run Cypress tests a few more steps are required.
- Clear the database
- Create superuser (admin, admin)
- Run the service
- Ensure that task execution sandboxes are downloaded (it is recommended to do this beforehand, see section [**Download sandboxes**](#download-sandboxes) above)
- Run the tests

All of these steps can be done by running
All of these steps (aside from downloading sandboxes) can be done by running
```bash
./easy_toolbox.py flush-db && ./easy_toolbox.py add-superuser && ./easy_toolbox.py cypress-apply-settings && ./easy_toolbox.py run
```
Expand All @@ -103,12 +121,12 @@ As mentioned above GitHub Actions replaced most of the Hudson jobs. Right now th
- Transifex translations uploader

## Deployment
No changes can be seen on `szkopul.edu.pl` without deployment.
No changes can be seen on `szkopul.edu.pl` without deployment.
@twalen is responsible for conducting the deployments, and they are usually done during
maintenance window (see `szkopul.edu.pl` main page for details).

During deployment translation files are being uploaded and downloaded. The translation manager is
[Transifex](https://www.transifex.com/sio2project/sio2project/dashboard/). When you add localized text
During deployment translation files are being uploaded and downloaded. The translation manager is
[Transifex](https://www.transifex.com/sio2project/sio2project/dashboard/). When you add localized text
to OIOIOI it is uploaded to Transifex with GitHub Action and later, when translated, downloaded,
compiled and saved to the codebase. (Both of these jobs need to be run manually).

Expand All @@ -119,20 +137,20 @@ Ticketing was moved to GitHub Issues.
## FAQ

### When to use `./easy_toolbox.py build`?
Essentially, it is not easy to answer.
Essentially, it is not easy to answer.
Firstly, let's understand what each of the commands does.
As you may already know, SIO2 development environment works in containerized infrastructure.
We have four containers up and running, required for SIO2 to work properly.
Database (`db`), RabbitMQ (`broker`), Worker (`worker`) and OIOIOI (`web`).
Postgres and RabbitMQ already have existing docker images on Docker Hub.
We only need to build (here comes the magic word) SIO dependent images.
`Dockerfile` defines what steps are to be done in order to create the environment.
Once you built the image, you can set the container up.
Remember - things like dependencies (`requirements[_static].txt`, `setup.py`) are downloaded during the built,
so if you changed something in those places you either need to build the image again,
or apply these changes by hand (e.g. do `pip install`).
If you have good internet connection and adequate CPU, it shouldn't be hard to build the image again,
especially that it is more stable approach.
As you may already know, SIO2 development environment works in containerized infrastructure.
We have four containers up and running, required for SIO2 to work properly.
Database (`db`), RabbitMQ (`broker`), Worker (`worker`) and OIOIOI (`web`).
Postgres and RabbitMQ already have existing docker images on Docker Hub.
We only need to build (here comes the magic word) SIO dependent images.
`Dockerfile` defines what steps are to be done in order to create the environment.
Once you built the image, you can set the container up.
Remember - things like dependencies (`requirements[_static].txt`, `setup.py`) are downloaded during the built,
so if you changed something in those places you either need to build the image again,
or apply these changes by hand (e.g. do `pip install`).
If you have good internet connection and adequate CPU, it shouldn't be hard to build the image again,
especially that it is more stable approach.

### When to use `./easy_toolbox.py up`?
Whenever you don't have the containers up.
Expand All @@ -151,8 +169,8 @@ If not, check the output of `docker ps -a` and `docker logs <container_name>`.
### When to use `./easy_toolbox.py run`?
Whenever you want the Django web service to be running.
In development environment we use dev server, so it should catch all changes in the code.
You can have the server running all the time - just make sure,
that Django discovered your changes
You can have the server running all the time - just make sure,
that Django discovered your changes
(the server will restart with appropriate message like "detected changes in file `xyz.py`").

### What to do when I get permission denied error?
Expand Down
Loading