Skip to content

Added docker build and quick-start #101

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

Open
wants to merge 4 commits into
base: main
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
62 changes: 62 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Include any files or directories that you don't want to be copied to your
# container here (e.g., local build artifacts, temporary files, etc.).
#
# For more help, visit the .dockerignore file reference guide at
# https://docs.docker.com/go/build-context-dockerignore/

**/.DS_Store
**/.classpath
**/.dockerignore
**/.env
**/.factorypath
**/.git
**/.gitignore
**/.idea
**/.project
**/.sts4-cache
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/.next
**/.cache
**/*.dbmdl
**/*.jfm
**/charts
**/docker-compose*
**/compose.y*ml
**/Dockerfile*
**/secrets.dev.yaml
**/values.dev.yaml
**/vendor
LICENSE
README.md
**/*.class
**/*.iml
**/*.ipr
**/*.iws
**/*.log
**/.apt_generated
**/.gradle
**/.gradletasknamecache
**/.nb-gradle
**/.springBeans
**/build
**/dist
**/gradle-app.setting
**/nbbuild
**/nbdist
**/nbproject/private
**/target
*.ctxt
.mtj.tmp
.mvn/timing.properties
buildNumber.properties
dependency-reduced-pom.xml
hs_err_pid*
pom.xml.next
pom.xml.releaseBackup
pom.xml.tag
pom.xml.versionsBackup
release.properties
replay_pid*
30 changes: 30 additions & 0 deletions DEVELOPERS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# For developers and contributors

## Build and run locally

