Files
edx-platform/Dockerfile
Tim McCormack 67140624ed build: Install wget in development docker image (#33288)
It's needed by `make common_constraints.txt`. We're starting to see
failures running this command in lms-shell in devstack. This has probably
been going on the entire time, but the error suppression was only removed
recently in <https://github.com/openedx/edx-platform/pull/33271>.

The new RUN instruction for installing wget is added to the development
layer only, partly to limit image sizes and partly to make life harder for
any attacker who manages to gain code execution in production.

I've moved `USER app` from the end of the `base` layer to the start of the
`production` layer, since the only other layer (in this file) that builds
on `base` is `development`, which more or less immediately switches back
to root. (The intervening COPY instruction is not affected by the current
user.)

Ticket: https://github.com/openedx/edx-platform/issues/33287
2023-09-19 20:39:12 +00:00

193 lines
6.6 KiB
Docker

FROM ubuntu:focal as minimal-system
# Warning: This file is experimental.
#
# Short-term goals:
# * Be a suitable replacement for the `edxops/edxapp` image in devstack (in progress).
# * Take advantage of Docker caching layers: aim to put commands in order of
# increasing cache-busting frequency.
# * Related to ^, use no Ansible or Paver.
# Long-term goal:
# * Be a suitable base for production LMS and CMS images (THIS IS NOT YET THE CASE!).
ARG DEBIAN_FRONTEND=noninteractive
ARG SERVICE_VARIANT
ARG SERVICE_PORT
# Env vars: paver
# We intentionally don't use paver in this Dockerfile, but Devstack may invoke paver commands
# during provisioning. Enabling NO_PREREQ_INSTALL tells paver not to re-install Python
# requirements for every paver command, potentially saving a lot of developer time.
ARG NO_PREREQ_INSTALL='1'
# Env vars: locale
ENV LANG='en_US.UTF-8'
ENV LANGUAGE='en_US:en'
ENV LC_ALL='en_US.UTF-8'
# Env vars: configuration
ENV CONFIG_ROOT='/edx/etc'
ENV LMS_CFG="$CONFIG_ROOT/lms.yml"
ENV CMS_CFG="$CONFIG_ROOT/cms.yml"
# Env vars: path
ENV VIRTUAL_ENV="/edx/app/edxapp/venvs/edxapp"
ENV PATH="${VIRTUAL_ENV}/bin:${PATH}"
ENV PATH="/edx/app/edxapp/edx-platform/node_modules/.bin:${PATH}"
ENV PATH="/edx/app/edxapp/edx-platform/bin:${PATH}"
ENV PATH="/edx/app/edxapp/nodeenv/bin:${PATH}"
WORKDIR /edx/app/edxapp/edx-platform
# Create user before assigning any directory ownership to it.
RUN useradd -m --shell /bin/false app
# Use debconf to set locales to be generated when the locales apt package is installed later.
RUN echo "locales locales/default_environment_locale select en_US.UTF-8" | debconf-set-selections
RUN echo "locales locales/locales_to_be_generated multiselect en_US.UTF-8 UTF-8" | debconf-set-selections
# Install requirements that are absolutely necessary
RUN apt-get update && \
apt-get -y dist-upgrade && \
apt-get -y install --no-install-recommends \
python3 \
python3-venv \
python3.8 \
python3.8-minimal \
# python3-dev: required for building mysqlclient python package version 2.2.0
python3-dev \
libpython3.8 \
libpython3.8-stdlib \
libmysqlclient21 \
# libmysqlclient-dev: required for building mysqlclient python package version 2.2.0
libmysqlclient-dev \
pkg-config \
libssl1.1 \
libxmlsec1-openssl \
# lynx: Required by https://github.com/openedx/edx-platform/blob/b489a4ecb122/openedx/core/lib/html_to_text.py#L16
lynx \
ntp \
git \
build-essential \
gettext \
gfortran \
graphviz \
locales \
swig \
&& \
apt-get clean all && \
rm -rf /var/lib/apt/*
RUN mkdir -p /edx/var/edxapp
RUN mkdir -p /edx/etc
RUN chown app:app /edx/var/edxapp
# The builder-production stage is a temporary stage that installs required packages and builds the python virtualenv,
# installs nodejs and node_modules.
# The built artifacts from this stage are then copied to the base stage.
FROM minimal-system as builder-production
RUN apt-get update && \
apt-get -y install --no-install-recommends \
curl \
libssl-dev \
libffi-dev \
libfreetype6-dev \
libgeos-dev \
libgraphviz-dev \
libjpeg8-dev \
liblapack-dev \
libpng-dev \
libsqlite3-dev \
libxml2-dev \
libxmlsec1-dev \
libxslt1-dev
# Setup python virtual environment
# It is already 'activated' because $VIRTUAL_ENV/bin was put on $PATH
RUN python3.8 -m venv "${VIRTUAL_ENV}"
# Install python requirements
# Requires copying over requirements files, but not entire repository
COPY requirements requirements
RUN pip install -r requirements/pip.txt
RUN pip install -r requirements/edx/base.txt
# Install node and npm
RUN nodeenv /edx/app/edxapp/nodeenv --node=16.14.0 --prebuilt
RUN npm install -g npm@8.5.x
# This script is used by an npm post-install hook.
# We copy it into the image now so that it will be available when we run `npm install` in the next step.
# The script itself will copy certain modules into some uber-legacy parts of edx-platform which still use RequireJS.
COPY scripts/copy-node-modules.sh scripts/copy-node-modules.sh
# Install node modules
COPY package.json package.json
COPY package-lock.json package-lock.json
RUN npm set progress=false && npm ci
# The builder-development stage is a temporary stage that installs python modules required for development purposes
# The built artifacts from this stage are then copied to the development stage.
FROM builder-production as builder-development
RUN pip install -r requirements/edx/development.txt
# base stage
FROM minimal-system as base
# Copy python virtual environment, nodejs and node_modules
COPY --from=builder-production /edx/app/edxapp/venvs/edxapp /edx/app/edxapp/venvs/edxapp
COPY --from=builder-production /edx/app/edxapp/nodeenv /edx/app/edxapp/nodeenv
COPY --from=builder-production /edx/app/edxapp/edx-platform/node_modules /edx/app/edxapp/edx-platform/node_modules
# Copy over remaining parts of repository (including all code)
COPY . .
# Install Python requirements again in order to capture local projects
RUN pip install -e .
# Production target
FROM base as production
USER app
ENV EDX_PLATFORM_SETTINGS='docker-production'
ENV SERVICE_VARIANT "${SERVICE_VARIANT}"
ENV SERVICE_PORT "${SERVICE_PORT}"
ENV DJANGO_SETTINGS_MODULE="${SERVICE_VARIANT}.envs.$EDX_PLATFORM_SETTINGS"
EXPOSE ${SERVICE_PORT}
CMD gunicorn \
-c /edx/app/edxapp/edx-platform/${SERVICE_VARIANT}/docker_${SERVICE_VARIANT}_gunicorn.py \
--name ${SERVICE_VARIANT} \
--bind=0.0.0.0:${SERVICE_PORT} \
--max-requests=1000 \
--access-logfile \
- ${SERVICE_VARIANT}.wsgi:application
# Development target
FROM base as development
RUN apt-get update && \
apt-get -y install --no-install-recommends \
# wget is used in Makefile for common_constraints.txt
wget \
&& \
apt-get clean all && \
rm -rf /var/lib/apt/*
COPY --from=builder-development /edx/app/edxapp/venvs/edxapp /edx/app/edxapp/venvs/edxapp
RUN ln -s "$(pwd)/lms/envs/devstack-experimental.yml" "$LMS_CFG"
RUN ln -s "$(pwd)/cms/envs/devstack-experimental.yml" "$CMS_CFG"
# Temporary compatibility hack while devstack is supporting both the old `edxops/edxapp` image and this image.
# * Add in a dummy ../edxapp_env file
# * devstack sets /edx/etc/studio.yml as CMS_CFG.
RUN ln -s "$(pwd)/cms/envs/devstack-experimental.yml" "/edx/etc/studio.yml"
RUN touch ../edxapp_env
ENV EDX_PLATFORM_SETTINGS='devstack_docker'
ENV SERVICE_VARIANT "${SERVICE_VARIANT}"
EXPOSE ${SERVICE_PORT}
CMD ./manage.py ${SERVICE_VARIANT} runserver 0.0.0.0:${SERVICE_PORT}