Skip to content
Draft
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
335 changes: 335 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,335 @@
# syntax=docker/dockerfile:1
#
# Central multi-stage Dockerfile for all tool services.
#
# A single Maven build stage compiles every tool module so that Maven runs
# only once and Docker can cache the result across all subsequent stages.
#
# Build a specific tool service by targeting the appropriate stage, e.g.:
# docker build --target toolservice-emf -t emf-tool .
# docker build --target toolservice-emfatic -t emfatic-tool .
# docker build --target toolservice-ocl -t ocl-tool .
# docker build --target toolservice-conversion -t conversion-tool .
# docker build --target toolservice-xtext -t xtext-tool .

# ---------------------------------------------------------------------------
# Stage 1 – Maven build (all modules built in a single invocation)
# ---------------------------------------------------------------------------
FROM maven:3.8.5-openjdk-17 AS mavenbuilder

COPY services /usr/src/toolfunctions

WORKDIR /usr/src/toolfunctions

Comment on lines +20 to +23
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

The Maven build stage copies the entire services/ tree before running mvn, which means any change anywhere under services/ will invalidate the Docker cache for dependency download/build. To better leverage caching, copy services/pom.xml (and any other Maven metadata) first and run a dependency prefetch (or mvn -Pall -DskipTests ... as appropriate), then copy the rest of the sources and run the full build.

Suggested change
COPY services /usr/src/toolfunctions
WORKDIR /usr/src/toolfunctions
WORKDIR /usr/src/toolfunctions
# Copy Maven metadata first to leverage Docker layer caching for dependencies
COPY services/pom.xml /usr/src/toolfunctions/pom.xml
# Prefetch Maven dependencies without running tests or doing a full build
RUN mvn -Pall -DskipTests dependency:go-offline
# Now copy the full source tree and perform the actual build
COPY services /usr/src/toolfunctions

Copilot uses AI. Check for mistakes.
RUN mvn clean install -Pall

# Get runtime dependencies used by the tool-runner stages
RUN mvn org.apache.maven.plugins:maven-dependency-plugin:3.6.0:get \
-Dartifact=com.google.cloud.functions:function-maven-plugin:0.9.5 \
&& mvn org.apache.maven.plugins:maven-dependency-plugin:3.6.0:get \
-Dartifact=org.apache.maven.plugins:maven-deploy-plugin:2.7


# ---------------------------------------------------------------------------
# Stage 2a – Static frontend build for EMF
# ---------------------------------------------------------------------------
FROM node:19-bullseye AS staticbuild-emf

WORKDIR /usr/src/mdenet-tool

COPY static.emf/package*.json ./
COPY static.emf .

RUN npm install; npm run build; chmod -R 755 dist/
Comment on lines +40 to +43
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

Using npm install; npm run build; chmod ... with ; can mask failures because the shell exits with the status of the last command in the list. Use && chaining (and ideally npm ci when a lockfile is present) so the build reliably fails if install/build fails.

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +43
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

Dependency caching for this frontend stage is reduced because npm install runs after copying the full source tree. Consider copying only package*.json, running npm ci, then copying the rest of the sources and running the build (also use && instead of ; to avoid masking failures).

Copilot uses AI. Check for mistakes.


# ---------------------------------------------------------------------------
# Stage 2b – Static frontend build for Emfatic
# ---------------------------------------------------------------------------
FROM node:19-bullseye AS staticbuild-emfatic

WORKDIR /usr/src/mdenet-tool

COPY static.emfatic/package*.json ./
COPY static.emfatic .

RUN npm install; npm run build; chmod -R 755 dist/
Comment on lines +36 to +56
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

This stage uses node:19-bullseye. Node 19 is long EOL, so continuing to build on it increases security risk and may break future dependency installs. Please switch these frontend build stages to a supported LTS base image (and keep it consistent with the Node version used in the Xtext service stage).

Copilot uses AI. Check for mistakes.
Comment on lines +53 to +56
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

Same as the EMF static build: npm install; npm run build; ... should be changed to use && (to avoid masking failures) and preferably npm ci for reproducible installs when package-lock.json is present.

Copilot uses AI. Check for mistakes.


# ---------------------------------------------------------------------------
# Stage 2c – Static frontend build for OCL
# ---------------------------------------------------------------------------
FROM node:19-bullseye AS staticbuild-ocl

WORKDIR /usr/src/mdenet-tool

COPY static.ocl/package*.json ./
COPY static.ocl .

RUN npm install; npm run build; chmod -R 755 dist/
Comment on lines +66 to +69
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

