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

DevContainer! #11443

Open
wants to merge 8 commits into
base: release-v0.16.x
Choose a base branch
from
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
50 changes: 50 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// For format details, see https://aka.ms/devcontainer.json.
{
"name": "Kolibri Dev Container",
"build": {
"dockerfile": "../docker/base.dockerfile",
"context": ".."
},
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {
"username": "devuser",
"upgradePackages": true,
"installZsh": false,
"configureZshAsDefaultShell": false,
"installOhMyZsh": false,
"installOhMyZshConfig": false,
"nonFreePackages": false
}
},
"workspaceMount": "source=${localWorkspaceFolder},target=/kolibri,type=bind",
"workspaceFolder": "/kolibri",
"forwardPorts": [
3000
],
"portsAttributes": {
"3000": {
"label": "Webpack port",
"onAutoForward": "silent"
}
},
"containerEnv": {
"KOLIBRI_RUN_MODE": "docker_dev",
"KOLIBRI_HOME": "/kolibri/.devcontainer/persist_dir/.kolibri"
},
"remoteEnv": {
"GIT_EDITOR": "nano"
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"octref.vetur",
"editorconfig.editorconfig"
]
}
},
"onCreateCommand": "yarn install --non-interactive --frozen-lockfile && pip install -e . && pre-commit install",
"containerUser": "devuser",
"remoteUser": "devuser"
}
1 change: 1 addition & 0 deletions .devcontainer/persist_dir/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This directory is used by the devcontainer to persist kolibri related directories.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
# can be used to pass in a pre-build pex file or fixtures for tests
docker/mnt/