To build the solution, you must have a Java 1.8 JDK+FX and Apache Ant. This
can be installed by [sdkman](https://sdkman.io/) by executing `sdk env install`.
From the `server/` directory, run `ant -f mirth-build.xml -DdisableSigning=true`.

After build, run the server by invoking `server/setup/oieserver` in bash.

## Build and run with docker

```bash
# Build using docker
docker build -t oie-dev .
# Start an ephemeral image
# NOTE: All data will be deleted on stop due to --rm. Use a volume for "real" use.
docker run --rm -p 8443:8443 oie-dev
```

## Connect

Then use [Ballista](https://github.com/kayyagari/ballista) to connect to
https://localhost:8443/ and login using admin admin.

If you are using Mirth Connect Administrator Launcher, you may need to omit
`-DdisableSigning=true` to support JWS signatures and run MCAL passing `-k -d`
to make it ignore self-signed certificates. Launchers like
[Ballista](https://github.com/kayyagari/ballista) do not require signing, and
signing adds considerable time to the build process.
96 changes: 96 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# syntax=docker/dockerfile:1.7-labs
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: I think we should stay on docker/dockerfile:1

Copy link
Contributor Author

Choose a reason for hiding this comment

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

docker/dockerfile:1 doesn't support COPY --exclude=... and would thus result in increased image sizes.

Copy link
Contributor

Choose a reason for hiding this comment

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

question: Could the --exclude directives be run as rm-s in the builder stage?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You cannot run an rm in the same layer as a COPY, so the image size would still be inflated. I think the alternative here would be to add an option to mirth-server.xml to not copy them to setup.

The other options I'm disagreeing with are:

  1. Copy each item from setup by name (verbose, fragile if new item added)
  2. Copy to a third location (symlink?), then copy to final (ew for complexity)
  3. Take the hit on layer-size (48 MB)
  4. ADD with special tar (ew for time/space and general disgust)

I generally agree with the advice to stay on docker/dockerfile:1, but --exclude is fairly well supported by this point, and should get taken out of labs soon.

Copy link
Contributor

@kpalang kpalang Jul 7, 2025

Choose a reason for hiding this comment

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

Out of curiosity since I don't currently have the means to test this, but when doing a multi-stage build with a COPY --from, will the layers from the first stage be included in the second stage or is there any squashing action going on?


# Stages:
# 1. Builder Stage: Compiles the application and resolves dependencies. Produces
# JAR files that can be deployed.
# 1a. Install dependencies
# 1b. Build the application
# 2. Runner Stage: Creates a lightweight image that runs the application using the JRE.

FROM ubuntu:noble-20250415.1 AS builder
WORKDIR /app
# sdkman requires bash
SHELL ["/bin/bash", "-c"]

# Stage 1a: Install dependencies
# Install necessary tools
COPY .sdkmanrc .
RUN apt-get update\
&& apt-get install -y zip curl\
&& curl -s "https://get.sdkman.io?ci=true" | bash \
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need SDKMan and not just an ubuntu jdk image?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think either is acceptable, and avoiding sdkman would certainly make the dockerfile simpler. I think I went this route because the zulu jdk image does not contain ant, so I had to pull additional packages regardless.

I'll see what that would look like.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See mgaffigan@123bbe2 for changes to avoid sdkman. Problems are:

  • Zulu nor Temurin seem to publish a JDK with FX included. Install from deb or tgz requires quite a few deps.
  • Ant requires separate installation
  • Docker revisions can get out of sync with .sdkmanrc

I don't love sdkman, but it does seem simpler to use it in the builder container.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with the opinion that neither of the two options are perfect. Using a jdk image can easily drift with our preferred version from .sdkmanrc, and installing sdkman in a container is just nasty.

But in this case installing sdkman in the container is the better way to go to ensure as identical as possible envs.

Zulu nor Temurin seem to publish a JDK with FX included. Install from deb or tgz requires quite a few deps.

I'm not sure this is true. the 8.0.442.fx-zulu specified in .sdkmanrc is one example of that. Unless you're talking about Docker images.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm referring to docker images. Azul and Temurin publish tgz of JavaFX, but they do not provide pre-built images. See mgaffigan@123bbe2 for the changes to install from tgz rather than sdkman.

Copy link
Contributor

Choose a reason for hiding this comment

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

nitpick: Downloading and executing arbitrary scripts is not good practice. The correct way should be to download the binaries from GH and set them up ourselves, but it quite big hassle and I've never completed it, so might be good enough for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure I see the difference between using sdkman and installing sdkman - since they both download and run untrusted scripts.

If we were aiming for zero-trust, then we would need to shift to installing from tgz and add hash verifications. sdkman is fundamentally opposed to that. Practically, I would recommend separately maintaining and publishing a javafx container then basing this file on that.

Copy link
Contributor

Choose a reason for hiding this comment

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

In my mind the difference is that we have no control over the script being downloaded from https://get.sdkman.io. It carries the risks of DNS poisoning (although highly unlikely), and malicious changes by sdkman maintainers themselves - also highly unlikely given their size. But then again, xz was even larger.

What I'm saying is this is something we should keep in mind. I don't have a viable alternative right now.

&& source "$HOME/.sdkman/bin/sdkman-init.sh" && sdk env install \
&& rm -rf /var/lib/apt/lists/*

# Stage 1b: Build the application
# Copy the entire source tree (excluding .dockerignore files), and build
COPY --exclude=docker . .
WORKDIR /app/server
RUN source "$HOME/.sdkman/bin/sdkman-init.sh" \
&& ANT_OPTS="-Dfile.encoding=UTF8" ant -f mirth-build.xml -DdisableSigning=true

##########################################
#
# Ubuntu JDK Image
#
##########################################

FROM eclipse-temurin:21.0.7_6-jdk-noble as jdk-run

RUN groupadd engine \
&& usermod -l engine ubuntu \
&& adduser engine engine \
&& mkdir -p /opt/engine/appdata \
&& chown -R engine:engine /opt/engine

WORKDIR /opt/engine
COPY --chown=engine:engine --from=builder \
--exclude=cli-lib \
--exclude=mirth-cli-launcher.jar \
--exclude=mccommand \
--exclude=manager-lib \
--exclude=mirth-manager-launcher.jar \
--exclude=mcmanager \
/app/server/setup ./

VOLUME /opt/engine/appdata
VOLUME /opt/engine/custom-extensions
EXPOSE 8443

USER engine
ENTRYPOINT ["./configure-from-env.sh"]
CMD ["./oieserver"]

##########################################
#
# Alpine JRE Image
#
##########################################

FROM eclipse-temurin:21.0.7_6-jre-alpine as jre-run

# Alpine does not include bash by default, so we install it
RUN apk add --no-cache bash
# useradd and groupadd are not available in Alpine
RUN addgroup -S engine \
&& adduser -S -g engine engine \
&& mkdir -p /opt/engine/appdata \
&& chown -R engine:engine /opt/engine

WORKDIR /opt/engine
COPY --chown=engine:engine --from=builder \
--exclude=cli-lib \
--exclude=mirth-cli-launcher.jar \
--exclude=mccommand \
--exclude=manager-lib \
--exclude=mirth-manager-launcher.jar \
--exclude=mcmanager \
/app/server/setup ./

VOLUME /opt/engine/appdata
VOLUME /opt/engine/custom-extensions

EXPOSE 8443

USER engine
ENTRYPOINT ["./configure-from-env.sh"]
CMD ["./oieserver"]
Comment on lines +31 to +96
Copy link
Contributor

Choose a reason for hiding this comment

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

question: These images have been moved to engine-docker and will be built with OpenIntegrationEngine/engine-docker#1. Would it be reasonable to edit the Dockerfile in this repo to be a build/local container only?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you clarify what you are suggesting be removed? I think it is useful to be able to do a local build of ubuntu or alpine, since those are the release environments and would thus both be needed for testing.

Loading