diff --git a/images/auth-service/Dockerfile b/images/auth-service/Dockerfile deleted file mode 100644 index ccd744dd..00000000 --- a/images/auth-service/Dockerfile +++ /dev/null @@ -1,49 +0,0 @@ -##### -## Docker image for the Django auth service -##### - -ARG ESGF_REPOSITORY_BASE=esgfdeploy -ARG ESGF_IMAGES_VERSION=latest -ARG GIT_REPOSITORY=https://github.com/cedadev/django-auth-service.git -ARG GIT_VERSION=b5f8c31817a1373828470b0899265be69455a6ec - -FROM ${ESGF_REPOSITORY_BASE}/python-build:${ESGF_IMAGES_VERSION} as python-build - -FROM ${ESGF_REPOSITORY_BASE}/conda:${ESGF_IMAGES_VERSION} - -USER root - -# Install gunicorn server, whitenoise to handle static files and -# django-flexi-settings for smart handling of settings -RUN pip install --no-cache-dir \ - 'gunicorn==20.0.4' \ - 'django-flexi-settings==0.1.1' \ - 'whitenoise==5.2.0' - -# Install gunicorn config file -COPY gunicorn.conf.py /etc/gunicorn/conf.py -COPY wsgi-serve.sh /usr/local/bin/ - -# Configure Django to use the flexi settings module -ENV DJANGO_SETTINGS_MODULE flexi_settings.settings -# Install the default settings -ENV DJANGO_FLEXI_SETTINGS_ROOT /etc/django/settings.py -COPY conf /etc/django -# Make sure the settings directory exists -RUN mkdir -p /etc/django/settings.d - -# Install init scripts and serving script -COPY django-serve.sh /usr/local/bin/ - -# Use ONBUILD instructions to install and configure the application -COPY --from=python-build /build/wheelhouse /build/wheelhouse -# Install the wheels that we copied -RUN pip install --no-deps /build/wheelhouse/*.whl -# Install the app settings -COPY settings.d/* /etc/django/settings.d/ -# Make sure to run as the ESGF user -USER $ESGF_UID - -# By default, serve the Django application on port 8080 -EXPOSE 8080 -CMD ["/usr/local/bin/django-serve.sh"] diff --git a/images/auth-service/conf/defaults.py b/images/auth-service/conf/defaults.py deleted file mode 100644 index f1f3ba61..00000000 --- a/images/auth-service/conf/defaults.py +++ /dev/null @@ -1,125 +0,0 @@ -""" -Default settings, including security best practices. -""" - -import os - -from django.core.management.utils import get_random_secret_key - - -# By default, don't run in DEBUG mode -DEBUG = False - -# In a Docker container, ALLOWED_HOSTS is always '*' - let the proxy worry about hosts -ALLOWED_HOSTS = ['*'] - -# Make sure Django interprets the script name correctly if set -if 'SCRIPT_NAME' in os.environ: - FORCE_SCRIPT_NAME = os.environ['SCRIPT_NAME'] - -# Security settings -SECURE_CONTENT_TYPE_NOSNIFF = True -SECURE_BROWSER_XSS_FILTER = True -SESSION_COOKIE_SECURE = True -CSRF_COOKIE_SECURE = True -CSRF_COOKIE_HTTPONLY = True -X_FRAME_OPTIONS = 'DENY' -SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') - -# Set a default random secret key -# This can be overridden by files included later if desired -SECRET_KEY = get_random_secret_key() - -# All logging should go to stdout/stderr to be collected -import logging -LOG_FORMAT = '[%(levelname)s] [%(asctime)s] [%(name)s:%(lineno)s] [%(threadName)s] %(message)s' -LOGGING = { - 'version' : 1, - 'disable_existing_loggers' : False, - 'formatters' : { - 'default' : { - 'format' : LOG_FORMAT, - }, - }, - 'filters' : { - # Logging filter that only accepts records with a level < WARNING - # This allows us to log level >= WARNING to stderr and level < WARNING to stdout - 'less_than_warning' : { - '()': 'django.utils.log.CallbackFilter', - 'callback': lambda record: record.levelno < logging.WARNING, - }, - }, - 'handlers' : { - 'stdout' : { - 'class' : 'logging.StreamHandler', - 'stream' : 'ext://sys.stdout', - 'formatter' : 'default', - 'filters': ['less_than_warning'], - }, - 'stderr' : { - 'class' : 'logging.StreamHandler', - 'stream' : 'ext://sys.stderr', - 'formatter' : 'default', - 'level' : 'WARNING', - }, - }, - 'loggers' : { - '' : { - 'handlers' : ['stdout', 'stderr'], - 'level' : 'INFO', - 'propogate' : True, - }, - }, -} - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], - }, - }, -] - -# By default, no databases are defined -DATABASES = {} - -# Authentication settings -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - -# IMPORTANT: CookieStorage (and hence FallbackStorage, which is the default) interacts -# badly with Chrome's prefetching, causing messages to be rendered twice -# or not at all...! -MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage' - -# Default internationalization settings -LANGUAGE_CODE = 'en-gb' -TIME_ZONE = 'Europe/London' -USE_I18N = True -USE_L10N = True -USE_TZ = True - -# Static files (CSS, JavaScript, Images) -# Make sure to include the WSGI script name in the static URL -STATIC_URL = '{}/static/'.format(os.environ.get('SCRIPT_NAME', '')) -STATIC_ROOT = '/var/django/staticfiles' diff --git a/images/auth-service/conf/settings.py b/images/auth-service/conf/settings.py deleted file mode 100644 index e0f70371..00000000 --- a/images/auth-service/conf/settings.py +++ /dev/null @@ -1,20 +0,0 @@ -""" -Root settings file - -Includes settings files from a sibling directory called settings.d. -""" - -import os -from pathlib import Path - -from flexi_settings import include, include_dir - - -base_dir = Path(__file__).resolve().parent - -# First, include the defaults -include(base_dir / "defaults.py") -# Then include the user settings -include_dir(base_dir / "settings.d") -# Always include the whitenoise settings to configure static files -include(base_dir / "whitenoise.py") diff --git a/images/auth-service/conf/whitenoise.py b/images/auth-service/conf/whitenoise.py deleted file mode 100644 index 213daf52..00000000 --- a/images/auth-service/conf/whitenoise.py +++ /dev/null @@ -1,18 +0,0 @@ -""" -Modify settings to serve static files using whitenoise. -""" - -_SECURITY_MIDDLEWARE = 'django.middleware.security.SecurityMiddleware' -_WHITENOISE_MIDDLEWARE = 'whitenoise.middleware.WhiteNoiseMiddleware' - -# Make sure MIDDLEWARE is a list, not a tuple -MIDDLEWARE = list(globals().get('MIDDLEWARE', [])) -# As per the docs, inject the whitenoise middleware after the security middleware -try: - index = MIDDLEWARE.index(_SECURITY_MIDDLEWARE) -except ValueError: - index = -1 -MIDDLEWARE.insert(index + 1, _WHITENOISE_MIDDLEWARE) - -# Use the whitenoise static file storage for caching, compression etc. -STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' diff --git a/images/auth-service/django-serve.sh b/images/auth-service/django-serve.sh deleted file mode 100755 index 118ea01d..00000000 --- a/images/auth-service/django-serve.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/bash - -# Extract the WSGI application from the Django settings -echo "[info] Extracting WSGI application from Django settings" -# The Django WSGI_APPLICATION setting has all dots, whereas gunicorn expects "py.mod:var" -# So we need to replace the right-most dot with a colon -wsgi_application_script=" -from django.conf import settings -print(settings.WSGI_APPLICATION[::-1].replace('.', ':', 1)[::-1]) -" -WSGI_APPLICATION="$(django-admin shell -c "$wsgi_application_script")" - -echo "[info] Running WSGI application $WSGI_APPLICATION" -exec /usr/local/bin/wsgi-serve.sh $WSGI_APPLICATION diff --git a/images/auth-service/gunicorn.conf.py b/images/auth-service/gunicorn.conf.py deleted file mode 100644 index 28bd525b..00000000 --- a/images/auth-service/gunicorn.conf.py +++ /dev/null @@ -1,25 +0,0 @@ -# Default settings for gunicorn -# Also allows for overriding with environment variables - -import os - -# Configure the bind address -_host = os.environ.get("GUNICORN_HOST", "0.0.0.0") -_port = os.environ.get("GUNICORN_PORT", "8080") -bind = os.environ.get("GUNICORN_BIND", '{}:{}'.format(_host, _port)) - -# Configure the workers -workers = int(os.environ.get("GUNICORN_WORKERS", "2")) -threads = int(os.environ.get("GUNICORN_THREADS", "4")) -worker_class = os.environ.get("GUNICORN_WORKER_CLASS", "gthread") - -# Configure logging -loglevel = os.environ.get("GUNICORN_LOGLEVEL", 'info') -errorlog = "-" -# Access logging on by default -if os.environ.get('GUNICORN_ACCESSLOG', '1') in {'1', 'yes', 'on', 'true'}: - accesslog = '-' -else: - accesslog = None -# Use the value of the remote ip header in the access log format -access_log_format = '%({x-forwarded-for}i)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"' diff --git a/images/auth-service/settings.d/00-settings.py b/images/auth-service/settings.d/00-settings.py deleted file mode 100644 index a99c7680..00000000 --- a/images/auth-service/settings.d/00-settings.py +++ /dev/null @@ -1,45 +0,0 @@ -import re - -from django.conf import settings -from urllib.parse import urlparse - -from authenticate.utils import get_requested_resource - -# Application definition - -INSTALLED_APPS = [ - 'django.contrib.staticfiles', - 'django.contrib.sessions', - 'authenticate', -] - -ROOT_URLCONF = 'auth_service.urls' -WSGI_APPLICATION = 'auth_service.wsgi.application' - -# Use a non database session engine -SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' -SESSION_COOKIE_SECURE = False - -# Authorization exemption function -def is_exempt(request): - - if not settings.SECURED_PATHS: - return False - - resource = get_requested_resource(request) - if resource: - - is_secured_path = False - - # Check exempt path patterns against requested URL - path = urlparse(resource).path.lstrip("/") - for expr in settings.SECURED_PATHS: - - if re.compile(expr).match(path): - is_secured_path = True - break - - return not is_secured_path - -SECURED_PATHS = [] # e.g. [".*"] -AUTHORIZATION_EXEMPT_FILTER = is_exempt diff --git a/images/auth-service/wsgi-serve.sh b/images/auth-service/wsgi-serve.sh deleted file mode 100755 index bfff3dd7..00000000 --- a/images/auth-service/wsgi-serve.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/bash - -# Allows for the specification of WSGI application using an environment variable - -echo "[info] Starting gunicorn" -exec gunicorn --config /etc/gunicorn/conf.py "$@" diff --git a/images/conda/Dockerfile b/images/conda/Dockerfile deleted file mode 100755 index a0da0736..00000000 --- a/images/conda/Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -##### -## Base image for all images that require a basic Conda installation -##### - -ARG ESGF_REPOSITORY_BASE=esgfdeploy -ARG ESGF_IMAGES_VERSION=latest -FROM ${ESGF_REPOSITORY_BASE}/base:${ESGF_IMAGES_VERSION} - -USER root - -# Configure environment -ENV MAMBA_HOME /opt/conda -ENV PATH $MAMBA_HOME/bin:$PATH -# Don't buffer stdout and stderr as it breaks realtime logging -ENV PYTHONUNBUFFERED 1 - -# Install and configure Conda -ARG CONDA_VERSION=23.11.0 -ARG MF_RELEASE=0 -ARG MF_MD5SUM=ee57176f95c313b23850e0221498f8e8 -ARG MF_VERSION=$CONDA_VERSION-$MF_RELEASE -ARG INSTALLER=miniconda.sh -ARG ACTIVATE_SCRIPT=/usr/local/bin/mamba_activate.sh -RUN curl -fsSL -o $INSTALLER https://github.com/conda-forge/miniforge/releases/download/$MF_VERSION/Miniforge3-$MF_VERSION-Linux-x86_64.sh && \ - echo "${MF_MD5SUM} ${INSTALLER}" | md5sum --check - && \ - /bin/bash $INSTALLER -f -b -p $MAMBA_HOME && \ - rm $INSTALLER && \ - echo "conda ${CONDA_VERSION}" >> $MAMBA_HOME/conda-meta/pinned && \ - ${MAMBA_HOME}/bin/conda shell.bash hook > $ACTIVATE_SCRIPT && \ - . $ACTIVATE_SCRIPT && \ - conda config --system --set auto_update_conda false && \ - conda config --system --set show_channel_urls true && \ - mamba update --all --quiet --yes && \ - conda list python | grep '^python ' | tr -s ' ' | cut -d '.' -f 1,2 | sed 's/$/.*/' >> $MAMBA_HOME/conda-meta/pinned && \ - conda clean --all -f -y - -USER $ESGF_UID diff --git a/images/conda/README.md b/images/conda/README.md deleted file mode 100755 index fdfa3073..00000000 --- a/images/conda/README.md +++ /dev/null @@ -1,10 +0,0 @@ -##### -## Image for providing a conda environment -## -## Intended for use as a base image for Python images -##### - -This image provides a [Python 3.7](https://docs.python.org/3.7/) environment using -[Miniconda](https://docs.conda.io/en/latest/miniconda.html). - -It is used as the base image for all Python application images. diff --git a/images/jdk/Dockerfile b/images/jdk/Dockerfile deleted file mode 100644 index 09a2b742..00000000 --- a/images/jdk/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -##### -## Image containing the full JDK -## -## Intended for use by builder images that need to unpack war files -## Runtime Java images should use the JRE only -##### - -ARG ESGF_REPOSITORY_BASE=esgfdeploy -ARG ESGF_IMAGES_VERSION=latest -FROM ${ESGF_REPOSITORY_BASE}/base:${ESGF_IMAGES_VERSION} - -USER root - -RUN dnf makecache && \ - dnf install -y java-11-openjdk-devel && \ - dnf clean all diff --git a/images/jre/Dockerfile b/images/jre/Dockerfile deleted file mode 100644 index 1ee29c32..00000000 --- a/images/jre/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -##### -## Image containing the JRE -## -## Intended for use as a base image for runtime Java images -##### - -ARG ESGF_REPOSITORY_BASE=esgfdeploy -ARG ESGF_IMAGES_VERSION=latest -FROM ${ESGF_REPOSITORY_BASE}/base:${ESGF_IMAGES_VERSION} - -USER root - -RUN dnf makecache && \ - dnf install -y java-11-openjdk-headless && \ - dnf clean all - -USER $ESGF_UID diff --git a/images/opa/Dockerfile b/images/opa/Dockerfile deleted file mode 100644 index 97f2385d..00000000 --- a/images/opa/Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -##### -## Docker image for the OPA server -##### - -ARG ESGF_REPOSITORY_BASE=esgfdeploy -ARG ESGF_IMAGES_VERSION=latest -ARG OPA_URL=https://github.com/open-policy-agent/opa/releases/download/v0.27.1/opa_linux_amd64 - -FROM ${ESGF_REPOSITORY_BASE}/base:${ESGF_IMAGES_VERSION} - -ARG OPA_URL - -USER root - -RUN curl -L $OPA_URL -o /opa -RUN chown -R $ESGF_USER:$ESGF_GROUP /opa -RUN chmod +x /opa - -USER $ESGF_UID - -ENTRYPOINT ["/opa"] -CMD ["run"] diff --git a/images/python-build/Dockerfile b/images/python-build/Dockerfile deleted file mode 100755 index a82b4395..00000000 --- a/images/python-build/Dockerfile +++ /dev/null @@ -1,55 +0,0 @@ -##### -## Docker image that can be used to build wheels for a Python application and its dependencies -##### - -ARG ESGF_REPOSITORY_BASE=esgfdeploy -ARG ESGF_IMAGES_VERSION=latest -FROM ${ESGF_REPOSITORY_BASE}/conda:${ESGF_IMAGES_VERSION} - -USER root - -# Install common dependencies: -# gcc as it is often required to build things -# git for projects that use setuptools_scm -RUN dnf makecache && dnf install -y gcc git && dnf clean all - -# Use ONBUILD triggers to checkout the application code -# Clone the repository and checkout the version -ONBUILD ARG GIT_REPOSITORY -ONBUILD ARG GIT_VERSION -# Make sure that any git submodules are also pulled -ONBUILD RUN \ - git clone $GIT_REPOSITORY /application && \ - pushd /application && \ - git checkout $GIT_VERSION && \ - git submodule update --init --recursive && \ - popd - -# Because we are using poetry, generate a requirements file from poetry.lock -# So it can be installed by python-build. -ONBUILD RUN python -m pip install --quiet poetry -ONBUILD RUN poetry self add poetry-plugin-export -ONBUILD WORKDIR /application -ONBUILD RUN poetry export \ - --format requirements.txt \ - --output requirements.txt \ - --without-hashes \ - --no-interaction - -# Use ONBUILD triggers to build the wheels -# Move into the application source directory so that consumers can use relative requirements paths -ONBUILD WORKDIR /application -# Allow the requirements file to be overridden, using /application/requirements.txt by default -ONBUILD ARG REQUIREMENTS_FILE=./requirements.txt -# Build wheels for the application -ONBUILD RUN \ - pip wheel \ - --wheel-dir /build/wheelhouse \ - --no-deps \ - --requirement $REQUIREMENTS_FILE && \ - pip wheel \ - --wheel-dir /build/wheelhouse \ - --no-deps \ - /application - -ONBUILD USER $ESGF_UID diff --git a/images/search-builder/Dockerfile b/images/search-builder/Dockerfile deleted file mode 100644 index cea887c2..00000000 --- a/images/search-builder/Dockerfile +++ /dev/null @@ -1,72 +0,0 @@ -##### -## Image for running THREDDS -##### - -ARG ESGF_REPOSITORY_BASE=esgfdeploy -ARG ESGF_IMAGES_VERSION=latest -FROM ${ESGF_REPOSITORY_BASE}/jdk:${ESGF_IMAGES_VERSION} - -ARG IVY_VERSION=2.3.0 -ARG IVY_URL=https://archive.apache.org/dist/ant/ivy/$IVY_VERSION/apache-ivy-$IVY_VERSION-bin-with-deps.tar.gz -ARG IVY_SHA512=073b497e5e45fa5dcca5881180ccde0a -ARG PYTHON_MD5=d235bdfa75b8396942e360a70487ee00 - -# Install dependencies -RUN dnf makecache && \ - dnf install -y git ant openssl-devel && \ - dnf -y groupinstall "development tools" && \ - dnf clean all - -RUN curl -fsSl -o Python-2.7.18.tgz https://www.python.org/ftp/python/2.7.18/Python-2.7.18.tgz - #echo "$PYTHON_MD5 *Python-2.7.18.tgz" | md5sum --strict --check && \ -RUN tar -xzf Python-2.7.18.tgz --strip-components=1 -RUN ./configure --prefix=/usr/local --enable-shared --enable-unicode=ucs4 -RUN make && make altinstall -ENV LD_LIBRARY_PATH=/usr/local/lib:/usr/local/bin/python2.7:\$LD_LIBRARY_PATH - -RUN python2.7 -m ensurepip --upgrade - -RUN which python2.7 -RUN cp /usr/local/bin/python2.7 /usr/bin/python - -RUN curl -fsSl -o ivy.tar.gz $IVY_URL && \ - # echo "$IVY_SHA512 *ivy.tar.gz" | md5sum --strict --check && \ - tar -xzf ivy.tar.gz --strip-components=1 && \ - java -jar ivy-$IVY_VERSION.jar - -RUN pip2 install ez_setup - -# Build esgf-node-manager -ARG ESGF_NODE_MANAGER_VERSION=15682f64212782a56eacdb356432e9e21d643e1d -RUN git clone https://github.com/ESGF/esgf-node-manager.git /src/esgf-node-manager && \ - pushd /src/esgf-node-manager && \ - git checkout $ESGF_NODE_MANAGER_VERSION && \ - popd -RUN pushd /src/esgf-node-manager && \ - ant make_dist publish_local && \ - popd - -# Build esgf-security -ARG ESGF_SECURITY_VERSION=a510b3f4807a683e34e32ffae11ee45f6481fd59 -RUN git clone https://github.com/ESGF/esgf-security.git /src/esgf-security && \ - pushd /src/esgf-security && \ - git checkout $ESGF_SECURITY_VERSION && \ - popd -RUN pushd /src/esgf-security && \ - ant clean_all make_dist publish_local && \ - popd - -# # Build esg-search -ARG ESG_SEARCH_VERSION=fa1092dae808d15cc623ee5f4b274d94762ad171 -RUN git clone https://github.com/ESGF/esg-search.git /src/esg-search && \ - pushd /src/esg-search && \ - git checkout $ESG_SEARCH_VERSION && \ - popd -RUN pushd /src/esg-search && \ - ant clean_all make_dist publish_local && \ - popd - -# Unpack the esg-search war into /application -RUN mkdir /application && \ - pushd /application && \ - jar xvf /src/esg-search/dist/esg-search.war diff --git a/images/thredds/Dockerfile b/images/thredds/Dockerfile index e4784297..b9d042bd 100644 --- a/images/thredds/Dockerfile +++ b/images/thredds/Dockerfile @@ -5,7 +5,11 @@ ARG ESGF_REPOSITORY_BASE=esgfdeploy ARG ESGF_IMAGES_VERSION=latest -FROM ${ESGF_REPOSITORY_BASE}/jdk:${ESGF_IMAGES_VERSION} as builder +FROM ${ESGF_REPOSITORY_BASE}/base:${ESGF_IMAGES_VERSION} as builder + +RUN dnf makecache && \ + dnf install -y java-11-openjdk-devel && \ + dnf clean all # Unpack the THREDDS war ARG THREDDS_VERSION=5.5 diff --git a/images/tomcat/Dockerfile b/images/tomcat/Dockerfile index 56ee1121..2b23a959 100644 --- a/images/tomcat/Dockerfile +++ b/images/tomcat/Dockerfile @@ -4,7 +4,11 @@ ARG ESGF_REPOSITORY_BASE=esgfdeploy ARG ESGF_IMAGES_VERSION=latest -FROM ${ESGF_REPOSITORY_BASE}/jre:${ESGF_IMAGES_VERSION} +FROM ${ESGF_REPOSITORY_BASE}/base:${ESGF_IMAGES_VERSION} + +RUN dnf makecache && \ + dnf install -y java-21-openjdk-headless && \ + dnf clean all USER root