.devcontainer/persist_dir/*
!.devcontainer/persist_dir/README.md

# other docker files
docker-whl.cid
docker-whl.iid
Expand Down
73 changes: 30 additions & 43 deletions docker/base.dockerfile
Original file line number Diff line number Diff line change
@@ -1,43 +1,30 @@
FROM ubuntu:jammy

ENV NODE_VERSION=16.20.0

# install required packages
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
curl \
software-properties-common \
gettext \
git \
git-lfs \
psmisc \
python3 \
python3-pip \
python3-sphinx

# add yarn ppa
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list

# install nodejs and yarn
RUN apt-get update && \
ARCH=$(dpkg --print-architecture) && \
curl -sSO https://deb.nodesource.com/node_16.x/pool/main/n/nodejs/nodejs_$NODE_VERSION-1nodesource1_$ARCH.deb && \
dpkg -i ./nodejs_$NODE_VERSION-1nodesource1_$ARCH.deb && \
rm nodejs_$NODE_VERSION-1nodesource1_$ARCH.deb && \
apt-get install yarn

RUN git lfs install

# Check if symbolic links exist before creating them
RUN if [ ! -f /usr/bin/python ]; then ln -s /usr/bin/python3 /usr/bin/python; fi \
&& if [ ! -f /usr/bin/pip ]; then ln -s /usr/bin/pip3 /usr/bin/pip; fi

# copy Kolibri source code into image
COPY . /kolibri

# do the time-consuming base install commands
RUN cd /kolibri \
&& pip3 install -r requirements/dev.txt \
&& pip3 install -r requirements/test.txt \
&& yarn install --network-timeout 100000
# This Dockerfile serves as a base image for Kolibri installations. It installs python, required OS packages, node, npm, yarn and python dependencies.

# Declare python version argument.
ARG PYTHON_VARIANT="3.9-slim"
FROM python:${PYTHON_VARIANT}

# Declare node major version argument.
ARG NODE_MAJOR_VERSION="16"

# Install only the absolutely-required packages to run Kolibri -- Git, Git-LFS, ip, ps and Node (plus npm).
RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y ca-certificates curl gnupg git git-lfs procps iproute2 \
&& mkdir -p /etc/apt/keyrings \
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There isn't much benefit to setting up nodesource as a apt-repo inside the image. Also, there are better ways to handle this in a docker file, to better take advantage of caching.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nodesource suggested setting up apt-repo so that apt update and apt install can figure out nodesource repo.
https://github.com/nodesource/distributions?tab=readme-ov-file#installation-instructions

Regarding caching, I tried to keep the commands in one RUN command to make best use of caching. If there's more we can do to further improve on that then please let me know and I will do it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, they'd suggest an apt-repo, but this is a container! It will likely only ever be installed once so it'll never use it for checking for updates!

For example, if the node.js version changes, this installs ca-certificates curl gnupg git git-lfs procps iproute2 all over again. So no this isn't making the best use of caching.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, they'd suggest an apt-repo, but this is a container! It will likely only ever be installed once so it'll never use it for checking for updates!

So without apt-repo, how should we install node?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your changes here modified how we were doing it before, which was not to use the apt-repo.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah right, I will fix that with our refactor of base & dev dockerfiles.

&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR_VERSION.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \
&& apt-get update && apt-get install -t nodistro -y nodejs

# Install yarn.
RUN npm install --global yarn

# Change working directory for the commands that follow.
WORKDIR /kolibri
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably, one could have built an image of Kolibri, containing its source, with this file before this change. After this change, which removes COPY . /kolibri, the base image no longer contains the source, which could have unknown effects 'downstream' on things that may rely on this.

The dev version already copies the source but I think it's worth considering whether a container that is used to develop Kolibri, like using the DevContainer tool, needs to intersect or build on top of the same image potentially used to deploy Kolibri (something which we want to eventually support-- having a clear docker image for Kolibri).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially, my thought process was on those lines so I kept the devcontainer dockerfile completely isolated from deployable dockerfiles. But then eventually it turned out that keeping maintainability in mind utilising the base dockerfile would be better so went that route.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@bjester bjester Dec 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keeping maintainability in mind utilising the base dockerfile

These changes are backwards incompatible though, so you haven't kept any maintainability.

The two images, a dev container image and a deployable image, have some commonalities such as installing python requirements, but overall have different use cases and responsibilities. For instance, a deployable Kolibri image doesn't need node.js (an existing dilemna) because node.js is only needed for building static JS/CSS resources.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, so having a separate dockerfile for devcontainer is better, isn't it? 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed this a while back, and I asked that you think about this holistically considering we have the desire to make running Kolibri in a docker container more well documented and to potentially have a well-defined shippable image. As I said, the two use cases have commonalities in how define and build these docker images but they have different responsibilities. With base.dockerfile and dev.dockerfile we already have some of that implemented and separated, but it isn't perfect and it isn't adapted for dev containers. Your changes here have integrated dev containers with what we already have, but have targeted much of that to base and thus muddled base vs dev. TL;DR we already have a separate dockerfile for development but your changes here only affect base.dockerfile!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally agree with you on this that the current approach of this PR has put everything in just the base.dockerfile.

I think we need to decide on how our shippable docker image for Kolibri will look like so that we can decide whether we should build our devcontainer image on top of that or not. I think I should talk to David to sort this out as soon as we can...?


# Copy python dependency files and install them.
COPY requirements/ ./requirements
COPY requirements.txt ./
RUN pip install --upgrade --root-user-action=ignore --default-timeout=150 pip \
&& pip install -r requirements.txt --upgrade --root-user-action=ignore --default-timeout=150 \
&& pip install -r requirements/dev.txt --upgrade --root-user-action=ignore --default-timeout=150 \
&& pip install -r requirements/test.txt --upgrade --root-user-action=ignore --default-timeout=150 \
&& pip install -r requirements/docs.txt --upgrade --root-user-action=ignore --default-timeout=150
2 changes: 2 additions & 0 deletions docker/dev.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ COPY . /kolibri

WORKDIR /kolibri

RUN yarn install --non-interactive --frozen-lockfile

ENTRYPOINT ["python", "/docker/entrypoint.py"]

# Install kolibri from source
Expand Down
Binary file added docs/dev-container-loading.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
80 changes: 77 additions & 3 deletions docs/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,19 @@ Finally, add the Learning Equality repo as a remote called `upstream`. That way
git fetch --all # Check if there are changes upstream
git checkout -t upstream/develop # Checkout the development branch

Choose your development environment setup
------------------------------------------

The following are the options available for setting up the development environment.

* :ref:`Host setup (Recommended) <host-setup>`: Use host setup if you are planning to contribute on a regular basis because host setup is a more efficient setup for long term code contributions.

* :ref:`Docker Dev Container setup <dev-container-setup>`: Use Dev Container setup if you want to quickly get started working on your task because this setup does not require installing Python and JavaScript runtime and their dependencies.

.. _host-setup:

Host setup
----------

Python and Pip
~~~~~~~~~~~~~~
Expand Down Expand Up @@ -186,6 +199,7 @@ To initialize the database run the following command:

kolibri manage migrate

.. _running_server:

Running the server
------------------
Expand Down Expand Up @@ -511,11 +525,71 @@ Go to Kolibri's `GitHub page <https://github.com/learningequality/kolibri>`__, a

Another member of the team will review your code, and either ask for updates on your part or merge your PR to Kolibri codebase. Until the PR is merged you can push new commits to your branch and add updates to it.

Learn more about our :ref:`dev_workflow` and :ref:`release_process`
Learn more about our :ref:`dev_workflow` and :ref:`release_process`.

.. _dev-container-setup:

Dev Container setup
-------------------

Dev Containers lets you use a Docker container as a full-featured development environment. It allows you to open the Kolibri codebase inside a docker container and take advantage of your editor or IDE's full feature set including IntelliSense, Code Navigation, GUI Debugging and Extensions. A Dev Container eliminates the need to install runtimes and dependencies.

Dev Container is well supported in VSCode, PyCharm and many other IDEs. We recommend using VSCode as your IDE for running the Kolibri Dev Container.

The following guide covers how to setup the Kolibri Dev Container in VSCode.

Installing Docker
~~~~~~~~~~~~~~~~~

Check whether Docker and Docker compose are installed in your system by running:

.. code-block:: bash

# Docker v18.06+ and Docker Compose v1.21+ is required for Dev Containers.
$ docker --version
Docker version 18.09.2, build 6247962
$ docker-compose --version
docker-compose version 1.29.2, build 5becea4c

If the above commands error out then that means you don't have Docker. You need to `install Docker <https://docs.docker.com/desktop/install/linux-install/>`__ to proceed further.

Installing Dev Container Extension
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Development using Docker
------------------------
Install the `Dev Containers extension in VSCode <https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers>`__.

Starting Dev Container
~~~~~~~~~~~~~~~~~~~~~~~
Open the Kolibri folder that you cloned in VSCode. After opening, click on the "Open a Remote Window" icon present in the bottom left corner.

.. image:: ./remote-window-open-vscode.png

Then click on the "Reopen in Container" option from the list.

.. image:: ./reopen-in-container-vscode.png

Then you will see that Dev Container is getting set up. You can click on "show log" to see the logs. It usually takes around five minutes for Dev Container to set up. Once the initial setup is complete, the next time you open, it will take just a few seconds.

.. image:: ./dev-container-loading.png

Running Kolibri inside Dev Container
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Once the Dev Container setup is complete, you will start seeing all the files on the left side of VSCode. Then you can open a new bash terminal on VSCode by using the shortcut ``Ctrl+Shift+```.

Any command you run on this terminal will work inside the Dev Container. Remember, all other commands mentioned in this documentation, including git related commands like ``git add``, ``git commit`` and so on, should be executed in this Dev Container terminal.

Finally, you can follow the :ref:`guide to start running the Kolibri server <running_server>`.

.. note::

If you would like to learn more about Dev Containers in general, refer `Developing inside a Container <https://code.visualstudio.com/docs/devcontainers/containers>`__.

Development using Docker (Legacy)
---------------------------------

.. warning::
The following documentation is for the legacy Docker setup and may be outdated. We recommend using :ref:`dev-container-setup` instead.

Engineers who are familiar with Docker can start a Kolibri instance without setting up the full JavaScript and Python development environments on the host machine.

Expand Down
Binary file added docs/remote-window-open-vscode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/reopen-in-container-vscode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.