Same issue here: using ; between npm commands can allow the Docker build to succeed even if npm install/npm run build fails (depending on the last command). Use && chaining and consider npm ci for lockfile-based installs.

Copilot uses AI. Check for mistakes.


# ---------------------------------------------------------------------------
# Stage 2d – Static frontend build for Conversion (Epsilon)
# ---------------------------------------------------------------------------
FROM node:19-bullseye AS staticbuild-conversion

WORKDIR /usr/src/mdenet-tool

COPY static.conversion/package*.json ./
COPY static.conversion .

RUN npm install; npm run build; chmod -R 755 dist/
Comment on lines +79 to +82
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

Same issue here: npm install; npm run build; ... should use && to avoid masking failures, and npm ci is preferred for reproducible builds when package-lock.json exists.

Copilot uses AI. Check for mistakes.


# ---------------------------------------------------------------------------
# Stage 2e – Static frontend build for Xtext
# ---------------------------------------------------------------------------
FROM node:19-bullseye AS staticbuild-xtext

ARG TRUSTED_ORIGINS

RUN apt-get update && apt-get install -y --no-install-recommends zip
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

This apt-get install in the frontend build stage doesn't remove /var/lib/apt/lists/*, leaving cached package indexes in the layer. Add the usual cleanup to keep the build stage smaller/faster (especially useful when iterating locally).

