Skip to content

Commit

Permalink
[deploy] add docker compose deployment (#882)
Browse files Browse the repository at this point in the history
* Add backend service

* Add agent-docker service

* Add agent-mcq service

* Add mongo-db container

* Layered services images

* Add frontend service

* [deploy] From Ubuntu to Rocky8

* [deploy] Update README

* [deploy] Add initial MongoDB setup

* [deploy] Update INGInious stack doc

* [deploy] Rebase and update documentation

* [deploy] Revert setup sub-division

* [deploy] Add core containers build to CI

* Use code escape in documentation

Suggested changes by @anthonygego

Co-authored-by: Anthony Gégo <anthony.gego@uclouvain.be>

* [deploy/compose] Build base image in stack deploy

* [deploy] Update doc about core containers build

* [deploy/base] Document the containerfile

* [deploy] Update review comments

- Add .env file with defaults values for REGISTRY and VERSION variables
- Fix "docker compose" syntax for modern deployements

---------

Co-authored-by: Anthony Gégo <anthony.gego@uclouvain.be>
  • Loading branch information
nrybowski and anthonygego committed Dec 6, 2023
1 parent 80e367a commit 21abf3d
Show file tree
Hide file tree
Showing 13 changed files with 330 additions and 17 deletions.
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
REGISTRY=ghcr.io
VERSION=latest
20 changes: 20 additions & 0 deletions .github/workflows/core_containers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Build and push core containers

on:
push:
branches: [master]

workflow_dispatch:

jobs:
containers_build_and_push:
uses: INGInious/.github/.github/workflows/containers.yml@6506916a602fc6bf47d6e8f34586732d3c8e1502
with:
working-directory: base-containers
context-path: context.yml
compose-path: compose.yml
registry: ghcr.io
container_type: core
secrets:
GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }}
GHCR_TOKEN: ${{ secrets.GHCR_TOKEN }}
44 changes: 44 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,50 @@ INGInious can be used as an external grader for EDX. The course `Paradigms of Co
.. _Docker: https://www.docker.com/
.. _Paradigms of Computer Programming - Fundamentals: https://www.edx.org/course/louvainx/louvainx-louv1-1x-paradigms-computer-2751

How to install?
---------------

Simply run:

.. code-block::
$ docker compose up --build
> Note that you can override the registry and containers version by setting the `REGISTRY` and
> `VERSION` environment variables.

And access http://localhost:9000 in your browser.

*The default login and password are* ``superadmin``.

The ``--build`` argument is optional, use it if you want to rebuild locally the core containers.
If you want to simply pull them from the project's registry, this argument is not required.

Docker-compose will create a ``tasks`` folder if it does not exist already.

You can then add new courses to your fresh INGInious instance by installing them in the ``tasks`` folder.

For example, the INGInious tutorial course is installed with the following commands:

.. code-block::
$ git clone https://github.com/UCL-INGI/INGInious-demo-tasks.git
$ mv INGInious-demo-tasks/tutorial tasks/
*If you encounter permission errors, you should run the following command:*

.. code-block::
$ sudo chown -R <your_user>:<your_user_group> tasks
*This can happen when the tasks directory is created by docker-compose.*

Note that the `configuration.deploy.yaml` file provided is a sample configuration, the secret key **must** be changed by administrators in production deployments.

.. _Manual installation: https://docs.inginious.org/en/latest/admin_doc/install_doc/installation.html

`Manual installation`_ is also possible with pip.

Documentation
-------------

Expand Down
16 changes: 16 additions & 0 deletions configuration.deploy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
backend: tcp://backend:2000
backup_directory: /inginious/backups
local-config: {}
mongo_opt:
database: INGInious
host: db
plugins: []
session_parameters:
ignore_change_ip: false
secret_key: 96f4628a2e4d0ce26b6352713f8ac8359b838f4800f1972790622899664bd0f4
secure: false
timeout: 86400
superadmins:
- superadmin
tasks_directory: /inginious/tasks
use_minified_js: true
16 changes: 16 additions & 0 deletions deploy/agent-docker.containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
ARG VERSION=latest
ARG REGISTRY

FROM ${REGISTRY}/inginious/core-base:${VERSION}

COPY inginious/agent/__init__.py inginious/agent/
COPY inginious/agent/docker_agent/ inginious/agent/docker_agent/
COPY inginious-agent-docker .

RUN dnf install -y gcc python39-devel

# See https://github.com/pypa/setuptools_scm/#usage-from-docker
RUN --mount=source=.git,target=.git,type=bind \
pip3 install --no-cache-dir -e .

CMD ["sh", "-c", "python3 inginious-agent-docker ${BACKEND} --tmpdir=/tmp/agent_data/"]
14 changes: 14 additions & 0 deletions deploy/agent-mcq.containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
ARG VERSION=latest
ARG REGISTRY

FROM ${REGISTRY}/inginious/core-base:${VERSION}

COPY inginious/agent/__init__.py inginious/agent/
COPY inginious/agent/mcq_agent/ inginious/agent/mcq_agent/
COPY inginious-agent-mcq .

# See https://github.com/pypa/setuptools_scm/#usage-from-docker
RUN --mount=source=.git,target=.git,type=bind \
pip3 install --no-cache-dir -e .

CMD ["sh", "-c", "python3 inginious-agent-mcq ${BACKEND}"]
13 changes: 13 additions & 0 deletions deploy/backend.containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
ARG VERSION=latest
ARG REGISTRY

FROM ${REGISTRY}/inginious/core-base:${VERSION}

COPY inginious/backend/ inginious/backend/
COPY inginious-backend .

# See https://github.com/pypa/setuptools_scm/#usage-from-docker
RUN --mount=source=.git,target=.git,type=bind \
pip3 install --no-cache-dir -e .

CMD ["sh", "-c", "python3 inginious-backend ${AGENT} ${CLIENT}"]
50 changes: 50 additions & 0 deletions deploy/db_setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from pymongo import MongoClient
from gridfs import GridFS

from inginious.frontend.user_manager import UserManager

def try_mongodb_opts(host="localhost", database_name='INGInious'):
""" Try MongoDB configuration """
try:
mongo_client = MongoClient(host=host)
# Effective access only occurs when we call a method on the connexion
mongo_version = str(mongo_client.server_info()['version'])
print("Found mongodb server running version %s on %s." % (mongo_version, host))
except Exception as e:
print("Cannot connect to MongoDB on host %s: %s" % (host, str(e)))
return None

try:
database = mongo_client[database_name]
# Effective access only occurs when we call a method on the database.
database.list_collection_names()
except Exception as e:
print("Cannot access database %s: %s" % (database_name, str(e)))
return None

try:
# Effective access only occurs when we call a method on the gridfs object.
GridFS(database).find_one()
except Exception as e:
print("Cannot access gridfs %s: %s" % (database_name, str(e)))
return None

return database

if __name__ == '__main__':
username = "superadmin"
realname = "INGInious superadmin"
email = "superadmin@inginious.org"
password = "superadmin"

print('Initial DB setup.')

database = try_mongodb_opts('db')

database.users.insert_one({"username": username,
"realname": realname,
"email": email,
"password": UserManager.hash_password(password),
"bindings": {},
"language": "en"})
print('Superadmin user added!')
18 changes: 18 additions & 0 deletions deploy/frontend.containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
ARG VERSION=latest
ARG REGISTRY

FROM ${REGISTRY}/inginious/core-base:${VERSION}

COPY inginious/frontend inginious/frontend/
COPY inginious/client inginious/client/
COPY inginious-webapp .

RUN dnf install -y git gcc python39-devel

# See https://github.com/pypa/setuptools_scm/#usage-from-docker
RUN --mount=source=.git,target=.git,type=bind \
pip3 install --no-cache-dir -e .

COPY deploy/db_setup.py /tmp/db_setup.py

CMD ["sh", "-c", "python3 /tmp/db_setup.py; python3 inginious-webapp"]
16 changes: 16 additions & 0 deletions deploy/inginious-base.containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Base core container. This is not a service per-se but is used as a common layer for the core services.
FROM rockylinux:8

ENV INGINIOUS_COMPOSE=1

RUN dnf update -y && dnf install -y python39 python39-pip git
RUN pip3 install importlib-metadata

WORKDIR /inginious
COPY setup.py README.rst ./
COPY inginious/common/ inginious/common/
COPY inginious/__init__.py inginious/

# See https://github.com/pypa/setuptools_scm/#usage-from-docker
RUN --mount=source=.git,target=.git,type=bind \
pip3 install --no-cache-dir -e .
100 changes: 100 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
services:

base:
image: ${REGISTRY}/inginious/core-base:${VERSION}
build:
dockerfile: deploy/inginious-base.containerfile
args:
- VERSION=${VERSION}
- REGISTRY=${REGISTRY}
command: /bin/true

db:
image: mongo:6.0.2
networks:
- inginious

backend:
image: ${REGISTRY}/inginious/core-backend:${VERSION}
depends_on:
- base
build:
dockerfile: deploy/backend.containerfile
args:
- VERSION=${VERSION}
- REGISTRY=${REGISTRY}
environment:
AGENT: "tcp://0.0.0.0:2001"
CLIENT: "tcp://0.0.0.0:2000"
networks:
- inginious

agent-docker:
image: ${REGISTRY}/inginious/core-agent_docker:${VERSION}
depends_on:
- backend
deploy:
replicas: 1
build:
dockerfile: deploy/agent-docker.containerfile
args:
- VERSION=${VERSION}
- REGISTRY=${REGISTRY}
environment:
BACKEND: "tcp://backend:2001"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# See https://github.com/UCL-INGI/INGInious/issues/352
- ./tasks/:/inginious/tasks
- ./backups/:/inginious/backups
# See https://github.com/UCL-INGI/INGInious/issues/799
- /tmp/agent_data/:/tmp/agent_data/
networks:
- inginious

agent-mcq:
image: ${REGISTRY}/inginious/core-agent_mcq:${VERSION}
depends_on:
- backend
deploy:
replicas: 1
build:
dockerfile: deploy/agent-mcq.containerfile
args:
- VERSION=${VERSION}
- REGISTRY=${REGISTRY}
environment:
BACKEND: "tcp://backend:2001"
volumes:
# See https://github.com/UCL-INGI/INGInious/issues/352
- ./tasks/:/inginious/tasks
- ./backups/:/inginious/backups
# See https://github.com/UCL-INGI/INGInious/issues/799
- /tmp/agent_data/:/tmp/agent_data/
networks:
- inginious

frontend:
image: ${REGISTRY}/inginious/core-frontend:${VERSION}
build:
dockerfile: deploy/frontend.containerfile
args:
- VERSION=${VERSION}
- REGISTRY=${REGISTRY}
depends_on:
- backend
- agent-docker
- agent-mcq
environment:
- INGINIOUS_WEBAPP_HOST=0.0.0.0
volumes:
- ./configuration.deploy.yaml:/inginious/configuration.yaml
- ./tasks/:/inginious/tasks
- ./backups/:/inginious/backups
ports:
- 9000:8080
networks:
- inginious

networks:
inginious:
10 changes: 7 additions & 3 deletions inginious/frontend/arch_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@

from zmq.asyncio import ZMQEventLoop, Context

from inginious.agent.docker_agent import DockerAgent
from inginious.agent.mcq_agent import MCQAgent
from inginious.backend.backend import Backend
from inginious.client.client import Client

def start_asyncio_and_zmq(debug_asyncio=False):
Expand Down Expand Up @@ -88,6 +85,13 @@ def create_arch(configuration, tasks_fs, context, course_factory):
else:
debug_ports = range(64100, 64111)

""" Those imports are required in pip-based installation but are not available in
docker-compose based ones. """

from inginious.agent.docker_agent import DockerAgent
from inginious.agent.mcq_agent import MCQAgent
from inginious.backend.backend import Backend

client = Client(context, "inproc://backend_client")
backend = Backend(context, "inproc://backend_agent", "inproc://backend_client")
agent_docker = DockerAgent(context, "inproc://backend_agent", "Docker - Local agent", concurrency, tasks_fs, debug_host, debug_ports, tmp_dir, ssh_allowed=True)
Expand Down
28 changes: 14 additions & 14 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@
else:
install_requires += ["sh>=1.11"]

scripts = [] if os.environ.get("INGINIOUS_COMPOSE") else [
'inginious-agent-docker',
'inginious-agent-mcq',
'inginious-backend',
'inginious-webapp',
'inginious-webdav',
'inginious-install',
'inginious-autotest',
'utils/sync/inginious-synchronize',
'utils/container_update/inginious-container-update',
'utils/database_updater/inginious-database-update'
]

# Setup
setup(
name="INGInious",
Expand All @@ -69,20 +82,7 @@
"test": test_requires,
"doc": test_requires + doc_requires
},

scripts=[
'inginious-agent-docker',
'inginious-agent-mcq',
'inginious-backend',
'inginious-webapp',
'inginious-webdav',
'inginious-install',
'inginious-autotest',
'utils/sync/inginious-synchronize',
'utils/container_update/inginious-container-update',
'utils/database_updater/inginious-database-update'
],

scripts=scripts,
include_package_data=True,
test_suite='nose.collector',
author="INGInious contributors",
Expand Down

0 comments on commit 21abf3d

Please sign in to comment.