Suggested change
RUN apt-get update && apt-get install -y --no-install-recommends zip
RUN apt-get update && apt-get install -y --no-install-recommends zip && rm -rf /var/lib/apt/lists/*

Copilot uses AI. Check for mistakes.

WORKDIR /usr/src/mdenet-tool

COPY xtext/static.xtext/package*.json ./
COPY xtext/static.xtext .

RUN npm install; npm run build; chmod -R 755 dist/
Comment on lines +96 to +99
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

Same issue here: npm install; npm run build; ... should use && to ensure failures fail the build, and prefer npm ci for lockfile installs.

Copilot uses AI. Check for mistakes.

# CORS configuration for webapp
COPY xtext/acemodebundler/web.xml /usr/src/mdenet-tool/dist/WEB-INF/web.xml

RUN sed -i "s|http://127.0.0.1:8080|$TRUSTED_ORIGINS|g" /usr/src/mdenet-tool/dist/WEB-INF/web.xml

RUN cd dist && zip -r ROOT.war .


# ---------------------------------------------------------------------------
# Stage 3a – EMF tool service
# ---------------------------------------------------------------------------
FROM nginx:1.24.0-bullseye AS toolservice-emf

# Needed to avoid prompts blocking the build process
ENV DEBIAN_FRONTEND=noninteractive

# Needed for Cloud Build
ENV PORT=80

RUN apt-get update \
&& apt-get install -y python3-minimal maven tini netcat \
&& rm -rf /var/lib/apt/lists/*

# Copy built tool and sources (only the modules required for the emf profile)
COPY --from=mavenbuilder /root/.m2 /root/.m2
COPY --from=mavenbuilder /usr/src/toolfunctions/pom.xml /toolservice/pom.xml
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.core /toolservice/com.mde-network.ep.toolfunctions.core
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.emf /toolservice/com.mde-network.ep.toolfunctions.emf
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.emffunction /toolservice/com.mde-network.ep.toolfunctions.emffunction

# Copy files for webserver
COPY static.emf/nginx.conf.template /etc/nginx.conf.template

RUN rm -r /usr/share/nginx/html/*
COPY --from=staticbuild-emf /usr/src/mdenet-tool/dist /usr/share/nginx/html

WORKDIR /toolservice

# Copy start script and make it executable
ADD static.emf/start.sh /
RUN chmod +x /start.sh

ENTRYPOINT ["/usr/bin/tini", "--", "/start.sh"]


# ---------------------------------------------------------------------------
# Stage 3b – Emfatic tool service
# ---------------------------------------------------------------------------
FROM nginx:1.24.0-bullseye AS toolservice-emfatic

ENV DEBIAN_FRONTEND=noninteractive
ENV PORT=80

RUN apt-get update \
&& apt-get install -y python3-minimal maven tini netcat \
&& rm -rf /var/lib/apt/lists/*

# Copy built tool and sources (only the modules required for the emfatic profile)
COPY --from=mavenbuilder /root/.m2 /root/.m2
COPY --from=mavenbuilder /usr/src/toolfunctions/pom.xml /toolservice/pom.xml
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.core /toolservice/com.mde-network.ep.toolfunctions.core
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.emf /toolservice/com.mde-network.ep.toolfunctions.emf
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.emfatic /toolservice/com.mde-network.ep.toolfunctions.emfatic
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.emfaticfunction /toolservice/com.mde-network.ep.toolfunctions.emfaticfunction

# Copy files for webserver
COPY static.emfatic/nginx.conf.template /etc/nginx.conf.template

RUN rm -r /usr/share/nginx/html/*
COPY --from=staticbuild-emfatic /usr/src/mdenet-tool/dist /usr/share/nginx/html

WORKDIR /toolservice

ADD static.emfatic/start.sh /
RUN chmod +x /start.sh

ENTRYPOINT ["/usr/bin/tini", "--", "/start.sh"]


# ---------------------------------------------------------------------------
# Stage 3c – OCL tool service
# ---------------------------------------------------------------------------
FROM nginx:1.24.0-bullseye AS toolservice-ocl

ENV DEBIAN_FRONTEND=noninteractive
ENV PORT=80

RUN apt-get update \
&& apt-get install -y python3-minimal openjdk-17-jdk maven tini netcat \
&& rm -rf /var/lib/apt/lists/*

# Copy built tool and sources (only the modules required for the ocl profile)
COPY --from=mavenbuilder /root/.m2 /root/.m2
COPY --from=mavenbuilder /usr/src/toolfunctions/pom.xml /toolservice/pom.xml
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.core /toolservice/com.mde-network.ep.toolfunctions.core
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.eclipseocl /toolservice/com.mde-network.ep.toolfunctions.eclipseocl
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.eclipseoclfunction /toolservice/com.mde-network.ep.toolfunctions.eclipseoclfunction

# Copy files for webserver
COPY static.ocl/nginx.conf.template /etc/nginx.conf.template

RUN rm -r /usr/share/nginx/html/*
COPY --from=staticbuild-ocl /usr/src/mdenet-tool/dist /usr/share/nginx/html

WORKDIR /toolservice

ADD static.ocl/start.sh /
RUN chmod +x /start.sh

ENTRYPOINT ["/usr/bin/tini", "--", "/start.sh"]


# ---------------------------------------------------------------------------
# Stage 3d – Conversion (Epsilon) tool service
# ---------------------------------------------------------------------------
FROM nginx:1.24.0-bullseye AS toolservice-conversion

ENV DEBIAN_FRONTEND=noninteractive
ENV PORT=80

RUN apt-get update \
&& apt-get install -y python3-minimal maven tini netcat \
&& rm -rf /var/lib/apt/lists/*

# Copy tool sources
COPY services/epsilon /toolservice

# Copy additional built tool and sources (only the modules required for the epsilon profile)
COPY --from=mavenbuilder /root/.m2 /root/.m2
COPY --from=mavenbuilder /usr/src/toolfunctions/pom.xml /toolservice-add/pom.xml
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.core /toolservice-add/com.mde-network.ep.toolfunctions.core
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.emf /toolservice-add/com.mde-network.ep.toolfunctions.emf
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.epsilon /toolservice-add/com.mde-network.ep.toolfunctions.epsilon
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.epsilonfunction /toolservice-add/com.mde-network.ep.toolfunctions.epsilonfunction

# Copy files for webserver
COPY static.conversion/nginx.conf.template /etc/nginx.conf.template

RUN rm -r /usr/share/nginx/html/*
COPY --from=staticbuild-conversion /usr/src/mdenet-tool/dist /usr/share/nginx/html

WORKDIR /toolservice

# Due to https://issues.apache.org/jira/browse/MDEP-568, m-dependency-p
# is not a practical solution for ensuring all dependencies are available.
#
# We use https://github.com/qaware/go-offline-maven-plugin instead.
RUN mvn -B de.qaware.maven:go-offline-maven-plugin:1.2.8:resolve-dependencies

ADD static.conversion/start.sh /
RUN chmod +x /start.sh

ENTRYPOINT ["/usr/bin/tini", "--", "/start.sh"]


# ---------------------------------------------------------------------------
# Stage 3e – Xtext tool service
# ---------------------------------------------------------------------------
FROM tomcat:9.0.76-jdk17-temurin AS toolservice-xtext

# See https://github.com/mdenet/educationplatform-docker/blob/main/README.md#environment-variables
ARG ES_ADDRESS
ARG ES_DEPLOY_ADDRESS

# toolservice main endpoint port
ENV TS_PORT=9000
# editor server internal port
ENV ES_PORT=10001

ENV INSTALL_DIR=/usr/local

# Paths for editor builds
ENV ES_DIR=/editorserver
ENV ES_BUILD_LOCATION=${ES_DIR}/build
ENV ES_UPLOAD_LOCATION=${ES_DIR}/uploads
ENV ES_DEPLOY_FILE_LOCATION=${CATALINA_HOME}/webapps

# The release of node to install
ENV NODE_VERSION=19.9.0
Comment on lines +278 to +279
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

NODE_VERSION=19.9.0 is an EOL Node release. Please switch to a currently supported LTS version to reduce CVE exposure and keep npm dependency installs working over time.

Copilot uses AI. Check for mistakes.

RUN apt-get update && apt-get install -y --no-install-recommends unzip zip xz-utils maven cron psmisc

Comment on lines +281 to +282
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

apt-get update && apt-get install ... in this stage doesn't clean /var/lib/apt/lists/*, which leaves package index files in the image and increases size. Consider adding the standard cleanup (and similarly remove any temporary artifacts created during Node installation) to keep the final image leaner.

Copilot uses AI. Check for mistakes.
# Install node (detect architecture for arm64/x64 compatibility)
WORKDIR $INSTALL_DIR
RUN ARCH=$(dpkg --print-architecture) \
&& if [ "$ARCH" = "arm64" ] || [ "$ARCH" = "aarch64" ]; then NODE_ARCH="linux-arm64"; else NODE_ARCH="linux-x64"; fi \
&& NODE_RELEASE="node-v${NODE_VERSION}-${NODE_ARCH}" \
&& echo "Installing ${NODE_RELEASE}" \
&& curl --output ${NODE_RELEASE}.tar.xz https://nodejs.org/download/release/v${NODE_VERSION}/${NODE_RELEASE}.tar.xz \
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

The Xtext service installs Node by downloading a tarball via curl without any integrity verification (checksum/signature). This is a supply-chain risk; prefer installing Node from a trusted distribution mechanism (OS packages/Nodesource) or verify the download using published SHASUMS before extracting.

Suggested change
&& curl --output ${NODE_RELEASE}.tar.xz https://nodejs.org/download/release/v${NODE_VERSION}/${NODE_RELEASE}.tar.xz \
&& curl -fsSL -o ${NODE_RELEASE}.tar.xz https://nodejs.org/download/release/v${NODE_VERSION}/${NODE_RELEASE}.tar.xz \
&& curl -fsSL -o SHASUMS256.txt https://nodejs.org/download/release/v${NODE_VERSION}/SHASUMS256.txt \
&& grep " ${NODE_RELEASE}.tar.xz\$" SHASUMS256.txt > SHASUMS256.txt.node \
&& sha256sum -c SHASUMS256.txt.node \

Copilot uses AI. Check for mistakes.
&& tar -xf ${NODE_RELEASE}.tar.xz \
&& ln -s ${INSTALL_DIR}/${NODE_RELEASE} ${INSTALL_DIR}/node
ENV PATH="$INSTALL_DIR/node/bin:${PATH}"

WORKDIR /usr/src/toolfunctions

# Copy built tool and sources (only the modules required for the xtext profile)
COPY --from=mavenbuilder /root/.m2 /root/.m2
COPY --from=mavenbuilder /usr/src/toolfunctions/pom.xml /toolservice/pom.xml
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.core /toolservice/com.mde-network.ep.toolfunctions.core
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.emf /toolservice/com.mde-network.ep.toolfunctions.emf
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.xtext /toolservice/com.mde-network.ep.toolfunctions.xtext
COPY --from=mavenbuilder /usr/src/toolfunctions/com.mde-network.ep.toolfunctions.xtextfunction /toolservice/com.mde-network.ep.toolfunctions.xtextfunction

COPY xtext/acemodebundler /acemodebundler
COPY xtext/editorserver ${ES_DIR}

WORKDIR /acemodebundler

RUN npm ci

WORKDIR ${ES_DIR}

RUN npm ci --omit=dev

EXPOSE ${ES_PORT}
EXPOSE ${TS_PORT}
# 8080 is the default tomcat public port
EXPOSE 8080

COPY xtext/start.sh ${ES_DIR}/start.sh
COPY xtext/cron-setup.sh ${ES_DIR}/cron-setup.sh

RUN chmod +x ${ES_DIR}/start.sh
RUN chmod +x ${ES_DIR}/cron-setup.sh

# deploy tool static files
COPY --from=staticbuild-xtext /usr/src/mdenet-tool/dist/ROOT.war ${ES_DEPLOY_FILE_LOCATION}/ROOT.war

# Cron time for scheduled stop
ENV XTEXT_ES_STOP_CRON_TIME="* 4 * * *"

# setup cron job to periodically stop the server
RUN ./cron-setup.sh

ENTRYPOINT [ "/bin/bash", "start.sh" ]
Loading